{"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\nfrom tqdm.notebook import tqdm\nimport wandb\nimport random\nimport numpy as np\nimport pandas as pd\nimport warnings\nimport matplotlib.pyplot as plt\nfrom IPython.display import Audio, display\nimport plotly.express as px\nfrom plotly.subplots import make_subplots\nimport plotly.graph_objects as go\nimport librosa\nfrom librosa.display import waveshow\n\nimport torch\nimport torchvision\nimport torchvision.models as models\nimport torchaudio\nfrom torch import nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.utils.data import Dataset\nimport torchaudio.functional as F\nimport torchaudio.transforms as T\n\nprint(torch.__version__)\nprint(torchaudio.__version__)\nprint(wandb.__version__)\n\nimport plotly.io as pio\npio.templates.default = \"plotly_dark\"\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:22.799613Z","iopub.execute_input":"2022-04-21T17:32:22.801208Z","iopub.status.idle":"2022-04-21T17:32:29.561516Z","shell.execute_reply.started":"2022-04-21T17:32:22.801094Z","shell.execute_reply":"2022-04-21T17:32:29.560723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = dict(\n    seed = 42,\n    use_wandb = True,\n    \n    batch_size=256,\n    device = 'cuda' if torch.cuda.is_available() else 'cpu',\n    num_epochs = 15,\n    \n    # preprocessing\n    target_sample_rate = 32_000,\n    n_fft = 1024,\n    hop_length = 512,\n    n_mels = 64,\n    num_samples = 22050,\n    duration_seconds = 7,\n    num_classes=152,\n    # model\n    lr = 0.003\n)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:29.563483Z","iopub.execute_input":"2022-04-21T17:32:29.563725Z","iopub.status.idle":"2022-04-21T17:32:29.615723Z","shell.execute_reply.started":"2022-04-21T17:32:29.563692Z","shell.execute_reply":"2022-04-21T17:32:29.614893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if config['use_wandb']:\n    from kaggle_secrets import UserSecretsClient\n    user_secrets = UserSecretsClient()\n    secret_value_0 = user_secrets.get_secret(\"WANDB_API_KEY\")\n\n    wandb.login(key=secret_value_0)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:29.618950Z","iopub.execute_input":"2022-04-21T17:32:29.619429Z","iopub.status.idle":"2022-04-21T17:32:33.223115Z","shell.execute_reply.started":"2022-04-21T17:32:29.619396Z","shell.execute_reply":"2022-04-21T17:32:33.222369Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(seed=42):\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.backends.cudnn.deterministic = True\n\nseed_everything(config['seed'])","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.225094Z","iopub.execute_input":"2022-04-21T17:32:33.225295Z","iopub.status.idle":"2022-04-21T17:32:33.232916Z","shell.execute_reply.started":"2022-04-21T17:32:33.225268Z","shell.execute_reply":"2022-04-21T17:32:33.232212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ROOT_DIR = os.path.abspath('../input/birdclef-2022')\nRAW_TRAIN_DATA_DIR = os.path.join(ROOT_DIR, 'train_audio')\nTRAIN_DATA_PATH = os.path.join(ROOT_DIR, 'train_metadata.csv')\nPROCESSED_ROOT_DIR = os.path.abspath('../input/birdcleff2022mfcc7seconds')\nPROCESSED_TRAIN_DATA_DIR = os.path.join('../input/birdcleff2022mfcc7seconds/birdcall_processesed/data')","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.234301Z","iopub.execute_input":"2022-04-21T17:32:33.234850Z","iopub.status.idle":"2022-04-21T17:32:33.241647Z","shell.execute_reply.started":"2022-04-21T17:32:33.234810Z","shell.execute_reply":"2022-04-21T17:32:33.240922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(TRAIN_DATA_PATH)\ndf.drop(['scientific_name', 'common_name', 'author', 'license', 'rating', 'url', 'type'], axis=1, inplace=True)\ndf.head(10)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.242919Z","iopub.execute_input":"2022-04-21T17:32:33.243444Z","iopub.status.idle":"2022-04-21T17:32:33.363642Z","shell.execute_reply.started":"2022-04-21T17:32:33.243406Z","shell.execute_reply":"2022-04-21T17:32:33.362929Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label_to_id = {}\nid_to_label = {}\n\nfor i, label in enumerate(os.listdir(RAW_TRAIN_DATA_DIR)):\n    label_to_id[label] = i\n    id_to_label[i] = label","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.364873Z","iopub.execute_input":"2022-04-21T17:32:33.365116Z","iopub.status.idle":"2022-04-21T17:32:33.390031Z","shell.execute_reply.started":"2022-04-21T17:32:33.365081Z","shell.execute_reply":"2022-04-21T17:32:33.389426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# df['primary_label'] = df['primary_label'].replace(label_to_id)\n# df['path'] = df['filename'].apply(lambda x: os.path.join(TRAIN_DATA_DIR, x))\ndf.head(10)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.391875Z","iopub.execute_input":"2022-04-21T17:32:33.392358Z","iopub.status.idle":"2022-04-21T17:32:33.407289Z","shell.execute_reply.started":"2022-04-21T17:32:33.392307Z","shell.execute_reply":"2022-04-21T17:32:33.406230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class BirdCLEFDataset(Dataset):\n\n    def __init__(self, df, data_dir, split='train', transforms=None):\n        self.df = df\n        self.data_dir = data_dir\n        self.split = split\n        self.transforms = transforms.to(config['device'])\n        self.target_sr = config['target_sample_rate']\n        self.num_samples = config['target_sample_rate']*config['duration_seconds']\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        waveform, sample_rate = torchaudio.load(self.df['path'][idx])\n        waveform = waveform.to(config['device'])\n        waveform = self._resample(waveform, sample_rate)\n        waveform = self._mix_down(waveform)\n        waveform = self._cut_if_necessary(waveform)\n        waveform = self._right_pad_if_necessary(waveform)\n        waveform = self.transforms(waveform)\n\n        if self.split == 'train':\n            label = torch.tensor(self.df['primary_label'][idx])\n            return waveform, label\n        else:\n            return waveform\n    \n    def _cut_if_necessary(self, signal):\n        # waveform = Tensor(1, num_samples, )\n        if signal.shape[1] > self.num_samples:\n            signal = signal[:, :self.num_samples]\n\n        return signal\n    \n    def _right_pad_if_necessary(self, signal):\n        if signal.shape[1] < self.num_samples:\n            num_missing_samples = self.num_samples - signal.shape[1]\n            last_dim_padding = (0, num_missing_samples) # (num of vals to be padded on left side, num of vals to be padded on right side)\n            signal = torch.nn.functional.pad(signal, last_dim_padding)\n        \n        return signal\n\n    def _resample(self, waveform, sr):\n        if sr != self.target_sr:\n            resampler = torchaudio.transforms.Resample(sr, self.target_sr).to(config['device'])\n            waveform = resampler(waveform)\n\n        return waveform\n\n    def _mix_down(self, waveform):\n        '''\n        Convert to audio waveform into mono waveform\n        '''\n        if waveform.shape[0] > 1:\n            waveform = torch.mean(waveform, dim=0, keepdim=True)\n\n        return waveform\n\nclass BirdclefMFCCDataset(Dataset):\n    \n    def __init__(self, df, split='train', transforms=None):\n        self.df = df\n        self.split = split\n        self.transforms = transforms\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        waveform = torch.from_numpy(np.load(self.df['filepath'][idx]))\n        label = torch.tensor(self.df['label'][idx])\n        \n        if self.transforms:\n            waveform = self.transforms(waveform)\n        \n        if self.split == 'train':\n            return waveform, torch.tensor(label)\n        else:\n            return waveform","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.408970Z","iopub.execute_input":"2022-04-21T17:32:33.409514Z","iopub.status.idle":"2022-04-21T17:32:33.428760Z","shell.execute_reply.started":"2022-04-21T17:32:33.409474Z","shell.execute_reply":"2022-04-21T17:32:33.427967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# mel_spectrogram = torchaudio.transforms.MelSpectrogram(\n#     sample_rate=config['target_sample_rate'],\n#     n_fft=config['n_fft'],\n#     hop_length=config['hop_length'],\n#     n_mels=config['n_mels']\n# )\n\n# dataset = BirdCLEFDataset(df, TRAIN_DATA_DIR, 'train', transforms=mel_spectrogram)\n# signal, label = dataset[np.random.randint(0, len(dataset))]","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.433170Z","iopub.execute_input":"2022-04-21T17:32:33.433623Z","iopub.status.idle":"2022-04-21T17:32:33.440942Z","shell.execute_reply.started":"2022-04-21T17:32:33.433581Z","shell.execute_reply":"2022-04-21T17:32:33.440045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# librosa.display.specshow(signal[0].cpu().numpy(), sr=config['target_sample_rate'], hop_length=config['hop_length'])\n# plt.xlabel(\"Time\")\n# plt.ylabel(\"MFCC\")\n# plt.colorbar()\n# plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:33.442285Z","iopub.execute_input":"2022-04-21T17:32:33.442634Z","iopub.status.idle":"2022-04-21T17:32:33.449152Z","shell.execute_reply.started":"2022-04-21T17:32:33.442595Z","shell.execute_reply":"2022-04-21T17:32:33.448275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"resnet50","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:39:10.533004Z","iopub.execute_input":"2022-04-21T17:39:10.533741Z","iopub.status.idle":"2022-04-21T17:39:10.541150Z","shell.execute_reply.started":"2022-04-21T17:39:10.533703Z","shell.execute_reply":"2022-04-21T17:39:10.539845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# resnet18 = models.resnet18()\n# resnet18.conv1 = torch.nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n# resnet18.fc = torch.nn.Linear(512, config['num_classes'])\n# x = torch.randn(64, 1, 64, 438)\n# output = resnet18(x)\n# print(output.shape)\n\nresnet50 = models.resnet50()\nresnet50.conv1 = torch.nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\nresnet50.fc = torch.nn.Linear(2048, config['num_classes'])\nx = torch.randn(64, 1, 64, 438)\noutput = resnet18(x)\nprint(output.shape)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:39:24.681858Z","iopub.execute_input":"2022-04-21T17:39:24.682129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if config['use_wandb']:\n    wandb.init(\n        project=\"BirdCLEF 2022\",\n        entity=\"raghavprabhakar\",\n        config=config\n    )","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:42.087907Z","iopub.status.idle":"2022-04-21T17:32:42.089314Z","shell.execute_reply.started":"2022-04-21T17:32:42.089056Z","shell.execute_reply":"2022-04-21T17:32:42.089085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The train function for every Epoch\ndef fit(model, dataset, dataloader, optim, criterion, mode='train'):\n    # Choice of training and testing mode\n    if mode == 'train':\n        model.train()\n    else:\n        model.eval()\n\n    running_loss = 0.0\n    running_corrects = 0.0\n    \n    tqdm_loop = tqdm(\n        dataloader,\n        total=dataset.__len__() // dataloader.batch_size,\n        desc=mode, leave=True\n    )\n\n    # Loop over the dataloader and train over every batch of images\n    for i, data in enumerate(tqdm_loop):\n        # Copy data to the gpu\n        images, labels = data\n        images, labels = images.to(config['device']), labels.to(config['device'])\n        \n        # Zero the parameter gradients during training\n        if mode=='train':\n            optim.zero_grad()\n\n        # Predict classes using images from the training set\n        outputs = model(images)\n\n        # Compute the loss based on model output and real labels\n        loss = criterion(outputs, labels)\n\n        # Calculate statistics\n        running_loss += loss.item()\n        running_corrects += (outputs.max(1)[1] == labels).sum().item()\n        \n        # Perform model updates according to the loss function (criterion)\n        if mode=='train':\n            # Backpropagate the loss\n            loss.backward()\n            # Adjust parameters based on the calculated gradients\n            optim.step()\n    \n    # Record the average statistics\n    epoch_loss = running_loss / dataset.__len__()\n    epoch_acc = running_corrects / dataset.__len__()\n    \n    tqdm_loop.set_postfix(loss=epoch_loss, acc=epoch_acc)\n\n\n    return epoch_loss, epoch_acc","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:42.090668Z","iopub.status.idle":"2022-04-21T17:32:42.091113Z","shell.execute_reply.started":"2022-04-21T17:32:42.090862Z","shell.execute_reply":"2022-04-21T17:32:42.090886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optim = torch.optim.Adam(resnet18.parameters(), lr=config['lr'])\nloss_fn = nn.CrossEntropyLoss()","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:42.092430Z","iopub.status.idle":"2022-04-21T17:32:42.092838Z","shell.execute_reply.started":"2022-04-21T17:32:42.092605Z","shell.execute_reply":"2022-04-21T17:32:42.092629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ndf = pd.DataFrame(os.listdir('../input/birdcleff2022mfcc7seconds/birdcall_processesed/data'), columns=['filepath'])\ndf['filepath'] = df['filepath'].apply(lambda x: os.path.join(PROCESSED_TRAIN_DATA_DIR, x))\ndf['label'] = df['filepath'].apply(lambda  x: int(x.split('_')[-1].split('.')[0]))\ndf.head()\n\ntrain_df, valid_df = train_test_split(df, test_size=0.2)\ntrain_df = train_df.reset_index()\nvalid_df = valid_df.reset_index()\nprint(train_df.shape, valid_df.shape)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:42.093959Z","iopub.status.idle":"2022-04-21T17:32:42.094885Z","shell.execute_reply.started":"2022-04-21T17:32:42.094642Z","shell.execute_reply":"2022-04-21T17:32:42.094667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = dataset = BirdclefMFCCDataset(train_df)\nvalid_dataset = dataset = BirdclefMFCCDataset(valid_df)\n\ntrain_dataloader = DataLoader(train_dataset, batch_size=config['batch_size'], shuffle=True)\nvalid_dataloader = DataLoader(valid_dataset, batch_size=config['batch_size'], shuffle=True)","metadata":{"execution":{"iopub.status.busy":"2022-04-21T17:32:42.096236Z","iopub.status.idle":"2022-04-21T17:32:42.096628Z","shell.execute_reply.started":"2022-04-21T17:32:42.096413Z","shell.execute_reply":"2022-04-21T17:32:42.096435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loss, valid_loss = [], []\ntrain_acc, valid_acc = [], []\nbest_acc = 0\n# Run train loop for given number of epochs\nfor epoch in range(config['num_epochs']):\n    print(f'Epoch: {epoch+1} / {config[\"num_epochs\"]}')\n    print('-' * 10)\n\n    # Train model one epoch and display statistics\n    train_epoch_loss, train_epoch_acc = fit(resnet18.to(config['device']), train_dataset, train_dataloader, optim, loss_fn, mode='train')\n    train_loss.append(train_epoch_loss)\n    train_acc.append(train_epoch_acc)\n    print(f'Train Loss: {train_epoch_loss:.4f} | Train Acc: {train_epoch_acc:.4f}')\n\n    # Run validation for one epoch and display statistics\n    with torch.no_grad():\n        valid_epoch_loss, valid_epoch_acc = fit(resnet18.to(config['device']), valid_dataset, valid_dataloader, optim, loss_fn, mode='valid')\n        valid_loss.append(valid_epoch_loss)\n        valid_acc.append(valid_epoch_acc)\n        print(f'Valid Loss: {valid_epoch_loss:.4f} | Valid Acc: {valid_epoch_acc:.4f}')\n    \n    if config['use_wandb']:\n        wandb.log({\n            \"train_loss\": train_epoch_loss,\n            \"valid_loss\": valid_epoch_loss,\n            \"train_acc\": train_epoch_acc,\n            \"valid_acc\": valid_epoch_acc,\n\n        })\n    \n    if valid_epoch_acc >= best_acc:\n        print(f'Model improved from {best_acc} to {valid_epoch_acc}, Saving best model...')\n        torch.save(resnet18.state_dict(), f'resnet50_best.pt')\n        best_acc = valid_epoch_acc\n\n# Save the model and all the metrics in a log file\n\ncheckpoint = {\n            'total_epochs'      : config['num_epochs'],\n            'state_dict'        : resnet18.state_dict(),\n            'optimizer'         : optim.state_dict(),\n            'train_loss'        : train_loss,\n            'train_acc'         : train_acc,\n            'val_loss'          : valid_loss,\n            'val_acc'           : valid_acc,\n            }\ntorch.save(checkpoint, 'resnet50_last.pt')\nprint(\"Model Saved\")","metadata":{"tags":[],"execution":{"iopub.status.busy":"2022-04-21T17:32:42.098000Z","iopub.status.idle":"2022-04-21T17:32:42.098391Z","shell.execute_reply.started":"2022-04-21T17:32:42.098177Z","shell.execute_reply":"2022-04-21T17:32:42.098199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}