{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","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"},{"sourceId":12044794,"sourceType":"datasetVersion","datasetId":7579612}],"dockerImageVersionId":31041,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom pathlib import Path\nimport math\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport torch.nn as nn\nfrom transformers import AutoModelForImageClassification\nimport torchaudio\nimport librosa\n\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T00:21:23.885997Z","iopub.execute_input":"2025-06-04T00:21:23.886395Z","iopub.status.idle":"2025-06-04T00:21:45.098590Z","shell.execute_reply.started":"2025-06-04T00:21:23.886351Z","shell.execute_reply":"2025-06-04T00:21:45.097554Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"paths = [\n    \"/kaggle/input/0602-models-v5/0602models/efficientnet-b2_fold1/checkpoint-14000\",\n    \"/kaggle/input/0602-models-v5/0602models/efficientnet-b2_fold2/checkpoint-14000\",\n    \"/kaggle/input/0602-models-v5/0602models/efficientnet-b2_fold3/checkpoint-14000\",\n    \"/kaggle/input/0602-models-v5/0602models/regnet-y-008_fold1/checkpoint-14000\",\n    \"/kaggle/input/0602-models-v5/0602models/regnet-y-008_fold2/checkpoint-14000\",\n    \"/kaggle/input/0602-models-v5/0602models/regnet-y-008_fold3/checkpoint-14000\"\n]\nmodels = []\nfor path in paths:\n    model = AutoModelForImageClassification.from_pretrained(path)\n    model.eval()\n    models.append(model)                                             ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T00:21:45.100530Z","iopub.execute_input":"2025-06-04T00:21:45.100992Z","iopub.status.idle":"2025-06-04T00:22:10.925373Z","shell.execute_reply.started":"2025-06-04T00:21:45.100967Z","shell.execute_reply":"2025-06-04T00:22:10.924477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Configuration for mel spectrogram\nmel_spec_params = {\n    \"sample_rate\": 32000,\n    \"n_mels\": 128,\n    \"f_min\": 20,\n    \"f_max\": 16000,\n    \"n_fft\": 1024,\n    \"hop_length\": 500,\n    \"normalized\": True,\n    \"center\": True,\n    \"pad_mode\": \"constant\",\n    \"norm\": \"slaney\",\n    \"mel_scale\": \"slaney\"\n}\ntop_db = 80\nsegment_length = 5 * mel_spec_params[\"sample_rate\"]  # 5 seconds\n\nmel_transform = torchaudio.transforms.MelSpectrogram(**mel_spec_params)\ndb_transform = torchaudio.transforms.AmplitudeToDB(stype='power', top_db=top_db)\n\ndef normalize_melspec(X, eps=1e-6):\n    \"\"\"Normalize mel spectrogram\"\"\"\n    mean = X.mean((1, 2), keepdim=True)\n    std = X.std((1, 2), keepdim=True)\n    Xstd = (X - mean) / (std + eps)\n\n    norm_min, norm_max = (\n        Xstd.min(-1)[0].min(-1)[0],\n        Xstd.max(-1)[0].max(-1)[0],\n    )\n    fix_ind = (norm_max - norm_min) > eps * torch.ones_like(\n        (norm_max - norm_min)\n    )\n    V = torch.zeros_like(Xstd)\n    if fix_ind.sum():\n        V_fix = Xstd[fix_ind]\n        norm_max_fix = norm_max[fix_ind, None, None]\n        norm_min_fix = norm_min[fix_ind, None, None]\n        V_fix = torch.max(\n            torch.min(V_fix, norm_max_fix),\n            norm_min_fix,\n        )\n        V_fix = (V_fix - norm_min_fix) / (norm_max_fix - norm_min_fix)\n        V[fix_ind] = V_fix\n    return V\n\ndef prepare_spec(wav):\n    \"\"\"Create mel spectrogram from audio file\"\"\"\n    \n    # Create mel spectrogram\n    mel_spectrogram = mel_transform(wav)\n    mel_spectrogram = db_transform(mel_spectrogram)\n    mel_spectrogram = normalize_melspec(mel_spectrogram)\n    \n    # Scale to 0-255 range for image-like processing\n    mel_spectrogram = mel_spectrogram * 255\n    \n    # Convert to 3-channel image format (RGB)\n    mel_spectrogram = mel_spectrogram.expand(3, -1, -1).permute(1, 2, 0).numpy()\n\n    # Final formatting: Convert to [C, H, W] format\n    spec = mel_spectrogram.transpose(2, 0, 1)\n    \n    return torch.from_numpy(spec)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T00:22:10.926272Z","iopub.execute_input":"2025-06-04T00:22:10.926896Z","iopub.status.idle":"2025-06-04T00:22:10.978385Z","shell.execute_reply.started":"2025-06-04T00:22:10.926870Z","shell.execute_reply":"2025-06-04T00:22:10.977658Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# List of test soundscapes (only visible during submission)\ntest_soundscape_path = '/kaggle/input/birdclef-2025/test_soundscapes'\ntest_soundscapes = [os.path.join(test_soundscape_path, afile) for afile in sorted(os.listdir(test_soundscape_path)) if afile.endswith('.ogg')]\n\n#test_soundscape_path = '/kaggle/input/birdclef-2025/train_soundscapes'\n#test_soundscapes = [os.path.join(test_soundscape_path, afile) for afile in sorted(os.listdir(test_soundscape_path)) if afile.endswith('.ogg')]\n#test_soundscapes = test_soundscapes[:5]\n\npreds = [np.empty(shape=(0, 206), dtype='float32') for _ in range(len(models))]\nids = []\n\nfor soundscape in tqdm(test_soundscapes):\n    # Load audio\n    sig, rate = librosa.load(path=soundscape, sr=None)\n\n    # Split into 5s chunks\n    chunks = []\n    for i in range(0, len(sig), rate*5):\n        chunk = sig[max(0, int(i-rate*2.5)):int(i+rate*7.5)]\n        chunk = torch.from_numpy(chunk).unsqueeze(0)\n        chunks.append(chunk)\n\n    # create IDs for each chunk\n    filename = os.path.basename(soundscape).split('.')[0]\n    rec_ids = [f'{filename}_{(frame_id+1)*5}' for frame_id in range(len(chunks))]\n    ids += rec_ids\n    \n    for m_idx, model in enumerate(models):\n        rec_preds = np.empty(shape=(0, 206), dtype='float32')  # predictions for recording\n        for i, chunk in enumerate(chunks):\n            spec = prepare_spec(chunk)\n            logits = model(spec.unsqueeze(0)).logits\n            chunk_preds = nn.functional.softmax(logits, dim=-1)  # predictions for chunk\n            chunk_preds = chunk_preds.detach().numpy()\n            chunk_preds = chunk_preds[:, :206]  # drop last column (no call probabilities)\n            rec_preds = np.concatenate([rec_preds, chunk_preds], axis=0)\n        # average predictions for each chunk with neighboring chunks (window width 5)\n        smooth_preds = rec_preds.copy()\n        for i in range (len(chunks)):\n            smooth_preds[i, :] = rec_preds[max(0, i-2):i+3].mean(axis = 0)            \n        preds[m_idx] = np.concatenate([preds[m_idx], smooth_preds], axis=0)\n\n# ensembling\npreds = np.array(preds)\n#preds = preds.mean(axis=0, keepdims=True)\n#preds = preds.min(axis=0, keepdims=True)\npreds = preds.max(axis=0, keepdims=True)\npreds = preds.squeeze()\n\n# Class labels from train audio\nlabels = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))\n# Save prediction as csv\npred_df = pd.DataFrame(ids, columns=['row_id'])\npred_df.loc[:, labels] = preds\npred_df.to_csv('submission.csv', index=False)\npred_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T00:23:59.175305Z","iopub.execute_input":"2025-06-04T00:23:59.175609Z","iopub.status.idle":"2025-06-04T00:23:59.288383Z","shell.execute_reply.started":"2025-06-04T00:23:59.175586Z","shell.execute_reply":"2025-06-04T00:23:59.287524Z"}},"outputs":[],"execution_count":null}]}