{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11828226,"sourceType":"datasetVersion","datasetId":6852834},{"sourceId":227215399,"sourceType":"kernelVersion"},{"sourceId":240877712,"sourceType":"kernelVersion"},{"sourceId":243926008,"sourceType":"kernelVersion"}],"dockerImageVersionId":30918,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false},"papermill":{"default_parameters":{},"duration":29.711705,"end_time":"2025-03-12T13:10:48.026302","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2025-03-12T13:10:18.314597","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Inference notebook Event Detection","metadata":{}},{"cell_type":"markdown","source":"ResNet\n* Training Notebook [here.](https://www.kaggle.com/code/loekie/training-notebook-resnet)\n* Dataset Creation [here](https://www.kaggle.com/code/myso1987/birdclef2025-1-crop-audio-5s) Dataset creation by MYSO\n\nEvent detection\n* Training Notebook [here.](https://www.kaggle.com/code/loekie/training-notebook-event-detection)\n* Dataset Creation [here](https://www.kaggle.com/code/loekie/data-preparation-event-detection)","metadata":{}},{"cell_type":"markdown","source":"## Imports","metadata":{}},{"cell_type":"code","source":"import os\nimport gc\nimport time\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nfrom torchvision import models\nimport torchaudio\nimport torchaudio.transforms as AT\nfrom contextlib import contextmanager\nimport concurrent.futures\nimport math","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:00:01.978691Z","iopub.execute_input":"2025-06-05T21:00:01.979055Z","iopub.status.idle":"2025-06-05T21:00:01.984843Z","shell.execute_reply.started":"2025-06-05T21:00:01.979028Z","shell.execute_reply":"2025-06-05T21:00:01.983598Z"},"papermill":{"duration":12.967807,"end_time":"2025-03-12T13:10:34.46791","exception":false,"start_time":"2025-03-12T13:10:21.500103","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Configuration","metadata":{}},{"cell_type":"code","source":"# No change compared to original\ntest_audio_dir = '../input/birdclef-2025/test_soundscapes/'\nfile_list = [f for f in sorted(os.listdir(test_audio_dir))]\nfile_list = [file.split('.')[0] for file in file_list if file.endswith('.ogg')]\n\ndebug = False\nif len(file_list) == 0:\n    debug = True\n    debug_st_num = 5\n    debug_num = 8\n    test_audio_dir = '../input/birdclef-2025/train_soundscapes/'\n    file_list = [f for f in sorted(os.listdir(test_audio_dir))]\n    file_list = [file.split('.')[0] for file in file_list if file.endswith('.ogg')]\n    file_list = file_list[debug_st_num:debug_st_num+debug_num]\n\nprint('Debug mode:', debug)\nprint('Number of test soundscapes:', len(file_list))","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:00:01.986301Z","iopub.execute_input":"2025-06-05T21:00:01.986680Z","iopub.status.idle":"2025-06-05T21:00:02.120684Z","shell.execute_reply.started":"2025-06-05T21:00:01.986633Z","shell.execute_reply":"2025-06-05T21:00:02.119479Z"},"papermill":{"duration":0.104002,"end_time":"2025-03-12T13:10:34.575366","exception":false,"start_time":"2025-03-12T13:10:34.471364","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# We only changed the mel spectrogram configurations to fit the mel spectrogram configurations of the ResNet and Event detection\nwav_sec = 5\nsample_rate = 32000\nmin_segment = sample_rate*wav_sec\n\nclass_labels = sorted(os.listdir('../input/birdclef-2025/train_audio/'))\n\nn_fft=1280\nwin_length=1024\nhop_length=512\nf_min=20\nf_max=16000\nn_mels=64\n\nmel_spectrogram = AT.MelSpectrogram(\n    sample_rate=sample_rate,\n    n_fft=n_fft,\n    win_length=win_length,\n    hop_length=hop_length,\n    center=True,\n    f_min=f_min,\n    f_max=f_max,\n    pad_mode=\"reflect\",\n    power=2.0,\n    norm='slaney',\n    n_mels=n_mels,\n    mel_scale=\"htk\",\n    # normalized=True\n)\n\ndef normalize_std(spec, eps=1e-23):\n    mean = torch.mean(spec)\n    std = torch.std(spec)\n    return torch.where(std == 0, spec-mean, (spec - mean) / (std+eps))\n\ndef audio_to_mel(filepath=None):\n    waveform, sample_rate = torchaudio.load(filepath,backend=\"soundfile\")\n    len_wav = waveform.shape[1]\n    waveform = waveform[0,:].reshape(1, len_wav) # stereo->mono mono->mono\n    waveform = waveform / torch.max(torch.abs(waveform))\n    waveform = waveform + 1.5849e-05*(torch.rand(1, len_wav)-0.5) \n    PREDS = []\n    for i in range(12):\n        waveform2 = waveform[:,i*sample_rate*5:i*sample_rate*5+sample_rate*5]\n        melspec = mel_spectrogram(waveform2)\n        melspec = torch.log(melspec)\n        melspec = normalize_std(melspec)\n        melspec = torch.unsqueeze(melspec, dim=0)\n        \n        PREDS.append(melspec)\n    return torch.vstack(PREDS)","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:00:02.122475Z","iopub.execute_input":"2025-06-05T21:00:02.122768Z","iopub.status.idle":"2025-06-05T21:00:02.243668Z","shell.execute_reply.started":"2025-06-05T21:00:02.122743Z","shell.execute_reply":"2025-06-05T21:00:02.241884Z"},"papermill":{"duration":0.124095,"end_time":"2025-03-12T13:10:34.702541","exception":false,"start_time":"2025-03-12T13:10:34.578446","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Model initialisation","metadata":{}},{"cell_type":"code","source":"# No change compared to original\nclass Model_resnet34(nn.Module):\n    def __init__(self, pretrained=False):\n        super().__init__()\n\n        # Use timm\n        model = models.resnet34(pretrained=pretrained)\n\n        num_ftrs = model.fc.in_features\n        model.fc = nn.Linear(num_ftrs, len(class_labels))\n        self.model = model\n\n    def forward(self, x):\n        x = torch.cat((x,x,x),1)\n        x = self.model(x)\n        return x\n\nmodel = Model_resnet34(pretrained=False)\nmodel.load_state_dict(torch.load('/kaggle/input/k/loekie/birdclef2025-2-train-baseline-5s/model_cfg_3.pth', weights_only=True, map_location=torch.device('cpu')))\nmodel.eval();","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:00:02.245020Z","iopub.execute_input":"2025-06-05T21:00:02.245394Z","iopub.status.idle":"2025-06-05T21:00:04.174967Z","shell.execute_reply.started":"2025-06-05T21:00:02.245364Z","shell.execute_reply":"2025-06-05T21:00:04.173458Z"},"papermill":{"duration":1.849403,"end_time":"2025-03-12T13:10:36.555055","exception":false,"start_time":"2025-03-12T13:10:34.705652","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# New model class for the Event detection Resnet\nclass Model_resnet34_call(nn.Module):\n    def __init__(self, pretrained=False):\n        super().__init__()\n        model = models.resnet34(pretrained=pretrained)\n        num_ftrs = model.fc.in_features\n        model.fc = nn.Linear(num_ftrs, 2)\n        self.model = model\n\n    def forward(self, x):\n        x = torch.cat((x,x,x),1)\n        x = self.model(x)\n        return x\n\nmodel_call = Model_resnet34_call(pretrained=False) \nmodel_call.load_state_dict(torch.load('/kaggle/input/birdclef2025-2-train-baseline-5s-call-nocall/model_cfg_0.pth', weights_only=True, map_location=torch.device('cpu')))\nmodel_call.eval();","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-05T21:00:04.176190Z","iopub.execute_input":"2025-06-05T21:00:04.176537Z","iopub.status.idle":"2025-06-05T21:00:05.783732Z","shell.execute_reply.started":"2025-06-05T21:00:04.176511Z","shell.execute_reply":"2025-06-05T21:00:05.781898Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Predicting test files","metadata":{}},{"cell_type":"code","source":"def prediction(afile):    \n    global pred\n    path = test_audio_dir + afile + '.ogg'\n    with torch.inference_mode():\n        sig = audio_to_mel(path)\n       \n        outputs = model(sig)\n        outputs = torch.sigmoid(outputs).detach().cpu().numpy()\n\n        outputs_call = model_call(sig)\n        outputs_call = torch.sigmoid(outputs_call).detach().cpu().numpy()\n        \n        chunks = [[] for i in range(12)]\n        for i in range(len(chunks)):        \n            chunk_end_time = (i + 1) * 5\n            row_id = afile + '_' + str(chunk_end_time)\n            pred['row_id'].append(row_id)\n\n            # If an event is detected, the outputs are appended\n            if outputs_call[i][0]>0.5:\n                bird_no = 0\n                for bird in class_labels:         \n                    pred[bird].append(outputs[i,bird_no])\n                    bird_no += 1\n            # If not, the outputs are supressed by taking the square root\n            else:\n                bird_no = 0\n                for bird in class_labels:         \n                    pred[bird].append(math.sqrt(outputs[i,bird_no]))\n                    bird_no += 1\n        gc.collect()","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:14:31.590467Z","iopub.execute_input":"2025-06-05T21:14:31.590977Z","iopub.status.idle":"2025-06-05T21:14:31.600129Z","shell.execute_reply.started":"2025-06-05T21:14:31.590926Z","shell.execute_reply":"2025-06-05T21:14:31.598412Z"},"papermill":{"duration":0.012347,"end_time":"2025-03-12T13:10:36.570713","exception":false,"start_time":"2025-03-12T13:10:36.558366","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred = {'row_id': []}\nfor species_code in class_labels:\n    pred[species_code] = []\n    \nstart = time.time()\nwith concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:\n    _ = list(executor.map(prediction, file_list))\nend_t = time.time()\n\nif debug == True:\n    print(700*(end_t - start)/60/debug_num)","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:14:34.493223Z","iopub.execute_input":"2025-06-05T21:14:34.493787Z","iopub.status.idle":"2025-06-05T21:14:45.810550Z","shell.execute_reply.started":"2025-06-05T21:14:34.493749Z","shell.execute_reply":"2025-06-05T21:14:45.809206Z"},"papermill":{"duration":8.10507,"end_time":"2025-03-12T13:10:44.678845","exception":false,"start_time":"2025-03-12T13:10:36.573775","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results = pd.DataFrame(pred, columns = ['row_id'] + class_labels) \n    \nresults.to_csv(\"submission.csv\", index=False)    \n\nif debug:\n    display(results.head())","metadata":{"execution":{"iopub.status.busy":"2025-06-05T21:00:17.178989Z","iopub.status.idle":"2025-06-05T21:00:17.179429Z","shell.execute_reply":"2025-06-05T21:00:17.179248Z"},"papermill":{"duration":0.119152,"end_time":"2025-03-12T13:10:44.80127","exception":false,"start_time":"2025-03-12T13:10:44.682118","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}