{"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":44224,"databundleVersionId":5188730,"sourceType":"competition"},{"sourceId":10857313,"sourceType":"datasetVersion","datasetId":6744065},{"sourceId":273666,"sourceType":"modelInstanceVersion","modelInstanceId":234319,"modelId":256024}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\ndir_path = '/kaggle/working/'\nfile_name = 'results.json'\n\nfor file in os.listdir(dir_path):\n    if file == file_name:\n        os.remove(os.path.join(dir_path, file))\n        break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-21T04:42:43.725125Z","iopub.execute_input":"2025-04-21T04:42:43.725651Z","iopub.status.idle":"2025-04-21T04:42:43.732341Z","shell.execute_reply.started":"2025-04-21T04:42:43.725625Z","shell.execute_reply":"2025-04-21T04:42:43.731623Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport librosa\nimport librosa.display\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport gc\nfrom tqdm import tqdm\n\n\nDATA_PATH = \"/kaggle/input/birdclef-2023/train_audio/\"\nOUTPUT_PATH = \"/kaggle/working/spectrograms/\"\nos.makedirs(OUTPUT_PATH, exist_ok=True)\n\n\ndef process_audio(audio_path, save_path):\n    try:\n        if os.path.exists(save_path):  \n            return\n        \n        \n        y, sr = librosa.load(audio_path, sr=16000)\n        \n        \n        mel_spec = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128)\n        mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n        \n        fig, ax = plt.subplots(figsize=(2, 2), dpi=100)\n        librosa.display.specshow(mel_spec_db, sr=sr, cmap='magma', ax=ax)\n        ax.set_axis_off()\n        fig.savefig(save_path, bbox_inches='tight', pad_inches=0)\n\n        \n        plt.close(fig)\n        del y, mel_spec, mel_spec_db\n        gc.collect()\n\n    except Exception as e:\n        print(f\" Error processing {audio_path}: {e}\")\n\n\nfor bird_class in tqdm(os.listdir(DATA_PATH), desc=\"Processing Bird Classes\"):\n    bird_folder = os.path.join(DATA_PATH, bird_class)\n    if os.path.isdir(bird_folder):\n        output_class_dir = os.path.join(OUTPUT_PATH, bird_class)\n        os.makedirs(output_class_dir, exist_ok=True)\n\n        audio_files = [f for f in os.listdir(bird_folder) if f.endswith(\".ogg\")]\n        audio_files = audio_files[:15]  \n\n        for audio_file in tqdm(audio_files, desc=f\"Processing {bird_class}\", leave=False):\n            audio_path = os.path.join(bird_folder, audio_file)\n            save_path = os.path.join(output_class_dir, f\"{audio_file}.png\")\n            process_audio(audio_path, save_path)\n\nprint(\" Finished processing spectrograms (max 10 per bird species)\")\ngc.collect()  \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-21T04:42:43.734588Z","execution_failed":"2025-04-21T06:57:32.075Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport json  \nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom sklearn.metrics import f1_score\nfrom PIL import Image\nfrom tqdm import tqdm\nimport gc\nfrom sklearn.model_selection import train_test_split\n\n\nRESULTS_PATH = \"/kaggle/working/\"\n\n\nSPECTROGRAM_PATH = \"/kaggle/working/spectrograms/\"\nOUTPUT_PATH = \"/kaggle/working/\"\nos.makedirs(OUTPUT_PATH, exist_ok=True)\n\n\nclass BirdCLEFDataset(Dataset):\n    def __init__(self, file_list, labels, transform=None):\n        self.file_list = file_list\n        self.labels = labels\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.file_list)\n    \n    def __getitem__(self, idx):\n        img_path = self.file_list[idx]\n        label = self.labels[idx]\n        image = Image.open(img_path).convert('RGB')\n\n        if self.transform:\n            image = self.transform(image)\n        \n        return image, label\n\n\nbird_classes = sorted(os.listdir(SPECTROGRAM_PATH))  \nvalid_classes = []\nclass_to_idx = {}  \n\nfile_list = []\nlabels = []\n\nfor bird_class in bird_classes:\n    class_folder = os.path.join(SPECTROGRAM_PATH, bird_class)\n    if os.path.isdir(class_folder):\n        spectrograms = [os.path.join(class_folder, f) for f in os.listdir(class_folder) if f.endswith(\".png\")]\n\n        if len(spectrograms) < 2:\n            print(f\" Skipping {bird_class} (only {len(spectrograms)} samples)\")\n            continue\n\n        class_idx = len(valid_classes)\n        valid_classes.append(bird_class)\n        class_to_idx[bird_class] = class_idx  \n\n        file_list.extend(spectrograms)\n        labels.extend([class_idx] * len(spectrograms))  \n\nnum_classes = len(valid_classes)  \nprint(f\" {num_classes} valid bird classes loaded!\")\n\n\nif len(set(labels)) < 2:\n    raise ValueError(\" Not enough valid classes to train! Add more samples per class.\")\n\n\ntrain_files, test_files, train_labels, test_labels = train_test_split(\n    file_list, labels, test_size=0.2, stratify=labels, random_state=42\n)\n\n\ntransform = transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.ToTensor()\n])\n\ntrain_dataset = BirdCLEFDataset(train_files, train_labels, transform=transform)\ntest_dataset = BirdCLEFDataset(test_files, test_labels, transform=transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)\ntest_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)\n\n\nclass BirdCNN(nn.Module):\n    def __init__(self, num_classes):\n        super(BirdCNN, self).__init__()\n        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)\n        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)\n        self.conv3 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)\n        self.pool = nn.MaxPool2d(2, 2)\n        self.relu = nn.ReLU()\n        self.dropout = nn.Dropout(0.3)\n\n        sample_input = torch.randn(1, 3, 128, 128)  \n        with torch.no_grad():\n            sample_output = self._forward_conv(sample_input)\n        fc_input_size = sample_output.view(sample_output.size(0), -1).size(1)\n\n        self.fc1 = nn.Linear(fc_input_size, 128)\n        self.fc2 = nn.Linear(128, num_classes)\n\n    def _forward_conv(self, x):\n        x = self.pool(self.relu(self.conv1(x)))\n        x = self.pool(self.relu(self.conv2(x)))\n        x = self.pool(self.relu(self.conv3(x)))\n        return x\n\n    def forward(self, x):\n        x = self._forward_conv(x)\n        x = x.view(x.size(0), -1)\n        x = self.relu(self.fc1(x))\n        x = self.dropout(x)\n        x = self.fc2(x)\n        return x\n\nnum_classes = len(set(labels))  \nmodel = BirdCNN(num_classes)\n\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\n\ntraining_results = {\"loss_per_epoch\": [], \"accuracy_per_epoch\": []}\n\ndef train_model(model, train_loader, criterion, optimizer, epochs=10):\n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        correct = 0\n        total = 0\n\n        for images, labels in train_loader:\n            images, labels = images.to(device), labels.to(device)\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n            _, preds = torch.max(outputs, 1)\n            correct += (preds == labels).sum().item()\n            total += labels.size(0)\n\n        accuracy = correct / total * 100\n        training_results[\"loss_per_epoch\"].append(running_loss / len(train_loader))\n        training_results[\"accuracy_per_epoch\"].append(accuracy)\n\n        print(f\"Epoch {epoch+1}/{epochs} | Loss: {running_loss/len(train_loader):.4f} | Accuracy: {accuracy:.2f}%\")\n\ntrain_model(model, train_loader, criterion, optimizer, epochs=10)\n\n\ndef compute_f1(model, data_loader):\n    model.eval()\n    all_preds, all_labels = [], []\n    with torch.no_grad():\n        for images, labels in data_loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            _, preds = torch.max(outputs, 1)\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    print(f\" Unique Predicted Classes: {set(all_preds)}\")\n    print(f\"Unique True Labels: {set(all_labels)}\")\n    return f1_score(all_labels, all_preds, average='macro'), set(all_preds), set(all_labels)\n\n\nf1, predicted_classes, true_labels = compute_f1(model, test_loader)\n\ntraining_results[\"final_f1_score\"] = f1\ntraining_results[\"unique_predicted_classes\"] = list(predicted_classes)\ntraining_results[\"unique_true_labels\"] = list(true_labels)\n\n\n\nprint(f\"Results saved to {RESULTS_PATH}results.json\")\nprint(f\" Macro F1-Score: {f1}\")\n\nresults_file = os.path.join(RESULTS_PATH, \"results.json\")\n\n\nif os.path.exists(results_file):\n    try:\n        with open(results_file, \"r\") as f:\n            existing_results = json.load(f)\n    except (json.JSONDecodeError, FileNotFoundError):  \n        print(\" Error reading results.json. Creating a new file.\")\n        existing_results = []\nelse:\n    existing_results = []\n\n\nexisting_results.append({\"f1_score no data augmentation\": f1})\n\n\nwith open(results_file, \"w\") as f:\n    json.dump(existing_results, f, indent=4)\n\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-04-21T06:57:32.096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport json\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms\nfrom sklearn.metrics import f1_score\nfrom PIL import Image\nfrom tqdm import tqdm\nimport gc\nfrom sklearn.model_selection import train_test_split\n\n\nSPECTROGRAM_PATH = \"/kaggle/working/spectrograms/\"  \nRESULTS_PATH = \"/kaggle/working/\"\nos.makedirs(RESULTS_PATH, exist_ok=True)\n\n\nclass BirdCLEFDataset(Dataset):\n    def __init__(self, file_list, labels, transform=None):\n        self.file_list = file_list\n        self.labels = labels\n        self.transform = transform\n    \n    def __len__(self):\n        return len(self.file_list)\n    \n    def __getitem__(self, idx):\n        img_path = self.file_list[idx]\n        label = self.labels[idx]\n        image = Image.open(img_path).convert('RGB')\n\n        if self.transform:\n            image = self.transform(image)\n        \n        return image, label\n\n\nbird_classes = sorted(os.listdir(SPECTROGRAM_PATH))\nvalid_classes = []\nclass_to_idx = {}  \nfile_list = []\nlabels = []\n\nfor bird_class in bird_classes:\n    class_folder = os.path.join(SPECTROGRAM_PATH, bird_class)\n    if os.path.isdir(class_folder):\n        spectrograms = [os.path.join(class_folder, f) for f in os.listdir(class_folder) if f.endswith(\".png\")]\n        if len(spectrograms) < 2:\n            print(f\"Skipping {bird_class} (only {len(spectrograms)} samples)\")\n            continue\n\n        class_idx = len(valid_classes)\n        valid_classes.append(bird_class)\n        class_to_idx[bird_class] = class_idx  \n\n        file_list.extend(spectrograms)\n        labels.extend([class_idx] * len(spectrograms))  \n\nnum_classes = len(valid_classes)\nprint(f\"{num_classes} valid bird classes loaded!\")\n\nif len(set(labels)) < 2:\n    raise ValueError(\"🚨 Not enough valid classes to train! Add more samples per class.\")\n\n\ntrain_files, test_files, train_labels, test_labels = train_test_split(\n    file_list, labels, test_size=0.2, stratify=labels, random_state=42\n)\n\n\ntrain_transform = transforms.Compose([\n    transforms.Resize((224, 224)),  \n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomRotation(15),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2),\n    transforms.RandomApply([transforms.GaussianBlur(kernel_size=3)], p=0.3),\n    transforms.ToTensor()\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize((224, 224)),  \n    transforms.ToTensor()\n])\n\ntrain_dataset = BirdCLEFDataset(train_files, train_labels, transform=train_transform)\ntest_dataset = BirdCLEFDataset(test_files, test_labels, transform=test_transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, num_workers=2)\ntest_loader = DataLoader(test_dataset, batch_size=16, shuffle=False, num_workers=2)\n\n\nclass EfficientNetBirds(nn.Module):\n    def __init__(self, num_classes):\n        super(EfficientNetBirds, self).__init__()\n        self.model = models.efficientnet_b0(weights=None)  \n        self.model.classifier = nn.Sequential(\n            nn.Dropout(0.3),\n            nn.Linear(1280, num_classes)  \n        )\n\n    def forward(self, x):\n        return self.model(x)\n\nnum_classes = len(set(labels))\nmodel = EfficientNetBirds(num_classes)\n\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\ntraining_results = {\"loss_per_epoch\": [], \"accuracy_per_epoch\": []}\n\ndef train_model(model, train_loader, criterion, optimizer, epochs=10):\n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        correct = 0\n        total = 0\n\n        for images, labels in train_loader:\n            images, labels = images.to(device), labels.to(device)\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n            _, preds = torch.max(outputs, 1)\n            correct += (preds == labels).sum().item()\n            total += labels.size(0)\n\n        accuracy = correct / total * 100\n        training_results[\"loss_per_epoch\"].append(running_loss / len(train_loader))\n        training_results[\"accuracy_per_epoch\"].append(accuracy)\n\n        print(f\"Epoch {epoch+1}/{epochs} | Loss: {running_loss/len(train_loader):.4f} | Accuracy: {accuracy:.2f}%\")\n\ntrain_model(model, train_loader, criterion, optimizer, epochs=10)\n\n\ndef compute_f1(model, data_loader):\n    model.eval()\n    all_preds, all_labels = [], []\n    with torch.no_grad():\n        for images, labels in data_loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            _, preds = torch.max(outputs, 1)\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    print(f\" Unique Predicted Classes: {set(all_preds)}\")\n    print(f\" Unique True Labels: {set(all_labels)}\")\n    return f1_score(all_labels, all_preds, average='macro')\n\n\nf1 = compute_f1(model, test_loader)\n\nresults_file = os.path.join(RESULTS_PATH, \"results.json\")\n\n\nif os.path.exists(results_file):\n    try:\n        with open(results_file, \"r\") as f:\n            existing_results = json.load(f)\n    except json.JSONDecodeError:\n        print(\" Error reading results.json. Resetting file.\")\n        existing_results = []\nelse:\n    existing_results = []\n\n\nexisting_results.append({\"f1_score with With Augmentation & EfficientNet\": f1})\n\n\nwith open(results_file, \"w\") as f:\n    json.dump(existing_results, f, indent=4)\n\nprint(f\"F1-score appended to {results_file}\")\nprint(f\"Macro F1-Score (With Augmentation & EfficientNet): {f1}\")\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-04-21T06:57:32.100Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Print the Result","metadata":{}},{"cell_type":"code","source":"import json\n\nwith open('/kaggle/working/results.json') as f:\n    d = json.load(f)\n    print(str(d))\n    ","metadata":{"trusted":true,"execution":{"execution_failed":"2025-04-21T06:57:32.101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\n\n# Define Paths\nDATASET_PATH = \"/kaggle/input/birdclef-2023/train_audio\"\nMETADATA_FILE = \"/kaggle/input/birdclef-2023/train_metadata.csv\"  # Update with actual path\n\n# Load Metadata CSV\nmetadata = pd.read_csv(METADATA_FILE)\n\n# Convert to dictionary {primary_label → common_name}\nfolder_to_name = dict(zip(metadata[\"primary_label\"], metadata[\"common_name\"]))\n\n# List all bird folders & get real names\nbird_folders = sorted(os.listdir(DATASET_PATH))  # List all folders\n\nprint(f\" Found {len(bird_folders)} bird species:\\n\")\n\nfor folder in bird_folders:\n    bird_name = folder_to_name.get(folder, \"Unknown Species\")  # Get name from mapping\n    print(f\"{folder} → {bird_name}\")  # Print folder code + real bird name\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-04-21T06:57:32.101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport librosa\nimport librosa.display\nimport numpy as np\nimport timm\nimport matplotlib.pyplot as plt\nimport torch.nn as nn\nimport torch.optim as optim\nimport json\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score\nfrom PIL import Image\n\n# ✅ Define Paths\nAUDIO_PATH = \"/kaggle/input/birdclef-2023/train_audio/\"\nMETADATA_PATH = \"/kaggle/input/birdclef-2023/train_metadata.csv\"\nSPECTROGRAM_PATH = \"/kaggle/working/spectrograms/\"\nMODEL_PATH = \"/kaggle/working/efficientnet_bird.pth\"\nRESULTS_PATH = \"/kaggle/working/results.json\"\n\nos.makedirs(SPECTROGRAM_PATH, exist_ok=True)\n\n# ✅ Convert Audio to Spectrograms\ndef convert_audio_to_spectrogram(audio_path, save_path):\n    try:\n        y, sr = librosa.load(audio_path, sr=16000)\n        mel_spec = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128)\n        mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n        plt.figure(figsize=(2, 2), dpi=100)\n        librosa.display.specshow(mel_spec_db, sr=sr, cmap=\"magma\")\n        plt.axis(\"off\")\n        plt.savefig(save_path, bbox_inches=\"tight\", pad_inches=0)\n        plt.close()\n    except Exception as e:\n        print(f\"Error processing {audio_path}: {e}\")\n\n# ✅ Process All Audio Files\nfor bird_class in os.listdir(AUDIO_PATH):\n    bird_folder = os.path.join(AUDIO_PATH, bird_class)\n    output_class_dir = os.path.join(SPECTROGRAM_PATH, bird_class)\n    os.makedirs(output_class_dir, exist_ok=True)\n\n    if os.path.isdir(bird_folder):\n        audio_files = [f for f in os.listdir(bird_folder) if f.endswith(\".ogg\")][:15]  # Limit 10 per class\n\n        for audio_file in audio_files:\n            audio_path = os.path.join(bird_folder, audio_file)\n            save_path = os.path.join(output_class_dir, f\"{audio_file}.png\")\n            convert_audio_to_spectrogram(audio_path, save_path)\n\n# ✅ Dataset Class\nclass BirdDataset(Dataset):\n    def __init__(self, file_list, labels, transform=None):\n        self.file_list = file_list\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.file_list)\n\n    def __getitem__(self, idx):\n        img_path = self.file_list[idx]\n        label = self.labels[idx]\n        image = Image.open(img_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# ✅ Collect Spectrograms & Labels\nfile_list = []\nlabels = []\nbird_classes = sorted(os.listdir(SPECTROGRAM_PATH))\nclass_to_idx = {bird: idx for idx, bird in enumerate(bird_classes)}\n\nfor bird_class in bird_classes:\n    class_folder = os.path.join(SPECTROGRAM_PATH, bird_class)\n    if os.path.isdir(class_folder):\n        spectrograms = [os.path.join(class_folder, f) for f in os.listdir(class_folder) if f.endswith(\".png\")]\n        if len(spectrograms) < 2:\n            continue\n        file_list.extend(spectrograms)\n        labels.extend([class_to_idx[bird_class]] * len(spectrograms))\n\nnum_classes = len(class_to_idx)\n\n# ✅ Train-Test Split\ntrain_files, test_files, train_labels, test_labels = train_test_split(\n    file_list, labels, test_size=0.2, stratify=labels, random_state=42\n)\n\n# ✅ Data Augmentation\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # EfficientNet requires 224x224 images\n    transforms.ToTensor(),\n])\n\ntrain_dataset = BirdDataset(train_files, train_labels, transform=transform)\ntest_dataset = BirdDataset(test_files, test_labels, transform=transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)\ntest_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)\n\n# ✅ Define EfficientNet Model\nclass EfficientNetBirdClassifier(nn.Module):\n    def __init__(self, num_classes):\n        super(EfficientNetBirdClassifier, self).__init__()\n        self.model = timm.create_model(\"efficientnet_b0\", pretrained=True)\n        self.model.classifier = nn.Linear(1280, num_classes)  # Adjust for bird classes\n\n    def forward(self, x):\n        return self.model(x)\n\nmodel = EfficientNetBirdClassifier(num_classes)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n# ✅ Train Model\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001)\n\ndef train_model(model, train_loader, criterion, optimizer, epochs=10):\n    for epoch in range(epochs):\n        model.train()\n        running_loss = 0.0\n        correct = 0\n        total = 0\n\n        for images, labels in train_loader:\n            images, labels = images.to(device), labels.to(device)\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n            _, preds = torch.max(outputs, 1)\n            correct += (preds == labels).sum().item()\n            total += labels.size(0)\n\n        accuracy = correct / total * 100\n        print(f\"Epoch {epoch+1}/{epochs} | Loss: {running_loss/len(train_loader):.4f} | Accuracy: {accuracy:.2f}%\")\n\ntrain_model(model, train_loader, criterion, optimizer, epochs=10)\n\n# ✅ Evaluate Model with F1 Score\ndef evaluate_model(model, data_loader):\n    model.eval()\n    all_preds = []\n    all_labels = []\n\n    with torch.no_grad():\n        for images, labels in data_loader:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            _, preds = torch.max(outputs, 1)\n\n            all_preds.extend(preds.cpu().numpy())\n            all_labels.extend(labels.cpu().numpy())\n\n    f1 = f1_score(all_labels, all_preds, average=\"weighted\")\n    return f1\n\nf1 = evaluate_model(model, test_loader)\n\n# ✅ Save Model & Results\ntorch.save(model.state_dict(), MODEL_PATH)\n\nresults = {\"f1_score\": f1}\nimport json\nimport os\n\n# Ensure RESULTS_PATH exists\nif os.path.exists(RESULTS_PATH) and os.path.getsize(RESULTS_PATH) > 0:\n    # Read the existing data\n    with open(RESULTS_PATH, \"r\") as f:\n        try:\n            existing_results = json.load(f)\n        except json.JSONDecodeError:\n            existing_results = []\nelse:\n    existing_results = []\n\n# Ensure existing_results is a list\nif not isinstance(existing_results, list):\n    existing_results = [existing_results]\n\n# Append the new results\nexisting_results.append(results)\n\n# Write back to the file\nwith open(RESULTS_PATH, \"w\") as f:\n    json.dump(existing_results, f, indent=4)\n\nprint(f\"Model saved at {MODEL_PATH}\")\nprint(f\"F1 Score: {f1} - Results appended to {RESULTS_PATH}\")\n\n\n# ✅ Load Model for Inference\ndef load_model(model_path, num_classes):\n    model = EfficientNetBirdClassifier(num_classes)\n    model.load_state_dict(torch.load(model_path, map_location=device))\n    model.to(device)\n    model.eval()\n    return model\n\nmodel = load_model(MODEL_PATH, num_classes)\n\n# ✅ Inference Function\ndef predict_bird(image_path, model):\n    image = Image.open(image_path).convert(\"RGB\")\n    transform = transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n    ])\n    image = transform(image).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        output = model(image)\n        predicted_class_id = torch.argmax(output, dim=1).item()\n        bird_name = list(class_to_idx.keys())[predicted_class_id]\n\n    return bird_name\n\n# ✅ Test on a New Audio File\ntest_audio = \"/kaggle/input/birdclef-2023/train_audio/abethr1/XC128013.ogg\"\ntest_spectrogram = \"/kaggle/working/spectrograms/abethr1/XC128013.ogg.png\"\n\nconvert_audio_to_spectrogram(test_audio, test_spectrogram)\npredicted_bird = predict_bird(test_spectrogram, model)\n\nprint(f\"Predicted Bird Species: {predicted_bird}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-21T14:34:42.396206Z","iopub.execute_input":"2025-04-21T14:34:42.396477Z","iopub.status.idle":"2025-04-21T14:52:23.231621Z","shell.execute_reply.started":"2025-04-21T14:34:42.396454Z","shell.execute_reply":"2025-04-21T14:52:23.230845Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport gc\nimport torch\nimport librosa\nimport librosa.display\nimport pandas as pd\nimport timm\nimport matplotlib.pyplot as plt\nimport torch.nn as nn\nfrom torchvision import transforms\nfrom PIL import Image\n\n\nMODEL_PATH = \"/kaggle/working/efficientnet_bird.pth\"\nMETADATA_PATH = \"/kaggle/input/birdclef-2023/train_metadata.csv\"\nTEMP_SPECTROGRAM = \"/kaggle/working/temp_spectrogram.png\"\n\n\nmetadata = pd.read_csv(METADATA_PATH)\nlabel_to_name = dict(zip(metadata[\"primary_label\"], metadata[\"common_name\"]))\n\n\ndef convert_audio_to_spectrogram(audio_path, save_path):\n    y, sr = librosa.load(audio_path, sr=16000)\n    mel_spec = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=128)\n    mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n    plt.figure(figsize=(2, 2), dpi=100)\n    librosa.display.specshow(mel_spec_db, sr=sr, cmap=\"magma\")\n    plt.axis(\"off\")\n    plt.savefig(save_path, bbox_inches=\"tight\", pad_inches=0)\n    plt.close()\n\n    del y, mel_spec, mel_spec_db\n    torch.cuda.empty_cache()\n    gc.collect()\n\n\nclass EfficientNetBirdClassifier(nn.Module):\n    def __init__(self, num_classes):\n        super(EfficientNetBirdClassifier, self).__init__()\n        self.model = timm.create_model(\"efficientnet_b0\", pretrained=False)  \n        self.model.classifier = nn.Linear(1280, num_classes)\n\n    def forward(self, x):\n        return self.model(x)\n\n\ndef load_model(model_path, num_classes):\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    model = EfficientNetBirdClassifier(num_classes)\n    model.load_state_dict(torch.load(model_path, map_location=device))\n    model.to(device)\n    model.eval()\n    return model, device\n\n\ndef predict_bird(audio_file, model, device):\n    convert_audio_to_spectrogram(audio_file, TEMP_SPECTROGRAM)\n\n    transform = transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n    ])\n    image = Image.open(TEMP_SPECTROGRAM).convert(\"RGB\")\n    image = transform(image).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        output = model(image)\n        predicted_class_id = torch.argmax(output, dim=1).item()\n    \n    del image, output\n    torch.cuda.empty_cache()\n    gc.collect()\n\n    \n    predicted_label = list(label_to_name.keys())[predicted_class_id]\n    \n    return label_to_name.get(predicted_label, \"Unknown Bird\")\n\n\nAUDIO_FILE = \"/kaggle/input/birdclef-2023/train_audio/abythr1/XC115981.ogg\"\nnum_classes = len(label_to_name)\nmodel, device = load_model(MODEL_PATH, num_classes)\npredicted_bird = predict_bird(AUDIO_FILE, model, device)\n\nprint(f\"Detected Bird: {predicted_bird}\")\n\n\nimport os\nfrom kaggle_secrets import UserSecretsClient\nfrom google import genai\n\n# Get API key from Kaggle Secrets\n\n\ntry:\n    user_secrets = UserSecretsClient()\n    API_KEY = user_secrets.get_secret(\"GoogleApikey\")\n    client = genai.Client(api_key=API_KEY)\n    response = client.models.generate_content(\n        model=\"gemini-2.0-flash\", contents=str(predicted_bird)+\"tell it's common location and tell some info from wikipedia\"\n    )\n    print(response.text)\n\nexcept Exception as e:\n    print(f\"An error occurred and make sure API key is loaded in Add-ons/Secrets\")\n\n\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-04-21T06:57:32.102Z"}},"outputs":[],"execution_count":null}]}