{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","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":5148212,"sourceType":"datasetVersion","datasetId":2991134},{"sourceId":121796742,"sourceType":"kernelVersion"}],"dockerImageVersionId":30407,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport torch\nimport os\nimport pytorch_lightning as pl\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn import model_selection\nimport torchvision.transforms as transforms\nimport torchvision.io \nimport librosa\nfrom PIL import Image\nimport albumentations as alb\nimport torch.multiprocessing as mp\nimport warnings\n\nwarnings.filterwarnings('ignore')","metadata":{"papermill":{"duration":6.667352,"end_time":"2022-04-22T06:00:08.901647","exception":false,"start_time":"2022-04-22T06:00:02.234295","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:31.357760Z","iopub.execute_input":"2025-08-23T10:52:31.358073Z","iopub.status.idle":"2025-08-23T10:52:31.364720Z","shell.execute_reply.started":"2025-08-23T10:52:31.358040Z","shell.execute_reply":"2025-08-23T10:52:31.363371Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pytorch_lightning.callbacks import ModelCheckpoint, BackboneFinetuning, EarlyStopping\n","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:31.366111Z","iopub.execute_input":"2025-08-23T10:52:31.366465Z","iopub.status.idle":"2025-08-23T10:52:31.380212Z","shell.execute_reply.started":"2025-08-23T10:52:31.366423Z","shell.execute_reply":"2025-08-23T10:52:31.379194Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q torchtoolbox timm","metadata":{"papermill":{"duration":9.48179,"end_time":"2022-04-22T06:00:18.413844","exception":false,"start_time":"2022-04-22T06:00:08.932054","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:31.381826Z","iopub.execute_input":"2025-08-23T10:52:31.382059Z","iopub.status.idle":"2025-08-23T10:52:42.341545Z","shell.execute_reply.started":"2025-08-23T10:52:31.382037Z","shell.execute_reply":"2025-08-23T10:52:42.340348Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    use_aug = False\n    num_classes = 264\n    batch_size = 64\n    epochs = 20\n    PRECISION = 16    \n    PATIENCE = 8    \n    seed = 64\n    model = \"tf_efficientnet_b1_ns\"\n    pretrained = True            \n    weight_decay = 1e-3\n    use_mixup = True\n    mixup_alpha = 0.6\n    DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')    \n\n    data_root = \"/kaggle/input/birdclef-2023/\"\n    train_images = \"/kaggle/input/split-creating-melspecs-stage-1/specs/train/\"\n    valid_images = \"/kaggle/input/split-creating-melspecs-stage-1/specs/valid/\"\n    train_path = \"/kaggle/input/bc2023-train-val-df/train.csv\"\n    valid_path = \"/kaggle/input/bc2023-train-val-df/valid.csv\"\n    \n    \n    SR = 32000\n    DURATION = 5\n    MAX_READ_SAMPLES = 5\n    LR = 10e-4\n    ","metadata":{"papermill":{"duration":0.099568,"end_time":"2022-04-22T06:00:18.542447","exception":false,"start_time":"2022-04-22T06:00:18.442879","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:42.343956Z","iopub.execute_input":"2025-08-23T10:52:42.344339Z","iopub.status.idle":"2025-08-23T10:52:42.442575Z","shell.execute_reply.started":"2025-08-23T10:52:42.344302Z","shell.execute_reply":"2025-08-23T10:52:42.441234Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pl.seed_everything(Config.seed, workers=True)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:42.443945Z","iopub.execute_input":"2025-08-23T10:52:42.444276Z","iopub.status.idle":"2025-08-23T10:52:42.462576Z","shell.execute_reply.started":"2025-08-23T10:52:42.444245Z","shell.execute_reply":"2025-08-23T10:52:42.461459Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def config_to_dict(cfg):\n    return dict((name, getattr(cfg, name)) for name in dir(cfg) if not name.startswith('__'))","metadata":{"papermill":{"duration":0.033041,"end_time":"2022-04-22T06:00:18.664481","exception":false,"start_time":"2022-04-22T06:00:18.63144","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:42.465258Z","iopub.execute_input":"2025-08-23T10:52:42.465659Z","iopub.status.idle":"2025-08-23T10:52:42.470851Z","shell.execute_reply.started":"2025-08-23T10:52:42.465629Z","shell.execute_reply":"2025-08-23T10:52:42.469674Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train = pd.read_csv(Config.train_path)\ndf_valid = pd.read_csv(Config.valid_path)\ndf_train.head()","metadata":{"papermill":{"duration":58.466679,"end_time":"2022-04-22T06:01:17.158088","exception":false,"start_time":"2022-04-22T06:00:18.691409","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:42.472717Z","iopub.execute_input":"2025-08-23T10:52:42.473102Z","iopub.status.idle":"2025-08-23T10:52:42.660241Z","shell.execute_reply.started":"2025-08-23T10:52:42.473062Z","shell.execute_reply":"2025-08-23T10:52:42.658970Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Config.num_classes = len(df_train.primary_label.unique())","metadata":{"papermill":{"duration":0.035353,"end_time":"2022-04-22T06:01:17.283888","exception":false,"start_time":"2022-04-22T06:01:17.248535","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:42.661732Z","iopub.execute_input":"2025-08-23T10:52:42.662075Z","iopub.status.idle":"2025-08-23T10:52:42.668598Z","shell.execute_reply.started":"2025-08-23T10:52:42.662044Z","shell.execute_reply":"2025-08-23T10:52:42.667347Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train = pd.concat([df_train, pd.get_dummies(df_train['primary_label'])], axis=1)\ndf_valid = pd.concat([df_valid, pd.get_dummies(df_valid['primary_label'])], axis=1)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:42.669812Z","iopub.execute_input":"2025-08-23T10:52:42.670134Z","iopub.status.idle":"2025-08-23T10:52:42.701185Z","shell.execute_reply.started":"2025-08-23T10:52:42.670095Z","shell.execute_reply":"2025-08-23T10:52:42.699912Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Create & Fill birds with 0 samples in validation","metadata":{}},{"cell_type":"code","source":"birds = list(df_train.primary_label.unique())","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:42.702541Z","iopub.execute_input":"2025-08-23T10:52:42.702885Z","iopub.status.idle":"2025-08-23T10:52:42.709780Z","shell.execute_reply.started":"2025-08-23T10:52:42.702856Z","shell.execute_reply":"2025-08-23T10:52:42.708543Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"missing_birds = list(set(list(df_train.primary_label.unique())).difference(list(df_valid.primary_label.unique())))","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:48.565100Z","iopub.execute_input":"2025-08-23T10:52:48.565523Z","iopub.status.idle":"2025-08-23T10:52:48.572566Z","shell.execute_reply.started":"2025-08-23T10:52:48.565471Z","shell.execute_reply":"2025-08-23T10:52:48.571297Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"non_missing_birds = list(set(list(df_train.primary_label.unique())).difference(missing_birds))","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:49.941965Z","iopub.execute_input":"2025-08-23T10:52:49.942963Z","iopub.status.idle":"2025-08-23T10:52:49.948668Z","shell.execute_reply.started":"2025-08-23T10:52:49.942924Z","shell.execute_reply":"2025-08-23T10:52:49.947501Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(non_missing_birds)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:51.482088Z","iopub.execute_input":"2025-08-23T10:52:51.483196Z","iopub.status.idle":"2025-08-23T10:52:51.489528Z","shell.execute_reply.started":"2025-08-23T10:52:51.483155Z","shell.execute_reply":"2025-08-23T10:52:51.488376Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_valid[missing_birds] = 0\ndf_valid = df_valid[df_train.columns] ## Fix order","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:53.247727Z","iopub.execute_input":"2025-08-23T10:52:53.248144Z","iopub.status.idle":"2025-08-23T10:52:53.262622Z","shell.execute_reply.started":"2025-08-23T10:52:53.248108Z","shell.execute_reply":"2025-08-23T10:52:53.261669Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# df_train.iloc[:,17:]","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:54.410632Z","iopub.execute_input":"2025-08-23T10:52:54.411004Z","iopub.status.idle":"2025-08-23T10:52:54.415787Z","shell.execute_reply.started":"2025-08-23T10:52:54.410974Z","shell.execute_reply":"2025-08-23T10:52:54.414612Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations as A\nfrom torchtoolbox.transform import Cutout\ndef get_train_transform():\n    return A.Compose([\n        Cutout()\n    ])","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:52:54.820524Z","iopub.execute_input":"2025-08-23T10:52:54.821266Z","iopub.status.idle":"2025-08-23T10:52:54.838219Z","shell.execute_reply.started":"2025-08-23T10:52:54.821229Z","shell.execute_reply":"2025-08-23T10:52:54.836961Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BirdDataset(torch.utils.data.Dataset):\n\n    def __init__(self, df, sr = Config.SR, duration = Config.DURATION, augmentations = None, train = True):\n\n        self.df = df\n        self.sr = sr \n        self.train = train\n        self.duration = duration\n        self.augmentations = augmentations\n        if train:\n            self.img_dir = Config.train_images\n        else:\n            self.img_dir = Config.valid_images\n\n    def __len__(self):\n        return len(self.df)\n\n    @staticmethod\n    def normalize(image):\n        image = image / 255.0\n        #image = torch.stack([image, image, image])\n        return image\n\n    def __getitem__(self, idx):\n\n        row = self.df.iloc[idx]\n        impath = self.img_dir + f\"{row.filename}.npy\"\n\n        image = np.load(str(impath))[:Config.MAX_READ_SAMPLES]\n        \n        ########## RANDOM SAMPLING ################\n        if self.train:\n            image = image[np.random.choice(len(image))]\n        else:\n            image = image[0]\n            \n        #####################################################################\n        \n        image = torch.tensor(image).float()\n\n        if self.augmentations:\n            image = self.augmentations(image.unsqueeze(0)).squeeze()\n            \n        image.size()\n        \n        image = torch.stack([image])\n\n        image = self.normalize(image)\n\n\n        return image, torch.tensor(row[17:]).float()\n","metadata":{"papermill":{"duration":0.039034,"end_time":"2022-04-22T06:01:17.350173","exception":false,"start_time":"2022-04-22T06:01:17.311139","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:56.394116Z","iopub.execute_input":"2025-08-23T10:52:56.395071Z","iopub.status.idle":"2025-08-23T10:52:56.404781Z","shell.execute_reply.started":"2025-08-23T10:52:56.395032Z","shell.execute_reply":"2025-08-23T10:52:56.403670Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_fold_dls(df_train, df_valid, aug=None):\n\n    ds_train = BirdDataset(\n        df_train, \n        sr = Config.SR,\n        duration = Config.DURATION,\n        augmentations = aug,\n        train = True\n    )\n    ds_val = BirdDataset(\n        df_valid, \n        sr = Config.SR,\n        duration = Config.DURATION,\n        augmentations = None,\n        train = False\n    )\n    dl_train = DataLoader(ds_train, batch_size=Config.batch_size , shuffle=True, num_workers = 0)    \n    dl_val = DataLoader(ds_val, batch_size=Config.batch_size, num_workers = 0)\n    return dl_train, dl_val, ds_train, ds_val","metadata":{"papermill":{"duration":0.036289,"end_time":"2022-04-22T06:01:17.539606","exception":false,"start_time":"2022-04-22T06:01:17.503317","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:52:57.044854Z","iopub.execute_input":"2025-08-23T10:52:57.045903Z","iopub.status.idle":"2025-08-23T10:52:57.052187Z","shell.execute_reply.started":"2025-08-23T10:52:57.045861Z","shell.execute_reply":"2025-08-23T10:52:57.051000Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_batch(img_ds, num_items, num_rows, num_cols, predict_arr=None):\n    fig = plt.figure(figsize=(12, 6))    \n    img_index = np.random.randint(0, len(img_ds)-1, num_items)\n    for index, img_index in enumerate(img_index):  # list first 9 images\n        img, lb = img_ds[img_index]        \n        ax = fig.add_subplot(num_rows, num_cols, index + 1, xticks=[], yticks=[])\n        if isinstance(img, torch.Tensor):\n            img = img.detach().numpy()\n        if isinstance(img, np.ndarray):\n            img = img.transpose(1, 2, 0)\n            ax.imshow(img)        \n            \n        title = f\"Spec\"\n        ax.set_title(title)  ","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:00.282089Z","iopub.execute_input":"2025-08-23T10:53:00.282473Z","iopub.status.idle":"2025-08-23T10:53:00.289688Z","shell.execute_reply.started":"2025-08-23T10:53:00.282439Z","shell.execute_reply":"2025-08-23T10:53:00.288437Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"aug = get_train_transform()\ndl_train, dl_val, ds_train, ds_val = get_fold_dls(df_train, df_valid)\nshow_batch(ds_val, 8, 2, 4)","metadata":{"papermill":{"duration":0.584852,"end_time":"2022-04-22T06:01:18.338238","exception":false,"start_time":"2022-04-22T06:01:17.753386","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:53:00.472364Z","iopub.execute_input":"2025-08-23T10:53:00.473109Z","iopub.status.idle":"2025-08-23T10:53:01.215655Z","shell.execute_reply.started":"2025-08-23T10:53:00.473072Z","shell.execute_reply":"2025-08-23T10:53:01.214625Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.optim.lr_scheduler import CosineAnnealingLR, CosineAnnealingWarmRestarts, ReduceLROnPlateau, OneCycleLR\n\ndef get_optimizer(lr, params):\n    model_optimizer = torch.optim.AdamW(\n            filter(lambda p: p.requires_grad, params), \n            lr=lr,\n            weight_decay=Config.weight_decay\n        )\n    interval = \"epoch\"\n    \n    lr_scheduler = CosineAnnealingWarmRestarts(\n                            model_optimizer, \n                            T_0=Config.epochs, \n                            T_mult=1, \n                            eta_min=1e-6, \n                            last_epoch=-1\n                        )\n\n    return {\n        \"optimizer\": model_optimizer, \n        \"lr_scheduler\": {\n            \"scheduler\": lr_scheduler,\n            \"interval\": interval,\n            \"monitor\": \"val_loss\",\n            \"frequency\": 1\n        }\n    }","metadata":{"papermill":{"duration":0.048043,"end_time":"2022-04-22T06:01:22.109544","exception":false,"start_time":"2022-04-22T06:01:22.061501","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:53:03.863922Z","iopub.execute_input":"2025-08-23T10:53:03.864723Z","iopub.status.idle":"2025-08-23T10:53:03.872142Z","shell.execute_reply.started":"2025-08-23T10:53:03.864679Z","shell.execute_reply":"2025-08-23T10:53:03.870881Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchtoolbox.tools import mixup_data, mixup_criterion\nimport torch.nn as nn\nfrom torch.nn.functional import cross_entropy\nimport torchmetrics\nimport timm","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:12.831322Z","iopub.execute_input":"2025-08-23T10:53:12.832506Z","iopub.status.idle":"2025-08-23T10:53:13.203525Z","shell.execute_reply.started":"2025-08-23T10:53:12.832438Z","shell.execute_reply":"2025-08-23T10:53:13.202560Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sklearn.metrics\n\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\n\ndef map_score(solution, submission):\n    solution = solution#.drop(['row_id'], axis=1, errors='ignore')\n    submission = submission#.drop(['row_id'], axis=1, errors='ignore')\n    score = sklearn.metrics.average_precision_score(\n        solution.values,\n        submission.values,\n        average='micro',\n    )\n    return score","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:13.205344Z","iopub.execute_input":"2025-08-23T10:53:13.206220Z","iopub.status.idle":"2025-08-23T10:53:13.214601Z","shell.execute_reply.started":"2025-08-23T10:53:13.206184Z","shell.execute_reply":"2025-08-23T10:53:13.213315Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dummy = df_valid[birds].copy()\ndummy[birds] = np.random.rand(dummy.shape[0],dummy.shape[1])","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:15.728087Z","iopub.execute_input":"2025-08-23T10:53:15.728493Z","iopub.status.idle":"2025-08-23T10:53:15.805442Z","shell.execute_reply.started":"2025-08-23T10:53:15.728446Z","shell.execute_reply":"2025-08-23T10:53:15.804561Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"padded_cmap(df_valid[birds], dummy[birds], padding_factor = 5)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:15.931341Z","iopub.execute_input":"2025-08-23T10:53:15.932413Z","iopub.status.idle":"2025-08-23T10:53:16.989704Z","shell.execute_reply.started":"2025-08-23T10:53:15.932359Z","shell.execute_reply":"2025-08-23T10:53:16.988550Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"padded_cmap(df_valid[birds], dummy[birds], padding_factor = 1)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:18.554413Z","iopub.execute_input":"2025-08-23T10:53:18.554828Z","iopub.status.idle":"2025-08-23T10:53:19.372901Z","shell.execute_reply.started":"2025-08-23T10:53:18.554793Z","shell.execute_reply":"2025-08-23T10:53:19.371733Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"map_score(df_valid[birds], dummy[birds])","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:19.374870Z","iopub.execute_input":"2025-08-23T10:53:19.375649Z","iopub.status.idle":"2025-08-23T10:53:19.656569Z","shell.execute_reply.started":"2025-08-23T10:53:19.375597Z","shell.execute_reply":"2025-08-23T10:53:19.655463Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BirdClefModel(pl.LightningModule):\n    def __init__(self, model_name=Config.model, num_classes = Config.num_classes, pretrained = Config.pretrained):\n        super().__init__()\n        self.num_classes = num_classes\n\n        self.backbone = timm.create_model(model_name, pretrained=pretrained, in_chans=1)\n        \n#         self.train_losses = []\n#         self.val_losses = []\n        self.train_acc_history = []\n        self.val_acc_history = []\n\n        if 'res' in model_name:\n            self.in_features = self.backbone.fc.in_features\n            self.backbone.fc = nn.Linear(self.in_features, num_classes)\n        elif 'dense' in model_name:\n            self.in_features = self.backbone.classifier.in_features\n            self.backbone.classifier = nn.Linear(self.in_features, num_classes)\n        elif 'efficientnet' in model_name:\n            self.in_features = self.backbone.classifier.in_features\n            self.backbone.classifier = nn.Sequential(\n                nn.Linear(self.in_features, num_classes)\n            )\n        \n        self.loss_function = nn.BCEWithLogitsLoss() \n\n    def forward(self,images):\n        logits = self.backbone(images)\n        return logits\n        \n    def configure_optimizers(self):\n        return get_optimizer(lr=Config.LR, params=self.parameters())\n\n    def train_with_mixup(self, X, y):\n        X, y_a, y_b, lam = mixup_data(X, y, alpha=Config.mixup_alpha)\n        y_pred = self(X)\n        loss_mixup = mixup_criterion(cross_entropy, y_pred, y_a, y_b, lam)\n        return loss_mixup\n\n    def training_step(self, batch, batch_idx):\n        image, target = batch    \n        y_pred = self(image)\n\n        if Config.use_mixup:\n            loss = self.train_with_mixup(image, target)\n        else:\n            y_pred = self(image)\n            loss = self.loss_function(y_pred,target)\n        \n#         self.train_losses.append(loss.item())\n        self.log(\"train_loss\", loss, on_step=True, on_epoch=True, prog_bar=True)\n        \n        # Calculate training accuracy\n        y_pred_class = (y_pred > 0.5).float()\n        train_acc = (y_pred_class == target).float().mean()\n        self.train_acc_history.append(train_acc.item())\n        self.log(\"train_acc\", train_acc, on_step=True, on_epoch=True, prog_bar=True)\n\n        return loss        \n\n    def validation_step(self, batch, batch_idx):\n        image, target = batch     \n        y_pred = self(image)\n        val_loss = self.loss_function(y_pred, target)\n#         self.val_losses.append(val_loss.item())\n        self.log(\"val_loss\", val_loss, on_step=True, on_epoch=True, logger=True, prog_bar=True)\n        \n        # Calculate validation accuracy\n        y_pred_class = (y_pred > 0.5).float()\n        val_acc = (y_pred_class == target).float().mean()\n        self.val_acc_history.append(val_acc.item())\n        self.log(\"val_acc\", val_acc, on_step=True, on_epoch=True, logger=True, prog_bar=True)\n\n        return {\"val_loss\": val_loss, \"logits\": y_pred, \"targets\": target}\n    \n    def train_dataloader(self):\n        return self._train_dataloader \n    \n    def validation_dataloader(self):\n        return self._validation_dataloader\n    \n  #     def plot_species_accuracy(self, true, pred):\n#         species_acc = {}\n#         for i, species in enumerate(birds):\n#             species_acc[species] = (true[:, i] == pred[:, i]).mean()\n\n#         plt.figure(figsize=(12, 8))\n#         plt.bar(list(species_acc.keys()), list(species_acc.values()))\n#         plt.xticks(rotation=90)\n#         plt.xlabel('Species')\n#         plt.ylabel('Accuracy')\n#         plt.title('Accuracy per Species')\n#         plt.savefig('species_accuracy.png')\n#         plt.close()\n    \n        \n    def validation_epoch_end(self,outputs):\n        avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()\n        output_val = torch.cat([x['logits'] for x in outputs],dim=0).sigmoid().cpu().detach().numpy()\n        target_val = torch.cat([x['targets'] for x in outputs],dim=0).cpu().detach().numpy()\n        \n        # print(output_val.shape)\n        val_df = pd.DataFrame(target_val, columns = birds)\n        pred_df = pd.DataFrame(output_val, columns = birds)\n        \n        avg_score = padded_cmap(val_df, pred_df, padding_factor = 5)\n        avg_score2 = padded_cmap(val_df, pred_df, padding_factor = 3)\n        avg_score3 = sklearn.metrics.label_ranking_average_precision_score(target_val,output_val)\n            \n#         competition_metrics(output_val,target_val)\n        print(f'epoch {self.current_epoch} validation loss {avg_loss}')\n        print(f'epoch {self.current_epoch} validation C-MAP score pad 5 {avg_score}')\n        print(f'epoch {self.current_epoch} validation C-MAP score pad 3 {avg_score2}')\n        print(f'epoch {self.current_epoch} validation AP score {avg_score3}')\n        \n        \n        val_df.to_pickle('val_df.pkl')\n        pred_df.to_pickle('pred_df.pkl')\n        \n#         self.plot_species_accuracy(target_val, output_val)\n#         self. plot_species_cmap(target_val, output_val)\n#         self.plot_high_species_cmap(target_val, output_val)\n    \n        return {'val_loss': avg_loss,'val_cmap':avg_score}\n    \n    def on_train_end(self):\n#         self.plot_train_loss()\n#         self.plot_val_loss()\n        self.plot_train_val_accuracy()\n#         self.plot_loss_curves()\n\n    def plot_train_loss(self):\n        plt.figure(figsize=(10, 6))\n        plt.plot(self.train_losses[:20], label='Training Loss')\n        plt.xlabel('Epoch')\n        plt.ylabel('Loss')\n        plt.title('Training Loss')\n        plt.legend()\n        plt.savefig('train_loss_plot.png')\n        plt.close()\n\n    def plot_val_loss(self):\n        plt.figure(figsize=(10, 6))\n        plt.plot(self.val_losses[:20], label='Validation Loss')\n        plt.xlabel('Epoch')\n        plt.ylabel('Loss')\n        plt.title('Validation Loss')\n        plt.legend()\n        plt.savefig('val_loss_plot.png')\n        plt.close()\n        \n        \n    def plot_train_val_accuracy(self):\n        plt.figure(figsize=(10, 6))\n        plt.plot(self.train_acc_history[:20], label='Training Accuracy')\n        plt.plot(self.val_acc_history[:20], label='Validation Accuracy')\n        plt.xticks([0, 5, 10, 15, 20])\n        plt.xlabel('Epoch')\n        plt.ylabel('Accuracy')\n        plt.title('Training and Validation Accuracy')\n        plt.ylim(0, 1) \n        plt.legend()\n        plt.savefig('accuracy_plot.png')\n        plt.close()\n    \n\n    def plot_loss_curves(self):\n        plt.figure(figsize=(10, 6))\n        plt.plot(self.train_losses, label='Training Loss')\n        plt.plot(self.val_losses, label='Validation Loss')\n        plt.xlabel('Epoch')\n        plt.ylabel('Loss')\n        plt.title('Training and Validation Losses')\n        plt.legend()\n        plt.savefig('loss_plot.png')\n        plt.close() \n        \n    def plot_high_species_cmap(self, true, pred):\n        species_cmap = {}\n        val_df = pd.DataFrame(true, columns=birds)\n        pred_df = pd.DataFrame(pred, columns=birds)\n\n        for species in birds:\n            cmap_score = padded_cmap(val_df[[species]], pred_df[[species]], padding_factor=5)\n            if cmap_score > 0.8:\n                species_cmap[species] = cmap_score\n\n        if species_cmap:\n            plt.figure(figsize=(12, 8))\n            plt.bar(list(species_cmap.keys()), list(species_cmap.values()))\n            plt.xticks(rotation=90)\n            plt.xlabel('Species')\n            plt.ylabel('cMAP')\n            plt.title('cMAP per Species (cMAP > 0.8)')\n            plt.savefig('species_cmap_gt_0.8.png')\n            plt.close()\n    \n    def plot_species_cmap(self, true, pred):\n        species_cmap = {}\n        val_df = pd.DataFrame(true, columns=birds)\n        pred_df = pd.DataFrame(pred, columns=birds)\n\n        for species in birds:\n            species_cmap[species] = padded_cmap(val_df[[species]], pred_df[[species]], padding_factor=5)\n\n        plt.figure(figsize=(12, 8))\n        plt.bar(list(species_cmap.keys()), list(species_cmap.values()))\n        plt.xticks(rotation=90)\n        plt.xlabel('Species')\n        plt.ylabel('cMAP')\n        plt.title('cMAP per Species')\n        plt.savefig('species_cmap.png')\n        plt.close()","metadata":{"papermill":{"duration":0.156714,"end_time":"2022-04-22T06:01:22.301564","exception":false,"start_time":"2022-04-22T06:01:22.14485","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:53:22.289891Z","iopub.execute_input":"2025-08-23T10:53:22.290258Z","iopub.status.idle":"2025-08-23T10:53:22.323351Z","shell.execute_reply.started":"2025-08-23T10:53:22.290226Z","shell.execute_reply":"2025-08-23T10:53:22.322419Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pytorch_lightning.loggers import WandbLogger\nimport gc\n\ndef run_training():\n    print(f\"Running training...\")\n    logger = None\n    \n    \n    dl_train, dl_val, ds_train, ds_val = get_fold_dls(df_train, df_valid)\n    \n    audio_model = BirdClefModel()\n\n    early_stop_callback = EarlyStopping(monitor=\"val_loss\", min_delta=0.00, patience=Config.PATIENCE, verbose= True, mode=\"min\")\n    checkpoint_callback = ModelCheckpoint(monitor='val_loss',\n                                          dirpath= \"/kaggle/working/exp1/\",\n                                      save_top_k=1,\n                                      save_last= True,\n                                      save_weights_only=True,\n                                      filename= f'./{Config.model}_loss',\n                                      verbose= True,\n                                      mode='min')\n    \n    callbacks_to_use = [checkpoint_callback,early_stop_callback]\n\n\n    trainer = pl.Trainer(\n        gpus=1,\n        val_check_interval=0.5,\n        deterministic=True,\n        max_epochs=Config.epochs,\n        logger=logger,\n        auto_lr_find=False,    \n        callbacks=callbacks_to_use,\n        precision=Config.PRECISION, accelerator=\"gpu\" \n    )\n\n    print(\"Running trainer.fit\")\n    trainer.fit(audio_model, train_dataloaders = dl_train, val_dataloaders = dl_val)                \n\n    gc.collect()\n    torch.cuda.empty_cache()\n","metadata":{"papermill":{"duration":0.052364,"end_time":"2022-04-22T06:01:22.708806","exception":false,"start_time":"2022-04-22T06:01:22.656442","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2025-08-23T10:53:27.990281Z","iopub.execute_input":"2025-08-23T10:53:27.991097Z","iopub.status.idle":"2025-08-23T10:53:27.999190Z","shell.execute_reply.started":"2025-08-23T10:53:27.991060Z","shell.execute_reply":"2025-08-23T10:53:27.997839Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"run_training()","metadata":{"execution":{"iopub.status.busy":"2025-08-23T10:53:31.588022Z","iopub.execute_input":"2025-08-23T10:53:31.588432Z","iopub.status.idle":"2025-08-23T11:45:08.126419Z","shell.execute_reply.started":"2025-08-23T10:53:31.588396Z","shell.execute_reply":"2025-08-23T11:45:08.125533Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred = pd.read_pickle('/kaggle/working/pred_df.pkl')\ntrue = pd.read_pickle('/kaggle/working/val_df.pkl')","metadata":{"execution":{"iopub.status.busy":"2025-08-23T11:45:08.128340Z","iopub.execute_input":"2025-08-23T11:45:08.128648Z","iopub.status.idle":"2025-08-23T11:45:08.142460Z","shell.execute_reply.started":"2025-08-23T11:45:08.128620Z","shell.execute_reply":"2025-08-23T11:45:08.141429Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"true.sum(axis=1)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T11:45:08.143773Z","iopub.execute_input":"2025-08-23T11:45:08.144149Z","iopub.status.idle":"2025-08-23T11:45:08.157563Z","shell.execute_reply.started":"2025-08-23T11:45:08.144087Z","shell.execute_reply":"2025-08-23T11:45:08.156534Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred.sum(axis=1)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T11:45:08.159420Z","iopub.execute_input":"2025-08-23T11:45:08.159760Z","iopub.status.idle":"2025-08-23T11:45:08.182504Z","shell.execute_reply.started":"2025-08-23T11:45:08.159733Z","shell.execute_reply":"2025-08-23T11:45:08.181548Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"padded_cmap(true, pred, padding_factor = 5)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T11:45:08.183680Z","iopub.execute_input":"2025-08-23T11:45:08.184030Z","iopub.status.idle":"2025-08-23T11:45:09.282469Z","shell.execute_reply.started":"2025-08-23T11:45:08.183991Z","shell.execute_reply":"2025-08-23T11:45:09.281190Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import plotly.graph_objects as go\nfrom sklearn.metrics import confusion_matrix\n\ndef plot_confusion_matrix(true, pred, labels):\n    # Check the shapes of true and pred\n    print(f\"true shape: {true.shape}\")\n    print(f\"pred shape: {pred.shape}\")\n    print(f\"labels length: {len(labels)}\")\n\n    # Convert true and pred to the same format\n    if true.shape[1] == len(labels):\n        true_labels = true.idxmax(axis=1)\n    else:\n        true_labels = np.argmax(true.values, axis=1)\n\n    if pred.shape[1] == len(labels):\n        pred_labels = pred.idxmax(axis=1)\n    else:\n        pred_labels = np.argmax(pred.values, axis=1)\n\n    # Compute the confusion matrix\n    cm = confusion_matrix(true_labels, pred_labels)\n    \n    cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\n\n    # Plot the confusion matrix\n    fig = go.Figure(data=go.Heatmap(\n        z=cm_normalized,\n        x=labels,\n        y=labels,\n        colorscale='RdBu'\n    ))\n\n    fig.update_layout(\n        title='Confusion Matrix',\n        xaxis_title='Predicted Label',\n        yaxis_title='True Label',\n        width=800,\n        height=800\n    )\n\n    fig.show()\n\n\nplot_confusion_matrix(true, pred, birds)","metadata":{"execution":{"iopub.status.busy":"2025-08-23T11:45:09.283989Z","iopub.execute_input":"2025-08-23T11:45:09.284379Z","iopub.status.idle":"2025-08-23T11:45:09.936361Z","shell.execute_reply.started":"2025-08-23T11:45:09.284333Z","shell.execute_reply":"2025-08-23T11:45:09.935331Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Convert Lightning .ckpt to plain PyTorch .pt ---\nimport os\nfrom pathlib import Path\nimport torch\n\n# 1) Choose checkpoint path\nckpt_dir = Path(\"/kaggle/working/exp1\")\nbest_ckpt = ckpt_dir / \"tf_efficientnet_b1_ns_loss.ckpt\"\nlast_ckpt = ckpt_dir / \"last.ckpt\"\nckpt_path = best_ckpt if best_ckpt.exists() else last_ckpt\nprint(\"Using checkpoint:\", ckpt_path)\n\n# 2) Recreate your LightningModule class exactly as in training (already defined above)\n#    BirdClefModel uses timm EfficientNet with in_chans=1 and replaces .classifier.\n#    Config.model should be \"tf_efficientnet_b1_ns\" (or whatever you trained with).\nlit_model = BirdClefModel(model_name=Config.model,\n                          num_classes=Config.num_classes,\n                          pretrained=False)\n\n# 3) Load weights from Lightning checkpoint\nckpt = torch.load(ckpt_path, map_location=\"cpu\")\nlit_model.load_state_dict(ckpt[\"state_dict\"], strict=True)\n\n# 4) Save only the *backbone* (plain nn.Module) as .pt for deployment\npt_out = \"/kaggle/working/birdclef_model.pt\"\ntorch.save(lit_model.backbone.state_dict(), pt_out)\nprint(\"Saved:\", pt_out)\n\n# 5) (Optional) also ensure labels.json is next to it for API\n# If you already created labels.json earlier, just copy it:\nsrc_labels = Path(\"/kaggle/working/labels.json\")\nif src_labels.exists():\n    print(\"labels.json already present:\", src_labels)\nelse:\n    # Create from your training dataframe if needed:\n    import pandas as pd, json\n    df = pd.read_csv(\"/kaggle/working/train.csv\")  # adjust if you stored metadata elsewhere\n    labels = sorted(df[\"primary_label\"].unique())\n    id2label = {i: lab for i, lab in enumerate(labels)}\n    with open(\"/kaggle/working/labels.json\", \"w\") as f:\n        json.dump(id2label, f)\n    print(\"Wrote labels.json at /kaggle/working/labels.json\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-23T12:42:22.033683Z","iopub.execute_input":"2025-08-23T12:42:22.034474Z","iopub.status.idle":"2025-08-23T12:42:22.370709Z","shell.execute_reply.started":"2025-08-23T12:42:22.034432Z","shell.execute_reply":"2025-08-23T12:42:22.369567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}