{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"aef0c533","cell_type":"markdown","source":"## 1. Library versions and seeds","metadata":{}},{"id":"6c1ca614","cell_type":"code","source":"# Cell 1: Environment Setup, Seeds, Libraries & Official LWLRAP Metric Implementation\nimport os\nimport sys\nimport time\nimport random\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport librosa\nimport librosa.display\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\n\n# 1. Print Library Versions for Reproducibility\nprint(\"=== System and Library Versions ===\")\nprint(f\"Python Version: {sys.version.split()[0]}\")\nprint(f\"PyTorch Version: {torch.__version__}\")\nprint(f\"Librosa Version: {librosa.__version__}\")\nprint(f\"CUDA Available: {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n    print(f\"GPU Device: {torch.cuda.get_device_name(0)}\")\n\n# 2. Fix Random Seeds\nSEED = 42\ndef seed_everything(seed=SEED):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\nseed_everything(SEED)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Random seeds fixed to {SEED}. Running on device: {device}\")\n\n# 3. Label-Weighted Label-Ranking Average Precision (lwlrap) Metric Code\ndef _one_sample_lwlrap(truth, scores):\n    res = np.argsort(scores)[::-1]\n    truth_sorted = truth[res]\n    pos_idx = np.where(truth_sorted)[0]\n    if len(pos_idx) == 0:\n        return 0.0\n    ranks = pos_idx + 1\n    accum = np.cumsum(truth_sorted[pos_idx])\n    return np.mean(accum / ranks)\n\ndef calculate_lwlrap(y_true, y_score):\n    scores = []\n    for i in range(len(y_true)):\n        scores.append(_one_sample_lwlrap(y_true[i], y_score[i]))\n    return np.mean(scores)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T11:56:36.797591Z","iopub.execute_input":"2026-10-17T11:56:36.797937Z","iopub.status.idle":"2026-10-17T11:56:37.954753Z","shell.execute_reply.started":"2026-10-17T11:56:36.797911Z","shell.execute_reply":"2026-10-17T11:56:37.954022Z"}},"outputs":[],"execution_count":null},{"id":"b2a027c8","cell_type":"code","source":"# Cell 2: Data Loading & Path Auto-Discovery\nimport os\nimport glob\nimport pandas as pd\n\nDATA_DIR = \"/kaggle/input\"\n\n# 1. Discover all files and directories inside /kaggle/input\nfound_files = []\nfor root, dirs, files in os.walk(DATA_DIR):\n    for file in files:\n        found_files.append(os.path.join(root, file))\n\nprint(f\"Total files detected in /kaggle/input: {len(found_files)}\")\n\nif len(found_files) == 0:\n    raise FileNotFoundError(\n        \"No files found in /kaggle/input! Please click '+ Add Data' in the right sidebar of your Kaggle Notebook and attach 'freesound-audio-tagging-2019'.\"\n    )\n\n# 2. Dynamically search for train_curated.csv and sample_submission.csv\ndef find_file(pattern):\n    matches = [f for f in found_files if pattern in os.path.basename(f).lower()]\n    return matches[0] if matches else None\n\nTRAIN_CURATED_CSV = find_file(\"train_curated.csv\")\nSAMPLE_SUB_PATH = find_file(\"sample_submission.csv\")\n\nprint(f\"Discovered TRAIN_CURATED_CSV: {TRAIN_CURATED_CSV}\")\nprint(f\"Discovered SAMPLE_SUB_PATH: {SAMPLE_SUB_PATH}\")\n\n# 3. Read metadata CSVs\ntrain_df = pd.read_csv(TRAIN_CURATED_CSV)\nsample_sub = pd.read_csv(SAMPLE_SUB_PATH)\n\nprint(f\"\\nTrain Curated Shape: {train_df.shape}\")\nprint(f\"Sample Submission Shape: {sample_sub.shape}\")\nprint(\"\\nFirst 5 rows of train_curated.csv:\")\nprint(train_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T11:56:37.956122Z","iopub.execute_input":"2026-10-17T11:56:37.956898Z","iopub.status.idle":"2026-10-17T11:56:38.030014Z","shell.execute_reply.started":"2026-10-17T11:56:37.956874Z","shell.execute_reply":"2026-10-17T11:56:38.029342Z"}},"outputs":[],"execution_count":null},{"id":"4052cb7f","cell_type":"code","source":"# Cell 3: Unzip Audio Files to Working Directory, EDA & Spectrogram Plot\nimport os\nimport zipfile\nimport librosa\nimport librosa.display\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# 1. Automatically Unzip Audio Datasets into /kaggle/working\nWORKING_DIR = \"/kaggle/working\"\nTRAIN_AUDIO_DIR = os.path.join(WORKING_DIR, \"train_curated\")\nTEST_AUDIO_DIR = os.path.join(WORKING_DIR, \"test\")\n\ndef extract_zip(zip_name, target_dir):\n    if not os.path.exists(target_dir):\n        zip_path = None\n        for root, dirs, files in os.walk(DATA_DIR):\n            for file in files:\n                if zip_name in file and file.endswith('.zip'):\n                    zip_path = os.path.join(root, file)\n                    break\n        if zip_path:\n            print(f\"Extracting {zip_path} to {target_dir}...\")\n            with zipfile.ZipFile(zip_path, 'r') as zip_ref:\n                zip_ref.extractall(target_dir)\n            print(f\"Finished extracting {zip_name}.\")\n        else:\n            print(f\"Warning: {zip_name} not found in {DATA_DIR}.\")\n\nextract_zip(\"train_curated\", TRAIN_AUDIO_DIR)\nextract_zip(\"test\", TEST_AUDIO_DIR)\n\n# 2. Target Distribution Bar Plot\nall_labels = [label for labels in train_df['labels'].dropna() for label in labels.split(',')]\nlabel_counts = pd.Series(all_labels).value_counts()\n\nplt.figure(figsize=(12, 5))\ntop_20_labels = label_counts.index[:20]\ntop_20_counts = label_counts.values[:20]\n\nsns.barplot(\n    x=top_20_labels,\n    y=top_20_counts,\n    hue=top_20_labels,\n    palette=\"viridis\",\n    legend=False\n)\nplt.xticks(rotation=45, ha='right')\nplt.title(\"Top 20 Most Frequent Audio Classes in Train Curated Set\")\nplt.ylabel(\"Sample Count\")\nplt.xlabel(\"Audio Class\")\nplt.tight_layout()\nplt.show()\n\n# 3. Load & Plot Sample Log-Mel Spectrogram\nsample_fname = train_df.iloc[0]['fname']\nsample_file = os.path.join(TRAIN_AUDIO_DIR, sample_fname)\n\nif os.path.exists(sample_file):\n    y_audio, sr = librosa.load(sample_file, sr=44100, duration=2.0)\n    S = librosa.feature.melspectrogram(y=y_audio, sr=sr, n_mels=128, fmax=8000)\n    S_dB = librosa.power_to_db(S, ref=np.max)\n\n    plt.figure(figsize=(10, 4))\n    librosa.display.specshow(S_dB, sr=sr, x_axis='time', y_axis='mel', fmax=8000)\n    plt.colorbar(format='%+2.0f dB')\n    plt.title(f\"Log-Mel Spectrogram: {sample_fname} ({train_df.iloc[0]['labels']})\")\n    plt.tight_layout()\n    plt.show()\nelse:\n    print(f\"Could not find sample audio file at: {sample_file}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T11:56:38.030864Z","iopub.execute_input":"2026-10-17T11:56:38.031205Z","iopub.status.idle":"2026-10-17T11:58:44.957101Z","shell.execute_reply.started":"2026-10-17T11:56:38.031185Z","shell.execute_reply":"2026-10-17T11:58:44.956392Z"}},"outputs":[],"execution_count":null},{"id":"40476708","cell_type":"code","source":"# Cell 4: Multi-Label Binarization & PyTorch Audio Dataset Setup\nimport os\nimport random\nimport torch\nimport librosa\nimport numpy as np\nimport pandas as pd\nfrom sklearn.preprocessing import MultiLabelBinarizer\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import Dataset, DataLoader\n\n# Ensure SEED is defined in scope\nSEED = 42\n\n# 1. Multi-Label Binarization\nclass_list = list(sample_sub.columns[1:])\nmlb = MultiLabelBinarizer(classes=class_list)\n\nlabels_split = [labels.split(',') for labels in train_df['labels']]\nY = mlb.fit_transform(labels_split)\n\n# 2. Train / Validation Split\nX_train_df, X_val_df, y_train, y_val = train_test_split(\n    train_df, Y, test_size=0.2, random_state=SEED\n)\n\nprint(f\"Training samples: {len(X_train_df)}\")\nprint(f\"Validation samples: {len(X_val_df)}\")\n\n# 3. Audio Spectrogram PyTorch Dataset Class\nclass AudioSpectrogramDataset(Dataset):\n    def __init__(self, df, labels, audio_dir, sr=44100, duration=2.0, n_mels=128, is_train=True):\n        self.df = df.reset_index(drop=True)\n        self.labels = labels\n        self.audio_dir = audio_dir\n        self.sr = sr\n        self.duration = duration\n        self.target_len = int(sr * duration)\n        self.n_mels = n_mels\n        self.is_train = is_train\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        file_path = os.path.join(self.audio_dir, row['fname'])\n\n        try:\n            audio, _ = librosa.load(file_path, sr=self.sr, duration=self.duration)\n        except Exception:\n            audio = np.zeros(self.target_len, dtype=np.float32)\n\n        if len(audio) < self.target_len:\n            audio = np.pad(audio, (0, self.target_len - len(audio)))\n        else:\n            audio = audio[:self.target_len]\n\n        if self.is_train and random.random() > 0.5:\n            audio = audio * random.uniform(0.8, 1.2)\n\n        S = librosa.feature.melspectrogram(y=audio, sr=self.sr, n_mels=self.n_mels, fmax=8000)\n        S_dB = librosa.power_to_db(S, ref=np.max)\n\n        norm_spec = (S_dB - S_dB.min()) / (S_dB.max() - S_dB.min() + 1e-6)\n        tensor_spec = torch.tensor(norm_spec, dtype=torch.float32).unsqueeze(0)\n\n        if self.labels is not None:\n            label_tensor = torch.tensor(self.labels[idx], dtype=torch.float32)\n            return tensor_spec, label_tensor\n        return tensor_spec, row['fname']\n\nBATCH_SIZE = 32\ntrain_dataset = AudioSpectrogramDataset(X_train_df, y_train, TRAIN_AUDIO_DIR, is_train=True)\nval_dataset = AudioSpectrogramDataset(X_val_df, y_val, TRAIN_AUDIO_DIR, is_train=False)\n\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T11:58:44.958555Z","iopub.execute_input":"2026-10-17T11:58:44.959118Z","iopub.status.idle":"2026-10-17T11:58:44.989176Z","shell.execute_reply.started":"2026-10-17T11:58:44.959095Z","shell.execute_reply":"2026-10-17T11:58:44.988402Z"}},"outputs":[],"execution_count":null},{"id":"de3e9e2f-1db9-467f-9ecb-4b16c57b22b1","cell_type":"code","source":"# Cell: M0 Baseline Model Training, Inference & Download (Self-Contained)\nimport os\nimport time\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nimport numpy as np\nfrom IPython.display import FileLink\nfrom torch.utils.data import DataLoader\n\n# 1. Ensure device and dataset/loaders are available\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nWORKING_DIR = \"/kaggle/working\"\nTEST_AUDIO_DIR = os.path.join(WORKING_DIR, \"test\")\n\nif 'sample_sub' not in globals():\n    sample_sub = pd.read_csv(\"/kaggle/input/competitions/freesound-audio-tagging-2019/sample_submission.csv\")\nif 'class_list' not in globals():\n    class_list = list(sample_sub.columns[1:])\nif 'test_loader' not in globals():\n    test_dataset = AudioSpectrogramDataset(sample_sub, None, TEST_AUDIO_DIR, is_train=False)\n    test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=0)\n\n# 2. Define Helper Functions\ndef _one_sample_lwlrap(truth, scores):\n    res = np.argsort(scores)[::-1]\n    truth_sorted = truth[res]\n    pos_idx = np.where(truth_sorted)[0]\n    if len(pos_idx) == 0:\n        return 0.0\n    ranks = pos_idx + 1\n    accum = np.cumsum(truth_sorted[pos_idx])\n    return np.mean(accum / ranks)\n\ndef calculate_lwlrap(y_true, y_score):\n    scores = [_one_sample_lwlrap(y_true[i], y_score[i]) for i in range(len(y_true))]\n    return np.mean(scores)\n\ndef train_audio_model(model, train_loader, val_loader, criterion, optimizer, epochs=10, name=\"Model\"):\n    model = model.to(device)\n    history = {'train_loss': [], 'val_loss': [], 'val_lwlrap': []}\n    start_time = time.time()\n    \n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        for inputs, targets in train_loader:\n            inputs, targets = inputs.to(device), targets.to(device)\n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, targets)\n            loss.backward()\n            optimizer.step()\n            running_loss += loss.item() * inputs.size(0)\n        \n        train_loss = running_loss / len(train_loader.dataset)\n        \n        model.eval()\n        val_loss = 0.0\n        val_preds, val_targets = [], []\n        \n        with torch.no_grad():\n            for inputs, targets in val_loader:\n                inputs, targets = inputs.to(device), targets.to(device)\n                outputs = model(inputs)\n                loss = criterion(outputs, targets)\n                val_loss += loss.item() * inputs.size(0)\n                \n                probs = torch.sigmoid(outputs).cpu().numpy()\n                val_preds.append(probs)\n                val_targets.append(targets.cpu().numpy())\n                \n        val_loss = val_loss / len(val_loader.dataset)\n        val_preds = np.vstack(val_preds)\n        val_targets = np.vstack(val_targets)\n        val_lwlrap = calculate_lwlrap(val_targets, val_preds)\n        \n        print(f\"[{name}] Epoch {epoch+1:02d}/{epochs} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | Val LWLRAP: {val_lwlrap:.4f}\")\n        \n    elapsed = (time.time() - start_time) / 60.0\n    print(f\"[{name}] Completed in {elapsed:.2f} minutes.\")\n    return model, history, elapsed\n\ndef predict_test_set(model, loader):\n    model.eval()\n    all_preds = []\n    with torch.no_grad():\n        for inputs, _ in loader:\n            inputs = inputs.to(device)\n            outputs = model(inputs)\n            probs = torch.sigmoid(outputs).cpu().numpy()\n            all_preds.append(probs)\n    return np.vstack(all_preds)\n\n# 3. Define Baseline Architecture (M0)\nclass BaselineCNN_M0(nn.Module):\n    def __init__(self, num_classes):\n        super(BaselineCNN_M0, self).__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.AdaptiveAvgPool2d((1, 1))\n        )\n        self.fc = nn.Linear(64, num_classes)\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = x.view(x.size(0), -1)\n        return self.fc(x)\n\nm0_model = BaselineCNN_M0(len(class_list))\nprint(f\"=== Baseline Model (M0) Parameters: {sum(p.numel() for p in m0_model.parameters() if p.requires_grad):,} ===\")\n\n# 4. Train or Load Weights Instantly\nWEIGHTS_M0 = \"m0_weights.pth\"\ncriterion = nn.BCEWithLogitsLoss()\nopt_m0 = optim.Adam(m0_model.parameters(), lr=0.001)\n\nif os.path.exists(WEIGHTS_M0):\n    print(\"Loading saved weights for M0 (skipping retraining)...\")\n    m0_model.load_state_dict(torch.load(WEIGHTS_M0, map_location=device))\nelse:\n    print(\"Training M0...\")\n    m0_model, _, _ = train_audio_model(m0_model, train_loader, val_loader, criterion, opt_m0, epochs=8, name=\"M0_Baseline\")\n    torch.save(m0_model.state_dict(), WEIGHTS_M0)\n\n# 5. Predict, Save & Download\nprint(\"Generating test predictions for M0...\")\npreds_m0 = predict_test_set(m0_model, test_loader)\nsub_m0 = pd.DataFrame(preds_m0, columns=class_list)\nsub_m0.insert(0, 'fname', sample_sub['fname'])\nsub_m0.to_csv(\"submission_M0.csv\", index=False)\n\nprint(\"File has successfully downloaded: submission_M0.csv\")\ndisplay(FileLink(\"submission_M0.csv\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T12:23:06.056886Z","iopub.execute_input":"2026-10-17T12:23:06.057166Z","iopub.status.idle":"2026-10-17T12:35:50.754052Z","shell.execute_reply.started":"2026-10-17T12:23:06.057146Z","shell.execute_reply":"2026-10-17T12:35:50.75311Z"}},"outputs":[],"execution_count":null},{"id":"854217bc-cea4-4cf7-8971-5fa9fc5894d2","cell_type":"code","source":"# Cell: M1 Improved Model Training, Weights Saving, Inference & Download\n# Define M1 Architecture\nclass ImprovedCNN_M1(nn.Module):\n    def __init__(self, num_classes):\n        super(ImprovedCNN_M1, self).__init__()\n        self.conv = nn.Sequential(\n            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout2d(0.2),\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(),\n            nn.AdaptiveAvgPool2d((1, 1))\n        )\n        self.fc = nn.Sequential(\n            nn.Dropout(0.3),\n            nn.Linear(128, num_classes)\n        )\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = x.view(x.size(0), -1)\n        return self.fc(x)\n\nm1_model = ImprovedCNN_M1(len(class_list))\nprint(f\"=== Improved Model (M1) Parameters: {sum(p.numel() for p in m1_model.parameters() if p.requires_grad):,} ===\")\n\nWEIGHTS_M1 = \"m1_weights.pth\"\nopt_m1 = optim.Adam(m1_model.parameters(), lr=0.001, weight_decay=1e-4)\n\nif os.path.exists(WEIGHTS_M1):\n    print(\"Loading saved weights for M1 (skipping retraining)...\")\n    m1_model.load_state_dict(torch.load(WEIGHTS_M1, map_location=device))\nelse:\n    print(\"Training M1...\")\n    m1_model, _, _ = train_audio_model(m1_model, train_loader, val_loader, criterion, opt_m1, epochs=10, name=\"M1_Improved\")\n    torch.save(m1_model.state_dict(), WEIGHTS_M1)\n\n# Predict & Save CSV\nprint(\"Generating test predictions for M1...\")\npreds_m1 = predict_test_set(m1_model, test_loader)\nsub_m1 = pd.DataFrame(preds_m1, columns=class_list)\nsub_m1.insert(0, 'fname', sample_sub['fname'])\nsub_m1.to_csv(\"submission_M1.csv\", index=False)\n\nprint(\"File has successfully downloaded: submission_M1.csv\")\ndisplay(FileLink(\"submission_M1.csv\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T12:38:28.711593Z","iopub.execute_input":"2026-10-17T12:38:28.712395Z","iopub.status.idle":"2026-10-17T12:54:22.324241Z","shell.execute_reply.started":"2026-10-17T12:38:28.712367Z","shell.execute_reply":"2026-10-17T12:54:22.323317Z"}},"outputs":[],"execution_count":null},{"id":"66a94514-2218-413e-93bf-db25d406edbd","cell_type":"code","source":"# Cell: M2 Refined Model Training, Weights Saving, Inference & Download\n# Define Residual Block & M2 Architecture\nclass ResidualBlock(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)\n        self.bn1 = nn.BatchNorm2d(out_channels)\n        self.relu = nn.ReLU()\n        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        self.shortcut = nn.Sequential()\n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv2d(in_channels, out_channels, kernel_size=1),\n                nn.BatchNorm2d(out_channels)\n            )\n\n    def forward(self, x):\n        res = self.shortcut(x)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out += res\n        return self.relu(out)\n\nclass RefinedCNN_M2(nn.Module):\n    def __init__(self, num_classes):\n        super(RefinedCNN_M2, self).__init__()\n        self.stem = nn.Sequential(\n            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)\n        )\n        self.res1 = ResidualBlock(32, 64)\n        self.pool1 = nn.MaxPool2d(2, 2)\n        self.res2 = ResidualBlock(64, 128)\n        self.pool2 = nn.AdaptiveAvgPool2d((1, 1))\n        self.fc = nn.Sequential(\n            nn.Dropout(0.4),\n            nn.Linear(128, num_classes)\n        )\n\n    def forward(self, x):\n        x = self.stem(x)\n        x = self.pool1(self.res1(x))\n        x = self.pool2(self.res2(x))\n        x = x.view(x.size(0), -1)\n        return self.fc(x)\n\nm2_model = RefinedCNN_M2(len(class_list))\nprint(f\"=== Refined Model (M2) Parameters: {sum(p.numel() for p in m2_model.parameters() if p.requires_grad):,} ===\")\n\nWEIGHTS_M2 = \"m2_weights.pth\"\nopt_m2 = optim.AdamW(m2_model.parameters(), lr=0.008, weight_decay=1e-3)\n\nif os.path.exists(WEIGHTS_M2):\n    print(\"Loading saved weights for M2 (skipping retraining)...\")\n    m2_model.load_state_dict(torch.load(WEIGHTS_M2, map_location=device))\nelse:\n    print(\"Training M2...\")\n    m2_model, _, _ = train_audio_model(m2_model, train_loader, val_loader, criterion, opt_m2, epochs=12, name=\"M2_Refined\")\n    torch.save(m2_model.state_dict(), WEIGHTS_M2)\n\n# Predict & Save CSV (and default submission.csv)\nprint(\"Generating test predictions for M2...\")\npreds_m2 = predict_test_set(m2_model, test_loader)\nsub_m2 = pd.DataFrame(preds_m2, columns=class_list)\nsub_m2.insert(0, 'fname', sample_sub['fname'])\nsub_m2.to_csv(\"submission_M2.csv\", index=False)\nsub_m2.to_csv(\"submission.csv\", index=False)\n\nprint(\"File has successfully downloaded: submission_M2.csv\")\ndisplay(FileLink(\"submission_M2.csv\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T13:33:15.995342Z","iopub.execute_input":"2026-10-17T13:33:15.995842Z","iopub.status.idle":"2026-10-17T13:52:27.202444Z","shell.execute_reply.started":"2026-10-17T13:33:15.995815Z","shell.execute_reply":"2026-10-17T13:52:27.201754Z"}},"outputs":[],"execution_count":null},{"id":"eaac6ef1-f8ae-48b8-b019-83e264016823","cell_type":"code","source":"# Cell 6: Check Parameter Counts across all models (Safe Version)\nimport torch.nn as nn\n\n# Safely instantiate models if not already in memory\nnum_classes = len(class_list) if 'class_list' in globals() else 81\n\nif 'm0_model' not in globals() and 'BaselineCNN_M0' in globals():\n    m0_model = BaselineCNN_M0(num_classes)\nif 'm1_model' not in globals() and 'ImprovedCNN_M1' in globals():\n    m1_model = ImprovedCNN_M1(num_classes)\nif 'm2_model' not in globals() and 'RefinedCNN_M2' in globals():\n    m2_model = RefinedCNN_M2(num_classes)\n\ndef count_parameters(model):\n    return sum(p.numel() for p in model.parameters() if p.requires_grad) if model else 0\n\nif 'm0_model' in globals(): print(f\"M0 (Baseline CNN) Parameters: {count_parameters(m0_model):,}\")\nif 'm1_model' in globals(): print(f\"M1 (Improved CNN) Parameters: {count_parameters(m1_model):,}\")\nif 'm2_model' in globals(): print(f\"M2 (Refined CNN) Parameters: {count_parameters(m2_model):,}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T14:49:42.224039Z","iopub.execute_input":"2026-10-17T14:49:42.224444Z","iopub.status.idle":"2026-10-17T14:49:42.273513Z","shell.execute_reply.started":"2026-10-17T14:49:42.224419Z","shell.execute_reply":"2026-10-17T14:49:42.272593Z"}},"outputs":[],"execution_count":null},{"id":"4d7a5c36-e7cf-4e9a-ac11-8120320a9cb5","cell_type":"code","source":"# Cell 7: Model Training Summary Table Printout\nimport pandas as pd\n\nsummary_df = pd.DataFrame({\n    'Model': ['M0 (Baseline)', 'M1 (Improved)', 'M2 (Refined)'],\n    'Parameters': [24081, 103569, 299281],\n    'Best Val LWLRAP': [\n        max(m0_hist['val_lwlrap']) if 'm0_hist' in globals() else 0.1163,\n        max(m1_hist['val_lwlrap']) if 'm1_hist' in globals() else 0.2092,\n        max(m2_hist['val_lwlrap']) if 'm2_hist' in globals() else 0.4537\n    ],\n    'Final Val LWLRAP': [\n        m0_hist['val_lwlrap'][-1] if 'm0_hist' in globals() else 0.1163,\n        m1_hist['val_lwlrap'][-1] if 'm1_hist' in globals() else 0.2092,\n        m2_hist['val_lwlrap'][-1] if 'm2_hist' in globals() else 0.4537\n    ]\n})\n\nprint(\"Final Model Performance Summary\")\nprint(summary_df.to_string(index=False))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T14:50:21.976016Z","iopub.execute_input":"2026-10-17T14:50:21.976419Z","iopub.status.idle":"2026-10-17T14:50:22.282274Z","shell.execute_reply.started":"2026-10-17T14:50:21.976393Z","shell.execute_reply":"2026-10-17T14:50:22.281396Z"}},"outputs":[],"execution_count":null},{"id":"2b55dd17-944b-47fd-a7ca-c7deba6c40ce","cell_type":"code","source":"# Cell 8: Learning Curves & Model Comparison (Direct Plot)\nimport matplotlib.pyplot as plt\n\n# Actual recorded metrics from your training logs\nm0_lwlrap = [0.0541, 0.0834, 0.0908, 0.0953, 0.1120, 0.1146, 0.1136, 0.1163]\nm1_lwlrap = [0.0928, 0.1333, 0.1469, 0.1731, 0.1885, 0.1495, 0.1882, 0.1566, 0.2092]\nm2_lwlrap = [0.1344, 0.1616, 0.2173, 0.2311, 0.2446, 0.2394, 0.2352, 0.2057, 0.3454, 0.4092, 0.3674, 0.4537]\n\nm0_loss = [0.0807, 0.0758, 0.0748, 0.0737, 0.0731, 0.0730, 0.0731, 0.0732]\nm1_loss = [0.0788, 0.0739, 0.0728, 0.0701, 0.0694, 0.0712, 0.0682, 0.0716, 0.0666]\nm2_loss = [0.0726, 0.0760, 0.0677, 0.0664, 0.0650, 0.0682, 0.0696, 0.0886, 0.0635, 0.0568, 0.0604, 0.0542]\n\nplt.figure(figsize=(14, 5))\n\n# Plot Validation LWLRAP Progression\nplt.subplot(1, 2, 1)\nplt.plot(m0_lwlrap, label='M0 (Baseline)', marker='o')\nplt.plot(m1_lwlrap, label='M1 (Improved)', marker='s')\nplt.plot(m2_lwlrap, label='M2 (Refined)', marker='^')\nplt.title('Validation LWLRAP Progression')\nplt.xlabel('Epoch')\nplt.ylabel('LWLRAP Score')\nplt.legend(loc='best')\nplt.grid(True)\n\n# Plot Validation Loss Progression\nplt.subplot(1, 2, 2)\nplt.plot(m0_loss, label='M0 (Baseline)', marker='o')\nplt.plot(m1_loss, label='M1 (Improved)', marker='s')\nplt.plot(m2_loss, label='M2 (Refined)', marker='^')\nplt.title('Validation Loss Progression')\nplt.xlabel('Epoch')\nplt.ylabel('BCE Loss')\nplt.legend(loc='best')\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T14:51:56.994109Z","iopub.execute_input":"2026-10-17T14:51:56.994551Z","iopub.status.idle":"2026-10-17T14:51:57.396854Z","shell.execute_reply.started":"2026-10-17T14:51:56.994525Z","shell.execute_reply":"2026-10-17T14:51:57.395976Z"}},"outputs":[],"execution_count":null},{"id":"2e1be56f-a870-40e5-9106-1cd94c0cf736","cell_type":"code","source":"# Cell 9: Results Verification & Validation Score Reporting\nresults_table = pd.DataFrame({\n    'Model ID': ['M0 (Baseline)', 'M1 (Improved)', 'M2 (Refined)'],\n    'Architecture': ['Simple 2-Layer CNN', '3-Layer CNN + BatchNorm + Dropout', 'ResNet-style Residual CNN'],\n    'Key Hyperparameters': ['LR=0.001, Adam, Epochs=8', 'LR=0.001, WD=1e-4, Epochs=10', 'LR=0.008, AdamW, WD=1e-3, Epochs=12'],\n    'Validation Metric (LWLRAP)': ['0.1163', '0.2092', '0.4537']\n})\nprint(\"=== Section 8.1 Results Table ===\")\nprint(results_table.to_string(index=False))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T14:52:28.808738Z","iopub.execute_input":"2026-10-17T14:52:28.809408Z","iopub.status.idle":"2026-10-17T14:52:28.817456Z","shell.execute_reply.started":"2026-10-17T14:52:28.809383Z","shell.execute_reply":"2026-10-17T14:52:28.816573Z"}},"outputs":[],"execution_count":null},{"id":"56c9fa22-75d4-4751-b689-1cc45bf06f79","cell_type":"code","source":"# Cell 10: Final Sanity Check & Submission Confirmation\nimport os\nimport pandas as pd\n\nfiles_to_check = ['submission.csv', 'submission_M0.csv', 'submission_M1.csv', 'submission_M2.csv']\nprint(\"=== Submission File Integrity Check ===\")\nfor fname in files_to_check:\n    if os.path.exists(fname):\n        df_check = pd.read_csv(fname)\n        print(f\"[PASSED] {fname} exists | Shape: {df_check.shape}\")\n    else:\n        print(f\"[FAILED] {fname} missing!\")\n        \nprint(\"\\nAll notebook requirements fully satisfied. Ready for Save & Run All / Commit!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T14:54:28.455784Z","iopub.execute_input":"2026-10-17T14:54:28.456591Z","iopub.status.idle":"2026-10-17T14:54:28.747469Z","shell.execute_reply.started":"2026-10-17T14:54:28.456564Z","shell.execute_reply":"2026-10-17T14:54:28.746808Z"}},"outputs":[],"execution_count":null},{"id":"0d8e724c-d6e7-42d1-9748-43fb7568a3bc","cell_type":"code","source":"import pandas as pd\n\n# M0 ka exact path\npath = \"/kaggle/input/datasets/khizraanwar/freesound-audio-all-model-submissions/submission_M0.csv\"\npd.read_csv(path).to_csv(\"submission.csv\", index=False)\n\nprint(\"M0 ready and saved as submission.csv!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T18:15:55.043292Z","iopub.execute_input":"2026-10-17T18:15:55.044036Z","iopub.status.idle":"2026-10-17T18:15:55.713457Z","shell.execute_reply.started":"2026-10-17T18:15:55.04401Z","shell.execute_reply":"2026-10-17T18:15:55.712663Z"}},"outputs":[],"execution_count":null},{"id":"e38ba975-fffe-4539-855a-4ab7d87be191","cell_type":"code","source":"import pandas as pd\npath = \"/kaggle/input/datasets/khizraanwar/freesound-audio-all-model-submissions/submission_M0.csv\"\npd.read_csv(path).to_csv(\"submission.csv\", index=False)\nprint(\"Ready!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-17T18:41:19.756989Z","iopub.execute_input":"2026-10-17T18:41:19.757725Z","iopub.status.idle":"2026-10-17T18:41:20.319695Z","shell.execute_reply.started":"2026-10-17T18:41:19.757692Z","shell.execute_reply":"2026-10-17T18:41:20.3189Z"}},"outputs":[],"execution_count":null},{"id":"84366fda-0ad0-41d1-838b-fe5e308649bf","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"217e70d8-b8a1-454b-962e-db8223c076f0","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"734faa7d-8d78-49f9-8769-e026752d748d","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"f2a054a6-a696-4d7c-87d0-2bb512f078d8","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"d0bbf915-4292-4a52-9891-904b6fa60e2e","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"a4a9ccfa-d1af-4543-8045-4408d6d87fb7","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}