{"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":11695790,"sourceType":"datasetVersion","datasetId":7340853},{"sourceId":11716673,"sourceType":"datasetVersion","datasetId":7354742},{"sourceId":11721830,"sourceType":"datasetVersion","datasetId":7358381},{"sourceId":3732,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":2659,"modelId":312}],"dockerImageVersionId":31012,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import os\nimport glob\nimport json\nimport random\nimport numpy as np\nimport pandas as pd\nimport librosa\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom joblib import Parallel, delayed\n\nimport timm\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:02.488511Z","iopub.execute_input":"2025-05-07T17:53:02.488790Z","iopub.status.idle":"2025-05-07T17:53:02.493897Z","shell.execute_reply.started":"2025-05-07T17:53:02.488767Z","shell.execute_reply":"2025-05-07T17:53:02.493080Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Config","metadata":{}},{"cell_type":"code","source":"class Config:\n    train_dir = \"/kaggle/input/birdclef-2025/train_audio\"\n    train_csv = \"/kaggle/input/birdclef-2025/train.csv\"\n    train_soundscape = \"/kaggle/input/birdclef-2025/train_soundscapes\"\n    test_soundscape = \"/kaggle/input/birdclef-2025/test_soundscapes\"\n    sample_submission_csv = \"/kaggle/input/birdclef-2025/sample_submission.csv\"\n    \n    sr = 32000\n    n_fft = 1024\n    hop_length = 500\n    n_mels = 128\n    fmin = 40\n    fmax = 15000\n    power = 2\n    chunk_seconds = 5\n    image_shape = (128, 640, 1)  # height, width, channels\n    num_classes = 206\n\n    submission_mode = len(glob.glob(test_soundscape + \"/*.ogg\")) > 0\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:02.495058Z","iopub.execute_input":"2025-05-07T17:53:02.495552Z","iopub.status.idle":"2025-05-07T17:53:02.574234Z","shell.execute_reply.started":"2025-05-07T17:53:02.495522Z","shell.execute_reply":"2025-05-07T17:53:02.573700Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Seting up seeds same as training notebook","metadata":{}},{"cell_type":"code","source":"def set_seed(seed: int = 42):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    if torch.cuda.is_available():\n        torch.cuda.manual_seed(seed)\n        torch.cuda.manual_seed_all(seed)\n\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\n    print(f\"Seed set to: {seed}\")\n\nset_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:02.574960Z","iopub.execute_input":"2025-05-07T17:53:02.575218Z","iopub.status.idle":"2025-05-07T17:53:02.586638Z","shell.execute_reply.started":"2025-05-07T17:53:02.575190Z","shell.execute_reply":"2025-05-07T17:53:02.586057Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if Config.submission_mode:\n    sound_dir = sorted(glob.glob(f\"{Config.test_soundscape}/*.ogg\"))\nelse:\n    sound_dir = sorted(glob.glob(f\"{Config.train_soundscape}/*.ogg\"))[:5]\n\nprint(f\"[Info] Total .ogg files found: {len(sound_dir)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:02.587336Z","iopub.execute_input":"2025-05-07T17:53:02.587561Z","iopub.status.idle":"2025-05-07T17:53:02.685663Z","shell.execute_reply.started":"2025-05-07T17:53:02.587544Z","shell.execute_reply":"2025-05-07T17:53:02.685029Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Audio Processing","metadata":{}},{"cell_type":"code","source":"def process(audio_path):\n    filename = audio_path.split(\"/\")[-1].split(\".\")[0]\n    data, _ = librosa.load(audio_path, sr=Config.sr)\n    \n    # Scale up the data\n    data = data * 1024\n\n    # Divide into 5-second chunks\n    chunk_duration = 5\n    min_len = chunk_duration * Config.sr\n    \n    local_mapper = {}\n\n    for i in range(0, len(data), min_len):\n        t = i // Config.sr\n        row_id = f\"{filename}_{t + chunk_duration}\"\n        chunk_5s = data[i: i + min_len]\n        \n        if len(chunk_5s) < min_len:\n            continue  # Skip incomplete chunks\n\n        chunk_10s = np.tile(chunk_5s, 2)\n        chunk_10s = chunk_10s.reshape(-1, len(chunk_10s))\n\n        # Mel spectrogram\n        mel_sp = librosa.feature.melspectrogram(\n            y=chunk_10s[0],\n            sr=Config.sr,\n            fmin=Config.fmin,\n            fmax=Config.fmax,\n            power=Config.power,\n            n_mels=Config.n_mels,\n            n_fft=Config.n_fft,\n            hop_length=Config.hop_length\n        )\n        mel_sp = librosa.power_to_db(mel_sp, ref=1.0)\n\n        # Normalize\n        eps = 1e-12\n        mel_sp = (mel_sp - mel_sp.min()) / (mel_sp.max() - mel_sp.min() + eps)\n        mel_sp = mel_sp[:, :Config.image_shape[1]]  # crop or pad if needed\n        mel_sp = np.expand_dims(mel_sp, axis=0)     # add channel dimension\n\n        local_mapper[row_id] = mel_sp\n\n    return local_mapper\n\n# Load audio files in parallel\nall_mappers = Parallel(n_jobs=-1, backend='loky')(\n    delayed(process)(path) for path in sound_dir\n)\n\n# Merge all into a single dictionary\nglobal_mapper = {}\nfor mapper in all_mappers:\n    global_mapper.update(mapper)\n\nprint(f\"[Info] Processed and extracted features for {len(global_mapper)} chunks\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:02.687334Z","iopub.execute_input":"2025-05-07T17:53:02.687541Z","iopub.status.idle":"2025-05-07T17:53:27.441570Z","shell.execute_reply.started":"2025-05-07T17:53:02.687525Z","shell.execute_reply":"2025-05-07T17:53:27.440791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Print number of entries\nprint(f\"Total processed segments: {len(global_mapper)}\")\n\n# Preview a single entry\nfor key, value in global_mapper.items():\n    print(f\"Row ID: {key}\")\n    print(f\"Mel shape: {value.shape}\")\n    break  # Print only the first entry","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:27.442543Z","iopub.execute_input":"2025-05-07T17:53:27.442739Z","iopub.status.idle":"2025-05-07T17:53:27.447745Z","shell.execute_reply.started":"2025-05-07T17:53:27.442720Z","shell.execute_reply":"2025-05-07T17:53:27.446910Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"global_mapper.keys()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:27.448693Z","iopub.execute_input":"2025-05-07T17:53:27.449264Z","iopub.status.idle":"2025-05-07T17:53:27.501990Z","shell.execute_reply.started":"2025-05-07T17:53:27.449226Z","shell.execute_reply":"2025-05-07T17:53:27.501486Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"class Model(nn.Module):\n    def __init__(self, model_name: str = \"tf_efficientnet_b3\"):\n        super().__init__()\n        self.base_model = timm.create_model(\n            model_name=model_name,\n            pretrained=False,\n            in_chans=1,\n            num_classes=Config.num_classes\n        )\n\n    def forward(self, x):\n        return self.base_model(x)\n\nmodel_paths = [\n    \"/kaggle/input/birdclef-dataset-v3/checkpoint_epoch_4.pth\",\n    \"/kaggle/input/birdclef-dataset-v3/checkpoint_epoch_5.pth\",\n    \n]\n\ndevice = Config.device\nmodel_pool = []\nfor path in model_paths:\n    model = Model(model_name=\"tf_efficientnet_b3\").to(device)\n    state_dict = torch.load(path, map_location=device)\n    state_dict = {k.replace(\"backbone.\", \"base_model.\"): v for k, v in state_dict.items()}\n    model.load_state_dict(state_dict, strict=False)\n    model.eval()\n    model_pool.append(model)\n\nprint(f\"[INFO] Loaded {len(model_pool)} models.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:27.502776Z","iopub.execute_input":"2025-05-07T17:53:27.502989Z","iopub.status.idle":"2025-05-07T17:53:36.364924Z","shell.execute_reply.started":"2025-05-07T17:53:27.502968Z","shell.execute_reply":"2025-05-07T17:53:36.364311Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Test Dataset","metadata":{}},{"cell_type":"code","source":"class TestDataset(Dataset):\n    def __init__(self, mapper):\n        self.mapper = mapper\n        self.ids = list(mapper.keys())\n\n    def __len__(self):\n        return len(self.mapper)\n\n    def __getitem__(self, idx):\n        row_id = self.ids[idx]\n        x = self.mapper[row_id]\n        if x.shape == (1, 128, 640):\n            x = x.squeeze(0)\n        x = torch.tensor(x, dtype=torch.float32).unsqueeze(0)\n        return row_id, x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:36.366592Z","iopub.execute_input":"2025-05-07T17:53:36.366806Z","iopub.status.idle":"2025-05-07T17:53:36.371778Z","shell.execute_reply.started":"2025-05-07T17:53:36.366789Z","shell.execute_reply":"2025-05-07T17:53:36.370990Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_loader = DataLoader(TestDataset(global_mapper), batch_size=16, shuffle=False)\n\npred_mapper = {}\n\nfor row_ids, mels in test_loader:\n    mels = mels.to(device)\n    batch_preds = []\n\n    with torch.no_grad():\n        for model in model_pool:\n            outputs = model(mels)\n            probs = torch.sigmoid(outputs).cpu().numpy()\n            batch_preds.append(probs)\n\n    avg_preds = np.mean(batch_preds, axis=0)\n\n    for i, row_id in enumerate(row_ids):\n        pred_mapper[row_id] = avg_preds[i]\n\nprint(f\"[INFO] Predictions stored for {len(pred_mapper)} row_ids.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:36.372585Z","iopub.execute_input":"2025-05-07T17:53:36.372854Z","iopub.status.idle":"2025-05-07T17:53:38.072548Z","shell.execute_reply.started":"2025-05-07T17:53:36.372814Z","shell.execute_reply":"2025-05-07T17:53:38.071744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred_mapper","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:38.073410Z","iopub.execute_input":"2025-05-07T17:53:38.073662Z","iopub.status.idle":"2025-05-07T17:53:38.142652Z","shell.execute_reply.started":"2025-05-07T17:53:38.073640Z","shell.execute_reply":"2025-05-07T17:53:38.141950Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"sample_df = pd.read_csv(Config.sample_submission_csv)\nsubmission_columns = sample_df.columns.tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:38.143310Z","iopub.execute_input":"2025-05-07T17:53:38.143513Z","iopub.status.idle":"2025-05-07T17:53:38.160623Z","shell.execute_reply.started":"2025-05-07T17:53:38.143498Z","shell.execute_reply":"2025-05-07T17:53:38.160164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert pred_mapper to DataFrame\nsubmission_df = pd.DataFrame.from_dict(pred_mapper, orient=\"index\")\nsubmission_df.columns = submission_columns[1:]  # exclude \"row_id\"\nsubmission_df[\"row_id\"] = submission_df.index\nsubmission_df = submission_df[submission_columns]  # reorder columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:38.161301Z","iopub.execute_input":"2025-05-07T17:53:38.161544Z","iopub.status.idle":"2025-05-07T17:53:38.192970Z","shell.execute_reply.started":"2025-05-07T17:53:38.161519Z","shell.execute_reply":"2025-05-07T17:53:38.192458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save submission\nsubmission_path = \"/kaggle/working/submission.csv\"\nsubmission_df.to_csv(submission_path, index=False)\n\n# Display top few rows\nprint(\"Submission file saved at:\", submission_path)\nsubmission_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-07T17:53:38.193575Z","iopub.execute_input":"2025-05-07T17:53:38.193759Z","iopub.status.idle":"2025-05-07T17:53:38.237443Z","shell.execute_reply.started":"2025-05-07T17:53:38.193744Z","shell.execute_reply":"2025-05-07T17:53:38.236850Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}