{"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":"none","dataSources":[{"sourceId":91844,"databundleVersionId":11361821,"sourceType":"competition"},{"sourceId":11813985,"sourceType":"datasetVersion","datasetId":7420288},{"sourceId":11824459,"sourceType":"datasetVersion","datasetId":7427372}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport librosa\nimport glob\n\nimport torch\nimport torch.nn as nn\nimport albumentations\nimport os\nimport random\nfrom joblib import Parallel, delayed\nimport json\nfrom ast import literal_eval\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport timm\nfrom warnings import filterwarnings\nimport pandas.api.types\n\nimport sklearn.metrics\nfrom tqdm import tqdm\nfrom sklearn.model_selection import StratifiedKFold\nimport torch.nn.functional as F\nimport gc\n\nfilterwarnings(\"ignore\")\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:02:58.533910Z","iopub.execute_input":"2025-05-15T14:02:58.534242Z","iopub.status.idle":"2025-05-15T14:03:51.661934Z","shell.execute_reply.started":"2025-05-15T14:02:58.534213Z","shell.execute_reply":"2025-05-15T14:03:51.660901Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    train_dir = \"/kaggle/input/birdclef-2025/train_audio\"\n    seed = 42\n    train_csv = \"/kaggle/input/birdclef-2025/train.csv\"\n    train_soundscapes = \"/kaggle/input/birdclef-2025/train_soundscapes\"\n    test_soundscapes = \"/kaggle/input/birdclef-2025/test_soundscapes\"\n    sample_submission_csv = \"/kaggle/input/birdclef-2025/sample_submission.csv\"\n    sr = int(32e3)\n    n_fft = 1024\n    hop_length = 500\n    n_mels = 128\n    fmin = 40\n    fmax = 15000\n    power = 2\n    num_classes = 206\n    image_shape = (128, 640, 1)\n    submission_mode = len(glob.glob(\"/kaggle/input/birdclef-2025/test_soundscapes/*.ogg\")) > 0\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:03:51.664029Z","iopub.execute_input":"2025-05-15T14:03:51.664758Z","iopub.status.idle":"2025-05-15T14:03:51.677080Z","shell.execute_reply.started":"2025-05-15T14:03:51.664717Z","shell.execute_reply":"2025-05-15T14:03:51.675915Z"}},"outputs":[],"execution_count":null},{"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\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\"[INFO] Set seed: {seed}\")\n\nset_seed()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:03:51.678141Z","iopub.execute_input":"2025-05-15T14:03:51.678487Z","iopub.status.idle":"2025-05-15T14:03:51.712102Z","shell.execute_reply.started":"2025-05-15T14:03:51.678462Z","shell.execute_reply":"2025-05-15T14:03:51.711244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_files = glob.glob(Config.test_soundscapes + \"/*.ogg\")\n# sound_dir = test_files\nif len(test_files) > 0:\n    sound_dir = test_files\n    print(\"[INFO] Submission mode: using test_soundscapes.\")\nelse:\n    sound_dir = glob.glob(Config.train_soundscapes + \"/*.ogg\")[:5]\n    print(\"[INFO] Debug mode: using train_soundscapes.\")\nsound_dir","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:03:51.713048Z","iopub.execute_input":"2025-05-15T14:03:51.713411Z","iopub.status.idle":"2025-05-15T14:03:51.854058Z","shell.execute_reply.started":"2025-05-15T14:03:51.713387Z","shell.execute_reply":"2025-05-15T14:03:51.853271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\ndef process(audio_path):\n    filename = audio_path.split(\"/\")[-1].split(\".\")[0]\n    data, _ = librosa.load(audio_path, sr=Config.sr)\n\n    data = data * 1024\n\n    # Dividing the data into 5s 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        # Making row ids\n        t = i // Config.sr\n        row_id = f\"{filename}_{t + chunk_duration}\"\n\n        chunk_5s = data[i : i + min_len]\n        chunk_10s = np.tile(chunk_5s, 2)\n        chunk_10s = chunk_10s.reshape(-1, len(chunk_10s))\n\n        # Converting to mel spectrogram\n        mel_sp = librosa.feature.melspectrogram(\n            y=chunk_10s,\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)\n\n        # Normalizing the features\n        eps = 1e-12\n        mel_sp = (mel_sp - mel_sp.min()) / ((mel_sp.max() - mel_sp.min()) + eps)\n        mel_sp = mel_sp[:, :, :640]\n        local_mapper[row_id] = mel_sp\n\n    return local_mapper\n# Loading audio files\nall_mappers = Parallel(\n    n_jobs=-1,\n    backend=\"loky\"\n)(delayed(process)(filepath) for filepath in sound_dir)\n\n# Creating complete mapping\nglobal_mapper = {}\nfor mapper in all_mappers: \n    global_mapper.update(mapper)\n\nprint(f\"[INFO] Loaded all audio files, total_items: {len(global_mapper)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:03:51.855092Z","iopub.execute_input":"2025-05-15T14:03:51.855446Z","iopub.status.idle":"2025-05-15T14:04:22.415076Z","shell.execute_reply.started":"2025-05-15T14:03:51.855418Z","shell.execute_reply":"2025-05-15T14:04:22.413304Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"global_mapper.keys()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:04:22.416396Z","iopub.execute_input":"2025-05-15T14:04:22.417068Z","iopub.status.idle":"2025-05-15T14:04:22.423934Z","shell.execute_reply.started":"2025-05-15T14:04:22.417035Z","shell.execute_reply":"2025-05-15T14:04:22.422984Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\n\nmodels = [\n    \"/kaggle/input/lastoflast/fold_0_tf_efficientnet_b0_epoch_6_val_auc_0.9553_val_loss_41.2952 (1).pth\",\n    \"/kaggle/input/lastoflast/fold_2_regnety_008_epoch_9_val_auc_0.9446_val_loss_48.3645.pth\"\n]\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nclass Model(nn.Module):\n    def __init__(self, model_name: str):\n        super().__init__()\n\n        self.base_model = timm.create_model(\n            model_name=model_name,\n            num_classes=Config.num_classes,\n            pretrained=False,\n            in_chans=1,\n        )\n\n    def forward(self, x):\n        return self.base_model(x)\n\n# Sửa tại đây\nmodel_infos = [\n    (\"tf_efficientnet_b0\", models[0]),\n    (\"regnety_008\",         models[1])\n]\n\nmodels_pool = []\nfor model_name, model_path in model_infos:\n    model = Model(model_name=model_name)\n    model.load_state_dict(torch.load(model_path, map_location=device))\n    model.eval()\n    model.to(device)\n    models_pool.append(model)\n\nprint(\"[INFO] Loaded all models\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:04:22.427211Z","iopub.execute_input":"2025-05-15T14:04:22.427545Z","iopub.status.idle":"2025-05-15T14:04:23.559623Z","shell.execute_reply.started":"2025-05-15T14:04:22.427521Z","shell.execute_reply":"2025-05-15T14:04:23.558617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TestDataset(torch.utils.data.Dataset):\n    def __init__(self, mapper):\n        self.mapper = mapper\n        self.ids = list(self.mapper.keys())\n\n    def __len__(self): return len(self.ids)\n\n    def __getitem__(self, idx): return self.ids[idx], self.mapper[self.ids[idx]]\n\ntest_loader = torch.utils.data.DataLoader(\n    dataset = TestDataset(global_mapper),\n    batch_size = 16,\n    num_workers = 2,\n    shuffle = False,\n    drop_last = False\n)\n\n# To capture the model prediction per row id\npred_mapper = {}\n\nfor (row_ids, mels) in test_loader:\n    mels_t = torch.tensor(mels).to(device)\n\n    model_preds = []\n\n    with torch.no_grad():\n        for model in models_pool:\n            outputs = model(mels_t)\n            probs = torch.sigmoid(outputs).detach().cpu().numpy().squeeze()\n            model_preds.append(probs)  # Prediction of every model on current batch\n\n    # Averaging model predictions\n    mel_preds = np.mean(model_preds, axis=0)\n\n    for idx, row_id in enumerate(row_ids):\n        pred_mapper[row_id] = mel_preds[idx]\n\n    del mels_t\n\nprint(len(global_mapper), len(pred_mapper.keys()))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:04:23.560746Z","iopub.execute_input":"2025-05-15T14:04:23.561179Z","iopub.status.idle":"2025-05-15T14:04:34.104523Z","shell.execute_reply.started":"2025-05-15T14:04:23.561143Z","shell.execute_reply":"2025-05-15T14:04:34.103435Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Creating submission df\nsample_df = pd.read_csv(Config.sample_submission_csv)\nsubmission_df = pd.DataFrame(data=list(pred_mapper.values()), columns=sample_df.columns[1:])\nsubmission_df.insert(0, 'row_id', list(pred_mapper.keys()))\nsubmission_df = submission_df[sample_df.columns]\nsubmission_df.to_csv(\"/kaggle/working/submission.csv\", index=False)\nsubmission_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T14:04:34.105930Z","iopub.execute_input":"2025-05-15T14:04:34.106283Z","iopub.status.idle":"2025-05-15T14:04:34.235534Z","shell.execute_reply.started":"2025-05-15T14:04:34.106252Z","shell.execute_reply":"2025-05-15T14:04:34.234424Z"}},"outputs":[],"execution_count":null}]}