{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport logging\nimport datetime\nimport concurrent.futures\n\nimport numpy as np\nimport pandas as pd\nimport librosa\nimport glob\nfrom joblib import Parallel, delayed\nfrom multiprocessing import cpu_count\nimport matplotlib.pyplot as plt\n\nimport torch\nimport torchaudio\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\n\nfrom IPython.display import Audio\n\n# Requirements of the competition\ndevice = 'cpu'\n\nSAMPLE_RATE = 32000\nSECONDS = 5\nMAX_SPLIT = 4\nBATCH_SIZE = 64\nEPOCHS = 30\nLEARNING_RATE = .001\nNUM_SAMPLES = SAMPLE_RATE * SECONDS","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-17T20:24:19.386770Z","iopub.execute_input":"2023-05-17T20:24:19.387907Z","iopub.status.idle":"2023-05-17T20:24:23.114329Z","shell.execute_reply.started":"2023-05-17T20:24:19.387861Z","shell.execute_reply":"2023-05-17T20:24:23.112580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PATH = '/kaggle/input/birdclef-2023/'\ndf = pd.read_csv(PATH + \"train_metadata.csv\")\nclasses = df[\"primary_label\"].unique()\nclasses = pd.DataFrame(classes, columns=[\"name\"]).reset_index()\nclasses = classes.set_index('name').to_dict()['index']\ndf.head(3)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:24:23.117100Z","iopub.execute_input":"2023-05-17T20:24:23.119421Z","iopub.status.idle":"2023-05-17T20:24:23.310363Z","shell.execute_reply.started":"2023-05-17T20:24:23.119351Z","shell.execute_reply":"2023-05-17T20:24:23.309396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_espectogram(tensor,todb=True):\n    if todb:\n        output = torchaudio.transforms.AmplitudeToDB()(tensor.float()).cpu()\n    else:\n        output = tensor.float().cpu()\n    # Plot mel spectrogram\n    plt.figure(figsize=(10, 4))\n    plt.imshow(output[0], cmap='inferno', origin='lower')\n    plt.xlabel('Time')\n    plt.ylabel('Frequency')\n    plt.colorbar()\n    plt.title('Mel Spectrogram')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:24:23.311852Z","iopub.execute_input":"2023-05-17T20:24:23.313106Z","iopub.status.idle":"2023-05-17T20:24:23.321082Z","shell.execute_reply.started":"2023-05-17T20:24:23.313065Z","shell.execute_reply":"2023-05-17T20:24:23.319967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# mel_spectogram = torchaudio.transforms.MelSpectrogram(sample_rate=SAMPLE_RATE,\n#                                                       n_fft=4096*1,\n#                                                       win_length=1024,\n#                                                       hop_length=2048*1,\n#                                                       n_mels=64,\n#                                                       f_min=1000,\n#                                                       f_max = 15000)\n# path_original = df.loc[1,'filename']\n# name = path_original.split('/')[0]+ '_' + path_original.split('/')[1].split('.')[0]\n# signal, sr = torchaudio.load(os.path.join(PATH,\"train_audio\",path_original))\n# signal = resample_if_necessary(signal,sr)[:,:round(NUM_SAMPLES*0.7)]\n# length_signal = signal.shape[1]\n# if length_signal < NUM_SAMPLES:\n#     num_missing_samples = NUM_SAMPLES - length_signal\n#     num_repeats = int(num_missing_samples / length_signal) + 1\n#     repeated_signal = signal.repeat(1, num_repeats)[:, :num_missing_samples]\n#     signal = torch.cat([signal, repeated_signal], dim=1)\n# signal = mel_spectogram(signal[:,:NUM_SAMPLES])\n# plot_espectogram(signal)\n# signal.shape","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:24:23.324543Z","iopub.execute_input":"2023-05-17T20:24:23.325930Z","iopub.status.idle":"2023-05-17T20:24:23.336120Z","shell.execute_reply.started":"2023-05-17T20:24:23.325878Z","shell.execute_reply":"2023-05-17T20:24:23.334728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mel_spectogram = torchaudio.transforms.MelSpectrogram(sample_rate=SAMPLE_RATE,\n                                                      n_fft=4096*1,\n                                                      win_length=1024,\n                                                      hop_length=2048*1,\n                                                      n_mels=64,\n                                                      f_min=1000,\n                                                      f_max = 15000)\nPATH_WORK ='/kaggle/working/'\ndef resample_if_necessary(signal,sr):\n    if sr != SAMPLE_RATE:\n        resampler = torchaudio.transforms.Resample(sr,SAMPLE_RATE)\n        signal = resampler(signal)\n    return signal\ndef create_files(df):\n    df_new= {'path_original':[],\n           'original_index':[],\n          'label':[],\n          'path_signal':[]}\n    for index in df.index:\n        path_original = df.loc[index,'filename']\n        name = path_original.split('/')[0]+ '_' + path_original.split('/')[1].split('.')[0]\n        signal, sr = torchaudio.load(os.path.join(PATH,\"train_audio\",path_original))\n        signal = resample_if_necessary(signal,sr)\n        qnt = len(signal[0])//NUM_SAMPLES\n        if qnt==0:\n            length_signal = signal.shape[1]\n            if length_signal < NUM_SAMPLES:\n                num_missing_samples = NUM_SAMPLES - length_signal\n                num_repeats = int(num_missing_samples / length_signal) + 1\n                repeated_signal = signal.repeat(1, num_repeats)[:, :num_missing_samples]\n                signal = torch.cat([signal, repeated_signal], dim=1)\n                df_new['path_original'].append(path_original)\n                df_new['original_index'].append(index)\n                df_new['label'].append(df.loc[index,'primary_label'])\n                path_signal = name + '_'+str(qnt) + '_'+'0' +\".pt\"\n                df_new['path_signal'].append(path_signal)\n                torch.save(mel_spectogram (signal), os.path.join(PATH_WORK,\"temp\",path_signal))\n        else:\n            for i in np.arange(qnt):\n                    if i == MAX_SPLIT:\n                        break\n                    signal_temp = signal[:,i*NUM_SAMPLES:((i+1)*NUM_SAMPLES)]\n                    df_new['path_original'].append(path_original)\n                    df_new['original_index'].append(index)\n                    df_new['label'].append(df.loc[index,'primary_label'])\n                    path_signal = name + '_'+str(i) + '_'+'0' +\".pt\"\n                    df_new['path_signal'].append(path_signal)\n                    torch.save(mel_spectogram(signal_temp), os.path.join(PATH_WORK,\"temp\",path_signal))\n    return pd.DataFrame(df_new)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:24:23.338385Z","iopub.execute_input":"2023-05-17T20:24:23.338954Z","iopub.status.idle":"2023-05-17T20:24:23.458643Z","shell.execute_reply.started":"2023-05-17T20:24:23.338904Z","shell.execute_reply":"2023-05-17T20:24:23.457574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\ndirectory = os.path.join(PATH_WORK,\"temp\")\nif not os.path.exists(directory):\n    os.makedirs(directory)\nlogging.info('Getting paths')\nnum_cpu = int(cpu_count())\naudios_splitted = Parallel(n_jobs=num_cpu, prefer='processes')(\n    delayed(create_files)(part_series) \n    for part_series in np.array_split(df, num_cpu)\n)\naudio_splitted = pd.concat(audios_splitted)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:24:23.463702Z","iopub.execute_input":"2023-05-17T20:24:23.465124Z","iopub.status.idle":"2023-05-17T20:32:24.072117Z","shell.execute_reply.started":"2023-05-17T20:24:23.465065Z","shell.execute_reply":"2023-05-17T20:32:24.069556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nuseful_classes = audio_splitted['label'].value_counts()\nuseful_classes = useful_classes[useful_classes >= 10].index\n_ , test = train_test_split(audio_splitted.loc[audio_splitted['label'].isin(useful_classes)]['original_index'].drop_duplicates(),\n                            test_size=0.1)\naudio_splitted_test = audio_splitted.loc[audio_splitted.index.isin(test.index)].reset_index(drop=True)\naudio_splitted_train = audio_splitted.loc[~audio_splitted.index.isin(test.index)].reset_index(drop=True)\ntext=f'Teste Shape: {audio_splitted_test.shape}|Train Shape {audio_splitted_train.shape}'\nprint(text)\nlogging.info(text)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:24.075983Z","iopub.execute_input":"2023-05-17T20:32:24.077854Z","iopub.status.idle":"2023-05-17T20:32:25.152856Z","shell.execute_reply.started":"2023-05-17T20:32:24.077775Z","shell.execute_reply":"2023-05-17T20:32:25.151379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sklearn.metrics\ndef padded_cmap(solution, submission, padding_factor=5):\n    solution = solution.drop(['row_id'], axis=1, errors='ignore')\n    submission = submission.drop(['row_id'], axis=1, errors='ignore')\n    new_rows = []\n    for i in range(padding_factor):\n        new_rows.append([1 for i in range(len(solution.columns))])\n    new_rows = pd.DataFrame(new_rows)\n    new_rows.columns = solution.columns\n    padded_solution = pd.concat([solution, new_rows]).reset_index(drop=True).copy()\n    padded_submission = pd.concat([submission, new_rows]).reset_index(drop=True).copy()\n    score = sklearn.metrics.average_precision_score(\n        padded_solution.values,\n        padded_submission.values,\n        average='macro',\n    )\n    return score","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class BirdsSoundDatasets(Dataset):\n    def __init__(self,df,classes,device):\n        self.annotations = df\n        self.classes =classes\n    def __len__(self):\n        return len(self.annotations)\n    def __getitem__(self,index):\n        signal = torch.load(os.path.join(PATH_WORK,\"temp\",self.annotations.loc[index,'path_signal']))\n        label = self.classes [self.annotations.loc[index,'label']]\n        return signal, torch.tensor(label)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:25.154974Z","iopub.execute_input":"2023-05-17T20:32:25.155949Z","iopub.status.idle":"2023-05-17T20:32:25.164660Z","shell.execute_reply.started":"2023-05-17T20:32:25.155894Z","shell.execute_reply":"2023-05-17T20:32:25.163267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Dataset_train = BirdsSoundDatasets(audio_splitted_train,classes,device)\nDataset_test = BirdsSoundDatasets(audio_splitted_test,classes,device)\ntrain_data_loader = DataLoader(Dataset_train , batch_size=BATCH_SIZE,shuffle=True)\ntest_data_loader = DataLoader(Dataset_test , batch_size=BATCH_SIZE)\nlogging.info('Data loader Created!')","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:25.166355Z","iopub.execute_input":"2023-05-17T20:32:25.166753Z","iopub.status.idle":"2023-05-17T20:32:25.178704Z","shell.execute_reply.started":"2023-05-17T20:32:25.166701Z","shell.execute_reply":"2023-05-17T20:32:25.177460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_one_epoch(model, train_data_loader, loss_fn, optimizer, device):\n    # Set model to train mode\n    model.train()\n    \n    # Initialize variables to track loss and accuracy\n    epoch_loss = 0\n    epoch_acc = 0\n    # Loop over the training data\n    for batch_idx, (data, target) in enumerate(train_data_loader):\n        # Send the data and target to the device\n        data, target = data.to(device), target.to(device)\n        # Zero out gradients from previous iteration\n        optimizer.zero_grad()\n        # Forward pass\n        output = model(data)\n        # Compute loss\n        loss = loss_fn(output, target)\n        epoch_loss += loss.item()\n        # Backward pass\n        loss.backward()\n        # Update model parameters\n        optimizer.step()\n        # Compute accuracy\n        pred = output.argmax(dim=1, keepdim=True)\n        correct = pred.eq(target.view_as(pred)).sum().item()\n        epoch_acc += correct / len(data)\n    # Compute average loss and accuracy for the epoch\n    epoch_loss /= len(train_data_loader.dataset)\n    epoch_acc /= len(train_data_loader.dataset)   \n    return epoch_loss, epoch_acc\n\ndef evaluate(model, data_loader, loss_fn, device):\n    model.eval()\n    total_loss = 0\n    total_correct = 0\n    total_samples = 0\n    \n    with torch.no_grad():\n        for batch in data_loader:\n            inputs, targets = batch\n            inputs = inputs.to(device)\n            targets = targets.to(device)\n            outputs = model(inputs)\n            loss = loss_fn(outputs, targets)\n            total_loss += loss.item() * inputs.size(0)\n            preds = torch.argmax(outputs, dim=1)\n            total_correct += torch.sum(preds == targets)\n            total_samples += inputs.size(0)\n    avg_loss = total_loss / total_samples\n    accuracy = float(total_correct) / total_samples\n    return avg_loss, accuracy\n\ndef train(model, train_data_loader, test_data_loader, loss_fn, optimizer, device, epochs):\n    for epoch in range(1, epochs+1):\n        start_time = datetime.datetime.now()\n        train_loss, train_acc = train_one_epoch(model, train_data_loader, loss_fn, optimizer, device)\n        test_loss, test_acc = evaluate(model, test_data_loader, loss_fn, device)\n        end_time = datetime.datetime.now()\n        elapsed_time = end_time - start_time\n        elapsed_minutes = round(elapsed_time.total_seconds() / 60,2)\n        text=f'Epoch {epoch}/{epochs} | Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.4f} | Test Loss: {test_loss:.4f} | Test Acc: {test_acc:.4f} | Time (min): {elapsed_minutes}'\n        print(text)\n        logging.info(text)\n    print('Training finished')\n","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:25.182789Z","iopub.execute_input":"2023-05-17T20:32:25.183159Z","iopub.status.idle":"2023-05-17T20:32:25.203033Z","shell.execute_reply.started":"2023-05-17T20:32:25.183124Z","shell.execute_reply":"2023-05-17T20:32:25.202085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class LeNet5(nn.Module):\n    def __init__(self):\n        super(LeNet5, self).__init__()\n        self.conv1 = nn.Conv2d(1, 6, kernel_size=5, stride=1, padding=0)\n        self.avg_pool1 = nn.AvgPool2d(kernel_size=2, stride=2, padding=0)\n        self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1, padding=0)\n        self.avg_pool2 = nn.AvgPool2d(kernel_size=2, stride=2, padding=0)\n        self.dropout1 = nn.Dropout(p=0.3)  # add dropout with probability 0.3\n        self.fc1 = nn.Linear(3328, 264*4)\n        self.fc2 = nn.Linear(264*4, 264*2)\n        self.fc3 = nn.Linear(264*2, 264)\n\n    def forward(self, x):\n        x = self.conv1(x)\n        x = nn.functional.relu(x)\n        x = self.avg_pool1(x)\n        x = self.conv2(x)\n        x = nn.functional.relu(x)\n        x = self.avg_pool2(x)\n        x = torch.flatten(x, 1)\n        x = self.fc1(x)\n        x = nn.functional.relu(x)\n        x = self.dropout1(x)  \n        x = self.fc2(x)\n        x = nn.functional.relu(x)\n        x = self.fc3(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:25.204355Z","iopub.execute_input":"2023-05-17T20:32:25.205000Z","iopub.status.idle":"2023-05-17T20:32:25.220666Z","shell.execute_reply.started":"2023-05-17T20:32:25.204955Z","shell.execute_reply":"2023-05-17T20:32:25.219323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"logging.info('Running model...')\nmodel =  LeNet5()\nloss_fn = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(),lr=LEARNING_RATE)\ntrain(model,train_data_loader,test_data_loader,loss_fn,optimizer,device,EPOCHS)\ntorch.save(model.state_dict(),\"model.ptn\")\nlogging.info('Model Trained...')\nprint(\"Model saved\")","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:32:25.222332Z","iopub.execute_input":"2023-05-17T20:32:25.223478Z","iopub.status.idle":"2023-05-17T20:33:20.648250Z","shell.execute_reply.started":"2023-05-17T20:32:25.223426Z","shell.execute_reply":"2023-05-17T20:33:20.647248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"logging.info('Getting submission data.')\nsubmit_sample = list(glob.glob(\"/kaggle/input/birdclef-2023/test_soundscapes/*.ogg\"))\nlogging.info(f'Submisstion data: {submit_sample}')","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:33:20.649726Z","iopub.execute_input":"2023-05-17T20:33:20.650494Z","iopub.status.idle":"2023-05-17T20:33:20.660878Z","shell.execute_reply.started":"2023-05-17T20:33:20.650452Z","shell.execute_reply":"2023-05-17T20:33:20.658945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output_submition = []\nmodel.eval()\nfor file in submit_sample:    \n    name = submit_sample[0].split('/')[-1].split('.')[0]\n    time = SECONDS\n    signal, sr = torchaudio.load(file)\n    signal = signal.to(device)\n    signal = resample_if_necessary(signal,sr) \n    \n    for i in range(0,len(signal[0,:]),NUM_SAMPLES):\n        temp = mel_spectogram(signal[:,i:i+NUM_SAMPLES])\n        temp = nn.functional.softmax(model(temp.unsqueeze(0).float()),dim=1).float().detach().numpy()[0]\n        row_id=name+'_'+str(time)\n        output_submition.append([row_id,*temp])\n        time+=SECONDS","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:38:58.203158Z","iopub.execute_input":"2023-05-17T20:38:58.203602Z","iopub.status.idle":"2023-05-17T20:38:59.487325Z","shell.execute_reply.started":"2023-05-17T20:38:58.203565Z","shell.execute_reply":"2023-05-17T20:38:59.485901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submition = pd.DataFrame(output_submition,columns=['row_id',*list(classes.keys())])\nsubmission = df_submition\nlogging.info('Submmited!')\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:44:17.029043Z","iopub.execute_input":"2023-05-17T20:44:17.029526Z","iopub.status.idle":"2023-05-17T20:44:17.117708Z","shell.execute_reply.started":"2023-05-17T20:44:17.029488Z","shell.execute_reply":"2023-05-17T20:44:17.116356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-05-17T20:44:17.185373Z","iopub.execute_input":"2023-05-17T20:44:17.185876Z","iopub.status.idle":"2023-05-17T20:44:17.242736Z","shell.execute_reply.started":"2023-05-17T20:44:17.185793Z","shell.execute_reply":"2023-05-17T20:44:17.241252Z"},"trusted":true},"execution_count":null,"outputs":[]}]}