{"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":"gpu","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11394693,"sourceType":"datasetVersion","datasetId":7136305}],"dockerImageVersionId":31011,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torchaudio\nimport torchaudio.transforms as T\nimport torch.nn as nn\nfrom torchvision import models\n\n\n# ------------------------\n# Device setup\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# ------------------------\n# Define the model (same architecture as used for training)\nmodel = models.efficientnet_b0(pretrained=False)  # Do not load pre-trained weights\nNUM_CLASSES = 206  # Update to your actual number of classes\nmodel.classifier[1] = nn.Linear(model.classifier[1].in_features, NUM_CLASSES)\n\n# Load model weights\nmodel.load_state_dict(torch.load(\"/kaggle/input/llllll/birdclef_test_model.pth\"))\nmodel = model.to(device)\nmodel.eval()\n\n\n# ------------------------\n# Mel spectrogram processor (match training config!)\ndef process_audio_chunk(chunk, sr=32000):\n    waveform = torch.tensor(chunk).unsqueeze(0)  # shape: (1, n_samples)\n    mel_transform = T.MelSpectrogram(\n        sample_rate=sr,\n        n_fft=2048,\n        hop_length=512,\n        n_mels=128\n    )\n    mel = mel_transform(waveform)\n    mel = torchaudio.functional.amplitude_to_DB(mel, multiplier=10.0, db_multiplier=0.0, amin=1e-10, top_db=80.0)\n    return mel  # shape: (1, n_mels, time)\n\n# ------------------------\n# Load model\nclass_labels = sorted(os.listdir('/kaggle/input/birdclef-2025/train_audio/'))\nnum_classes = len(class_labels)\n\n\n\n# ------------------------\n# Predict on test soundscapes\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\npredictions = pd.DataFrame(columns=['row_id'] + class_labels)\n\nfor soundscape in test_soundscapes:\n    sig, rate = librosa.load(path=soundscape, sr=32000)  # Ensure sr matches training\n\n    # Split into 5-second chunks\n    for i in range(0, len(sig), rate * 5):\n        chunk = sig[i:i + rate * 5]\n        if len(chunk) < rate * 5:\n            continue  # skip short tail\n\n        # Process chunk\n        mel = process_audio_chunk(chunk)  # shape: (1, n_mels, time)\n        mel = mel.unsqueeze(0).to(device)  # shape: (B, 1, n_mels, time)\n\n        with torch.no_grad():\n            output = model(mel)\n            scores = torch.sigmoid(output).cpu().numpy().flatten()\n\n        soundscape_id = os.path.basename(soundscape).replace('.ogg', '')\n        end_time = (i + rate * 5) // rate\n        row_id = f\"{soundscape_id}_{end_time}\"\n\n        new_row = pd.DataFrame([[row_id] + list(scores)], columns=['row_id'] + class_labels)\n        predictions = pd.concat([predictions, new_row], ignore_index=True)\n\n# ------------------------\n# Save predictions\npredictions.to_csv('submission.csv', index=False)\nprint(\"Submission saved as 'submission.csv'\")\nprint(predictions.head())\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-14T09:05:27.110513Z","iopub.execute_input":"2025-04-14T09:05:27.110827Z","iopub.status.idle":"2025-04-14T09:05:30.916431Z","shell.execute_reply.started":"2025-04-14T09:05:27.110805Z","shell.execute_reply":"2025-04-14T09:05:30.915634Z"}},"outputs":[],"execution_count":null}]}