{"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"},{"sourceId":229137343,"sourceType":"kernelVersion"}],"dockerImageVersionId":30918,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nimport torchaudio\nfrom joblib import Parallel, delayed\nfrom tqdm.notebook import tqdm\nimport timm\nimport os\n\n# Set seed\nnp.random.seed(42)\ntorch.manual_seed(42);","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:31.018248Z","iopub.execute_input":"2025-03-23T18:57:31.018533Z","iopub.status.idle":"2025-03-23T18:57:41.723133Z","shell.execute_reply.started":"2025-03-23T18:57:31.018504Z","shell.execute_reply":"2025-03-23T18:57:41.722464Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\nDEVICE","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:41.723887Z","iopub.execute_input":"2025-03-23T18:57:41.724090Z","iopub.status.idle":"2025-03-23T18:57:41.778783Z","shell.execute_reply.started":"2025-03-23T18:57:41.724073Z","shell.execute_reply":"2025-03-23T18:57:41.778096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IS_SUBMISSION = True\nIDX_TO_LABEL = sorted(pd.read_csv('/kaggle/input/birdclef-2025/train.csv').primary_label.unique())\nNUM_LABELS = len(IDX_TO_LABEL)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:41.779465Z","iopub.execute_input":"2025-03-23T18:57:41.779765Z","iopub.status.idle":"2025-03-23T18:57:41.968720Z","shell.execute_reply.started":"2025-03-23T18:57:41.779745Z","shell.execute_reply":"2025-03-23T18:57:41.967811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_model():\n    return timm.create_model(\n        'tf_efficientnet_b0',\n        in_chans=1,\n        num_classes=NUM_LABELS,\n        pretrained=False,\n    )\n\n\ndef load_model(path):\n    model = make_model().to(DEVICE)\n    model.load_state_dict(torch.load(path, weights_only=True, map_location=DEVICE))\n    model.eval()\n    return model\n\n\nmodel = load_model('/kaggle/input/bc25-train-baseline/model_state_dict_epoch_19.pt')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:41.969602Z","iopub.execute_input":"2025-03-23T18:57:41.969896Z","iopub.status.idle":"2025-03-23T18:57:42.637769Z","shell.execute_reply.started":"2025-03-23T18:57:41.969875Z","shell.execute_reply":"2025-03-23T18:57:42.636895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"to_spec = torch.nn.Sequential(\n    torchaudio.transforms.MelSpectrogram(\n        sample_rate=32000,\n        n_mels=128,\n        n_fft=1920,\n        hop_length=640,\n        center=False,\n        power=2,\n    ),\n    torchaudio.transforms.AmplitudeToDB(\n        stype=\"power\",\n        top_db=80.0,\n    )\n).to(DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:42.638664Z","iopub.execute_input":"2025-03-23T18:57:42.638946Z","iopub.status.idle":"2025-03-23T18:57:42.688905Z","shell.execute_reply.started":"2025-03-23T18:57:42.638921Z","shell.execute_reply":"2025-03-23T18:57:42.688062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Quantizer:\n    def __init__(self, num_bits):\n        self.range = 2**num_bits\n        self.max = 2**(num_bits - 1) - 1\n        self.min = -2**(num_bits - 1)\n        if num_bits <= 8:\n            self.dtype = torch.int8\n        elif num_bits <= 16:\n            self.dtype = torch.int16\n        elif num_bits <= 32:\n            self.dtype = torch.int32\n\n    def quantize(self, tensor):\n        min_val = tensor.min()\n        max_val = tensor.max()\n        if min_val == max_val: # Edge case: all values are the same\n            return torch.full_like(tensor, 0, dtype=self.dtype), min_val, max_val\n        scale = self.range / (max_val - min_val)\n        quantized_tensor = torch.round((tensor - min_val) * scale + self.min).clamp(self.min, self.max).to(self.dtype)\n        return quantized_tensor, min_val, max_val\n\n    def dequantize(self, quantized_tensor, min_val, max_val):\n        if min_val == max_val:\n            return torch.full_like(quantized_tensor, min_val, dtype=torch.float32)\n        scale = (max_val - min_val) / self.range\n        return (quantized_tensor.to(torch.float32) - self.min) * scale + min_val\n\nq = Quantizer(16)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:42.690565Z","iopub.execute_input":"2025-03-23T18:57:42.690818Z","iopub.status.idle":"2025-03-23T18:57:42.697377Z","shell.execute_reply.started":"2025-03-23T18:57:42.690798Z","shell.execute_reply":"2025-03-23T18:57:42.696546Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_spec_chunks(soundscape):\n    spec = to_spec(torchaudio.load(soundscape)[0][0][:32000*60].to(DEVICE)) # get spec for entire audio\n    #spec = q.dequantize(*q.quantize(spec)) # simulate quantizing to be consistent with training\n    spec = torch.nn.functional.pad(spec, (0, 2)) # add two columns at the end to align each chunk\n    spec = spec.T.reshape(-1, 250, 128) # swap freq&time axis to reshape into chunks\n    spec = spec.permute(0, 2, 1) # swap freq&time axis back\n    spec = spec[:, :, :248] # remove extra/intermediate time steps\n    return spec\n\nget_spec_chunks('/kaggle/input/birdclef-2025/train_soundscapes/H02_20230420_112000.ogg').shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:42.698260Z","iopub.execute_input":"2025-03-23T18:57:42.698487Z","iopub.status.idle":"2025-03-23T18:57:43.913666Z","shell.execute_reply.started":"2025-03-23T18:57:42.698469Z","shell.execute_reply":"2025-03-23T18:57:43.912961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_soundscape_path = (\n    '/kaggle/input/birdclef-2025/test_soundscapes/' \n    if IS_SUBMISSION else \n    '/kaggle/input/birdclef-2025/train_soundscapes'\n)\ntest_soundscapes = [\n    os.path.join(test_soundscape_path, afile) \n    for afile in sorted(os.listdir(test_soundscape_path)) \n    if afile.endswith('.ogg')\n]\ntest_soundscapes = (\n    test_soundscapes\n    if IS_SUBMISSION else\n    test_soundscapes[:700]\n)\n\nall_chunks = Parallel(n_jobs=-1)(\n    delayed(get_spec_chunks)(f) for f in tqdm(test_soundscapes, desc=\"Loading files\")\n)\nsoundscape_to_chunks = dict(zip(test_soundscapes, all_chunks))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:57:43.914461Z","iopub.execute_input":"2025-03-23T18:57:43.914765Z","iopub.status.idle":"2025-03-23T18:58:05.139542Z","shell.execute_reply.started":"2025-03-23T18:57:43.914743Z","shell.execute_reply":"2025-03-23T18:58:05.138536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"FILE_IN_BATCH = 16\n\nprobs = []\nwith torch.inference_mode():\n    for i in tqdm(range(0, len(all_chunks), FILE_IN_BATCH), desc=\"Running inference\"):\n        logits = model(torch.concat(all_chunks[i:i+FILE_IN_BATCH])[:, None])\n        probs.append(torch.nn.functional.softmax(logits, dim=-1))\n\nprobs = torch.concat(probs).to('cpu').numpy() if len(probs) > 0 else []\n\nrow_ids = []\nfor soundscape in soundscape_to_chunks.keys():\n    for i in range(12):\n        row_ids.append(os.path.basename(soundscape).split('.')[0] + f'_{i * 5 + 5}')\n\npredictions = pd.DataFrame(probs, columns=IDX_TO_LABEL)\npredictions['row_id'] = row_ids\npredictions.to_csv('submission.csv', index=False)\npredictions.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-23T18:58:05.140665Z","iopub.execute_input":"2025-03-23T18:58:05.140999Z","iopub.status.idle":"2025-03-23T18:58:11.177709Z","shell.execute_reply.started":"2025-03-23T18:58:05.140969Z","shell.execute_reply":"2025-03-23T18:58:11.176846Z"}},"outputs":[],"execution_count":null}]}