{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-16T14:30:23.506203Z","iopub.execute_input":"2022-02-16T14:30:23.507227Z","iopub.status.idle":"2022-02-16T14:30:23.529613Z","shell.execute_reply.started":"2022-02-16T14:30:23.507023Z","shell.execute_reply":"2022-02-16T14:30:23.528939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r ../input/timm-pytorch-image-models /kaggle/working/\n!pip install /kaggle/working/timm-pytorch-image-models/pytorch-image-models-master/","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:23.531306Z","iopub.execute_input":"2022-02-16T14:30:23.531555Z","iopub.status.idle":"2022-02-16T14:30:37.060045Z","shell.execute_reply.started":"2022-02-16T14:30:23.531522Z","shell.execute_reply":"2022-02-16T14:30:37.059045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import glob\nimport os\nimport random\nimport warnings\nfrom functools import partial\n\n# import colorednoise as cn\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport pytorch_lightning as pl\nimport scipy as sp\nimport soundfile as sf\nimport timm\nimport torch\nimport torch.optim as optim\nfrom pytorch_lightning import LightningDataModule, callbacks\n\n# from pytorch_lightning.utilities import rank_zero_info\nfrom sklearn import model_selection\nfrom sklearn.metrics import f1_score\nfrom torch import nn\nfrom torch.nn import functional as F\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchaudio.transforms import AmplitudeToDB, MelSpectrogram","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:37.063561Z","iopub.execute_input":"2022-02-16T14:30:37.064036Z","iopub.status.idle":"2022-02-16T14:30:42.392999Z","shell.execute_reply.started":"2022-02-16T14:30:37.064003Z","shell.execute_reply":"2022-02-16T14:30:42.392124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport audioread\nimport logging\nimport os\nimport random\nimport time\nimport warnings\n\nimport librosa\nimport numpy as np\nimport pandas as pd\nimport soundfile as sf\nimport timm\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.utils.data as torchdata\n\nfrom contextlib import contextmanager\nfrom pathlib import Path\nfrom typing import Optional\n\nfrom albumentations.core.transforms_interface import ImageOnlyTransform\n# from torchlibrosa.stft import LogmelFilterBank, Spectrogram\n# from torchlibrosa.augmentation import SpecAugmentation\nfrom tqdm import tqdm","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:42.395598Z","iopub.execute_input":"2022-02-16T14:30:42.395905Z","iopub.status.idle":"2022-02-16T14:30:43.351051Z","shell.execute_reply.started":"2022-02-16T14:30:42.395865Z","shell.execute_reply":"2022-02-16T14:30:43.350279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed: int = 42):\n    random.seed(seed)\n    np.random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)  # type: ignore\n    torch.backends.cudnn.deterministic = True  # type: ignore\n    torch.backends.cudnn.benchmark = True  # type: ignore\n    \n    \ndef get_logger(out_file=None):\n    logger = logging.getLogger()\n    formatter = logging.Formatter(\"%(asctime)s - %(levelname)s - %(message)s\")\n    logger.handlers = []\n    logger.setLevel(logging.INFO)\n\n    handler = logging.StreamHandler()\n    handler.setFormatter(formatter)\n    handler.setLevel(logging.INFO)\n    logger.addHandler(handler)\n\n    if out_file is not None:\n        fh = logging.FileHandler(out_file)\n        fh.setFormatter(formatter)\n        fh.setLevel(logging.INFO)\n        logger.addHandler(fh)\n    logger.info(\"logger set up\")\n    return logger\n    \n    \n@contextmanager\ndef timer(name: str, logger: Optional[logging.Logger] = None):\n    t0 = time.time()\n    msg = f\"[{name}] start\"\n    if logger is None:\n        print(msg)\n    else:\n        logger.info(msg)\n    yield\n\n    msg = f\"[{name}] done in {time.time() - t0:.2f} s\"\n    if logger is None:\n        print(msg)\n    else:\n        logger.info(msg)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.35225Z","iopub.execute_input":"2022-02-16T14:30:43.35414Z","iopub.status.idle":"2022-02-16T14:30:43.366728Z","shell.execute_reply.started":"2022-02-16T14:30:43.35411Z","shell.execute_reply":"2022-02-16T14:30:43.366027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"logger = get_logger(\"main.log\")\nset_seed(1213)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.367958Z","iopub.execute_input":"2022-02-16T14:30:43.368203Z","iopub.status.idle":"2022-02-16T14:30:43.379671Z","shell.execute_reply.started":"2022-02-16T14:30:43.368169Z","shell.execute_reply":"2022-02-16T14:30:43.37888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    ######################\n    # Globals #\n    ######################\n    seed = 1213\n\n    ######################\n    # Data #\n    ######################\n    train_datadir = Path(\"../input/birdclef-2021/train_short_audio\")\n    train_csv = \"../input/birdclef-2021/train_metadata.csv\"\n    train_soundscape = \"../input/birdclef-2021/train_soundscape_labels.csv\"\n\n    ######################\n    # Dataset #\n    ######################\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}],\n        \"test\": [{\"name\": \"Normalize\"}]\n    }\n    period = 30\n    n_mels = 128\n    \n    sample_rate = 32000\n    target_columns = [\n        \"afrsil1\",\n        \"akekee\",\n        \"akepa1\",\n        \"akiapo\",\n        \"akikik\",\n        \"amewig\",\n        \"aniani\",\n        \"apapan\",\n        \"arcter\",\n        \"barpet\",\n        \"bcnher\",\n        \"belkin1\",\n        \"bkbplo\",\n        \"bknsti\",\n        \"bkwpet\",\n        \"blkfra\",\n        \"blknod\",\n        \"bongul\",\n        \"brant\",\n        \"brnboo\",\n        \"brnnod\",\n        \"brnowl\",\n        \"brtcur\",\n        \"bubsan\",\n        \"buffle\",\n        \"bulpet\",\n        \"burpar\",\n        \"buwtea\",\n        \"cacgoo1\",\n        \"calqua\",\n        \"cangoo\",\n        \"canvas\",\n        \"caster1\",\n        \"categr\",\n        \"chbsan\",\n        \"chemun\",\n        \"chukar\",\n        \"cintea\",\n        \"comgal1\",\n        \"commyn\",\n        \"compea\",\n        \"comsan\",\n        \"comwax\",\n        \"coopet\",\n        \"crehon\",\n        \"dunlin\",\n        \"elepai\",\n        \"ercfra\",\n        \"eurwig\",\n        \"fragul\",\n        \"gadwal\",\n        \"gamqua\",\n        \"glwgul\",\n        \"gnwtea\",\n        \"golphe\",\n        \"grbher3\",\n        \"grefri\",\n        \"gresca\",\n        \"gryfra\",\n        \"gwfgoo\",\n        \"hawama\",\n        \"hawcoo\",\n        \"hawcre\",\n        \"hawgoo\",\n        \"hawhaw\",\n        \"hawpet1\",\n        \"hoomer\",\n        \"houfin\",\n        \"houspa\",\n        \"hudgod\",\n        \"iiwi\",\n        \"incter1\",\n        \"jabwar\",\n        \"japqua\",\n        \"kalphe\",\n        \"kauama\",\n        \"laugul\",\n        \"layalb\",\n        \"lcspet\",\n        \"leasan\",\n        \"leater1\",\n        \"lessca\",\n        \"lesyel\",\n        \"lobdow\",\n        \"lotjae\",\n        \"madpet\",\n        \"magpet1\",\n        \"mallar3\",\n        \"masboo\",\n        \"mauala\",\n        \"maupar\",\n        \"merlin\",\n        \"mitpar\",\n        \"moudov\",\n        \"norcar\",\n        \"norhar2\",\n        \"normoc\",\n        \"norpin\",\n        \"norsho\",\n        \"nutman\",\n        \"oahama\",\n        \"omao\",\n        \"osprey\",\n        \"pagplo\",\n        \"palila\",\n        \"parjae\",\n        \"pecsan\",\n        \"peflov\",\n        \"perfal\",\n        \"pibgre\",\n        \"pomjae\",\n        \"puaioh\",\n        \"reccar\",\n        \"redava\",\n        \"redjun\",\n        \"redpha1\",\n        \"refboo\",\n        \"rempar\",\n        \"rettro\",\n        \"ribgul\",\n        \"rinduc\",\n        \"rinphe\",\n        \"rocpig\",\n        \"rorpar\",\n        \"rudtur\",\n        \"ruff\",\n        \"saffin\",\n        \"sander\",\n        \"semplo\",\n        \"sheowl\",\n        \"shtsan\",\n        \"skylar\",\n        \"snogoo\",\n        \"sooshe\",\n        \"sooter1\",\n        \"sopsku1\",\n        \"sora\",\n        \"spodov\",\n        \"sposan\",\n        \"towsol\",\n        \"wantat1\",\n        \"warwhe1\",\n        \"wesmea\",\n        \"wessan\",\n        \"wetshe\",\n        \"whfibi\",\n        \"whiter\",\n        \"whttro\",\n        \"wiltur\",\n        \"yebcar\",\n        \"yefcan\",\n        \"zebdov\",\n    ]\n    bird2id = {b: i for i, b in enumerate(target_columns)}\n    id2bird = {i: b for i, b in enumerate(target_columns)}\n    scored_birds = [\"akiapo\", \"aniani\", \"apapan\", \"barpet\", \"crehon\", \"elepai\", \"ercfra\", \"hawama\", \"hawcre\", \"hawgoo\", \"hawhaw\", \"hawpet1\", \"houfin\", \"iiwi\", \"jabwar\", \"maupar\", \"omao\", \"puaioh\", \"skylar\", \"warwhe1\", \"yefcan\"]\n    loader_params = {\n        \"train\": {\n            \"batch_size\": 64,\n            \"num_workers\": 20,\n            \"shuffle\": True\n        },\n        \"valid\": {\n            \"batch_size\": 64,\n            \"num_workers\": 20,\n            \"shuffle\": False\n        },\n        \"test\": {\n            \"batch_size\": 64,\n            \"num_workers\": 20,\n            \"shuffle\": False\n        }\n    }\n    models_cfg = [{\"resnest26d\": \"../input/birdclef2022-weights/resnest26d/fold0/birdclef_2022/10p941rk/checkpoints/best_f1.ckpt\",}]\n    num_classes = len(target_columns)\nprint(f\"model_num: {len(CFG.models_cfg)}\")","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.381371Z","iopub.execute_input":"2022-02-16T14:30:43.381719Z","iopub.status.idle":"2022-02-16T14:30:43.40148Z","shell.execute_reply.started":"2022-02-16T14:30:43.381683Z","shell.execute_reply":"2022-02-16T14:30:43.400673Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGET_SR = 32000\nDATADIR = Path(\"../input/birdclef-2022/test_soundscapes/\")","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.402882Z","iopub.execute_input":"2022-02-16T14:30:43.40334Z","iopub.status.idle":"2022-02-16T14:30:43.412165Z","shell.execute_reply.started":"2022-02-16T14:30:43.403278Z","shell.execute_reply":"2022-02-16T14:30:43.411274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_audios = list(DATADIR.glob(\"*.ogg\"))\nsample_submission = pd.read_csv('../input/birdclef-2022/sample_submission.csv')\nsample_submission","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.413553Z","iopub.execute_input":"2022-02-16T14:30:43.413925Z","iopub.status.idle":"2022-02-16T14:30:43.444785Z","shell.execute_reply.started":"2022-02-16T14:30:43.413885Z","shell.execute_reply":"2022-02-16T14:30:43.444132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gem_freq(x, p=3, eps=1e-6):\n    return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), 1)).pow(1.0 / p)\n\n\nclass GeMFreq(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        super().__init__()\n        self.p = torch.nn.Parameter(torch.ones(1) * p)\n        self.eps = eps\n\n    def forward(self, x):\n        return gem_freq(x, p=self.p, eps=self.eps)\n\n\nclass NormalizeMelSpec(nn.Module):\n    def __init__(self, eps=1e-6):\n        super().__init__()\n        self.eps = eps\n\n    def forward(self, X):\n        mean = X.mean((1, 2), keepdim=True)\n        std = X.std((1, 2), keepdim=True)\n        Xstd = (X - mean) / (std + self.eps)\n        norm_min, norm_max = Xstd.min(-1)[0].min(-1)[0], Xstd.max(-1)[0].max(-1)[0]\n        fix_ind = (norm_max - norm_min) > self.eps * torch.ones_like(\n            (norm_max - norm_min)\n        )\n        V = torch.zeros_like(Xstd)\n        if fix_ind.sum():\n            V_fix = Xstd[fix_ind]\n            norm_max_fix = norm_max[fix_ind, None, None]\n            norm_min_fix = norm_min[fix_ind, None, None]\n            V_fix = torch.max(\n                torch.min(V_fix, norm_max_fix),\n                norm_min_fix,\n            )\n            # print(V_fix.shape, norm_min_fix.shape, norm_max_fix.shape)\n            V_fix = (V_fix - norm_min_fix) / (norm_max_fix - norm_min_fix)\n            V[fix_ind] = V_fix\n        return V\n\nclass AttHead(nn.Module):\n    def __init__(\n        self, in_chans, p=0.5, num_class=397, train_period=15.0, infer_period=5.0\n    ):\n        super().__init__()\n        self.train_period = train_period\n        self.infer_period = infer_period\n        self.pooling = GeMFreq()\n\n        self.dense_layers = nn.Sequential(\n            nn.Dropout(p / 2),\n            nn.Linear(in_chans, 512),\n            nn.ReLU(),\n            nn.Dropout(p),\n        )\n        self.attention = nn.Conv1d(\n            in_channels=512,\n            out_channels=num_class,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=True,\n        )\n        self.fix_scale = nn.Conv1d(\n            in_channels=512,\n            out_channels=num_class,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=True,\n        )\n\n    def forward(self, feat):\n        feat = self.pooling(feat).squeeze(-2).permute(0, 2, 1)  # (bs, time, ch)\n\n        feat = self.dense_layers(feat).permute(0, 2, 1)  # (bs, 512, time)\n        time_att = torch.tanh(self.attention(feat))\n        assert self.train_period >= self.infer_period\n        if self.training or self.train_period == self.infer_period:\n\n            clipwise_pred = torch.sum(\n                torch.sigmoid(self.fix_scale(feat)) * torch.softmax(time_att, dim=-1),\n                dim=-1,\n            )  # sum((bs, 24, time), -1) -> (bs, 24)\n            logits = torch.sum(\n                self.fix_scale(feat) * torch.softmax(time_att, dim=-1),\n                dim=-1,\n            )\n        else:\n            framewise_pred_long = torch.sigmoid(self.fix_scale(feat))\n            clipwise_pred_long = torch.sum(framewise_pred_long * torch.softmax(time_att, dim=-1), dim=-1) \n            \n            feat_time = feat.size(-1)\n            start = (\n                feat_time / 2 - feat_time * (self.infer_period / self.train_period) / 2\n            )\n            end = start + feat_time * (self.infer_period / self.train_period)\n            start = int(start)\n            end = int(end)\n            feat = feat[:, :, start:end]\n            att = torch.softmax(time_att[:, :, start:end], dim=-1)\n#             print(feat_time, start, end)\n#             print(att_a.sum(), att.sum(), time_att.shape)\n            framewise_pred = torch.sigmoid(self.fix_scale(feat))\n            clipwise_pred = torch.sum(framewise_pred * att, dim=-1) \n            logits = torch.sum(\n                self.fix_scale(feat) * att,\n                dim=-1,\n            )\n            time_att = time_att[:, :, start:end]\n        return (\n            logits,\n            clipwise_pred,\n            self.fix_scale(feat).permute(0, 2, 1),\n            time_att.permute(0, 2, 1),\n            clipwise_pred_long,\n        )\n\nclass AttModel(nn.Module):\n    def __init__(\n        self,\n        backbone=\"resnet34\",\n        p=0.5,\n        n_mels=224,\n        num_class=397,\n        train_period=15.0,\n        infer_period=5.0,\n        in_chans=1,\n    ):\n        super().__init__()\n        self.n_mels = n_mels\n        self.logmelspec_extractor = nn.Sequential(\n            MelSpectrogram(\n                32000,\n                n_mels=n_mels,\n                f_min=20,\n                n_fft=2048,\n                hop_length=512,\n                normalized=True,\n            ),\n            AmplitudeToDB(top_db=80.0),\n            NormalizeMelSpec(),\n        )\n\n        self.backbone = timm.create_model(\n            backbone, features_only=True, pretrained=False, in_chans=in_chans\n        )\n        encoder_channels = self.backbone.feature_info.channels()\n        dense_input = encoder_channels[-1]\n        self.head = AttHead(\n            dense_input,\n            p=p,\n            num_class=num_class,\n            train_period=train_period,\n            infer_period=infer_period,\n        )\n\n    def forward(self, input):\n#         img = self.logmelspec_extractor(input)[\n#             :, None\n#         ]  # (batch_size, 1, mel_bins, time_steps)\n        feats = self.backbone(input)\n        return self.head(feats[-1])\n    \nclass Model(nn.Module):\n    def __init__(\n        self,\n        backbone=\"resnet34\",\n        p=0.5,\n        n_mels=224,\n        num_class=CFG.num_classes,\n        train_period=CFG.period,\n        infer_period=5.0,\n        in_chans=1,\n    ):\n        super().__init__()\n        self.model = AttModel(backbone, p, n_mels, num_class, train_period, infer_period, in_chans)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.447445Z","iopub.execute_input":"2022-02-16T14:30:43.447695Z","iopub.status.idle":"2022-02-16T14:30:43.47952Z","shell.execute_reply.started":"2022-02-16T14:30:43.447663Z","shell.execute_reply":"2022-02-16T14:30:43.478661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataset(torchdata.Dataset):\n    def __init__(self, df: pd.DataFrame, clip: np.ndarray, train_period=30, \n                 waveform_transforms=None):\n        self.df = df\n        self.clip = np.concatenate([clip, clip, clip])\n        self.train_period = train_period\n        self.waveform_transforms=waveform_transforms\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx: int):\n        SR = 32000\n        sample = self.df.loc[idx, :]\n        row_id = sample.row_id\n\n        end_seconds = int(sample.seconds)\n        start_seconds = int(end_seconds - 5)\n        \n        end_index = int(SR * (end_seconds + (self.train_period - 5) / 2) + len(self.clip) // 3)\n        start_index = int(SR * (start_seconds - (self.train_period - 5) / 2) + len(self.clip) // 3)\n        \n        y = self.clip[start_index:end_index].astype(np.float32)\n\n        y = np.nan_to_num(y)\n\n        if self.waveform_transforms:\n            y = self.waveform_transforms(y)\n\n        y = np.nan_to_num(y)\n        \n        return y, row_id","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.480816Z","iopub.execute_input":"2022-02-16T14:30:43.481115Z","iopub.status.idle":"2022-02-16T14:30:43.492688Z","shell.execute_reply.started":"2022-02-16T14:30:43.481081Z","shell.execute_reply":"2022-02-16T14:30:43.492064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_transforms(phase: str):\n    transforms = CFG.transforms\n    if transforms is None:\n        return None\n    else:\n        if transforms[phase] is None:\n            return None\n        trns_list = []\n        for trns_conf in transforms[phase]:\n            trns_name = trns_conf[\"name\"]\n            trns_params = {} if trns_conf.get(\"params\") is None else \\\n                trns_conf[\"params\"]\n            if globals().get(trns_name) is not None:\n                trns_cls = globals()[trns_name]\n                trns_list.append(trns_cls(**trns_params))\n\n        if len(trns_list) > 0:\n            return Compose(trns_list)\n        else:\n            return None\n\n\ndef get_waveform_transforms(config: dict, phase: str):\n    return get_transforms(config, phase)\n\n\ndef get_spectrogram_transforms(config: dict, phase: str):\n    transforms = config.get('spectrogram_transforms')\n    if transforms is None:\n        return None\n    else:\n        if transforms[phase] is None:\n            return None\n        trns_list = []\n        for trns_conf in transforms[phase]:\n            trns_name = trns_conf[\"name\"]\n            trns_params = {} if trns_conf.get(\"params\") is None else \\\n                trns_conf[\"params\"]\n            if hasattr(A, trns_name):\n                trns_cls = A.__getattribute__(trns_name)\n                trns_list.append(trns_cls(**trns_params))\n            else:\n                trns_cls = globals().get(trns_name)\n                if trns_cls is not None:\n                    trns_list.append(trns_cls(**trns_params))\n\n        if len(trns_list) > 0:\n            return A.Compose(trns_list, p=1.0)\n        else:\n            return None\n        \nclass Normalize:\n    def __call__(self, y: np.ndarray):\n        max_vol = np.abs(y).max()\n        y_vol = y * 1 / max_vol\n        return np.asfortranarray(y_vol)\n\n\nclass NewNormalize:\n    def __call__(self, y: np.ndarray):\n        y_mm = y - y.mean()\n        return y_mm / y_mm.abs().max()\n\n\nclass Compose:\n    def __init__(self, transforms: list):\n        self.transforms = transforms\n\n    def __call__(self, y: np.ndarray):\n        for trns in self.transforms:\n            y = trns(y)\n        return y\n\n\nclass AudioTransform:\n    def __init__(self, always_apply=False, p=0.5):\n        self.always_apply = always_apply\n        self.p = p\n\n    def __call__(self, y: np.ndarray):\n        if self.always_apply:\n            return self.apply(y)\n        else:\n            if np.random.rand() < self.p:\n                return self.apply(y)\n            else:\n                return y\n\n    def apply(self, y: np.ndarray):\n        raise NotImplementedError\n        \nclass NoiseInjection(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, max_noise_level=0.5, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.noise_level = (0.0, max_noise_level)\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        noise_level = np.random.uniform(*self.noise_level)\n        noise = np.random.randn(len(y))\n        augmented = (y + noise * noise_level).astype(y.dtype)\n        return augmented\n\n\nclass GaussianNoise(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, min_snr=5, max_snr=20, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.min_snr = min_snr\n        self.max_snr = max_snr\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        snr = np.random.uniform(self.min_snr, self.max_snr)\n        a_signal = np.sqrt(y ** 2).max()\n        a_noise = a_signal / (10 ** (snr / 20))\n\n        white_noise = np.random.randn(len(y))\n        a_white = np.sqrt(white_noise ** 2).max()\n        augmented = (y + white_noise * 1 / a_white * a_noise).astype(y.dtype)\n        return augmented\n\n\nclass PinkNoise(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, min_snr=5, max_snr=20, sr=32000):\n        super().__init__(always_apply, p)\n\n        self.min_snr = min_snr\n        self.max_snr = max_snr\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        snr = np.random.uniform(self.min_snr, self.max_snr)\n        a_signal = np.sqrt(y ** 2).max()\n        a_noise = a_signal / (10 ** (snr / 20))\n\n        pink_noise = cn.powerlaw_psd_gaussian(1, len(y))\n        a_pink = np.sqrt(pink_noise ** 2).max()\n        augmented = (y + pink_noise * 1 / a_pink * a_noise).astype(y.dtype)\n        return augmented\n\n\nclass PitchShift(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, max_range=5, sr=32000):\n        super().__init__(always_apply, p)\n        self.max_range = max_range\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        n_steps = np.random.randint(-self.max_range, self.max_range)\n        augmented = librosa.effects.pitch_shift(y, self.sr, n_steps)\n        return augmented\n\nclass TimeStretch(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, max_rate=1, sr=32000):\n        super().__init__(always_apply, p)\n        self.max_rate = max_rate\n        self.sr = sr\n\n    def apply(self, y: np.ndarray, **params):\n        rate = np.random.uniform(0, self.max_rate)\n        augmented = librosa.effects.time_stretch(y, rate)\n        return augmented\n\n\ndef _db2float(db: float, amplitude=True):\n    if amplitude:\n        return 10**(db / 20)\n    else:\n        return 10 ** (db / 10)\n\n\ndef volume_down(y: np.ndarray, db: float):\n    \"\"\"\n    Low level API for decreasing the volume\n    Parameters\n    ----------\n    y: numpy.ndarray\n        stereo / monaural input audio\n    db: float\n        how much decibel to decrease\n    Returns\n    -------\n    applied: numpy.ndarray\n        audio with decreased volume\n    \"\"\"\n    applied = y * _db2float(-db)\n    return applied\n\n\ndef volume_up(y: np.ndarray, db: float):\n    \"\"\"\n    Low level API for increasing the volume\n    Parameters\n    ----------\n    y: numpy.ndarray\n        stereo / monaural input audio\n    db: float\n        how much decibel to increase\n    Returns\n    -------\n    applied: numpy.ndarray\n        audio with increased volume\n    \"\"\"\n    applied = y * _db2float(db)\n    return applied\n\nclass RandomVolume(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, limit=10):\n        super().__init__(always_apply, p)\n        self.limit = limit\n\n    def apply(self, y: np.ndarray, **params):\n        db = np.random.uniform(-self.limit, self.limit)\n        if db >= 0:\n            return volume_up(y, db)\n        else:\n            return volume_down(y, db)\n\n\nclass OneOf:\n    def __init__(self, transforms: list):\n        self.transforms = transforms\n\n    def __call__(self, y: np.ndarray):\n        n_trns = len(self.transforms)\n        trns_idx = np.random.choice(n_trns)\n        trns = self.transforms[trns_idx]\n        y = trns(y)\n        return y\n\n\nclass CosineVolume(AudioTransform):\n    def __init__(self, always_apply=False, p=0.5, limit=10):\n        super().__init__(always_apply, p)\n        self.limit = limit\n\n    def apply(self, y: np.ndarray, **params):\n        db = np.random.uniform(-self.limit, self.limit)\n        cosine = np.cos(np.arange(len(y)) / len(y) * np.pi * 2)\n        dbs = _db2float(cosine * db)\n        return y * dbs\n\n\ndef drop_stripes(image: np.ndarray, dim: int, drop_width: int, stripes_num: int):\n    total_width = image.shape[dim]\n    lowest_value = image.min()\n    for _ in range(stripes_num):\n        distance = np.random.randint(low=0, high=drop_width, size=(1,))[0]\n        begin = np.random.randint(\n            low=0, high=total_width - distance, size=(1,))[0]\n\n        if dim == 0:\n            image[begin:begin + distance] = lowest_value\n        elif dim == 1:\n            image[:, begin + distance] = lowest_value\n        elif dim == 2:\n            image[:, :, begin + distance] = lowest_value\n    return image\n\nclass TimeFreqMasking(ImageOnlyTransform):\n    def __init__(self,\n                 time_drop_width: int,\n                 time_stripes_num: int,\n                 freq_drop_width: int,\n                 freq_stripes_num: int,\n                 always_apply=False,\n                 p=0.5):\n        super().__init__(always_apply, p)\n        self.time_drop_width = time_drop_width\n        self.time_stripes_num = time_stripes_num\n        self.freq_drop_width = freq_drop_width\n        self.freq_stripes_num = freq_stripes_num\n\n    def apply(self, img, **params):\n        img_ = img.copy()\n        if img.ndim == 2:\n            img_ = drop_stripes(\n                img_, dim=0, drop_width=self.freq_drop_width, stripes_num=self.freq_stripes_num)\n            img_ = drop_stripes(\n                img_, dim=1, drop_width=self.time_drop_width, stripes_num=self.time_stripes_num)\n        return img_","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.494234Z","iopub.execute_input":"2022-02-16T14:30:43.494489Z","iopub.status.idle":"2022-02-16T14:30:43.544556Z","shell.execute_reply.started":"2022-02-16T14:30:43.494457Z","shell.execute_reply":"2022-02-16T14:30:43.543656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.nn.modules.batchnorm import _BatchNorm\n\ndef prepare_model_for_inference(model, path: Path):\n    if not torch.cuda.is_available():\n        ckpt = torch.load(path, map_location=\"cpu\")\n    else:\n        ckpt = torch.load(path)\n    model.load_state_dict(ckpt[\"state_dict\"])\n    model.eval()\n\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.546155Z","iopub.execute_input":"2022-02-16T14:30:43.546606Z","iopub.status.idle":"2022-02-16T14:30:43.552309Z","shell.execute_reply.started":"2022-02-16T14:30:43.546572Z","shell.execute_reply":"2022-02-16T14:30:43.551595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def prediction_for_clip(test_df: pd.DataFrame, \n                        clip: np.ndarray, \n                        models, \n                        threshold=0.05, \n                        threshold_long=None):\n\n    dataset = TestDataset(df=test_df, \n                          clip=clip,\n                          train_period = CFG.period, \n                          waveform_transforms=get_transforms(phase=\"test\"))\n    loader = torchdata.DataLoader(dataset, batch_size=1, shuffle=False)\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    \n#     [model.eval() for model in models]\n    prediction_dict = {}\n    for image, row_id in tqdm(loader):\n        row_id = row_id[0]\n        image = image.to(device)\n\n        with torch.no_grad():\n            image = models[0].logmelspec_extractor(image)[:, None]\n            probas = []\n            probas_long = []\n            for model in models:\n                with torch.cuda.amp.autocast():\n                    _, clipwise_pred, _, _, clipwise_pred_long = model(image)\n                probas.append(clipwise_pred.detach().cpu().numpy().reshape(-1))\n                probas_long.append(clipwise_pred_long.detach().cpu().numpy().reshape(-1))\n            probas = np.array(probas)\n            probas_long = np.array(probas_long)\n#             probas = np.array([model(image)[1].detach().cpu().numpy().reshape(-1) for model in models])\n        if threshold_long is None:\n            events = probas.mean(0) >= threshold\n        else:\n            events = ((probas.mean(0) >= threshold).astype(int) \\\n                      + (probas_long.mean(0) >= threshold_long).astype(int)) >= 2\n        labels = np.argwhere(events).reshape(-1).tolist()\n#         labels = labels[:2]\n        if len(labels) == 0:\n            prediction_dict[str(row_id)] = \"nocall\"\n        else:\n            labels_str_list = list(map(lambda x: CFG.target_columns[x], labels))\n            label_string = \" \".join(labels_str_list)\n            prediction_dict[str(row_id)] = label_string\n    return prediction_dict","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.553892Z","iopub.execute_input":"2022-02-16T14:30:43.554478Z","iopub.status.idle":"2022-02-16T14:30:43.568008Z","shell.execute_reply.started":"2022-02-16T14:30:43.554443Z","shell.execute_reply":"2022-02-16T14:30:43.567328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model(backbone_name, weight_path):\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    model = Model(\n        backbone_name,\n        p=0.5,\n        n_mels=CFG.n_mels,\n        num_class=CFG.num_classes,\n        train_period=CFG.period,\n        infer_period=5,\n    )\n    model = prepare_model_for_inference(model, weight_path).to(device)\n    model = model.model\n    return model\n\ndef prediction(test_audios,\n               models_cfg,\n               threshold=0.05, \n               threshold_long=None):\n    \n    models = [load_model(list(models_cfg.keys())[0], list(models_cfg.values())[0]) for models_cfg in models_cfg]\n    warnings.filterwarnings(\"ignore\")\n    prediction_dicts = {}\n    for audio_path in test_audios:\n        with timer(f\"Loading {str(audio_path)}\", logger):\n            clip, _ = sf.read(audio_path)\n        seconds = []\n        row_ids = []\n        for second in range(5, 65, 5):\n            row_id = \"_\".join(audio_path.name.split(\".\")[:-1]) + f\"_{second}\"\n            seconds.append(second)\n            row_ids.append(row_id)\n        print(row_ids)\n        test_df = pd.DataFrame({\n            \"row_id\": row_ids,\n            \"seconds\": seconds\n        })\n        with timer(f\"Prediction on {audio_path}\", logger):\n            prediction_dict = prediction_for_clip(test_df,\n                                                  clip=clip,\n                                                  models=models,\n                                                  threshold=threshold, threshold_long=threshold_long)\n#         row_id = list(prediction_dict.keys())\n#         birds = list(prediction_dict.values())\n#         prediction_df = pd.DataFrame({\n#             \"row_id\": row_id,\n#             \"birds\": birds\n#         })\n#         prediction_dfs.append(prediction_df)\n#     prediction_df = pd.concat(prediction_dfs, axis=0, sort=False).reset_index(drop=True)\n        prediction_dicts.update(prediction_dict)\n    return prediction_dicts","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:30:43.570559Z","iopub.execute_input":"2022-02-16T14:30:43.571107Z","iopub.status.idle":"2022-02-16T14:30:43.582957Z","shell.execute_reply.started":"2022-02-16T14:30:43.571073Z","shell.execute_reply":"2022-02-16T14:30:43.582226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"threshold = 0.025\nthreshold_long = 0.05\n\nprediction_dicts = prediction(test_audios=all_audios,\n           models_cfg=CFG.models_cfg,\n           threshold=threshold, \n           threshold_long=threshold_long)\nprint(prediction_dicts)\n\nfor i in range(len(sample_submission)):\n    sample = sample_submission.row_id[i]\n    key = sample.split(\"_\")[0] + \"_\" + sample.split(\"_\")[1] + \"_\" + sample.split(\"_\")[3]\n    target_bird = sample.split(\"_\")[2]\n    print(key, target_bird)\n    if key in prediction_dicts:\n        sample_submission.iat[i, 1] = (target_bird in prediction_dicts[key])\nsample_submission.to_csv(\"submission.csv\", index=False)\n# submission = prediction(test_audios=all_audios,\n#                         models_cfg=CFG.models_cfg,\n#                         threshold=threshold, \n#                         threshold_long=threshold_long)\n# submission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:32:37.981195Z","iopub.execute_input":"2022-02-16T14:32:37.98148Z","iopub.status.idle":"2022-02-16T14:32:38.964277Z","shell.execute_reply.started":"2022-02-16T14:32:37.981451Z","shell.execute_reply":"2022-02-16T14:32:38.963447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission","metadata":{"execution":{"iopub.status.busy":"2022-02-16T14:32:40.211244Z","iopub.execute_input":"2022-02-16T14:32:40.211824Z","iopub.status.idle":"2022-02-16T14:32:40.219282Z","shell.execute_reply.started":"2022-02-16T14:32:40.211787Z","shell.execute_reply":"2022-02-16T14:32:40.218499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}