{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":70203,"databundleVersionId":8068726,"sourceType":"competition"}],"dockerImageVersionId":30684,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torchaudio\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision import models\nfrom torchvision.transforms import Compose\nimport torchaudio.transforms as T\n\n# Set up the directory path according to Kaggle's file system\nBASE_DIR = '/kaggle/input/birdclef-2024'\nTRAIN_AUDIO_DIR = os.path.join(BASE_DIR, 'train_audio')\nTEST_AUDIO_DIR = os.path.join(BASE_DIR, 'test_soundscapes')\nTRAIN_METADATA_FILE = os.path.join(BASE_DIR, 'train_metadata.csv')\nTEST_METADATA_FILE = os.path.join(BASE_DIR, 'test_metadata.csv')  # This is hypothetical\n\n# Dataset class\nclass BirdSoundDataset(Dataset):\n    def __init__(self, annotations_file, audio_dir, target_sample_rate=32000, num_samples=160000):\n        self.annotations = pd.read_csv(annotations_file)\n        self.audio_dir = audio_dir\n        self.target_sample_rate = target_sample_rate\n        self.num_samples = num_samples\n        self.label_map = {label: i for i, label in enumerate(self.annotations['primary_label'].unique())}\n        self.transformation = Compose([\n            T.MelSpectrogram(sample_rate=target_sample_rate, n_fft=2048, hop_length=512, n_mels=128),\n            T.AmplitudeToDB()\n        ])\n\n    def __len__(self):\n        return len(self.annotations)\n\n    def __getitem__(self, index):\n        audio_filename = self.annotations.iloc[index]['filename']\n        audio_path = os.path.join(self.audio_dir, audio_filename)\n        waveform, sample_rate = torchaudio.load(audio_path)\n        if sample_rate != self.target_sample_rate:\n            resampler = T.Resample(orig_freq=sample_rate, new_freq=self.target_sample_rate)\n            waveform = resampler(waveform)\n        waveform = waveform.mean(dim=0, keepdim=True)\n        if waveform.size(1) > self.num_samples:\n            waveform = waveform[:, :self.num_samples]\n        elif waveform.size(1) < self.num_samples:\n            padding = self.num_samples - waveform.size(1)\n            waveform = nn.functional.pad(waveform, (0, padding))\n        features = self.transformation(waveform)\n        label = self.label_map[self.annotations.iloc[index]['primary_label']]\n        return features, label\n\n# Define the AudioResNet model\nclass AudioResNet(nn.Module):\n    def __init__(self, num_classes):\n        super(AudioResNet, self).__init__()\n        resnet = models.resnet18(pretrained=True)\n        # Adjust the first convolutional layer to accept 1 channel input\n        resnet.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n        \n        # Replace the fully connected layer with a new one matching the number of classes\n        num_ftrs = resnet.fc.in_features\n        resnet.fc = nn.Linear(num_ftrs, num_classes)\n        \n        # Include global average pooling\n        self.resnet = nn.Sequential(\n            *list(resnet.children())[:-1],  # Take all layers except the original fully connected layer\n            nn.AdaptiveAvgPool2d((1, 1))    # This line adds adaptive pooling\n        )\n        self.fc = nn.Linear(num_ftrs, num_classes)  # Redefine the fully connected layer\n\n    def forward(self, x):\n        x = self.resnet(x)\n        x = torch.flatten(x, 1)  # Flatten the features into a single vector per image\n        x = self.fc(x)\n        return x\n\n# Initialize dataset and data loader\ntrain_dataset = BirdSoundDataset(TRAIN_METADATA_FILE, TRAIN_AUDIO_DIR)\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)\n\n# Model initialization\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = AudioResNet(num_classes=len(set(train_dataset.label_map.values()))).to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\ncriterion = nn.CrossEntropyLoss()\n\n# Training loop\nfor epoch in range(10):  # Adjust epochs as needed\n    model.train()\n    running_loss = 0.0\n    for features, labels in train_loader:\n        features, labels = features.to(device), labels.to(device)\n        optimizer.zero_grad()\n        outputs = model(features)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item()\n    print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader)}')\n\n# This is a basic training loop, remember to add validation and possibly save your model's state.\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]}]}