{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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":11973904,"sourceType":"datasetVersion","datasetId":7529881}],"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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:01:50.284736Z","iopub.execute_input":"2025-05-28T13:01:50.285067Z","iopub.status.idle":"2025-05-28T13:01:50.661996Z","shell.execute_reply.started":"2025-05-28T13:01:50.285033Z","shell.execute_reply":"2025-05-28T13:01:50.660222Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Train տվյալները\ndf_train = pd.read_csv(\"/kaggle/input/birdclef-2025/train.csv\")\nprint(\"📊 train.csv shape:\", df_train.shape)\ndisplay(df_train.head())\n\n# Taxonomy տվյալները\ndf_taxonomy = pd.read_csv(\"/kaggle/input/birdclef-2025/taxonomy.csv\")\nprint(\"\\n🌿 taxonomy.csv shape:\", df_taxonomy.shape)\ndisplay(df_taxonomy.head())\n\n# Ներկայացման նմուշ\ndf_sample = pd.read_csv(\"/kaggle/input/birdclef-2025/sample_submission.csv\")\nprint(\"\\n📤 sample_submission.csv shape:\", df_sample.shape)\ndisplay(df_sample.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:01:50.664762Z","iopub.execute_input":"2025-05-28T13:01:50.665221Z","iopub.status.idle":"2025-05-28T13:01:50.954575Z","shell.execute_reply.started":"2025-05-28T13:01:50.665195Z","shell.execute_reply":"2025-05-28T13:01:50.953472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install librosa matplotlib soundfile\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:01:50.955649Z","iopub.execute_input":"2025-05-28T13:01:50.955989Z","iopub.status.idle":"2025-05-28T13:01:57.092996Z","shell.execute_reply.started":"2025-05-28T13:01:50.955947Z","shell.execute_reply":"2025-05-28T13:01:57.091557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import librosa\nimport librosa.display\nimport matplotlib.pyplot as plt\nimport os\n\ndef show_mel_spectrogram(file_path, sr=32000):\n    audio, _ = librosa.load(file_path, sr=sr)\n    mel_spec = librosa.feature.melspectrogram(y=audio, sr=sr, n_mels=128)\n    mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n    plt.figure(figsize=(10, 4))\n    librosa.display.specshow(mel_spec_db, sr=sr, x_axis='time', y_axis='mel')\n    plt.colorbar(format='%+2.0f dB')\n    plt.title('Mel Spectrogram')\n    plt.tight_layout()\n    plt.show()\n\n# Օրինակ 1-ին train ֆայլը վերցնել\nexample_path = os.path.join(\"/kaggle/input/birdclef-2025/train_audio\", \"/kaggle/input/birdclef-2025/train_audio/1139490\", \"/kaggle/input/birdclef-2025/train_audio/1139490/CSA36385.ogg\")\nshow_mel_spectrogram(example_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:01:57.094476Z","iopub.execute_input":"2025-05-28T13:01:57.094825Z","iopub.status.idle":"2025-05-28T13:02:17.551037Z","shell.execute_reply.started":"2025-05-28T13:01:57.094792Z","shell.execute_reply":"2025-05-28T13:02:17.549801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import librosa\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nfrom tqdm import tqdm\n\ndef extract_mel_spectrograms(file_path, sr=32000, duration=5, hop_length=512, n_mels=128):\n    audio, _ = librosa.load(file_path, sr=sr)\n    total_secs = int(len(audio) / sr)\n    segments = []\n\n    for start in range(0, total_secs, duration):\n        end = start + duration\n        if end > total_secs:\n            break\n        start_sample = start * sr\n        end_sample = end * sr\n        segment = audio[start_sample:end_sample]\n\n        mel = librosa.feature.melspectrogram(y=segment, sr=sr, n_mels=n_mels, hop_length=hop_length)\n        mel_db = librosa.power_to_db(mel, ref=np.max)\n        segments.append(mel_db)\n\n    return segments\n\n# Օրինակ՝ փորձենք 1 ֆայլի վրա\nexample_path = os.path.join(\"/kaggle/input/birdclef-2025/train_audio\", \"1139490\", \"CSA36385.ogg\")\nmel_segments = extract_mel_spectrograms(example_path)\n\nprint(f\"📈 Պատրաստված է {len(mel_segments)} կտոր\")\nplt.figure(figsize=(10, 4))\nlibrosa.display.specshow(mel_segments[0], sr=32000, x_axis='time', y_axis='mel')\nplt.colorbar()\nplt.title(\"Mel Spectrogram - Segment 1\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:17.554137Z","iopub.execute_input":"2025-05-28T13:02:17.554898Z","iopub.status.idle":"2025-05-28T13:02:18.372766Z","shell.execute_reply.started":"2025-05-28T13:02:17.554849Z","shell.execute_reply":"2025-05-28T13:02:18.371858Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from glob import glob\n\ndef build_mel_dataset(train_df, base_audio_path, max_files=50):  # max_files=50 ժամանակավորապես\n    dataset = []\n\n    for i, row in tqdm(train_df.iterrows(), total=min(len(train_df), max_files)):\n        label = row['primary_label']\n        rel_path = row['filename']  # e.g., 1139490/CSA36385.ogg\n        full_path = os.path.join(base_audio_path, rel_path)\n\n        if not os.path.exists(full_path):\n            continue\n\n        try:\n            segments = extract_mel_spectrograms(full_path)\n            for mel in segments:\n                dataset.append({\n                    \"mel\": mel,\n                    \"label\": label\n                })\n        except Exception as e:\n            print(f\"❌ Error with {full_path}: {e}\")\n            continue\n\n        if i + 1 >= max_files:  # early stop\n            break\n\n    return dataset\n\n# Օգտագործում ենք\nmel_dataset = build_mel_dataset(df_train, base_audio_path=\"/kaggle/input/birdclef-2025/train_audio\", max_files=30)\n\nprint(f\"\\n✅ Ստացվեց {len(mel_dataset)} մել սպեկտրոգրամ կտոր ընդհանուր {len(set([x['label'] for x in mel_dataset]))} տարբեր թեգերով\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:18.373723Z","iopub.execute_input":"2025-05-28T13:02:18.374003Z","iopub.status.idle":"2025-05-28T13:02:28.519185Z","shell.execute_reply.started":"2025-05-28T13:02:18.373982Z","shell.execute_reply":"2025-05-28T13:02:28.517777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\nimport torch\n\n# Ստեղծում ենք label encoder\nlabel_encoder = LabelEncoder()\nall_labels = [x['label'] for x in mel_dataset]\nlabel_encoder.fit(all_labels)\nnum_classes = len(label_encoder.classes_)\n\nprint(\"📚 Դասերի քանակ:\", num_classes)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:28.521256Z","iopub.execute_input":"2025-05-28T13:02:28.522515Z","iopub.status.idle":"2025-05-28T13:02:36.641530Z","shell.execute_reply.started":"2025-05-28T13:02:28.522483Z","shell.execute_reply":"2025-05-28T13:02:36.640295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import Dataset\n\nclass BirdClefDataset(Dataset):\n    def __init__(self, data, label_encoder):\n        self.data = data\n        self.encoder = label_encoder\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        mel = self.data[idx]['mel']\n        label = self.data[idx]['label']\n\n        # Normalize spectrogram\n        mel = (mel - mel.min()) / (mel.max() - mel.min())\n\n        # To tensor, add channel dim\n        mel_tensor = torch.tensor(mel, dtype=torch.float32).unsqueeze(0)  # shape: [1, H, W]\n\n        # Label as index (for now)\n        label_index = self.encoder.transform([label])[0]\n        label_tensor = torch.tensor(label_index, dtype=torch.long)\n\n        return mel_tensor, label_tensor\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:36.642623Z","iopub.execute_input":"2025-05-28T13:02:36.643152Z","iopub.status.idle":"2025-05-28T13:02:36.653839Z","shell.execute_reply.started":"2025-05-28T13:02:36.643127Z","shell.execute_reply":"2025-05-28T13:02:36.651926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = BirdClefDataset(mel_dataset, label_encoder)\nx, y = dataset[0]\nprint(\"📐 Input shape:\", x.shape)\nprint(\"🏷️ Label index:\", y.item(), \"=\", label_encoder.inverse_transform([y.item()])[0])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:36.655312Z","iopub.execute_input":"2025-05-28T13:02:36.655712Z","iopub.status.idle":"2025-05-28T13:02:36.777420Z","shell.execute_reply.started":"2025-05-28T13:02:36.655678Z","shell.execute_reply":"2025-05-28T13:02:36.776347Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass BirdCLEFCNN(nn.Module):\n    def __init__(self, num_classes):\n        super(BirdCLEFCNN, self).__init__()\n        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1)\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)\n        self.pool = nn.MaxPool2d(2, 2)\n        self.dropout = nn.Dropout(0.3)\n        self.fc1 = nn.Linear(32 * 32 * 78, 128)  # depends on input shape\n        self.fc2 = nn.Linear(128, num_classes)\n\n    def forward(self, x):\n        x = self.pool(F.relu(self.conv1(x)))  # [B, 16, H/2, W/2]\n        x = self.pool(F.relu(self.conv2(x)))  # [B, 32, H/4, W/4]\n        x = x.view(x.size(0), -1)  # flatten\n        x = self.dropout(F.relu(self.fc1(x)))\n        x = self.fc2(x)\n        return x\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:36.778621Z","iopub.execute_input":"2025-05-28T13:02:36.779143Z","iopub.status.idle":"2025-05-28T13:02:36.789753Z","shell.execute_reply.started":"2025-05-28T13:02:36.779110Z","shell.execute_reply":"2025-05-28T13:02:36.788047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom sklearn.metrics import accuracy_score\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = BirdCLEFCNN(num_classes=num_classes).to(device)\n\ntrain_loader = DataLoader(dataset, batch_size=16, shuffle=True)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\ncriterion = nn.CrossEntropyLoss()\n\n# Train 1 epoch\nmodel.train()\nfor epoch in range(1):\n    running_loss = 0.0\n    all_preds = []\n    all_labels = []\n    \n    for inputs, labels in train_loader:\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        preds = torch.argmax(outputs, dim=1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\n    acc = accuracy_score(all_labels, all_preds)\n    print(f\"📚 Epoch {epoch+1} — Loss: {running_loss:.4f} — Accuracy: {acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:36.791542Z","iopub.execute_input":"2025-05-28T13:02:36.792152Z","iopub.status.idle":"2025-05-28T13:02:52.329060Z","shell.execute_reply.started":"2025-05-28T13:02:36.792115Z","shell.execute_reply":"2025-05-28T13:02:52.327897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mel_dataset = build_mel_dataset(df_train, base_audio_path=\"/kaggle/input/birdclef-2025/train_audio\", max_files=1000)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:02:52.330295Z","iopub.execute_input":"2025-05-28T13:02:52.330895Z","iopub.status.idle":"2025-05-28T13:06:10.160575Z","shell.execute_reply.started":"2025-05-28T13:02:52.330861Z","shell.execute_reply":"2025-05-28T13:06:10.159313Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from collections import Counter\n\nlabel_counts = Counter([x['label'] for x in mel_dataset])\nvalid_labels = set([label for label, count in label_counts.items() if count >= 2])\nfiltered_dataset = [x for x in mel_dataset if x['label'] in valid_labels]\n\nprint(f\"📦 Նախքան: {len(mel_dataset)} | Հետո ֆիլտրումից: {len(filtered_dataset)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:06:10.162997Z","iopub.execute_input":"2025-05-28T13:06:10.163306Z","iopub.status.idle":"2025-05-28T13:06:10.176564Z","shell.execute_reply.started":"2025-05-28T13:06:10.163283Z","shell.execute_reply":"2025-05-28T13:06:10.175096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\nfiltered_labels = [x['label'] for x in filtered_dataset]\nlabel_encoder = LabelEncoder()\nlabel_encoder.fit(filtered_labels)\n\nnum_classes = len(label_encoder.classes_)\nprint(\"📚 Վերջնական դասերի քանակ:\", num_classes)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:06:10.181806Z","iopub.execute_input":"2025-05-28T13:06:10.182132Z","iopub.status.idle":"2025-05-28T13:06:10.214103Z","shell.execute_reply.started":"2025-05-28T13:06:10.182111Z","shell.execute_reply":"2025-05-28T13:06:10.212843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_data, val_data = train_test_split(\n    filtered_dataset,\n    test_size=0.2,\n    stratify=filtered_labels,\n    random_state=42\n)\n\nprint(f\"✅ Train segments: {len(train_data)}, Validation segments: {len(val_data)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:06:10.215134Z","iopub.execute_input":"2025-05-28T13:06:10.215446Z","iopub.status.idle":"2025-05-28T13:06:10.266040Z","shell.execute_reply.started":"2025-05-28T13:06:10.215417Z","shell.execute_reply":"2025-05-28T13:06:10.264941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = BirdClefDataset(train_data, label_encoder)\nval_dataset = BirdClefDataset(val_data, label_encoder)\n\nfrom torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:06:10.267243Z","iopub.execute_input":"2025-05-28T13:06:10.267579Z","iopub.status.idle":"2025-05-28T13:06:10.274042Z","shell.execute_reply.started":"2025-05-28T13:06:10.267556Z","shell.execute_reply":"2025-05-28T13:06:10.272692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = BirdCLEFCNN(num_classes=num_classes).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\ncriterion = nn.CrossEntropyLoss()\n\nfor epoch in range(5):\n    model.train()\n    train_preds, train_labels = [], []\n    train_loss = 0.0\n    \n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        \n        train_loss += loss.item()\n        preds = torch.argmax(outputs, dim=1)\n        train_preds.extend(preds.cpu().numpy())\n        train_labels.extend(labels.cpu().numpy())\n    \n    train_acc = accuracy_score(train_labels, train_preds)\n\n    # Validation\n    model.eval()\n    val_preds, val_labels = [], []\n    val_loss = 0.0\n\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            val_loss += loss.item()\n            preds = torch.argmax(outputs, dim=1)\n            val_preds.extend(preds.cpu().numpy())\n            val_labels.extend(labels.cpu().numpy())\n    \n    val_acc = accuracy_score(val_labels, val_preds)\n\n    print(f\"📚 Epoch {epoch+1}: Train Loss={train_loss:.3f}, Acc={train_acc:.4f} | Val Loss={val_loss:.3f}, Acc={val_acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:06:10.275229Z","iopub.execute_input":"2025-05-28T13:06:10.275591Z","iopub.status.idle":"2025-05-28T13:21:27.823240Z","shell.execute_reply.started":"2025-05-28T13:06:10.275566Z","shell.execute_reply":"2025-05-28T13:21:27.821871Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\nclass BirdClefEffDataset(Dataset):\n    def __init__(self, data, label_encoder):\n        self.data = data\n        self.encoder = label_encoder\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        mel = self.data[idx]['mel']\n        label = self.data[idx]['label']\n\n        mel = (mel - mel.min()) / (mel.max() - mel.min())  # normalize\n        mel_tensor = torch.tensor(mel, dtype=torch.float32).unsqueeze(0)  # [1, H, W]\n\n        # Resize to 224×224\n        mel_tensor = F.interpolate(mel_tensor.unsqueeze(0), size=(224, 224), mode='bilinear', align_corners=False)\n        mel_tensor = mel_tensor.squeeze(0)  # back to [1, 224, 224]\n\n        label_index = self.encoder.transform([label])[0]\n        label_tensor = torch.tensor(label_index, dtype=torch.long)\n\n        return mel_tensor, label_tensor\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.824604Z","iopub.execute_input":"2025-05-28T13:21:27.825027Z","iopub.status.idle":"2025-05-28T13:21:27.835530Z","shell.execute_reply.started":"2025-05-28T13:21:27.825003Z","shell.execute_reply":"2025-05-28T13:21:27.834513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random\n\nclass BirdClefEffAugmentedDataset(Dataset):\n    def __init__(self, data, label_encoder):\n        self.data = data\n        self.encoder = label_encoder\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        mel = self.data[idx]['mel']\n        label = self.data[idx]['label']\n\n        mel = (mel - mel.min()) / (mel.max() - mel.min())\n        mel_tensor = torch.tensor(mel, dtype=torch.float32).unsqueeze(0)  # [1, H, W]\n\n        # SpecAugment-style masking\n        if random.random() < 0.8:\n            time_mask = random.randint(10, 40)\n            freq_mask = random.randint(5, 20)\n            time_start = random.randint(0, mel_tensor.shape[2] - time_mask)\n            freq_start = random.randint(0, mel_tensor.shape[1] - freq_mask)\n            mel_tensor[0, freq_start:freq_start+freq_mask, :] = 0\n            mel_tensor[0, :, time_start:time_start+time_mask] = 0\n\n        # Resize to 224x224\n        mel_tensor = F.interpolate(mel_tensor.unsqueeze(0), size=(224, 224), mode='bilinear', align_corners=False)\n        mel_tensor = mel_tensor.squeeze(0)\n\n        label_tensor = torch.tensor(self.encoder.transform([label])[0], dtype=torch.long)\n        return mel_tensor, label_tensor\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.836383Z","iopub.execute_input":"2025-05-28T13:21:27.836679Z","iopub.status.idle":"2025-05-28T13:21:27.871319Z","shell.execute_reply.started":"2025-05-28T13:21:27.836655Z","shell.execute_reply":"2025-05-28T13:21:27.870441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass LabelSmoothingCrossEntropy(nn.Module):\n    def __init__(self, smoothing=0.1):\n        super(LabelSmoothingCrossEntropy, self).__init__()\n        self.smoothing = smoothing\n\n    def forward(self, pred, target):\n        confidence = 1.0 - self.smoothing\n        logprobs = F.log_softmax(pred, dim=-1)\n        nll_loss = -logprobs.gather(dim=-1, index=target.unsqueeze(1)).squeeze(1)\n        smooth_loss = -logprobs.mean(dim=-1)\n        loss = confidence * nll_loss + self.smoothing * smooth_loss\n        return loss.mean()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.872279Z","iopub.execute_input":"2025-05-28T13:21:27.872649Z","iopub.status.idle":"2025-05-28T13:21:27.897642Z","shell.execute_reply.started":"2025-05-28T13:21:27.872619Z","shell.execute_reply":"2025-05-28T13:21:27.896717Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = LabelSmoothingCrossEntropy(smoothing=0.1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.898686Z","iopub.execute_input":"2025-05-28T13:21:27.899016Z","iopub.status.idle":"2025-05-28T13:21:27.916530Z","shell.execute_reply.started":"2025-05-28T13:21:27.898987Z","shell.execute_reply":"2025-05-28T13:21:27.915722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.optim.lr_scheduler import CosineAnnealingLR\n\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\nscheduler = CosineAnnealingLR(optimizer, T_max=5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.917358Z","iopub.execute_input":"2025-05-28T13:21:27.917765Z","iopub.status.idle":"2025-05-28T13:21:27.947329Z","shell.execute_reply.started":"2025-05-28T13:21:27.917741Z","shell.execute_reply":"2025-05-28T13:21:27.946468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scheduler.step()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:27.948307Z","iopub.execute_input":"2025-05-28T13:21:27.948591Z","iopub.status.idle":"2025-05-28T13:21:28.005236Z","shell.execute_reply.started":"2025-05-28T13:21:27.948570Z","shell.execute_reply":"2025-05-28T13:21:28.003921Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FocalLoss(nn.Module):\n    def __init__(self, alpha=1, gamma=2):\n        super().__init__()\n        self.alpha = alpha\n        self.gamma = gamma\n        self.ce = nn.CrossEntropyLoss()\n\n    def forward(self, inputs, targets):\n        ce_loss = self.ce(inputs, targets)\n        pt = torch.exp(-ce_loss)\n        focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss\n        return focal_loss.mean()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.006377Z","iopub.execute_input":"2025-05-28T13:21:28.006801Z","iopub.status.idle":"2025-05-28T13:21:28.013202Z","shell.execute_reply.started":"2025-05-28T13:21:28.006769Z","shell.execute_reply":"2025-05-28T13:21:28.012314Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torchaudio\nimport librosa\nimport os\nimport numpy as np\n\ndef predict_with_tta(model, filepath, label_encoder, device, tta_segments=[0, 5, 10]):\n    y, sr = librosa.load(filepath, sr=32000)\n    model.eval()\n    all_outputs = []\n\n    for start in tta_segments:\n        start_sample = start * sr\n        end_sample = start_sample + 5 * sr\n        if end_sample > len(y):\n            break\n        segment = y[start_sample:end_sample]\n\n        # Mel spectrogram\n        mel = librosa.feature.melspectrogram(y=segment, sr=sr, n_mels=128)\n        mel_db = librosa.power_to_db(mel, ref=np.max)\n        mel_db = (mel_db - mel_db.min()) / (mel_db.max() - mel_db.min())\n\n        tensor = torch.tensor(mel_db, dtype=torch.float32).unsqueeze(0).unsqueeze(0)  # [1, 1, H, W]\n        tensor = F.interpolate(tensor, size=(224, 224), mode='bilinear', align_corners=False)\n        tensor = tensor.to(device)\n\n        with torch.no_grad():\n            output = model(tensor)\n            probs = torch.softmax(output, dim=1)\n            all_outputs.append(probs.cpu().numpy())\n\n    # Միջինացնել բոլոր segment-ների արդյունքները\n    mean_probs = np.mean(all_outputs, axis=0)\n    return mean_probs.flatten()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.014469Z","iopub.execute_input":"2025-05-28T13:21:28.014821Z","iopub.status.idle":"2025-05-28T13:21:28.777533Z","shell.execute_reply.started":"2025-05-28T13:21:28.014792Z","shell.execute_reply":"2025-05-28T13:21:28.775934Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndef generate_submission(model, label_encoder, device, test_folder='/kaggle/input/birdclef-2025/test_soundscapes', sample_csv='/kaggle/input/birdclef-2025/sample_submission.csv', output_csv='/kaggle/working/submission.csv'):\n    sample_df = pd.read_csv(sample_csv)\n    row_ids = sample_df['row_id'].values\n    label_columns = sample_df.columns[1:]\n\n    final_preds = []\n\n    for row_id in row_ids:\n        filename = row_id.split(\"_\")[1]\n        full_path = os.path.join(test_folder, f\"soundscape_{filename}.ogg\")\n        if not os.path.exists(full_path):\n            print(\"❌ File not found:\", full_path)\n            final_preds.append([0.004] * len(label_columns))  # fallback\n            continue\n\n        probs = predict_with_tta(model, full_path, label_encoder, device)\n        final_preds.append(probs)\n\n    submission_df = pd.DataFrame(final_preds, columns=label_columns)\n    submission_df.insert(0, \"row_id\", row_ids)\n    submission_df.to_csv(output_csv, index=False)\n    print(f\"✅ submission.csv saved to {output_csv}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.778665Z","iopub.execute_input":"2025-05-28T13:21:28.779031Z","iopub.status.idle":"2025-05-28T13:21:28.786908Z","shell.execute_reply.started":"2025-05-28T13:21:28.778999Z","shell.execute_reply":"2025-05-28T13:21:28.785799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pseudo_label_dataset(model, folder, label_encoder, device, confidence_threshold=0.9):\n    pseudo_data = []\n\n    for fname in os.listdir(folder):\n        if not fname.endswith(\".ogg\"):\n            continue\n        path = os.path.join(folder, fname)\n        probs = predict_with_tta(model, path, label_encoder, device)\n\n        top_prob = np.max(probs)\n        top_idx = np.argmax(probs)\n\n        if top_prob >= confidence_threshold:\n            label_id = label_encoder.inverse_transform([top_idx])[0]\n            y, sr = librosa.load(path, sr=32000)\n            total_secs = int(len(y) / sr)\n\n            for start in range(0, total_secs, 5):\n                end = start + 5\n                if end > total_secs:\n                    break\n                start_sample = start * sr\n                end_sample = end * sr\n                segment = y[start_sample:end_sample]\n\n                mel = librosa.feature.melspectrogram(y=segment, sr=sr, n_mels=128)\n                mel_db = librosa.power_to_db(mel, ref=np.max)\n                mel_db = (mel_db - mel_db.min()) / (mel_db.max() - mel_db.min())\n\n                pseudo_data.append({\"mel\": mel_db, \"label\": label_id})\n\n    print(f\"✅ Ստացվեց {len(pseudo_data)} վստահված pseudo-label նմուշ\")\n    return pseudo_data\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.787919Z","iopub.execute_input":"2025-05-28T13:21:28.788304Z","iopub.status.idle":"2025-05-28T13:21:28.822041Z","shell.execute_reply.started":"2025-05-28T13:21:28.788276Z","shell.execute_reply":"2025-05-28T13:21:28.821078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pseudo_data = pseudo_label_dataset(\n    model=model,\n    folder=\"/kaggle/input/birdclef-2025/test_soundscapes\",\n    label_encoder=label_encoder,\n    device=device,\n    confidence_threshold=0.9\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.823056Z","iopub.execute_input":"2025-05-28T13:21:28.823368Z","iopub.status.idle":"2025-05-28T13:21:28.854215Z","shell.execute_reply.started":"2025-05-28T13:21:28.823347Z","shell.execute_reply":"2025-05-28T13:21:28.853425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pseudo_data = pseudo_label_dataset(\n    model=model,\n    folder=\"/kaggle/input/birdclef-2025/test_soundscapes\",\n    label_encoder=label_encoder,\n    device=device,\n    confidence_threshold=0.7  # 👈 նախկին 0.9-ի փոխարեն\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.855253Z","iopub.execute_input":"2025-05-28T13:21:28.855555Z","iopub.status.idle":"2025-05-28T13:21:28.871414Z","shell.execute_reply.started":"2025-05-28T13:21:28.855526Z","shell.execute_reply":"2025-05-28T13:21:28.870524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\nclass FocalLoss(nn.Module):\n    def __init__(self, gamma=2.0):\n        super(FocalLoss, self).__init__()\n        self.gamma = gamma\n\n    def forward(self, inputs, targets):\n        log_probs = F.log_softmax(inputs, dim=1)\n        probs = torch.exp(log_probs)\n        targets_onehot = F.one_hot(targets, num_classes=inputs.size(1)).float()\n        focal_weight = (1 - probs) ** self.gamma\n        loss = -targets_onehot * focal_weight * log_probs\n        return loss.sum(dim=1).mean()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.872318Z","iopub.execute_input":"2025-05-28T13:21:28.872991Z","iopub.status.idle":"2025-05-28T13:21:28.891442Z","shell.execute_reply.started":"2025-05-28T13:21:28.872968Z","shell.execute_reply":"2025-05-28T13:21:28.890449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = FocalLoss(gamma=2.0)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.892336Z","iopub.execute_input":"2025-05-28T13:21:28.892628Z","iopub.status.idle":"2025-05-28T13:21:28.919590Z","shell.execute_reply.started":"2025-05-28T13:21:28.892607Z","shell.execute_reply":"2025-05-28T13:21:28.918668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BirdClefEffAugmentedDataset(Dataset):\n    def __init__(self, data, label_encoder):\n        self.data = data\n        self.encoder = label_encoder\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        mel = self.data[idx]['mel']\n        label = self.data[idx]['label']\n\n        mel = (mel - mel.min()) / (mel.max() - mel.min())\n        mel_tensor = torch.tensor(mel, dtype=torch.float32).unsqueeze(0)\n\n        # SpecAugment\n        if random.random() < 0.8:\n            time_mask = random.randint(10, 40)\n            freq_mask = random.randint(5, 20)\n            time_start = random.randint(0, mel_tensor.shape[2] - time_mask)\n            freq_start = random.randint(0, mel_tensor.shape[1] - freq_mask)\n            mel_tensor[0, freq_start:freq_start+freq_mask, :] = 0\n            mel_tensor[0, :, time_start:time_start+time_mask] = 0\n\n        mel_tensor = F.interpolate(mel_tensor.unsqueeze(0), size=(224, 224), mode='bilinear', align_corners=False)\n        mel_tensor = mel_tensor.squeeze(0)\n        label_tensor = torch.tensor(self.encoder.transform([label])[0], dtype=torch.long)\n\n        return mel_tensor, label_tensor\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:21:28.920754Z","iopub.execute_input":"2025-05-28T13:21:28.921037Z","iopub.status.idle":"2025-05-28T13:21:28.942974Z","shell.execute_reply.started":"2025-05-28T13:21:28.921016Z","shell.execute_reply":"2025-05-28T13:21:28.941888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom sklearn.metrics import accuracy_score\n\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)  # Low LR for fine-tuning\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)\ncriterion = FocalLoss(gamma=2.0)\n\nfor epoch in range(10):\n    model.train()\n    total_loss = 0.0\n    preds, labels_all = [], []\n\n    for x, y in train_loader:\n        x, y = x.to(device), y.to(device)\n        optimizer.zero_grad()\n        y_pred = model(x)\n        loss = criterion(y_pred, y)\n        loss.backward()\n        optimizer.step()\n        total_loss += loss.item()\n        preds.extend(torch.argmax(y_pred, dim=1).cpu().numpy())\n        labels_all.extend(y.cpu().numpy())\n\n    acc = accuracy_score(labels_all, preds)\n    scheduler.step()\n    print(f\"📚 Final Epoch {epoch+1}: Loss={total_loss:.2f} | Acc={acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:48:27.485852Z","iopub.execute_input":"2025-05-28T13:48:27.486178Z","iopub.status.idle":"2025-05-28T13:59:25.954749Z","shell.execute_reply.started":"2025-05-28T13:48:27.486155Z","shell.execute_reply":"2025-05-28T13:59:25.952960Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"best_model_final.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:48:18.770621Z","iopub.execute_input":"2025-05-28T13:48:18.770936Z","iopub.status.idle":"2025-05-28T13:48:18.828677Z","shell.execute_reply.started":"2025-05-28T13:48:18.770910Z","shell.execute_reply":"2025-05-28T13:48:18.827662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# generate_submission(\n#     model=model,\n#     label_encoder=label_encoder,\n#     device=device,\n#     test_folder='/kaggle/input/birdclef-2025/test_soundscapes',\n#     sample_csv='/kaggle/input/birdclef-2025/sample_submission.csv',\n#     output_csv= '/kaggle/working/submission.csv'\n# )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:48:18.829759Z","iopub.execute_input":"2025-05-28T13:48:18.830482Z","iopub.status.idle":"2025-05-28T13:48:18.835370Z","shell.execute_reply.started":"2025-05-28T13:48:18.830450Z","shell.execute_reply":"2025-05-28T13:48:18.834153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\ndef generate_submission(model, label_encoder, device, test_folder='/kaggle/input/birdclef-2025/test_soundscapes', sample_csv='/kaggle/input/birdclef-2025/sample_submission.csv', output_csv='/kaggle/working/submission.csv'):\n    sample_df = pd.read_csv(sample_csv)\n    row_ids = sample_df['row_id'].values\n    label_columns = sample_df.columns[1:]\n\n    final_preds = []\n\n    for row_id in row_ids:\n        soundscape_id = \"_\".join(row_id.split(\"_\")[:2])\n        full_path = os.path.join(test_folder, f\"{soundscape_id}.ogg\")\n\n        if not os.path.exists(full_path):\n            print(\"❌ File not found:\", full_path)\n            final_preds.append([0.004] * len(label_columns))  # fallback\n            continue\n\n        try:\n            probs = predict_with_tta(model, full_path, label_encoder, device)\n            final_preds.append(probs)\n        except Exception as e:\n            print(f\"❌ Error processing {full_path}: {e}\")\n            final_preds.append([0.004] * len(label_columns))\n\n    submission_df = pd.DataFrame(final_preds, columns=label_columns)\n    submission_df.insert(0, \"row_id\", row_ids)\n    submission_df.to_csv(output_csv, index=False)\n    print(f\"✅ submission.csv saved to {output_csv}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-28T13:48:18.836452Z","iopub.execute_input":"2025-05-28T13:48:18.836916Z","iopub.status.idle":"2025-05-28T13:48:18.863296Z","shell.execute_reply.started":"2025-05-28T13:48:18.836881Z","shell.execute_reply":"2025-05-28T13:48:18.862076Z"}},"outputs":[],"execution_count":null}]}