{"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":"gpu","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **BirdCLEF 2025 Data Preprocessing Notebook**\nThis notebook is a copy of https://www.kaggle.com/code/kadircandrisolu/transforming-audio-to-mel-spec-birdclef-25.\n","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nimport math\nimport time\nimport librosa\nimport pandas as pd\nimport numpy as np\nfrom tqdm.notebook import tqdm\n\nimport torch\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:21.467794Z","iopub.execute_input":"2025-05-08T06:09:21.468061Z","iopub.status.idle":"2025-05-08T06:09:26.672800Z","shell.execute_reply.started":"2025-05-08T06:09:21.468040Z","shell.execute_reply":"2025-05-08T06:09:26.672048Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n \n    DEBUG_MODE = False\n    \n    OUTPUT_DIR = '/kaggle/working/'\n    DATA_ROOT = '/kaggle/input/birdclef-2025'\n    PSUEDO_DATA_ROOT = ''\n    FS = 32000\n    \n    # Mel spectrogram parameters\n    N_FFT = 2048\n    HOP_LENGTH = 512\n    WIN_LENGTH = 2048\n    N_MELS = 224\n    FMIN = 50\n    FMAX = 14000\n    \n    TARGET_DURATION = 5.0\n    TARGET_SHAPE = (224, 224)  \n    \n    N_MAX = 50 if DEBUG_MODE else None  \n\nconfig = Config()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:30.363288Z","iopub.execute_input":"2025-05-08T06:09:30.363731Z","iopub.status.idle":"2025-05-08T06:09:30.368462Z","shell.execute_reply.started":"2025-05-08T06:09:30.363704Z","shell.execute_reply":"2025-05-08T06:09:30.367540Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Debug mode: {'ON' if config.DEBUG_MODE else 'OFF'}\")\nprint(f\"Max samples to process: {config.N_MAX if config.N_MAX is not None else 'ALL'}\")\n\nprint(\"Loading taxonomy data...\")\ntaxonomy_df = pd.read_csv(f'{config.DATA_ROOT}/taxonomy.csv')\nspecies_class_map = dict(zip(taxonomy_df['primary_label'], taxonomy_df['class_name']))\n\nprint(\"Loading training metadata...\")\ntrain_df = pd.read_csv(f'{config.DATA_ROOT}/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:34.968035Z","iopub.execute_input":"2025-05-08T06:09:34.968382Z","iopub.status.idle":"2025-05-08T06:09:35.141740Z","shell.execute_reply.started":"2025-05-08T06:09:34.968355Z","shell.execute_reply":"2025-05-08T06:09:35.140920Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_list = sorted(train_df['primary_label'].unique())\nlabel_id_list = list(range(len(label_list)))\nlabel2id = dict(zip(label_list, label_id_list))\nid2label = dict(zip(label_id_list, label_list))\n\nprint(f'Found {len(label_list)} unique species')\nworking_df = train_df[['primary_label', 'rating', 'filename']].copy()\nworking_df['target'] = working_df.primary_label.map(label2id)\nworking_df['filepath'] = config.DATA_ROOT + '/train_audio/' + working_df.filename\nworking_df['samplename'] = working_df.filename.map(lambda x: x.split('/')[0] + '-' + x.split('/')[-1].split('.')[0])\nworking_df['class'] = working_df.primary_label.map(lambda x: species_class_map.get(x, 'Unknown'))\ntotal_samples = min(len(working_df), config.N_MAX or len(working_df))\nprint(f'Total samples to process: {total_samples} out of {len(working_df)} available')\nprint(f'Samples by class:')\nprint(working_df['class'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:37.485951Z","iopub.execute_input":"2025-05-08T06:09:37.486256Z","iopub.status.idle":"2025-05-08T06:09:37.551935Z","shell.execute_reply.started":"2025-05-08T06:09:37.486213Z","shell.execute_reply":"2025-05-08T06:09:37.551077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def audio2melspec(audio_data):\n    if np.isnan(audio_data).any():\n        mean_signal = np.nanmean(audio_data)\n        audio_data = np.nan_to_num(audio_data, nan=mean_signal)\n\n    mel_spec = librosa.feature.melspectrogram(\n        y=audio_data,\n        sr=config.FS,\n        n_fft=config.N_FFT,\n        hop_length=config.HOP_LENGTH,\n        n_mels=config.N_MELS,\n        fmin=config.FMIN,\n        fmax=config.FMAX,\n        power=2.0,\n        center=True,\n        pad_mode=\"reflect\",\n        norm='slaney',\n        htk=True,\n    )\n\n    mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n    mel_spec_norm = (mel_spec_db - mel_spec_db.min()) / (mel_spec_db.max() - mel_spec_db.min() + 1e-8)\n    \n    return mel_spec_norm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:40.462035Z","iopub.execute_input":"2025-05-08T06:09:40.462339Z","iopub.status.idle":"2025-05-08T06:09:40.467637Z","shell.execute_reply.started":"2025-05-08T06:09:40.462317Z","shell.execute_reply":"2025-05-08T06:09:40.466828Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.set_num_threads(1)\nmodel, (get_speech_timestamps, _, read_audio, _, _) = torch.hub.load(repo_or_dir='snakers4/silero-vad', model='silero_vad')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:43.453467Z","iopub.execute_input":"2025-05-08T06:09:43.453933Z","iopub.status.idle":"2025-05-08T06:09:45.352987Z","shell.execute_reply.started":"2025-05-08T06:09:43.453893Z","shell.execute_reply":"2025-05-08T06:09:45.352083Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Starting audio processing...\")\nprint(f\"{'DEBUG MODE - Processing only 50 samples' if config.DEBUG_MODE else 'FULL MODE - Processing all samples'}\")\nstart_time = time.time()\n\nall_bird_data = {}\nerrors = []\n\nfor i, row in tqdm(working_df.iterrows(), total=total_samples):\n    if config.N_MAX is not None and i >= config.N_MAX:\n        break\n    \n    try:\n        audio_data, _ = librosa.load(row.filepath, sr=config.FS)\n        \n        target_samples = int(config.TARGET_DURATION * config.FS)\n\n        if len(audio_data) < target_samples:\n            n_copy = math.ceil(target_samples / len(audio_data))\n            if n_copy > 1:\n                audio_data = np.concatenate([audio_data] * n_copy)\n\n        start_idx = max(0, int(len(audio_data) / 2 - target_samples / 2))\n        end_idx = min(len(audio_data), start_idx + target_samples)\n        center_audio = audio_data[start_idx:end_idx]\n\n        if len(center_audio) < target_samples:\n            center_audio = np.pad(center_audio, \n                                 (0, target_samples - len(center_audio)), \n                                 mode='constant')\n        \n        speech_timestamps = get_speech_timestamps(torch.Tensor(center_audio), model, threshold=0.4)\n        total_speech = 0;\n        #print(speech_timestamps)\n        for segment in speech_timestamps:\n            total_speech += segment['end'] - segment['start']\n\n        if total_speech / len(center_audio) > 0.5:\n            continue;\n        mel_spec = audio2melspec(center_audio)\n\n        if mel_spec.shape != config.TARGET_SHAPE:\n            mel_spec = cv2.resize(mel_spec, config.TARGET_SHAPE, interpolation=cv2.INTER_LINEAR)\n\n        all_bird_data[row.samplename] = mel_spec.astype(np.float32)\n        \n    except Exception as e:\n        print(f\"Error processing {row.filepath}: {e}\")\n        errors.append((row.filepath, str(e)))\n\nend_time = time.time()\nprint(f\"Processing completed in {end_time - start_time:.2f} seconds\")\nprint(f\"Successfully processed {len(all_bird_data)} files out of {total_samples} total\")\nprint(f\"Failed to process {len(errors)} files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-08T06:09:49.462383Z","iopub.execute_input":"2025-05-08T06:09:49.462694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nsamples = []\ndisplayed_classes = set()\n\nmax_samples = min(4, len(all_bird_data))\n\nfor i, row in working_df.iterrows():\n    if i >= (config.N_MAX or len(working_df)):\n        break\n        \n    if row['samplename'] in all_bird_data:\n        if config.DEBUG_MODE:\n            if row['class'] not in displayed_classes:\n                samples.append((row['samplename'], row['class'], row['primary_label']))\n                displayed_classes.add(row['class'])\n        else:\n            if row['class'] not in displayed_classes:\n                samples.append((row['samplename'], row['class'], row['primary_label']))\n                displayed_classes.add(row['class'])\n        \n        if len(samples) >= max_samples:  \n            break\n\nif samples:\n    plt.figure(figsize=(16, 12))\n    \n    for i, (samplename, class_name, species) in enumerate(samples):\n        plt.subplot(2, 2, i+1)\n        plt.imshow(all_bird_data[samplename], aspect='auto', origin='lower', cmap='viridis')\n        plt.title(f\"{class_name}: {species}\")\n        plt.colorbar(format='%+2.0f dB')\n    \n    plt.tight_layout()\n    debug_note = \"debug_\" if config.DEBUG_MODE else \"\"\n    plt.savefig(f'{debug_note}melspec_examples.png')\n    plt.show()","metadata":{"trusted":true,"execution":{"execution_failed":"2025-05-08T06:07:38.811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"temp = all_bird_data","metadata":{"trusted":true,"execution":{"execution_failed":"2025-05-08T06:07:38.812Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.save(config.OUTPUT_DIR + 'my_data_update_new_params_mel.npy', temp)","metadata":{"trusted":true,"execution":{"execution_failed":"2025-05-08T06:07:38.812Z"}},"outputs":[],"execution_count":null}]}