{"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":"markdown","source":"# Data exploration 🦜","metadata":{}},{"cell_type":"code","source":"!ls -l /kaggle/input/birdclef-2022\n\nPATH_DATASET = \"/kaggle/input/birdclef-2022\"\nPATH_CONVERTED = \"/kaggle/input/birdclef-convert-spectrograms-noise-reduce\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-11T17:28:19.880595Z","iopub.execute_input":"2022-05-11T17:28:19.881354Z","iopub.status.idle":"2022-05-11T17:28:20.582628Z","shell.execute_reply.started":"2022-05-11T17:28:19.881238Z","shell.execute_reply":"2022-05-11T17:28:20.58169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualise training meta data","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport seaborn as sn\nimport matplotlib.pyplot as plt\n\nsn.set()\n\ntrain_meta = pd.read_csv(os.path.join(PATH_DATASET, \"train_metadata.csv\"))\ntrain_meta[\"secondary_labels\"] = list(map(eval, train_meta[\"secondary_labels\"]))\ntrain_meta[\"type\"] = list(map(eval, train_meta[\"type\"]))\ndisplay(train_meta.head())","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:20.584874Z","iopub.execute_input":"2022-05-11T17:28:20.585479Z","iopub.status.idle":"2022-05-11T17:28:21.821616Z","shell.execute_reply.started":"2022-05-11T17:28:20.585439Z","shell.execute_reply":"2022-05-11T17:28:21.820923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = train_meta[\"primary_label\"].value_counts().plot.bar(figsize=(24, 3), grid=True) \nax.set_yscale('log')","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:21.823835Z","iopub.execute_input":"2022-05-11T17:28:21.824241Z","iopub.status.idle":"2022-05-11T17:28:27.387023Z","shell.execute_reply.started":"2022-05-11T17:28:21.824205Z","shell.execute_reply":"2022-05-11T17:28:27.386352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from itertools import chain\n\nsecondary_lbs = list(chain(*train_meta[\"secondary_labels\"]))\n# print(secondary_lbs)\nax = pd.Series(secondary_lbs).value_counts().plot.bar(figsize=(16, 3), grid=True)\nax.set_yscale('log')","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:27.388724Z","iopub.execute_input":"2022-05-11T17:28:27.388949Z","iopub.status.idle":"2022-05-11T17:28:30.557293Z","shell.execute_reply.started":"2022-05-11T17:28:27.388918Z","shell.execute_reply":"2022-05-11T17:28:30.556616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta[\"secondary_counts\"] = [len(sd) for sd in train_meta[\"secondary_labels\"]]\nax = train_meta[\"secondary_counts\"].value_counts().sort_index().plot.bar(figsize=(4, 3), grid=True)\nax.set_yscale('log')","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:30.558688Z","iopub.execute_input":"2022-05-11T17:28:30.558943Z","iopub.status.idle":"2022-05-11T17:28:31.025598Z","shell.execute_reply.started":"2022-05-11T17:28:30.558909Z","shell.execute_reply":"2022-05-11T17:28:31.024876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"types = list(chain(*train_meta[\"type\"]))\n# print(secondary_lbs)\nax = pd.Series(types).value_counts()[:100].plot.bar(figsize=(18, 3), grid=True)\nax.set_yscale('log')","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:31.026981Z","iopub.execute_input":"2022-05-11T17:28:31.027257Z","iopub.status.idle":"2022-05-11T17:28:35.283838Z","shell.execute_reply.started":"2022-05-11T17:28:31.027222Z","shell.execute_reply":"2022-05-11T17:28:35.282867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import plotly.express as px\n\nfig = px.scatter_geo(\n    train_meta,\n    lat=\"latitude\",\n    lon=\"longitude\",\n    color=\"common_name\",\n    width=1000,\n    height=500,\n    title=\"BirdCLEF 2022 Training Data\",\n)\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:35.285295Z","iopub.execute_input":"2022-05-11T17:28:35.285561Z","iopub.status.idle":"2022-05-11T17:28:39.121443Z","shell.execute_reply.started":"2022-05-11T17:28:35.285517Z","shell.execute_reply":"2022-05-11T17:28:39.119717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_meta[\"rating\"].value_counts().sort_index().plot.bar(grid=True)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:39.122935Z","iopub.execute_input":"2022-05-11T17:28:39.123482Z","iopub.status.idle":"2022-05-11T17:28:39.384584Z","shell.execute_reply.started":"2022-05-11T17:28:39.123441Z","shell.execute_reply":"2022-05-11T17:28:39.383898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import re\n\ndef norm_time(tm):\n    try:\n        dt = pd.to_datetime(tm, format='%H:%M')\n        return dt.hour + dt.minute / 60.\n    except Exception:\n        # print(ex)\n        pass\n\ntrain_meta[\"time_norm\"] = train_meta[\"time\"].apply(norm_time)\ntrain_meta[\"time_norm\"].hist(bins=50, grid=True)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:39.385951Z","iopub.execute_input":"2022-05-11T17:28:39.386224Z","iopub.status.idle":"2022-05-11T17:28:41.156726Z","shell.execute_reply.started":"2022-05-11T17:28:39.386189Z","shell.execute_reply":"2022-05-11T17:28:41.15609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## eBird Taxonomy 🦚 v2021","metadata":{}},{"cell_type":"code","source":"ebird = pd.read_csv(os.path.join(PATH_DATASET, \"eBird_Taxonomy_v2021.csv\"))\ndisplay(ebird.head())\nprint(len(ebird))","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:41.159642Z","iopub.execute_input":"2022-05-11T17:28:41.160177Z","iopub.status.idle":"2022-05-11T17:28:41.237636Z","shell.execute_reply.started":"2022-05-11T17:28:41.160148Z","shell.execute_reply":"2022-05-11T17:28:41.236947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Scored birds 🐦","metadata":{}},{"cell_type":"code","source":"import json\n\nwith open(os.path.join(PATH_DATASET, \"scored_birds.json\")) as fp:\n    scored_birds = json.load(fp)\n\nprint(scored_birds)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:41.238756Z","iopub.execute_input":"2022-05-11T17:28:41.239165Z","iopub.status.idle":"2022-05-11T17:28:41.248999Z","shell.execute_reply.started":"2022-05-11T17:28:41.239127Z","shell.execute_reply":"2022-05-11T17:28:41.247759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# primary_label = train_meta[\"primary_label\"].unique()\n# print(f\"Unique primary labels: {primary_label}\")\n# print(f\"missing scored in primary: {[lb for lb in scored_birds if lb not in primary_label]}\")","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:41.250314Z","iopub.execute_input":"2022-05-11T17:28:41.25072Z","iopub.status.idle":"2022-05-11T17:28:41.255006Z","shell.execute_reply.started":"2022-05-11T17:28:41.25061Z","shell.execute_reply":"2022-05-11T17:28:41.254256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data pre-processing 💽\n\nFor some optimization we moved the dataset conversion to a separate kernel as it is not needed to waste your GPU quota on constant task\n\nSo the image-dataset will be attached here\n\n**https://www.kaggle.com/jirkaborovec/birdclef-convert-spectrograms-noise-reduce**","metadata":{}},{"cell_type":"markdown","source":"## Prepare train 🪡 validation dataset","metadata":{}},{"cell_type":"code","source":"import glob\nfrom tqdm.auto import tqdm\nfrom pprint import pprint\n# from joblib import Parallel, delayed\n\nprint(f\"dataset size (audio): {len(train_meta)}\")\n\ntrain_records = []\nfor idx, row in tqdm(train_meta.iterrows(), total=len(train_meta)):\n    imgs = glob.glob(os.path.join(PATH_CONVERTED, \"train_images\", row[\"filename\"] + \".*\"))\n    # imgs = [p for p in imgs if _try_image(p)]\n    imgs = [os.path.sep.join(p.split(os.path.sep)[-2:]) for p in sorted(imgs)]\n    rows = [dict(row) for _ in range(len(imgs))]\n    _= [r.update({\"img_name\": img}) for r, img in zip(rows, imgs)]\n    train_records += rows\n    \ndf_train = pd.DataFrame(train_records)\ndisplay(df_train.head())\n\n# train_meta[\"img_name\"] = [f\"{fn}.jpg\" for fn in train_meta[\"filename\"]]\n# # mask = [_try_image(os.path.join(PATH_CONVERTED, \"train_images\", n)) for n in tqdm(train_meta[\"img_name\"])]\n# mask = Parallel(n_jobs=os.cpu_count())(delayed(_try_image)(os.path.join(PATH_CONVERTED, \"train_images\", n)) for n in tqdm(train_meta[\"img_name\"]))\n# train_meta = train_meta[mask]\n\nprint(f\"dataset size (image): {len(df_train)}\")","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:28:41.256616Z","iopub.execute_input":"2022-05-11T17:28:41.256944Z","iopub.status.idle":"2022-05-11T17:29:45.056436Z","shell.execute_reply.started":"2022-05-11T17:28:41.256912Z","shell.execute_reply":"2022-05-11T17:29:45.055737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Manual split for train/validation dataset to prevent leaking data if taking images for train and valid from the same audio**","metadata":{}},{"cell_type":"code","source":"import random\nval_split = 0.1\n\nval_fnames = []\nfor _, dfg in df_train.groupby(\"primary_label\"):\n    fnames = dfg[\"filename\"].unique()\n    random.shuffle(fnames)\n    val_spls = max(1, int(len(fnames) * val_split))\n    # skip val if there is only one audio\n    if len(fnames) > 1:\n        val_fnames += list(fnames[:val_spls])\n\nprint(len(val_fnames))","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:29:45.057771Z","iopub.execute_input":"2022-05-11T17:29:45.058189Z","iopub.status.idle":"2022-05-11T17:29:45.133564Z","shell.execute_reply.started":"2022-05-11T17:29:45.05815Z","shell.execute_reply":"2022-05-11T17:29:45.132874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_valid = df_train[df_train[\"filename\"].isin(val_fnames)]\ndisplay(df_valid.head(3))\nprint(len(df_valid))","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:29:45.134654Z","iopub.execute_input":"2022-05-11T17:29:45.136193Z","iopub.status.idle":"2022-05-11T17:29:45.168835Z","shell.execute_reply.started":"2022-05-11T17:29:45.136155Z","shell.execute_reply":"2022-05-11T17:29:45.168178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = df_train[~df_train[\"filename\"].isin(val_fnames)]\ndisplay(df_train.head(3))\nprint(len(df_train))","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:29:45.170111Z","iopub.execute_input":"2022-05-11T17:29:45.17036Z","iopub.status.idle":"2022-05-11T17:29:45.21533Z","shell.execute_reply.started":"2022-05-11T17:29:45.170327Z","shell.execute_reply":"2022-05-11T17:29:45.214535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Color 🦩 normalizations","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tqdm.auto import tqdm\nfrom joblib import Parallel, delayed\n\ndef _color_means(img_path):\n    img = plt.imread(img_path)\n    if np.max(img) > 1.5:\n        img = img / 255.0\n    clr_mean = np.mean(img) if img.ndim == 2 else {i: np.mean(img[..., i]) for i in range(3)}\n    clr_std = np.std(img) if img.ndim == 2 else {i: np.std(img[..., i]) for i in range(3)}\n    return clr_mean, clr_std\n\nimages = glob.glob(os.path.join(PATH_CONVERTED, \"train_images\", \"*\", \"*.png\"))\nclr_mean_std = Parallel(n_jobs=os.cpu_count())(delayed(_color_means)(fn) for fn in tqdm(images[::10]))","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:29:45.216712Z","iopub.execute_input":"2022-05-11T17:29:45.216962Z","iopub.status.idle":"2022-05-11T17:30:16.276422Z","shell.execute_reply.started":"2022-05-11T17:29:45.216929Z","shell.execute_reply":"2022-05-11T17:30:16.275629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_color_mean = pd.DataFrame([c[0] for c in clr_mean_std]).describe()\ndisplay(img_color_mean.T)\nimg_color_std = pd.DataFrame([c[1] for c in clr_mean_std]).describe()\ndisplay(img_color_std.T)\n\nimg_color_mean = list(img_color_mean.T[\"mean\"])\nimg_color_std = list(img_color_std.T[\"mean\"])\nprint(img_color_mean, img_color_std)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:30:16.277672Z","iopub.execute_input":"2022-05-11T17:30:16.277932Z","iopub.status.idle":"2022-05-11T17:30:16.322515Z","shell.execute_reply.started":"2022-05-11T17:30:16.277899Z","shell.execute_reply":"2022-05-11T17:30:16.321788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training with Lightning⚡Flash\n\n**Follow the example:** https://lightning-flash.readthedocs.io/en/stable/reference/audio_classification.html\n\nhttps://ai.googleblog.com/2019/05/efficientnet-improving-accuracy-and.html\n\n**Later you would need to adjust the image size to used model:**\n\n| **Base model** | resolution |\n|----------------|------------|\n| EfficientNetB0 | 224        |\n| EfficientNetB1 | 240        |\n| EfficientNetB2 | 260        |\n| EfficientNetB3 | 300        |\n| EfficientNetB4 | 380        |","metadata":{}},{"cell_type":"code","source":"!pip download -q 'lightning-flash[audio]' \"datasets==2.1.0\" noisereduce --dest frozen_packages --prefer-binary\n!pip download -q effdet \"icevision[all]\" 'lightning-flash[image]' --dest frozen_packages --prefer-binary\n!rm frozen_packages/torch-*\n!ls -l frozen_packages","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-11T17:30:16.323844Z","iopub.execute_input":"2022-05-11T17:30:16.324288Z","iopub.status.idle":"2022-05-11T17:37:07.531414Z","shell.execute_reply.started":"2022-05-11T17:30:16.32425Z","shell.execute_reply":"2022-05-11T17:37:07.530573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip --version\n!pip install -q 'lightning-flash[audio]' \"datasets==2.1.0\" -f frozen_packages\n!pip install -q effdet \"icevision[all]\" 'lightning-flash[image]' -f frozen_packages\n# !pip uninstall -y wandb","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-11T17:42:06.272546Z","iopub.execute_input":"2022-05-11T17:42:06.272869Z","iopub.status.idle":"2022-05-11T17:42:27.138348Z","shell.execute_reply.started":"2022-05-11T17:42:06.272839Z","shell.execute_reply":"2022-05-11T17:42:27.13743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\n\nimport flash\nfrom flash.audio import AudioClassificationData\nfrom flash.image import ImageClassifier","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:42:27.142156Z","iopub.execute_input":"2022-05-11T17:42:27.142393Z","iopub.status.idle":"2022-05-11T17:42:27.404444Z","shell.execute_reply.started":"2022-05-11T17:42:27.142366Z","shell.execute_reply":"2022-05-11T17:42:27.403697Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1. Create the DataModule 🗄️\n\nsee discussion about **[Suggested spectrogram augmentation?](https://www.kaggle.com/c/birdclef-2022/discussion/311995)**","metadata":{}},{"cell_type":"code","source":"from dataclasses import dataclass\nfrom torchvision import transforms as T\nfrom typing import Tuple, Callable, Optional\nfrom flash.core.data.io.input_transform import InputTransform\n\n@dataclass\nclass AudioClassificationInputTransform(InputTransform):\n\n    spectrogram_size: Tuple[int, int] = (128, 128)\n    color_mean: float = 0.4173\n    color_std: float = 0.15079\n\n    def train_input_per_sample_transform(self) -> Callable:\n        return T.Compose([\n            T.ToTensor(),\n            T.Lambda(lambda x: (x * 255).to(torch.uint8)),\n            T.RandomPosterize(bits=7, p=0.2),\n            T.RandomEqualize(),\n            T.Lambda(lambda x: x.to(torch.float32) / 255),\n            # T.GaussianBlur(kernel_size=5, sigma=(0.5, 4)),\n            T.Resize(self.spectrogram_size),\n            T.RandomAffine(degrees=0, translate=(0.01, 0.1)),\n            T.Normalize([self.color_mean] * 3, [self.color_std] * 3),\n        ])\n\n    def input_per_sample_transform(self) -> Callable:\n        return T.Compose([\n            T.ToTensor(),\n            T.Resize(self.spectrogram_size),\n            T.Normalize([self.color_mean] * 3, [self.color_std] * 3),\n        ])\n\n    def target_per_sample_transform(self) -> Callable:\n        return torch.as_tensor","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:42:38.46063Z","iopub.execute_input":"2022-05-11T17:42:38.460891Z","iopub.status.idle":"2022-05-11T17:42:38.472574Z","shell.execute_reply.started":"2022-05-11T17:42:38.460861Z","shell.execute_reply":"2022-05-11T17:42:38.471562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datamodule = AudioClassificationData.from_data_frame(\n    \"img_name\",\n    \"primary_label\",\n    train_data_frame=df_train,\n    train_images_root=os.path.join(PATH_CONVERTED, \"train_images\"),\n    train_transform=AudioClassificationInputTransform,\n    val_data_frame=df_valid,\n    val_images_root=os.path.join(PATH_CONVERTED, \"train_images\"),\n    val_transform=AudioClassificationInputTransform,\n    transform_kwargs=dict(spectrogram_size=(224, 224)),\n    batch_size=64,\n    num_workers=3,\n    #val_split=0.1,\n)\n\nprint(datamodule.labels)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:42:42.262233Z","iopub.execute_input":"2022-05-11T17:42:42.262652Z","iopub.status.idle":"2022-05-11T17:43:40.751473Z","shell.execute_reply.started":"2022-05-11T17:42:42.262617Z","shell.execute_reply":"2022-05-11T17:43:40.750733Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# datamodule.show_train_batch()\n\nnb_samples = 9\nfig, axarr = plt.subplots(ncols=3, nrows=3, figsize=(8, 8))\n\nfor batch in datamodule.train_dataloader():\n    print(batch.keys())\n    for i, (img, lb) in enumerate(list(zip(batch[\"input\"], batch[\"target\"]))[:nb_samples]):\n        img = np.rollaxis(img.numpy(), 0, 3)\n        print(np.min(img), np.max(img))\n        axarr[i % 3, i // 3].imshow(img, vmin=-5., vmax=5.)  #\n        axarr[i % 3, i // 3].set_title(lb)\n    break","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:43:40.753109Z","iopub.execute_input":"2022-05-11T17:43:40.75385Z","iopub.status.idle":"2022-05-11T17:43:50.417439Z","shell.execute_reply.started":"2022-05-11T17:43:40.753809Z","shell.execute_reply":"2022-05-11T17:43:50.415779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Build the model ⚙️","metadata":{}},{"cell_type":"code","source":"from torchmetrics import F1\nfrom timm.loss import LabelSmoothingCrossEntropy\n\nmodel = ImageClassifier(\n    backbone=\"tf_efficientnet_b0_ns\",\n    labels=datamodule.labels,\n    metrics=F1(num_classes=datamodule.num_classes, average=\"macro\"),\n    pretrained=True,\n    loss_fn=LabelSmoothingCrossEntropy(0.02),\n    optimizer=\"AdamW\",\n    learning_rate=0.002,\n    # lr_scheduler=(\"cosineannealinglr\", {\"T_max\": 5}),\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:43:50.418946Z","iopub.execute_input":"2022-05-11T17:43:50.419516Z","iopub.status.idle":"2022-05-11T17:43:52.879017Z","shell.execute_reply.started":"2022-05-11T17:43:50.419478Z","shell.execute_reply":"2022-05-11T17:43:52.878315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3. Finetune the model 🛠️","metadata":{}},{"cell_type":"code","source":"from pytorch_lightning.loggers import CSVLogger\n# from pytorch_lightning.callbacks import StochasticWeightAveraging\n\n# Trainer Args\nGPUS = int(torch.cuda.is_available())  # Set to 1 if GPU is enabled for notebook\n\n# swa = StochasticWeightAveraging(swa_epoch_start=0.6)\nlogger = CSVLogger(save_dir='logs/')\n\ntrainer = flash.Trainer(\n    max_epochs=5,\n    # gradient_clip_val=0.01,\n    gpus=GPUS,\n    precision=16 if GPUS else 32,\n    logger=logger,\n    accumulate_grad_batches=32,\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:44:26.511243Z","iopub.execute_input":"2022-05-11T17:44:26.511986Z","iopub.status.idle":"2022-05-11T17:44:26.523482Z","shell.execute_reply.started":"2022-05-11T17:44:26.511947Z","shell.execute_reply":"2022-05-11T17:44:26.522605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer.finetune(model, datamodule=datamodule, strategy=\"no_freeze\")\n\ntrainer.save_checkpoint(\"audio_classification_model.pt\")","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-05-11T17:44:29.333456Z","iopub.execute_input":"2022-05-11T17:44:29.334347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics = pd.read_csv(f'{trainer.logger.log_dir}/metrics.csv')\ndel metrics[\"step\"]\nmetrics.set_index(\"epoch\", inplace=True)\n# display(metrics.dropna(axis=1, how=\"all\").head())\ng = sn.relplot(data=metrics, kind=\"line\")\nplt.gcf().set_size_inches(15, 5)\nplt.grid()","metadata":{"execution":{"iopub.status.busy":"2022-05-11T17:38:31.372194Z","iopub.status.idle":"2022-05-11T17:38:31.372748Z","shell.execute_reply.started":"2022-05-11T17:38:31.372504Z","shell.execute_reply":"2022-05-11T17:38:31.372529Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# inference... 🚀\n\nsee the follow-up kernel: https://www.kaggle.com/jirkaborovec/birdclef-lightning-flash-inference\n\nor **full training & inference**: https://www.kaggle.com/code/jirkaborovec/birdclef-multi-label-flash-transformer","metadata":{}}]}