{"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-22T04:36:05.51928Z","iopub.execute_input":"2022-05-22T04:36:05.519883Z","iopub.status.idle":"2022-05-22T04:36:06.238813Z","shell.execute_reply.started":"2022-05-22T04:36:05.519783Z","shell.execute_reply":"2022-05-22T04:36:06.237971Z"},"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\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-22T04:36:06.241084Z","iopub.execute_input":"2022-05-22T04:36:06.241653Z","iopub.status.idle":"2022-05-22T04:36:07.413758Z","shell.execute_reply.started":"2022-05-22T04:36:06.241601Z","shell.execute_reply":"2022-05-22T04:36:07.413056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\nimport json\n\nwith open(os.path.join(PATH_DATASET, \"scored_birds.json\")) as fp:\n    scored_birds = json.load(fp)\nprint(scored_birds)\n    \ntest_sounds = glob.glob(os.path.join(PATH_DATASET, \"test_soundscapes\", \"soundscape_*.ogg\"))\nWITH_SUBMISSION = len(test_sounds) > 1\nprint(f\"WITH_SUBMISSION: {WITH_SUBMISSION}\")","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:36:07.415149Z","iopub.execute_input":"2022-05-22T04:36:07.415649Z","iopub.status.idle":"2022-05-22T04:36:07.429528Z","shell.execute_reply.started":"2022-05-22T04:36:07.415609Z","shell.execute_reply":"2022-05-22T04:36:07.428688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# print(len(train_meta))\n# train_meta = train_meta[train_meta[\"primary_label\"].isin(scored_birds)]\n# print(len(train_meta))\n# train_meta[\"secondary_labels\"] = [[lb for lb in lbs if lb in scored_birds] for lbs in train_meta[\"secondary_labels\"]]","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:36:07.431417Z","iopub.execute_input":"2022-05-22T04:36:07.432227Z","iopub.status.idle":"2022-05-22T04:36:07.435515Z","shell.execute_reply.started":"2022-05-22T04:36:07.432171Z","shell.execute_reply":"2022-05-22T04:36:07.434755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax = train_meta[\"primary_label\"].value_counts().plot.bar(figsize=(12, 3), grid=True) \nax.set_yscale('log')","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:36:07.436629Z","iopub.execute_input":"2022-05-22T04:36:07.437299Z","iopub.status.idle":"2022-05-22T04:36:10.366241Z","shell.execute_reply.started":"2022-05-22T04:36:07.437265Z","shell.execute_reply":"2022-05-22T04:36:10.365488Z"},"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-22T04:36:10.367398Z","iopub.execute_input":"2022-05-22T04:36:10.368343Z","iopub.status.idle":"2022-05-22T04:36:10.981498Z","shell.execute_reply.started":"2022-05-22T04:36:10.368301Z","shell.execute_reply":"2022-05-22T04:36:10.97938Z"},"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-22T04:36:10.983144Z","iopub.execute_input":"2022-05-22T04:36:10.983657Z","iopub.status.idle":"2022-05-22T04:36:15.432534Z","shell.execute_reply.started":"2022-05-22T04:36:10.983618Z","shell.execute_reply":"2022-05-22T04:36:15.431158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data prerocessing 💽\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    # TODO: use 0.5 for background bird\n    row = {**dict(row), **{row[\"primary_label\"]: 1}, **{lb: 0.2 for lb in row[\"secondary_labels\"]}}\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).fillna(0)\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-22T04:36:15.435902Z","iopub.execute_input":"2022-05-22T04:36:15.436489Z","iopub.status.idle":"2022-05-22T04:37:16.947832Z","shell.execute_reply.started":"2022-05-22T04:36:15.436419Z","shell.execute_reply":"2022-05-22T04:37:16.946961Z"},"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.05\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-22T04:37:16.949217Z","iopub.execute_input":"2022-05-22T04:37:16.949563Z","iopub.status.idle":"2022-05-22T04:37:17.158622Z","shell.execute_reply.started":"2022-05-22T04:37:16.949526Z","shell.execute_reply":"2022-05-22T04:37:17.157871Z"},"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-22T04:37:17.161918Z","iopub.execute_input":"2022-05-22T04:37:17.162434Z","iopub.status.idle":"2022-05-22T04:37:17.223361Z","shell.execute_reply.started":"2022-05-22T04:37:17.162394Z","shell.execute_reply":"2022-05-22T04:37:17.222668Z"},"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-22T04:37:17.224925Z","iopub.execute_input":"2022-05-22T04:37:17.227552Z","iopub.status.idle":"2022-05-22T04:37:17.34213Z","shell.execute_reply.started":"2022-05-22T04:37:17.227515Z","shell.execute_reply":"2022-05-22T04:37:17.341379Z"},"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","metadata":{}},{"cell_type":"code","source":"# !pip download -q 'lightning-flash[audio]' noisereduce --dest frozen_packages --prefer-binary\n# !pip download -q effdet \"icevision[all]\" 'lightning-flash[image]' --dest frozen_packages --prefer-binary\n# !pip wheel -q \"https://github.com/PyTorchLightning/lightning-flash/archive/refs/heads/feature/soft_targets.zip\" --wheel-dir frozen_packages\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-22T04:37:17.343628Z","iopub.execute_input":"2022-05-22T04:37:17.344104Z","iopub.status.idle":"2022-05-22T04:37:17.348248Z","shell.execute_reply.started":"2022-05-22T04:37:17.344063Z","shell.execute_reply":"2022-05-22T04:37:17.347426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip --version\n!mkdir frozen_packages\n!cp /kaggle/input/birdclef-eda-baseline-flash-efficientnet/frozen_packages/* frozen_packages/\n!cp /kaggle/input/birdclef-convert-spectrograms-noise-reduce/frozen_packages/* frozen_packages/\n!pip install -q 'lightning-flash[audio]' \"datasets<2.2.0\" --find-links frozen_packages/ --no-index\n!pip install -q \"frozen_packages/lightning_flash-0.8.0.dev0-py3-none-any.whl[image]\" --find-links frozen_packages/ --no-index\n!pip install -q timm -U --find-links frozen_packages/ --no-index\n# !pip install -q -U \"https://github.com/PyTorchLightning/lightning-flash/archive/refs/heads/feature/soft_targets.zip\"\n!pip uninstall -y wandb","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-05-22T04:37:17.34925Z","iopub.execute_input":"2022-05-22T04:37:17.349577Z","iopub.status.idle":"2022-05-22T04:38:04.277668Z","shell.execute_reply.started":"2022-05-22T04:37:17.349542Z","shell.execute_reply":"2022-05-22T04:38:04.276851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\n\nimport flash\nimport timm\nfrom flash.audio import AudioClassificationData\nfrom flash.image import ImageClassifier\n\nprint(timm.__version__)\nprint(flash.__version__)","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-05-22T04:38:04.279097Z","iopub.execute_input":"2022-05-22T04:38:04.279323Z","iopub.status.idle":"2022-05-22T04:38:15.575141Z","shell.execute_reply.started":"2022-05-22T04:38:04.279296Z","shell.execute_reply":"2022-05-22T04:38:15.574355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1. Create the DataModule 🗄️","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\nclass AddGaussianNoise(object):\n    def __init__(self, mean=0., std=1.):\n        self.std = std\n        self.mean = mean\n        \n    def __call__(self, img):\n        noise = torch.randn(img.size()[1:]) * self.std + self.mean\n        return torch.clip(img + noise.repeat(img.size()[0], 1, 1), 0., 1.)\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=3, sigma=(0.5, 10)),\n            T.Resize(self.spectrogram_size),\n            T.RandomAffine(degrees=0, translate=(0.02, 0.1)),\n            AddGaussianNoise(mean=0, std=0.10),\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-22T04:38:15.576881Z","iopub.execute_input":"2022-05-22T04:38:15.57715Z","iopub.status.idle":"2022-05-22T04:38:15.593827Z","shell.execute_reply.started":"2022-05-22T04:38:15.577112Z","shell.execute_reply":"2022-05-22T04:38:15.592318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SPECTROGRAM_SIZE = (384, 384)\nbirds = list(train_meta[\"primary_label\"].unique())\n# print(birds)\n\ndatamodule = AudioClassificationData.from_data_frame(\n    \"img_name\",\n    birds,\n    train_data_frame=df_train,\n    train_images_root=os.path.join(PATH_CONVERTED, \"train_images\"),\n    val_data_frame=df_valid,\n    val_images_root=os.path.join(PATH_CONVERTED, \"train_images\"),\n    transform=AudioClassificationInputTransform,\n    transform_kwargs=dict(spectrogram_size=SPECTROGRAM_SIZE),\n    batch_size=14,\n    num_workers=3,\n    #val_split=0.1,\n)\n\nprint(datamodule.num_classes)\nprint(datamodule.labels)\nprint(datamodule.multi_label)","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-05-22T04:38:15.594797Z","iopub.execute_input":"2022-05-22T04:38:15.59501Z","iopub.status.idle":"2022-05-22T04:40:16.896638Z","shell.execute_reply.started":"2022-05-22T04:38:15.594986Z","shell.execute_reply":"2022-05-22T04:40:16.895878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\n# 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=-3., vmax=3.)\n        axarr[i % 3, i // 3].set_title(lb)\n    break","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:40:16.898011Z","iopub.execute_input":"2022-05-22T04:40:16.898844Z","iopub.status.idle":"2022-05-22T04:40:25.966704Z","shell.execute_reply.started":"2022-05-22T04:40:16.898805Z","shell.execute_reply":"2022-05-22T04:40:25.963676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Build the model ⚙️","metadata":{}},{"cell_type":"code","source":"from torchmetrics import F1\n\nclass SoftF1(F1):\n    \n    def update(self, preds, target) -> None:\n        target = target >= self.threshold\n        super().update(preds, target)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:40:25.968161Z","iopub.execute_input":"2022-05-22T04:40:25.96903Z","iopub.status.idle":"2022-05-22T04:40:25.974671Z","shell.execute_reply.started":"2022-05-22T04:40:25.968975Z","shell.execute_reply":"2022-05-22T04:40:25.973592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://timm.fast.ai/asymmetric_loss\nfrom timm.loss import AsymmetricLossMultiLabel, SoftTargetCrossEntropy\n\nmodel = ImageClassifier(\n    backbone=\"cait_xxs36_384\",\n    labels=datamodule.labels,\n    multi_label=datamodule.multi_label,\n    metrics=SoftF1(num_classes=datamodule.num_classes, average=\"macro\"),\n    pretrained=False,\n    loss_fn=AsymmetricLossMultiLabel(),\n    optimizer=\"AdamW\",\n    learning_rate=0.005,\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:40:25.976414Z","iopub.execute_input":"2022-05-22T04:40:25.97744Z","iopub.status.idle":"2022-05-22T04:40:26.358858Z","shell.execute_reply.started":"2022-05-22T04:40:25.977322Z","shell.execute_reply":"2022-05-22T04:40:26.358057Z"},"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\n# from pytorch_lightning.callbacks import StochasticWeightAveraging\n# swa = StochasticWeightAveraging(swa_epoch_start=0.6)\n\n# Trainer Args\nGPUS = int(torch.cuda.is_available())  # Set to 1 if GPU is enabled for notebook\ntrainer = flash.Trainer(\n    max_epochs=10 if WITH_SUBMISSION else 3,\n    # gradient_clip_val=0.01,\n    gpus=GPUS,\n    precision=16 if GPUS else 32,\n    logger=CSVLogger(save_dir='logs/'),\n    accumulate_grad_batches=24,\n    val_check_interval=0.5,\n    limit_train_batches=1.0 if WITH_SUBMISSION else 0.1,\n    limit_val_batches=1.0 if WITH_SUBMISSION else 0.2,\n)","metadata":{"execution":{"iopub.status.busy":"2022-05-22T04:40:26.360326Z","iopub.execute_input":"2022-05-22T04:40:26.360619Z","iopub.status.idle":"2022-05-22T04:40:26.37137Z","shell.execute_reply.started":"2022-05-22T04:40:26.360584Z","shell.execute_reply":"2022-05-22T04:40:26.370633Z"},"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-22T04:40:26.372831Z","iopub.execute_input":"2022-05-22T04:40:26.373197Z"},"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":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# inference... 🔥","metadata":{}},{"cell_type":"code","source":"!pip install -q noisereduce --find-links /kaggle/input/birdclef-eda-baseline-flash-efficientnet/frozen_packages/ --no-index","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob\nimport torch\nimport librosa\nimport noisereduce\nimport numpy as np\nfrom math import ceil\n\nSPECTROGRAM_PARAMS = dict(\n    sample_rate=32_000,\n    hop_length=640,\n    n_fft=800,\n    n_mels=128,\n    fmin=20,\n    fmax=16_000,\n    win_length=512\n)\n\ndef create_spectrogram(\n    fname, reduce_noise: bool = False, frame_size: int = 5, spec_params: dict = SPECTROGRAM_PARAMS,\n) -> list:\n    waveform, sample_rate = librosa.core.load(fname, sr=spec_params[\"sample_rate\"], mono=True)\n    if reduce_noise:\n        waveform = noisereduce.reduce_noise(\n            y=waveform,\n            sr=sample_rate,\n            time_constant_s=float(frame_size),\n            time_mask_smooth_ms=250,\n            n_fft=spec_params[\"n_fft\"],\n            use_tqdm=False,\n            n_jobs=2,\n        )\n    nb = int(frame_size * sample_rate)\n    count = ceil(len(waveform) / float(nb))\n    spectrograms = []\n    for i in range(count):\n        frame = waveform[i * nb:(i + 1) * nb]\n        if len(frame) < nb:\n            if i == 0:\n                rep = round(float(nb) / len(frame))\n                frame = frame.repeat(int(rep))\n            else:\n                frame = waveform[-nb:]\n        sg = librosa.feature.melspectrogram(\n            y=frame,\n            sr=sample_rate,\n            n_fft=spec_params[\"n_fft\"],\n            win_length=spec_params[\"win_length\"],\n            hop_length=spec_params[\"hop_length\"],\n            n_mels=spec_params[\"n_mels\"],\n            fmin=spec_params[\"fmin\"],\n            fmax=spec_params[\"fmax\"],\n            power=1,\n        )\n        sg = librosa.amplitude_to_db(sg, ref=np.max)\n        spectrograms.append(np.nan_to_num(sg))\n    return spectrograms","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path_audio = glob.glob(os.path.join(PATH_DATASET, \"test_soundscapes\", \"soundscape_*.ogg\"))[0]\nprint(path_audio)\nsgs = create_spectrogram(path_audio, reduce_noise=False)[:5]\n\nfig, axarr = plt.subplots(nrows=len(sgs), figsize=(8, 2 * len(sgs)))\nfor i, sg in enumerate(sgs):\n    print(np.min(sg), np.max(sg))\n    im = axarr[i].imshow(sg, vmin=-80, vmax=0)\n    plt.colorbar(im, ax=axarr[i])\nfig.tight_layout()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm.auto import tqdm\nfrom functools import partial\nfrom joblib import Parallel, delayed\nfrom PIL import Image\n\nimg_extension = \".png\"\n\ndef convert_and_export(\n    fn, path_in, path_out, reduce_noise = False, frame_size: int = 5\n) -> list:\n    path_audio = os.path.join(path_in, fn)\n    sgs = create_spectrogram(path_audio, reduce_noise=reduce_noise, frame_size=frame_size)\n    records = []\n    for i, sg in enumerate(sgs):\n        path_img = os.path.join(path_out, fn + f\".{i:03}\" + img_extension)\n        os.makedirs(os.path.dirname(path_img), exist_ok=True)\n        sg = (sg + 80) / 80.0\n        sg = np.clip(sg, a_min=0, a_max=1) * 255\n        img = Image.fromarray(sg.astype(np.uint8))\n        img.resize((256,256)).save(path_img)\n        records.append({\"img_name\": os.path.basename(path_img), \"end_time\": (i + 1) * frame_size, \"file_id\": os.path.splitext(fn)[0]})\n    return records","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"PATH_TEST_IMAGES = os.path.join(\"/kaggle/temp\", \"test_images\")\n\n_convert_and_export = partial(\n    convert_and_export,\n    path_in=os.path.join(PATH_DATASET, \"test_soundscapes\"),\n    path_out=PATH_TEST_IMAGES,\n)\n\nsoundscapes = glob.glob(os.path.join(PATH_DATASET, \"test_soundscapes\", \"*.ogg\"))\nsoundscapes = list(map(os.path.basename, soundscapes))\nconverted = []\nfor batch in Parallel(n_jobs=3)(delayed(_convert_and_export)(fn) for fn in tqdm(soundscapes)):\n    converted += batch\n# _= list(map(_convert_and_export, tqdm(train_meta[\"filename\"])))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_converted = pd.DataFrame(converted)\ndisplay(df_converted.head())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Run predictions >>","metadata":{}},{"cell_type":"code","source":"model = ImageClassifier.load_from_checkpoint(\n    \"audio_classification_model.pt\"\n#     \"/kaggle/input/birdclef-submissions/birdclef_classification_model_384px.pt\"\n)\nprint(model.labels)\ntrainer = flash.Trainer(gpus=GPUS)","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datamodule = AudioClassificationData.from_data_frame(\n    input_field=\"img_name\",\n    predict_data_frame=df_converted,\n    predict_images_root=PATH_TEST_IMAGES,\n    transform=AudioClassificationInputTransform,\n    transform_kwargs=dict(spectrogram_size=SPECTROGRAM_SIZE),\n    batch_size=10,\n    num_workers=3,\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = []\nfor probs in trainer.predict(model, datamodule=datamodule):\n    # lbs = [torch.argmax(p[\"preds\"].float()).item() for p in preds]\n    predictions += [p[\"preds\"].cpu().numpy() for p in probs]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## >> Format submission\n\nUntill this is resolved https://www.kaggle.com/c/birdclef-2022/discussion/309001","metadata":{}},{"cell_type":"code","source":"submission = []\nfor i, row in tqdm(df_converted.iterrows(), total=len(df_converted)):\n    assert len(model.labels) == len(predictions[i])\n    preds = dict(zip(model.labels, predictions[i]))\n    for bird in scored_birds:\n        submission.append({\n            \"row_id\": f\"{row['file_id']}_{bird}_{row['end_time']}\",\n            \"target\": preds.get(bird, 0) > 0.1,\n        })","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_submission = pd.DataFrame(submission).set_index(\"row_id\")\ndf_submission.to_csv(\"submission.csv\")\n\n! head submission.csv","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}