{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:28:02.741102Z","iopub.execute_input":"2025-05-24T01:28:02.741474Z","iopub.status.idle":"2025-05-24T01:28:38.297821Z","shell.execute_reply.started":"2025-05-24T01:28:02.741422Z","shell.execute_reply":"2025-05-24T01:28:38.296589Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Data Acquisition and Exploration","metadata":{}},{"cell_type":"markdown","source":" ### Import libraries:","metadata":{}},{"cell_type":"code","source":"pip install numpy librosa soundfile torch torchaudio tensorflow tensorflow-io audiomentations","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:05:28.473412Z","iopub.execute_input":"2025-05-24T02:05:28.473865Z","iopub.status.idle":"2025-05-24T02:05:34.562910Z","shell.execute_reply.started":"2025-05-24T02:05:28.473834Z","shell.execute_reply":"2025-05-24T02:05:34.561668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport librosa\nimport librosa.display\nimport matplotlib.pyplot as plt\nimport IPython.display as ipd\nfrom sklearn.model_selection import train_test_split\nfrom tqdm.notebook import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:30:37.696068Z","iopub.execute_input":"2025-05-24T01:30:37.696417Z","iopub.status.idle":"2025-05-24T01:30:37.701175Z","shell.execute_reply.started":"2025-05-24T01:30:37.696391Z","shell.execute_reply":"2025-05-24T01:30:37.700107Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 1. Data Acquisition ","metadata":{"execution":{"iopub.status.busy":"2025-04-07T06:58:55.151634Z","iopub.execute_input":"2025-04-07T06:58:55.152005Z","iopub.status.idle":"2025-04-07T06:59:11.309254Z","shell.execute_reply.started":"2025-04-07T06:58:55.151973Z","shell.execute_reply":"2025-04-07T06:59:11.308167Z"}}},{"cell_type":"code","source":"DATA_ROOT = \"birdclef-2025\" \nTRAIN_METADATA_PATH = os.path.join(DATA_ROOT, \"train_metadata.csv\")\nTRAIN_AUDIO_DIR = os.path.join(DATA_ROOT, \"train_audio\")\n\n# Load the training metadata\ntry:\n    train_df = pd.read_csv(\"/kaggle/input/birdclef-2025/train.csv\")\n    print(\"Training metadata loaded successfully.\")\n    print(f\"Number of training examples: {len(train_df)}\")\nexcept FileNotFoundError:\n    print(f\"Error: Training metadata file not found at {TRAIN_METADATA_PATH}. \"\n          \"Please ensure the dataset is downloaded and the path is correct.\")\n    train_df = None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:30:51.925843Z","iopub.execute_input":"2025-05-24T01:30:51.926144Z","iopub.status.idle":"2025-05-24T01:30:52.123811Z","shell.execute_reply.started":"2025-05-24T01:30:51.926121Z","shell.execute_reply":"2025-05-24T01:30:52.122660Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 2. Data Exploration","metadata":{}},{"cell_type":"code","source":"if train_df is not None:\n    print(\"\\n--- Basic Information about the Training Data ---\")\n    print(train_df.head())\n    print(train_df.info())\n    print(train_df.describe())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:31:04.295920Z","iopub.execute_input":"2025-05-24T01:31:04.296285Z","iopub.status.idle":"2025-05-24T01:31:04.368740Z","shell.execute_reply.started":"2025-05-24T01:31:04.296250Z","shell.execute_reply":"2025-05-24T01:31:04.367715Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Explore Target Variable (Species)","metadata":{}},{"cell_type":"code","source":"    print(\"\\n--- Exploring the Target Variable (Species) ---\")\n    print(f\"Number of unique bird species: {train_df['primary_label'].nunique()}\")\n    species_counts = train_df['primary_label'].value_counts().sort_values(ascending=False)\n    print(\"\\nTop 10 most frequent species:\\n\", species_counts.head(10))\n\n    # Plot the distribution of the top N species\n    top_n = 20\n    plt.figure(figsize=(12, 6))\n    species_counts.head(top_n).plot(kind='bar')\n    plt.title(f\"Distribution of Top {top_n} Bird Species\")\n    plt.xlabel(\"Bird Species\")\n    plt.ylabel(\"Number of Recordings\")\n    plt.xticks(rotation=45, ha='right')\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:31:10.445682Z","iopub.execute_input":"2025-05-24T01:31:10.446013Z","iopub.status.idle":"2025-05-24T01:31:10.918289Z","shell.execute_reply.started":"2025-05-24T01:31:10.445987Z","shell.execute_reply":"2025-05-24T01:31:10.917162Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Explore Audio Files","metadata":{}},{"cell_type":"code","source":"    print(\"\\n--- Exploring Audio Files ---\")\n\n    # Example: Load and listen to a random audio file\n    random_audio_path = os.path.join(\"/kaggle/input/birdclef-2025/train.csv\",\n                                     train_df.sample(1)['primary_label'].iloc[0],\n                                     train_df.sample(1)['filename'].iloc[0])\n    print(f\"Loading and playing: {random_audio_path}\")\n    try:\n        audio, sr = librosa.load(\"/kaggle/input/birdclef-2025/train_audio/greani1/XC132190.ogg\", sr=None)  # Load with original sampling rate\n        print(f\"Shape of audio: {audio.shape}\")\n        print(f\"Sampling rate: {sr} Hz\")\n        ipd.display(ipd.Audio(audio, rate=sr))\n\n        # Visualize the waveform\n        plt.figure(figsize=(10, 4))\n        librosa.display.waveshow(audio, sr=sr)\n        plt.title(\"Waveform\")\n        plt.xlabel(\"Time (s)\")\n        plt.ylabel(\"Amplitude\")\n        plt.tight_layout()\n        plt.show()\n\n        # Visualize the spectrogram\n        n_fft = 2048\n        hop_length = 512\n        stft_result = librosa.stft(audio, n_fft=n_fft, hop_length=hop_length)\n        spectrogram = np.abs(stft_result)\n        log_spectrogram = librosa.amplitude_to_db(spectrogram, ref=np.max)\n\n        plt.figure(figsize=(10, 4))\n        librosa.display.specshow(log_spectrogram, sr=sr, hop_length=hop_length, x_axis='time', y_axis='log')\n        plt.colorbar(format='%+2.0f dB')\n        plt.title(\"Spectrogram (Log Scale)\")\n        plt.tight_layout()\n        plt.show()\n\n    except FileNotFoundError:\n        print(f\"Error: Audio file not found at {random_audio_path}\")\n    except Exception as e:\n        print(f\"Error loading audio file: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:31:18.499577Z","iopub.execute_input":"2025-05-24T01:31:18.499983Z","iopub.status.idle":"2025-05-24T01:31:35.939920Z","shell.execute_reply.started":"2025-05-24T01:31:18.499951Z","shell.execute_reply":"2025-05-24T01:31:35.938831Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Explore Duration of Audio Files","metadata":{}},{"cell_type":"code","source":"    print(\"\\n--- Exploring Audio File Durations ---\")\n    durations = []\n    for index, row in tqdm(train_df.iterrows(), total=len(train_df), desc=\"Analyzing audio durations\"):\n        audio_path = os.path.join(\"/kaggle/input/birdclef-2025/train_audio/greani1\", row['primary_label'], row['filename'])\n        try:\n            audio, sr = librosa.load(\"/kaggle/input/birdclef-2025/train_audio/greani1/XC132190.ogg\", sr=None, duration=None)  # Load full duration\n            durations.append(librosa.get_duration(y=audio, sr=sr))\n        except Exception as e:\n            durations.append(np.nan)\n            print(f\"Error loading {audio_path}: {e}\")\n\n    train_df['duration'] = durations\n    print(train_df['duration'].describe())\n\n    # Plot the distribution of audio durations\n    plt.figure(figsize=(8, 6))\n    plt.hist(train_df['duration'].dropna(), bins=50, color='skyblue', edgecolor='black')\n    plt.title(\"Distribution of Audio Durations\")\n    plt.xlabel(\"Duration (seconds)\")\n    plt.ylabel(\"Frequency\")\n    plt.grid(True)\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:31:45.927997Z","iopub.execute_input":"2025-05-24T01:31:45.928384Z","iopub.status.idle":"2025-05-24T01:46:10.495492Z","shell.execute_reply.started":"2025-05-24T01:31:45.928357Z","shell.execute_reply":"2025-05-24T01:46:10.494314Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Further Exploration Ideas","metadata":{}},{"cell_type":"code","source":"    print(\"\\n--- Further Exploration Ideas ---\")\n    print(\"- Explore the 'secondary_labels' column (if present in your dataset version).\")\n    print(\"- Investigate the geographical information (latitude, longitude) if available.\")\n    print(\"- Look for any correlations between metadata features.\")\n    print(\"- Explore the test data structure (if you are participating in a competition).\")\n    print(\"Skipping data exploration due to missing training metadata.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:18.817310Z","iopub.execute_input":"2025-05-24T01:47:18.817666Z","iopub.status.idle":"2025-05-24T01:47:18.824356Z","shell.execute_reply.started":"2025-05-24T01:47:18.817642Z","shell.execute_reply":"2025-05-24T01:47:18.823350Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Audio Data Preprocessing and Feature Extraction","metadata":{}},{"cell_type":"markdown","source":"#### load_audio Function:","metadata":{}},{"cell_type":"code","source":"def load_audio(audio_path, target_sr=None, duration=None):\n    try:\n        y, sr = librosa.load(audio_path, sr=target_sr)\n        if duration is not None:\n            target_samples = int(duration * sr)\n            if len(y) < target_samples:\n                padding = target_samples - len(y)\n                y = np.pad(y, (0, padding), 'constant')\n            elif len(y) > target_samples:\n                y = y[:target_samples]\n        return y, sr\n    except Exception as e:\n        print(f\"Error loading audio file {audio_path}: {e}\")\n        return None, None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:23.096945Z","iopub.execute_input":"2025-05-24T01:47:23.097321Z","iopub.status.idle":"2025-05-24T01:47:23.103609Z","shell.execute_reply.started":"2025-05-24T01:47:23.097293Z","shell.execute_reply":"2025-05-24T01:47:23.102237Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### extract_mel_spectrogram Function:","metadata":{}},{"cell_type":"code","source":"def extract_mel_spectrogram(audio, sr, n_fft=2048, hop_length=512, n_mels=128):\n    if audio is None:\n        return None\n    mel_spectrogram = librosa.feature.melspectrogram(y=audio, sr=sr,\n                                                     n_fft=n_fft,\n                                                     hop_length=hop_length,\n                                                     n_mels=n_mels)\n    return librosa.power_to_db(mel_spectrogram, ref=np.max)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:26.902995Z","iopub.execute_input":"2025-05-24T01:47:26.903347Z","iopub.status.idle":"2025-05-24T01:47:26.908659Z","shell.execute_reply.started":"2025-05-24T01:47:26.903312Z","shell.execute_reply":"2025-05-24T01:47:26.907421Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### process_audio_file Function:","metadata":{}},{"cell_type":"code","source":"def process_audio_file(audio_path, target_sr=32000, duration=5.0,\n                       n_fft=1024, hop_length=512, n_mels=64):\n    audio, sr = load_audio(audio_path, target_sr=target_sr, duration=duration)\n    if audio is not None:\n        features = extract_mel_spectrogram(audio, sr, n_fft, hop_length, n_mels)\n        return features\n    return None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:32.228521Z","iopub.execute_input":"2025-05-24T01:47:32.229121Z","iopub.status.idle":"2025-05-24T01:47:32.236803Z","shell.execute_reply.started":"2025-05-24T01:47:32.229056Z","shell.execute_reply":"2025-05-24T01:47:32.235126Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### process_directory Function:","metadata":{}},{"cell_type":"code","source":"def process_directory(audio_dir, output_dir, target_sr=32000, duration=5.0,\n                      n_fft=1024, hop_length=512, n_mels=64):\n    os.makedirs(output_dir, exist_ok=True)\n    for filename in os.listdir(audio_dir):\n        if filename.endswith(('.wav', '.ogg', '.flac', '.mp3')):  # Add more extensions if needed\n            audio_path = os.path.join(audio_dir, filename)\n            features = process_audio_file(audio_path, target_sr, duration,\n                                          n_fft, hop_length, n_mels)\n            if features is not None:\n                name, ext = os.path.splitext(filename)\n                output_path = os.path.join(output_dir, f\"{name}.npy\")\n                np.save(output_path, features)\n                print(f\"Processed and saved features for {filename} to {output_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:41.879144Z","iopub.execute_input":"2025-05-24T01:47:41.879545Z","iopub.status.idle":"2025-05-24T01:47:41.885912Z","shell.execute_reply.started":"2025-05-24T01:47:41.879509Z","shell.execute_reply":"2025-05-24T01:47:41.884817Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"####  if name == 'main': Block:","metadata":{}},{"cell_type":"code","source":"if __name__ == '__main__':\n    # Example usage:\n\n    # 1. Process a single audio file\n    audio_file_path = '/kaggle/input/birdclef-2025/train_audio/greani1/XC132190.ogg'  # Replace with the actual path\n    mel_spectrogram = process_audio_file(audio_file_path)\n    if mel_spectrogram is not None:\n        print(\"Mel spectrogram shape for single file:\", mel_spectrogram.shape)\n        # You can now use this 'mel_spectrogram' for further tasks\n\n    # 2. Process all audio files in a directory\n    audio_directory = '/kaggle/input/birdclef-2025/train_audio/'  # Replace with the actual path to your audio directory\n    output_directory = '/kaggle/input/birdclef-2025/train_audio/'  # Replace with the desired output directory\n    process_directory(audio_directory, output_directory)\n    print(f\"Processed all audio files in {audio_directory} and saved features to {output_directory}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:46.822936Z","iopub.execute_input":"2025-05-24T01:47:46.823338Z","iopub.status.idle":"2025-05-24T01:47:48.260197Z","shell.execute_reply.started":"2025-05-24T01:47:46.823306Z","shell.execute_reply":"2025-05-24T01:47:48.258807Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### visualize_mel_spectrogram Function:","metadata":{}},{"cell_type":"code","source":"def visualize_mel_spectrogram(mel_spectrogram_db, sr, title=\"Mel Spectrogram\"):\n    if mel_spectrogram_db is None:\n        print(\"No Mel spectrogram to visualize.\")\n        return\n\n    plt.figure(figsize=(10, 4))\n    librosa.display.specshow(mel_spectrogram_db, sr=sr, x_axis='time', y_axis='mel')\n    plt.colorbar(format='%+2.0f dB')\n    plt.title(title)\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:47:56.518219Z","iopub.execute_input":"2025-05-24T01:47:56.518808Z","iopub.status.idle":"2025-05-24T01:47:56.524579Z","shell.execute_reply.started":"2025-05-24T01:47:56.518772Z","shell.execute_reply":"2025-05-24T01:47:56.523539Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"####  visualize_features Function:","metadata":{}},{"cell_type":"code","source":"def visualize_features(mfccs, chroma, sr, title=\"Audio Features\"):\n    if mfccs is None or chroma is None:\n        print(\"No features to visualize.\")\n        return\n\n    plt.figure(figsize=(12, 6))\n    plt.suptitle(title)\n\n    plt.subplot(2, 1, 1)\n    librosa.display.specshow(mfccs, sr=sr, x_axis='time')\n    plt.colorbar(format='%+2.0f dB')\n    plt.title('MFCCs')\n\n    plt.subplot(2, 1, 2)\n    librosa.display.specshow(chroma, sr=sr, x_axis='time', y_axis='chroma', vmin=0, vmax=1)\n    plt.colorbar()\n    plt.title('Chroma Features')\n    plt.tight_layout(rect=[0, 0.03, 1, 0.95])  # Adjust layout to make space for suptitle\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:48:02.228625Z","iopub.execute_input":"2025-05-24T01:48:02.229175Z","iopub.status.idle":"2025-05-24T01:48:02.238000Z","shell.execute_reply.started":"2025-05-24T01:48:02.229123Z","shell.execute_reply":"2025-05-24T01:48:02.236561Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### extract_features Function:","metadata":{}},{"cell_type":"code","source":"def extract_features(audio_path, target_sr=None, duration=None, n_fft=2048, hop_length=512, n_mfcc=20, n_chroma=12):\n    try:\n        y, sr = librosa.load(audio_path, sr=target_sr, duration=duration)\n\n        # Extract MFCCs\n        mfccs = librosa.feature.mfcc(y=y, sr=sr, n_fft=n_fft, hop_length=hop_length, n_mfcc=n_mfcc)\n\n        # Extract Chroma features\n        chroma = librosa.feature.chroma_stft(y=y, sr=sr, n_fft=n_fft, hop_length=hop_length, n_chroma=n_chroma)\n\n        return mfccs, chroma, sr\n\n    except Exception as e:\n        print(f\"Error processing audio file {audio_path}: {e}\")\n        return None, None, None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:48:06.057962Z","iopub.execute_input":"2025-05-24T01:48:06.058297Z","iopub.status.idle":"2025-05-24T01:48:06.064515Z","shell.execute_reply.started":"2025-05-24T01:48:06.058270Z","shell.execute_reply":"2025-05-24T01:48:06.063295Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### if name == 'main': Block","metadata":{}},{"cell_type":"code","source":"if __name__ == '__main__':\n    audio_file = '/kaggle/input/birdclef-2025/train_audio/greani1/XC556246.ogg'  # Replace with the actual path to your audio file\n\n    mfccs, chroma, sr = extract_features(audio_file, target_sr=32000, duration=5.0, n_mfcc=20, n_chroma=12)\n\n    if mfccs is not None and chroma is not None:\n        print(\"Shape of MFCCs:\", mfccs.shape)\n        print(\"Shape of Chroma features:\", chroma.shape)\n        print(\"Sampling rate:\", sr)\n\n        visualize_features(mfccs, chroma, sr, title=f\"Features for {audio_file}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T01:48:12.588004Z","iopub.execute_input":"2025-05-24T01:48:12.588335Z","iopub.status.idle":"2025-05-24T01:48:13.578534Z","shell.execute_reply.started":"2025-05-24T01:48:12.588309Z","shell.execute_reply":"2025-05-24T01:48:13.577310Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Addressing Limited Training Data","metadata":{}},{"cell_type":"markdown","source":"#### Data Augmentation Techniques","metadata":{}},{"cell_type":"code","source":"pip install --upgrade audiomentations","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:11:39.138052Z","iopub.execute_input":"2025-05-24T02:11:39.138473Z","iopub.status.idle":"2025-05-24T02:11:43.550478Z","shell.execute_reply.started":"2025-05-24T02:11:39.138426Z","shell.execute_reply":"2025-05-24T02:11:43.549161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport librosa\nimport soundfile as sf\nimport torch\nimport torchaudio\nimport torchaudio.transforms as T\nimport tensorflow as tf\nimport tensorflow_io as tfio\n#from audiomentations import Compose, AddGaussianNoise, PitchShift, TimeStretch, Shift, Gain, SpecAugment\n#from audiomentations import Compose, AddGaussianNoise, PitchShift, TimeStretch, Shift, Gain, FrequencyMask, TimeMask\nfrom audiomentations import Compose, AddGaussianNoise, PitchShift, TimeStretch, Shift, Gain # waveform transforms\nimport random\nimport matplotlib.pyplot as plt\nimport os","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:15:14.057982Z","iopub.execute_input":"2025-05-24T02:15:14.058414Z","iopub.status.idle":"2025-05-24T02:15:14.063833Z","shell.execute_reply.started":"2025-05-24T02:15:14.058386Z","shell.execute_reply":"2025-05-24T02:15:14.062708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Configuration (Adjust as needed) ---\nSAMPLE_RATE = 32000  # BirdCLEF datasets often use 32kHz or higher\nDURATION = 5       # Standard clip duration (e.g., 5 seconds for BirdCLEF segments)\nN_MELS = 128       # Number of mel bins for spectrograms\nN_FFT = 2048       # FFT window size\nHOP_LENGTH = 512   # Hop length for STFT","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:17:07.476713Z","iopub.execute_input":"2025-05-24T02:17:07.477110Z","iopub.status.idle":"2025-05-24T02:17:07.482076Z","shell.execute_reply.started":"2025-05-24T02:17:07.477085Z","shell.execute_reply":"2025-05-24T02:17:07.480760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_audio(file_path, sr=SAMPLE_RATE, duration=DURATION):\n    \"\"\"Loads an audio file and resamples/pads/trims it to a target duration.\"\"\"\n    try:\n        y, current_sr = librosa.load(file_path, sr=None)\n        if current_sr != sr:\n            y = librosa.resample(y, orig_sr=current_sr, target_sr=sr)\n\n        # Pad or trim to desired duration\n        target_samples = int(duration * sr)\n        if len(y) < target_samples:\n            y = np.pad(y, (0, target_samples - len(y)), 'constant')\n        elif len(y) > target_samples:\n            y = y[:target_samples]\n        return y, sr\n    except Exception as e:\n        print(f\"Error loading audio {file_path}: {e}\")\n        return None, None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:17:36.747394Z","iopub.execute_input":"2025-05-24T02:17:36.747923Z","iopub.status.idle":"2025-05-24T02:17:36.754624Z","shell.execute_reply.started":"2025-05-24T02:17:36.747883Z","shell.execute_reply":"2025-05-24T02:17:36.753402Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Augmentation Functions (using librosa/numpy for waveform processing) ---\n\ndef time_stretch_audio(audio, sr, rate_range=(0.8, 1.2)):\n    rate = random.uniform(*rate_range)\n    # librosa.effects.time_stretch resamples, so target_sr is the original sr\n    return librosa.effects.time_stretch(audio, rate=rate)\n\ndef pitch_shift_audio(audio, sr, n_steps_range=(-2, 2)):\n    n_steps = random.uniform(*n_steps_range)\n    return librosa.effects.pitch_shift(audio, sr=sr, n_steps=n_steps)\n\ndef add_noise_audio(audio, noise_audio=None, snr_db_range=(3, 30)):\n    target_snr_db = random.uniform(*snr_db_range)\n\n    if noise_audio is None:\n        # Generate Gaussian noise\n        noise = np.random.randn(len(audio))\n    else:\n        # Use provided noise, pad/trim to match audio length\n        if len(noise_audio) < len(audio):\n            noise = np.pad(noise_audio, (0, len(audio) - len(noise_audio)), 'wrap') # Use wrap for continuous noise\n        else:\n            noise = noise_audio[:len(audio)]\n\n    # Calculate signal and noise power\n    P_signal = np.mean(audio**2)\n    P_noise = np.mean(noise**2)\n\n    # Calculate desired noise power for target SNR\n    target_P_noise = P_signal / (10**(target_snr_db / 10))\n\n    # Scale noise to desired power\n    scaled_noise = noise * np.sqrt(target_P_noise / P_noise)\n\n    return audio + scaled_noise\n\ndef time_shift_audio(audio, sr, shift_range=(-0.5, 0.5)):\n    shift_seconds = random.uniform(*shift_range)\n    shift_samples = int(shift_seconds * sr)\n    \n    # Use np.roll for circular shift, effectively moving parts from one end to the other\n    return np.roll(audio, shift_samples)\n\ndef volume_adjustment_audio(audio, gain_db_range=(-6, 6)):\n    gain_db = random.uniform(*gain_db_range)\n    gain_amplitude = 10**(gain_db / 20) # Convert dB to amplitude multiplier\n    return audio * gain_amplitude","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:18:59.707298Z","iopub.execute_input":"2025-05-24T02:18:59.707712Z","iopub.status.idle":"2025-05-24T02:18:59.717328Z","shell.execute_reply.started":"2025-05-24T02:18:59.707682Z","shell.execute_reply":"2025-05-24T02:18:59.716294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Spectrogram-based Augmentations (SpecAugment) ---\n\ndef apply_spec_augment(mel_spectrogram, time_mask_param=40, freq_mask_param=20, num_time_masks=1, num_freq_masks=1):\n    if isinstance(mel_spectrogram, np.ndarray):\n        # Convert to torch tensor for torchaudio's SpecAugment\n        mel_spectrogram_tensor = torch.from_numpy(mel_spectrogram).unsqueeze(0) # Add batch dimension\n    else:\n        mel_spectrogram_tensor = mel_spectrogram\n\n    augmented_spec = mel_spectrogram_tensor.clone() # Work on a copy\n\n    # Time Masking\n    for _ in range(num_time_masks):\n        mask_length = random.randint(0, time_mask_param)\n        mask_start = random.randint(0, augmented_spec.shape[-1] - mask_length)\n        augmented_spec[:, :, mask_start:mask_start + mask_length] = 0.0\n\n    # Frequency Masking\n    for _ in range(num_freq_masks):\n        mask_length = random.randint(0, freq_mask_param)\n        mask_start = random.randint(0, augmented_spec.shape[-2] - mask_length)\n        augmented_spec[:, mask_start:mask_start + mask_length, :] = 0.0\n\n    if isinstance(mel_spectrogram, np.ndarray):\n        return augmented_spec.squeeze(0).numpy() # Remove batch dimension and convert back\n    else:\n        return augmented_spec","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:19:28.192360Z","iopub.execute_input":"2025-05-24T02:19:28.192772Z","iopub.status.idle":"2025-05-24T02:19:28.199844Z","shell.execute_reply.started":"2025-05-24T02:19:28.192741Z","shell.execute_reply":"2025-05-24T02:19:28.198689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Mixup ---\n\ndef mixup_spectrograms(spec1, label1, spec2, label2, alpha=0.2):\n    lam = np.random.beta(alpha, alpha) # Lambda from Beta distribution\n    mixed_spec = lam * spec1 + (1 - lam) * spec2\n    mixed_label = lam * label1 + (1 - lam) * label2\n    return mixed_spec, mixed_label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:20:16.602332Z","iopub.execute_input":"2025-05-24T02:20:16.602728Z","iopub.status.idle":"2025-05-24T02:20:16.607841Z","shell.execute_reply.started":"2025-05-24T02:20:16.602698Z","shell.execute_reply":"2025-05-24T02:20:16.606630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Example Usage with a Dummy BirdCLEF-like Dataset Structure ---\n\nclass BirdCLEFAudioDataset:\n    def __init__(self, audio_files, labels, sr=SAMPLE_RATE, duration=DURATION):\n        self.audio_files = audio_files\n        self.labels = labels\n        self.sr = sr\n        self.duration = duration\n        self.noise_pool = self._load_noise_samples(sr=sr) # Load some background noise\n\n    def _load_noise_samples(self, noise_dir=\"noise_samples\", sr=SAMPLE_RATE):\n        \"\"\"Loads a few noise samples from a directory for background noise augmentation.\"\"\"\n        noise_samples = []\n        if os.path.exists(noise_dir):\n            for fname in os.listdir(noise_dir):\n                if fname.endswith(('.wav', '.ogg', '.flac')):\n                    noise_path = os.path.join(noise_dir, fname)\n                    try:\n                        noise, _ = librosa.load(noise_path, sr=sr)\n                        noise_samples.append(noise)\n                    except Exception as e:\n                        print(f\"Warning: Could not load noise file {noise_path}: {e}\")\n        print(f\"Loaded {len(noise_samples)} noise samples from {noise_dir}\")\n        return noise_samples\n\n    def __len__(self):\n        return len(self.audio_files)\n\n    def __getitem__(self, idx):\n        file_path = self.audio_files[idx]\n        label = self.labels[idx]\n\n        # Load audio (and handle resampling/padding/trimming)\n        audio, sr = load_audio(file_path, self.sr, self.duration)\n        if audio is None:\n            # Handle loading error, e.g., return a placeholder or skip\n            return np.zeros(int(self.duration * self.sr)), np.zeros_like(label) # Placeholder\n\n        # Apply augmentations with a probability\n        if random.random() < 0.7: # 70% chance to apply augmentations\n            # Randomly select a subset of augmentations or apply them sequentially\n            \n            # 1. Time Stretching\n            if random.random() < 0.5:\n                audio = time_stretch_audio(audio, sr, rate_range=(0.9, 1.1)) # Slightly less aggressive stretching\n\n            # 2. Pitch Shifting\n            if random.random() < 0.5:\n                audio = pitch_shift_audio(audio, sr, n_steps_range=(-1, 1)) # Slightly less aggressive shifting\n\n            # 3. Adding Noise\n            if random.random() < 0.6:\n                noise_audio = random.choice(self.noise_pool) if self.noise_pool else None\n                audio = add_noise_audio(audio, noise_audio=noise_audio, snr_db_range=(10, 25)) # Higher SNR means less noise\n\n            # 4. Time Shifting\n            if random.random() < 0.5:\n                audio = time_shift_audio(audio, sr, shift_range=(-0.1, 0.1)) # Small shifts\n\n            # 5. Volume Adjustment\n            if random.random() < 0.6:\n                audio = volume_adjustment_audio(audio, gain_db_range=(-4, 4))\n\n        # Convert to Mel Spectrogram\n        # For PyTorch\n        mel_spectrogram = librosa.feature.melspectrogram(y=audio, sr=sr, n_fft=N_FFT, hop_length=HOP_LENGTH, n_mels=N_MELS)\n        mel_spectrogram = librosa.power_to_db(mel_spectrogram, ref=np.max) # Convert to dB scale\n\n        # Apply SpecAugment on the spectrogram\n        if random.random() < 0.7:\n            mel_spectrogram = apply_spec_augment(\n                mel_spectrogram,\n                time_mask_param=int(mel_spectrogram.shape[1] * 0.1), # Mask up to 10% of time steps\n                freq_mask_param=int(mel_spectrogram.shape[0] * 0.1), # Mask up to 10% of freq bins\n                num_time_masks=2,\n                num_freq_masks=2\n            )\n        \n        # Mixup is usually applied at the batch level in the DataLoader\n        # For simplicity, we'll return the spectrogram and label for now.\n        return mel_spectrogram.astype(np.float32), label.astype(np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:20:55.622719Z","iopub.execute_input":"2025-05-24T02:20:55.623065Z","iopub.status.idle":"2025-05-24T02:20:55.635917Z","shell.execute_reply.started":"2025-05-24T02:20:55.623039Z","shell.execute_reply":"2025-05-24T02:20:55.634586Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Example using audiomentations (Recommended for waveform augmentations) ---\n\nclass BirdCLEFAudioDatasetAudiomentations(BirdCLEFAudioDataset):\n    def __init__(self, audio_files, labels, sr=SAMPLE_RATE, duration=DURATION):\n        super().__init__(audio_files, labels, sr, duration)\n        self.augment = Compose([\n            TimeStretch(min_rate=0.9, max_rate=1.1, p=0.5, leave_length_unchanged=True),\n            PitchShift(min_semitones=-1.0, max_semitones=1.0, p=0.5),\n            AddGaussianNoise(min_amplitude=0.001, max_amplitude=0.015, p=0.6), # Simulates moderate noise\n            Shift(min_shift=-0.1, max_shift=0.1, p=0.5),\n            Gain(min_gain_db=-4.0, max_gain_db=4.0, p=0.6),\n            # SpecAugment is applied after Mel Spectrogram conversion, not directly on waveform\n        ])\n        \n    def __getitem__(self, idx):\n        file_path = self.audio_files[idx]\n        label = self.labels[idx]\n\n        audio, sr = load_audio(file_path, self.sr, self.duration)\n        if audio is None:\n            return np.zeros(int(self.duration * self.sr)), np.zeros_like(label)\n\n        # Apply waveform augmentations\n        augmented_audio = self.augment(samples=audio, sample_rate=sr)\n\n        # Convert to Mel Spectrogram\n        mel_spectrogram = librosa.feature.melspectrogram(y=augmented_audio, sr=sr, n_fft=N_FFT, hop_length=HOP_LENGTH, n_mels=N_MELS)\n        mel_spectrogram = librosa.power_to_db(mel_spectrogram, ref=np.max) # Convert to dB scale\n\n        # Apply SpecAugment on the spectrogram\n        if random.random() < 0.7:\n            mel_spectrogram = apply_spec_augment(\n                mel_spectrogram,\n                time_mask_param=int(mel_spectrogram.shape[1] * 0.1),\n                freq_mask_param=int(mel_spectrogram.shape[0] * 0.1),\n                num_time_masks=2,\n                num_freq_masks=2\n            )\n        \n        return mel_spectrogram.astype(np.float32), label.astype(np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:25:14.266833Z","iopub.execute_input":"2025-05-24T02:25:14.267244Z","iopub.status.idle":"2025-05-24T02:25:14.276230Z","shell.execute_reply.started":"2025-05-24T02:25:14.267212Z","shell.execute_reply":"2025-05-24T02:25:14.274995Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Dummy Data Setup (replace with your actual BirdCLEF data loading) ---\n\n# Create dummy audio files and labels for demonstration\ndummy_audio_dir = \"dummy_birdclef_audio\"\nnoise_samples_dir = \"noise_samples\"\nos.makedirs(dummy_audio_dir, exist_ok=True)\nos.makedirs(noise_samples_dir, exist_ok=True)\n\ndummy_labels = []\ndummy_audio_paths = []\nnum_classes = 10\nnum_samples_per_class = 5\ntotal_samples = num_classes * num_samples_per_class\n\nprint(\"Generating dummy audio and noise files...\")\nfor i in range(total_samples):\n    dummy_file = os.path.join(dummy_audio_dir, f\"audio_{i:03d}.wav\")\n    y_dummy = np.random.randn(int(SAMPLE_RATE * DURATION)).astype(np.float32) * 0.5 # Random noise for dummy audio\n    sf.write(dummy_file, y_dummy, SAMPLE_RATE)\n    dummy_audio_paths.append(dummy_file)\n    \n    one_hot_label = np.zeros(num_classes)\n    one_hot_label[i % num_classes] = 1 # Simple dummy one-hot label\n    dummy_labels.append(one_hot_label)\n\n# Create dummy noise files\nfor i in range(3):\n    noise_file = os.path.join(noise_samples_dir, f\"noise_{i}.wav\")\n    y_noise = np.random.randn(int(SAMPLE_RATE * DURATION * 2)).astype(np.float32) * 0.1 # Longer noise\n    sf.write(noise_file, y_noise, SAMPLE_RATE)\n\nprint(\"Dummy data generation complete.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:25:19.116355Z","iopub.execute_input":"2025-05-24T02:25:19.116723Z","iopub.status.idle":"2025-05-24T02:25:19.898002Z","shell.execute_reply.started":"2025-05-24T02:25:19.116697Z","shell.execute_reply":"2025-05-24T02:25:19.897025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- How to integrate into your training loop (PyTorch example) ---\n\n# 1. Create your dataset instance\n# dataset = BirdCLEFAudioDataset(dummy_audio_paths, dummy_labels)\ndataset = BirdCLEFAudioDatasetAudiomentations(dummy_audio_paths, dummy_labels) # Using audiomentations\n\n# 2. Create a DataLoader (for batching and shuffling)\nfrom torch.utils.data import DataLoader\n\n# A custom collate_fn is often needed for audio, especially if lengths vary slightly\n# or if you plan to do mixup at the batch level.\ndef collate_fn_spectrogram(batch):\n    # batch is a list of (spectrogram, label) tuples\n    spectrograms = torch.stack([torch.from_numpy(item[0]) for item in batch])\n    labels = torch.stack([torch.from_numpy(item[1]) for item in batch])\n    return spectrograms, labels\n\ndataloader = DataLoader(dataset, batch_size=4, shuffle=True, collate_fn=collate_fn_spectrogram)\n\nprint(\"\\n--- Demonstrating data augmentation with PyTorch DataLoader ---\")\nfor batch_idx, (spectrograms, labels) in enumerate(dataloader):\n    print(f\"Batch {batch_idx+1}:\")\n    print(f\"  Spectrograms shape: {spectrograms.shape}\") # (batch_size, n_mels, n_frames)\n    print(f\"  Labels shape: {labels.shape}\")             # (batch_size, num_classes)\n\n    # Optional: Visualize an augmented spectrogram\n    if batch_idx == 0:\n        plt.figure(figsize=(10, 4))\n        librosa.display.specshow(spectrograms[0].numpy(), sr=SAMPLE_RATE, x_axis='time', y_axis='mel')\n        plt.colorbar(format='%+2.0f dB')\n        plt.title('Augmented Mel Spectrogram Example')\n        plt.tight_layout()\n        plt.show()\n\n    if batch_idx == 1: # Just show a couple of batches\n        break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:25:24.796798Z","iopub.execute_input":"2025-05-24T02:25:24.797138Z","iopub.status.idle":"2025-05-24T02:25:25.870484Z","shell.execute_reply.started":"2025-05-24T02:25:24.797114Z","shell.execute_reply":"2025-05-24T02:25:25.869264Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- TensorFlow Example (Conceptual) ---\n\n# For TensorFlow, you would typically use tf.data.Dataset and `tf.py_function`\n# or `tfio.audio` for augmentations.\n# tensorflow_io provides some built-in augmentations like SpecAugment (frequency and time mask).\n\ndef preprocess_tf_audio(file_path, label):\n    audio_tensor = tfio.audio.AudioIOTensor(file_path)\n    audio = audio_tensor.to_tensor()[:, 0] # Get mono channel if stereo\n    rate = audio_tensor.rate.numpy()\n\n    # Resample/Pad/Trim (similar logic as load_audio, but with TF operations)\n    audio = tf.cast(audio, tf.float32)\n    current_length = tf.shape(audio)[0]\n    target_length = tf.cast(SAMPLE_RATE * DURATION, tf.int32)\n    if current_length < target_length:\n        padding = target_length - current_length\n        audio = tf.pad(audio, [[0, padding]], \"CONSTANT\")\n    elif current_length > target_length:\n        audio = audio[:target_length]\n\n    # Example TensorFlow augmentations\n    # Note: Waveform augmentations like time stretching/pitch shifting are more complex\n    # directly in TensorFlow's graph mode without custom ops or tf.py_function.\n    # tfio.audio provides some, but less comprehensive than librosa/audiomentations.\n    \n    # Volume Adjustment (Gain) in TensorFlow\n    gain_db = tf.random.uniform([], minval=-4.0, maxval=4.0)\n    gain_amplitude = tf.pow(10.0, gain_db / 20.0)\n    audio = audio * gain_amplitude\n\n    # Add Gaussian Noise (simple version)\n    if tf.random.uniform([]) < 0.6:\n        noise = tf.random.normal(tf.shape(audio), stddev=0.01) # Small stddev for subtle noise\n        audio = audio + noise\n\n    # Mel Spectrogram\n    stft = tf.signal.stft(audio, frame_length=N_FFT, frame_step=HOP_LENGTH)\n    spectrogram = tf.abs(stft)\n    num_spectrogram_bins = stft.shape[-1]\n    linear_to_mel_matrix = tf.signal.linear_to_mel_weight_matrix(\n        num_mel_bins=N_MELS, num_spectrogram_bins=num_spectrogram_bins,\n        sample_rate=rate, lower_edge_hertz=20.0, upper_edge_hertz=rate/2)\n    mel_spectrogram = tf.tensordot(spectrogram, linear_to_mel_matrix, 1)\n    mel_spectrogram.set_shape(spectrogram.shape[:-1].concatenate(linear_to_mel_matrix.shape[-1:]))\n    mel_spectrogram = tf.math.log(mel_spectrogram + 1e-6) # Log-scale\n\n    # SpecAugment in TensorFlow\n    if tf.random.uniform([]) < 0.7:\n        mel_spectrogram = tfio.audio.freq_mask(mel_spectrogram, param=int(N_MELS * 0.1))\n        mel_spectrogram = tfio.audio.time_mask(mel_spectrogram, param=int(mel_spectrogram.shape[1] * 0.1))\n\n    return mel_spectrogram, label\n\n# # Example of how to use with tf.data.Dataset (uncomment to run TF part)\n# print(\"\\n--- Demonstrating data augmentation with TensorFlow tf.data ---\")\n# # Assuming dummy_audio_paths and dummy_labels are populated\n# tf_dataset = tf.data.Dataset.from_tensor_slices((dummy_audio_paths, dummy_labels))\n# tf_dataset = tf_dataset.map(lambda x, y: tf.py_function(\n#     preprocess_tf_audio, [x, y], (tf.float32, tf.float32)), num_parallel_calls=tf.data.AUTOTUNE)\n# tf_dataset = tf_dataset.batch(4)\n#\n# for batch_idx, (spectrograms, labels) in enumerate(tf_dataset):\n#     print(f\"Batch {batch_idx+1}:\")\n#     print(f\"  Spectrograms shape: {spectrograms.shape}\")\n#     print(f\"  Labels shape: {labels.shape}\")\n#     if batch_idx == 0:\n#         plt.figure(figsize=(10, 4))\n#         plt.imshow(tf.transpose(spectrograms[0]).numpy(), aspect='auto', origin='lower')\n#         plt.title('Augmented Mel Spectrogram Example (TensorFlow)')\n#         plt.colorbar()\n#         plt.tight_layout()\n#         plt.show()\n#     if batch_idx == 1:\n#         break\n\nprint(\"\\nCode execution complete. Remember to replace dummy data with your actual BirdCLEF+ dataset paths and labels.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-24T02:26:02.057839Z","iopub.execute_input":"2025-05-24T02:26:02.058223Z","iopub.status.idle":"2025-05-24T02:26:02.068749Z","shell.execute_reply.started":"2025-05-24T02:26:02.058178Z","shell.execute_reply":"2025-05-24T02:26:02.067578Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}