{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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"}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"#!pip install torch\n#!pip install torchaudio\n#!pip install scikit-learn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T18:27:06.694457Z","iopub.execute_input":"2025-05-15T18:27:06.694761Z","iopub.status.idle":"2025-05-15T18:27:06.705525Z","shell.execute_reply.started":"2025-05-15T18:27:06.694738Z","shell.execute_reply":"2025-05-15T18:27:06.70148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport os\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport gc\nimport dataclasses\nimport torchaudio\nimport traceback\nfrom pathlib import Path\nfrom typing import Optional, Callable, Tuple, List\nfrom torchaudio.transforms import Resample\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_auc_score, f1_score\nfrom sklearn.preprocessing import MultiLabelBinarizer\nfrom concurrent.futures import ThreadPoolExecutor\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.metrics import roc_auc_score, roc_curve\nimport matplotlib.pyplot as plt\nfrom pathlib import Path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:50:34.641371Z","iopub.execute_input":"2025-05-15T23:50:34.642105Z","iopub.status.idle":"2025-05-15T23:50:42.166521Z","shell.execute_reply.started":"2025-05-15T23:50:34.64208Z","shell.execute_reply":"2025-05-15T23:50:42.165442Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_directory = \"/kaggle/input/birdclef-2025/test_soundscapes\"\nsubmission = \"/kaggle/input/birdclef-2025/sample_submission.csv\"\ntrain_file = \"/kaggle/input/birdclef-2025/train.csv\"\ntaxonomy_file = \"/kaggle/input/birdclef-2025/taxonomy.csv\"\n\n@dataclasses.dataclass\nclass AudioParameters:\n    sample_rate: int = 32000\n    max_freq: int = 16000\n    min_freq: int = 20\n\nparams = AudioParameters()\n\nsubmission_df = pd.read_csv(submission)\nindex_to_class = submission_df.columns.drop(\"row_id\").tolist()\nclass_to_index = {label: idx for idx, label in enumerate(index_to_class)}\navailable_files = set(os.listdir(test_directory))\nsubmission_basenames = set(x.split(\"_\")[0] for x in submission_df[\"row_id\"])\nfile_paths = [\n    os.path.join(test_directory, fname)\n    for fname in os.listdir(test_directory)\n    if Path(fname).stem in submission_basenames and fname.endswith(\".ogg\")\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:50:55.558098Z","iopub.execute_input":"2025-05-15T23:50:55.558512Z","iopub.status.idle":"2025-05-15T23:50:55.575795Z","shell.execute_reply.started":"2025-05-15T23:50:55.558484Z","shell.execute_reply":"2025-05-15T23:50:55.574711Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CNNmodel(nn.Module):\n    def __init__(self, num_classes: int = 1):\n        super().__init__()\n        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1)\n        self.relu1 = nn.ReLU()\n        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)\n        self.relu2 = nn.ReLU()\n        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n        self.flatten = nn.Flatten()\n\n        temp = torch.zeros(1, 1, 128, 313)\n        with torch.no_grad():\n            x = self._forward_features(temp)\n        self.fc1 = nn.Linear(x.shape[1], num_classes)\n\n    def _forward_features(self, x):\n        x = self.pool1(self.relu1(self.conv1(x)))\n        x = self.pool2(self.relu2(self.conv2(x)))\n        x = self.flatten(x)\n        return x\n\n    def forward(self, x: torch.Tensor) -> torch.Tensor:\n        x = self._forward_features(x)\n        x = self.fc1(x)\n        return x\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = CNNmodel(num_classes=len(index_to_class)).to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:51:01.234842Z","iopub.execute_input":"2025-05-15T23:51:01.235236Z","iopub.status.idle":"2025-05-15T23:51:01.54498Z","shell.execute_reply.started":"2025-05-15T23:51:01.235204Z","shell.execute_reply":"2025-05-15T23:51:01.543959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mel_transform = torchaudio.transforms.MelSpectrogram(\n    sample_rate=params.sample_rate,\n    n_fft=1024,\n    hop_length=512,\n    n_mels=128\n).to(device)\n\n@torch.no_grad()\ndef predict(model, file_paths, device, chunk_size=5.0, sample_rate=32000):\n    model.eval()\n    predictions = []\n    row_ids = []\n\n    for file_path in file_paths:\n        try:\n            waveform, sr = torchaudio.load(file_path)\n        except Exception as e:\n            print(f\"Could not load {file_path}: {e}\")\n            continue\n\n        if sr != sample_rate:\n            waveform = Resample(sr, sample_rate)(waveform)\n\n        total_samples = waveform.shape[1]\n        step = int(chunk_size * sample_rate)\n\n        for start in range(0, total_samples, step):\n            end = start + step\n            if end > total_samples:\n                break\n\n            chunk = waveform[:, start:end].to(device)\n            spectrogram = mel_transform(chunk)\n            spectrogram = spectrogram.log2().clamp(min=-10)\n            spectrogram = spectrogram.unsqueeze(0)\n\n            output = model(spectrogram)\n            prob = torch.sigmoid(output).cpu().numpy()\n\n            seconds = int(start / sample_rate)\n            row_id = f\"{Path(file_path).stem}_{seconds}\"\n            row_ids.append(row_id)\n            predictions.append(prob.squeeze())\n\n    return np.array(predictions), row_ids","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:51:05.520314Z","iopub.execute_input":"2025-05-15T23:51:05.520662Z","iopub.status.idle":"2025-05-15T23:51:05.594118Z","shell.execute_reply.started":"2025-05-15T23:51:05.520632Z","shell.execute_reply":"2025-05-15T23:51:05.593188Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_ids = []\nmatrix = []\n\nif not file_paths:\n    print(\"No test files found. Returning original sample submission.\")\nelse:\n    with ThreadPoolExecutor(max_workers=4) as executor:\n        for audio_file in file_paths:\n            preds, ids = predict(model, [audio_file], device)\n            if ids:\n                submission_ids.extend(ids)\n                matrix.extend(preds)\n            gc.collect()\n\nif matrix:\n    pred_df = pd.DataFrame(\n        np.hstack([np.array(submission_ids).reshape(-1, 1), np.array(matrix).reshape(-1, len(index_to_class))]),\n        columns=[\"row_id\"] + index_to_class\n    )\n    pred_df[index_to_class] = pred_df[index_to_class].astype(float).round(6)\n\n    for i, row in pred_df.iterrows():\n        if row[\"row_id\"] in submission_df[\"row_id\"].values:\n            submission_df.loc[submission_df[\"row_id\"] == row[\"row_id\"], index_to_class] = row[index_to_class]\nelse:\n    print(\"No predictions generated. Filling with zeros.\")\n    submission_df[index_to_class] = 0.0\n\nassert submission_df.shape == pd.read_csv(submission).shape, \"Submission shape mismatch\"\nsubmission_df.to_csv(\"submission.csv\", index=False)\nprint(\"Final submission shape:\", submission_df.shape)\nprint(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:51:09.000339Z","iopub.execute_input":"2025-05-15T23:51:09.00068Z","iopub.status.idle":"2025-05-15T23:51:09.069816Z","shell.execute_reply.started":"2025-05-15T23:51:09.000651Z","shell.execute_reply":"2025-05-15T23:51:09.06884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\npredictions, row_ids = predict(model, file_paths, device)\n\n\ntrue_labels = []\nfor row_id in row_ids:\n    file_stem = row_id.split('_')[0] \n    label = true_labels_dict[file_stem] \n    true_labels.append(label)\n\n\nauc_score = roc_auc_score(true_labels, predictions)\nprint(f\"AUC Score: {auc_score:.4f}\")\n\n\nfpr, tpr, _ = roc_curve(true_labels, predictions)\nplt.figure(figsize=(6, 5))\nplt.plot(fpr, tpr, label=f\"AUC = {auc_score:.4f}\")\nplt.plot([0, 1], [0, 1], linestyle='--', color='gray')\nplt.xlabel(\"False Positive Rate\")\nplt.ylabel(\"True Positive Rate\")\nplt.title(\"ROC Curve\")\nplt.legend()\nplt.grid(True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T23:51:14.351288Z","iopub.execute_input":"2025-05-15T23:51:14.351598Z","iopub.status.idle":"2025-05-15T23:51:14.43534Z","shell.execute_reply.started":"2025-05-15T23:51:14.351577Z","shell.execute_reply":"2025-05-15T23:51:14.433886Z"}},"outputs":[],"execution_count":null}]}