{"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":"## This is submission shows ensemble of our own model, with public score 0.80 and private 0.79 (rank 7-8, Version 6). All dataset including trained models were public.\n## We also use a tensorflow model provided by host which rank 2 in private (see https://www.kaggle.com/code/leonshangguan/birdnet-inference). ","metadata":{}},{"cell_type":"code","source":"!pip install ../input/torchlibrosa/torchlibrosa-0.0.5-py3-none-any.whl > /dev/null","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:04.250475Z","iopub.execute_input":"2022-05-24T14:13:04.250965Z","iopub.status.idle":"2022-05-24T14:13:31.998431Z","shell.execute_reply.started":"2022-05-24T14:13:04.250924Z","shell.execute_reply":"2022-05-24T14:13:31.997487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport audioread\nimport logging\nimport os\nimport sys\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\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 List\nfrom typing import Optional\nfrom sklearn import metrics\n\nfrom albumentations.core.transforms_interface import ImageOnlyTransform\nfrom torchlibrosa.stft import LogmelFilterBank, Spectrogram\nfrom torchlibrosa.augmentation import SpecAugmentation\nfrom tqdm import tqdm\n\nimport albumentations as A\nimport albumentations.pytorch.transforms as T","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.000906Z","iopub.execute_input":"2022-05-24T14:13:32.001211Z","iopub.status.idle":"2022-05-24T14:13:32.010004Z","shell.execute_reply.started":"2022-05-24T14:13:32.00117Z","shell.execute_reply":"2022-05-24T14:13:32.009281Z"},"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)\n\n\ndef get_device() -> torch.device:\n    return torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n\ndevice = get_device()\nlogger = get_logger(\"main.log\")\nset_seed(42)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.011552Z","iopub.execute_input":"2022-05-24T14:13:32.01211Z","iopub.status.idle":"2022-05-24T14:13:32.029133Z","shell.execute_reply.started":"2022-05-24T14:13:32.012068Z","shell.execute_reply":"2022-05-24T14:13:32.028343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# define model","metadata":{}},{"cell_type":"code","source":"def init_layer(layer):\n    nn.init.xavier_uniform_(layer.weight)\n\n    if hasattr(layer, \"bias\"):\n        if layer.bias is not None:\n            layer.bias.data.fill_(0.)\n\n\ndef init_bn(bn):\n    bn.bias.data.fill_(0.)\n    bn.weight.data.fill_(1.0)\n\n\ndef init_weights(model):\n    classname = model.__class__.__name__\n    if classname.find(\"Conv2d\") != -1:\n        nn.init.xavier_uniform_(model.weight, gain=np.sqrt(2))\n        model.bias.data.fill_(0)\n    elif classname.find(\"BatchNorm\") != -1:\n        model.weight.data.normal_(1.0, 0.02)\n        model.bias.data.fill_(0)\n    elif classname.find(\"GRU\") != -1:\n        for weight in model.parameters():\n            if len(weight.size()) > 1:\n                nn.init.orghogonal_(weight.data)\n    elif classname.find(\"Linear\") != -1:\n        model.weight.data.normal_(0, 0.01)\n        model.bias.data.zero_()\n\n\ndef interpolate(x: torch.Tensor, ratio: int):\n    \"\"\"Interpolate data in time domain. This is used to compensate the\n    resolution reduction in downsampling of a CNN.\n    Args:\n      x: (batch_size, time_steps, classes_num)\n      ratio: int, ratio to interpolate\n    Returns:\n      upsampled: (batch_size, time_steps * ratio, classes_num)\n    \"\"\"\n    (batch_size, time_steps, classes_num) = x.shape\n    upsampled = x[:, :, None, :].repeat(1, 1, ratio, 1)\n    upsampled = upsampled.reshape(batch_size, time_steps * ratio, classes_num)\n    return upsampled\n\n\ndef pad_framewise_output(framewise_output: torch.Tensor, frames_num: int):\n    \"\"\"Pad framewise_output to the same length as input frames. The pad value\n    is the same as the value of the last frame.\n    Args:\n      framewise_output: (batch_size, frames_num, classes_num)\n      frames_num: int, number of frames to pad\n    Outputs:\n      output: (batch_size, frames_num, classes_num)\n    \"\"\"\n    output = F.interpolate(\n        framewise_output.unsqueeze(1),\n        size=(frames_num, framewise_output.size(2)),\n        align_corners=True,\n        mode=\"bilinear\").squeeze(1)\n\n    return output\n\n\nclass AttBlockV2(nn.Module):\n    def __init__(self,\n                 in_features: int,\n                 out_features: int,\n                 activation=\"linear\"):\n        super().__init__()\n\n        self.activation = activation\n        self.att = nn.Conv1d(\n            in_channels=in_features,\n            out_channels=out_features,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=True)\n        self.cla = nn.Conv1d(\n            in_channels=in_features,\n            out_channels=out_features,\n            kernel_size=1,\n            stride=1,\n            padding=0,\n            bias=True)\n\n        self.init_weights()\n\n    def init_weights(self):\n        init_layer(self.att)\n        init_layer(self.cla)\n\n    def forward(self, x):\n        # x: (n_samples, n_in, n_time)\n        norm_att = torch.softmax(torch.tanh(self.att(x)), dim=-1)\n        cla = self.nonlinear_transform(self.cla(x))\n        x = torch.sum(norm_att * cla, dim=2)\n        return x, norm_att, cla\n\n    def nonlinear_transform(self, x):\n        if self.activation == 'linear':\n            return x\n        elif self.activation == 'sigmoid':\n            return torch.sigmoid(x)\n\n\nclass TimmSED(nn.Module):\n    def __init__(\n        self, \n        base_model_name: str, \n        config=None,\n        pretrained=False, \n        num_classes=24, \n        in_channels=1\n    ):\n        super().__init__()\n        \n        self.config = config\n\n        self.spec_augmenter = SpecAugmentation(\n            time_drop_width=64 // 2, \n            time_stripes_num=2,\n            freq_drop_width=8 // 2, \n            freq_stripes_num=2)\n\n        self.bn0 = nn.BatchNorm2d(self.config.n_mels)\n\n        base_model = timm.create_model(\n            base_model_name, \n            pretrained=pretrained, \n            num_classes=0,\n            global_pool=\"\",\n            in_chans=in_channels,\n        )\n        \n        layers = list(base_model.children())[:-2]\n        self.encoder = nn.Sequential(*layers)\n\n        in_features = base_model.num_features\n\n        self.fc1 = nn.Linear(in_features, in_features, bias=True)\n        self.att_block = AttBlockV2(\n            in_features, num_classes, activation=\"sigmoid\")\n\n        self.init_weight()\n\n    def init_weight(self):\n        init_bn(self.bn0)\n        init_layer(self.fc1)\n        \n    def forward(self, input_data):\n        if self.config.in_channels == 3:\n            x = input_data\n        else:\n            x = input_data[:, [0], :, :] # (batch_size, 1, time_steps, mel_bins)\n\n        frames_num = x.shape[2]\n\n        x = x.transpose(1, 3)\n        x = self.bn0(x)\n        x = x.transpose(1, 3)\n\n        if self.training:\n            if random.random() < 0.25:\n                x = self.spec_augmenter(x)\n\n        x = x.transpose(2, 3)\n\n        x = self.encoder(x)\n        \n        # Aggregate in frequency axis\n        x = torch.mean(x, dim=2)\n\n        x1 = F.max_pool1d(x, kernel_size=3, stride=1, padding=1)\n        x2 = F.avg_pool1d(x, kernel_size=3, stride=1, padding=1)\n        x = x1 + x2\n\n        x = F.dropout(x, p=0.5, training=self.training)\n        x = x.transpose(1, 2)\n        x = F.relu_(self.fc1(x))\n        x = x.transpose(1, 2)\n        x = F.dropout(x, p=0.5, training=self.training)\n\n        (clipwise_output, norm_att, segmentwise_output) = self.att_block(x)\n        logit = torch.sum(norm_att * self.att_block.cla(x), dim=2)\n        segmentwise_logit = self.att_block.cla(x).transpose(1, 2)\n        segmentwise_output = segmentwise_output.transpose(1, 2)\n\n        interpolate_ratio = frames_num // segmentwise_output.size(1)\n\n        # Get framewise output\n        framewise_output = interpolate(segmentwise_output,\n                                       interpolate_ratio)\n        framewise_output = pad_framewise_output(framewise_output, frames_num)\n\n        framewise_logit = interpolate(segmentwise_logit, interpolate_ratio)\n        framewise_logit = pad_framewise_output(framewise_logit, frames_num)\n\n        output_dict = {\n            \"framewise_output\": framewise_output,\n            \"segmentwise_output\": segmentwise_output,\n            \"logit\": logit,\n            \"framewise_logit\": framewise_logit,\n            \"clipwise_output\": clipwise_output\n        }\n\n        return output_dict","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.032788Z","iopub.execute_input":"2022-05-24T14:13:32.033297Z","iopub.status.idle":"2022-05-24T14:13:32.070437Z","shell.execute_reply.started":"2022-05-24T14:13:32.033259Z","shell.execute_reply":"2022-05-24T14:13:32.069635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# define config","metadata":{}},{"cell_type":"code","source":"mean = (0.485) # R only for RGB\nstd = (0.229) # R only for RGB\n\nalbu_transforms = {\n    'train' : A.Compose([\n            A.Normalize(mean, std),\n    ]),\n    'valid' : A.Compose([\n            A.Normalize(mean, std),\n    ]),\n}\n\n\nmean2 = (0.485, 0.456, 0.406) # RGB\nstd2 = (0.229, 0.224, 0.225) # RGB\n\nalbu_transforms2 = {\n    'train' : A.Compose([\n            A.Normalize(mean2, std2),\n    ]),\n    'valid' : A.Compose([\n            A.Normalize(mean2, std2),\n    ]),\n}","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.073676Z","iopub.execute_input":"2022-05-24T14:13:32.073904Z","iopub.status.idle":"2022-05-24T14:13:32.082525Z","shell.execute_reply.started":"2022-05-24T14:13:32.07386Z","shell.execute_reply":"2022-05-24T14:13:32.081597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG_eca_nfnet_l0:\n\n    seed = 96000\n    train = False\n\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}]\n    }\n    \n    duration = 5\n    n_mels = 128\n    fmin = 50\n    fmax = 14000\n    n_fft = 1024\n    hop_length = 320\n    sr = 32000\n\n    target_columns = 'afrsil1 akekee akepa1 akiapo akikik amewig aniani apapan arcter \\\n                      barpet bcnher belkin1 bkbplo bknsti bkwpet blkfra blknod bongul \\\n                      brant brnboo brnnod brnowl brtcur bubsan buffle bulpet burpar buwtea \\\n                      cacgoo1 calqua cangoo canvas caster1 categr chbsan chemun chukar cintea \\\n                      comgal1 commyn compea comsan comwax coopet crehon dunlin elepai ercfra eurwig \\\n                      fragul gadwal gamqua glwgul gnwtea golphe grbher3 grefri gresca gryfra gwfgoo \\\n                      hawama hawcoo hawcre hawgoo hawhaw hawpet1 hoomer houfin houspa hudgod iiwi incter1 \\\n                      jabwar japqua kalphe kauama laugul layalb lcspet leasan leater1 lessca lesyel lobdow lotjae \\\n                      madpet magpet1 mallar3 masboo mauala maupar merlin mitpar moudov norcar norhar2 normoc norpin \\\n                      norsho nutman oahama omao osprey pagplo palila parjae pecsan peflov perfal pibgre pomjae puaioh \\\n                      reccar redava redjun redpha1 refboo rempar rettro ribgul rinduc rinphe rocpig rorpar rudtur ruff \\\n                      saffin sander semplo sheowl shtsan skylar snogoo sooshe sooter1 sopsku1 sora spodov sposan \\\n                      towsol wantat1 warwhe1 wesmea wessan wetshe whfibi whiter whttro wiltur yebcar yefcan zebdov'.split()\n\n   \n    base_model_name = \"eca_nfnet_l0\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 1\n    \n    ckpt_path = [\n        \"../input/birdclef-ensemble/eca_nfnet_l0_fold_0.bin\",\n        \"../input/birdclef-ensemble/eca_nfnet_l0_fold_1.bin\",\n        \"../input/birdclef-ensemble/eca_nfnet_l0_fold_2.bin\",\n        \"../input/birdclef-ensemble/eca_nfnet_l0_fold_3.bin\",\n        \"../input/birdclef-ensemble/eca_nfnet_l0_fold_4.bin\"\n    ]\n    \n    \nclass CFG_tf_efficientnetv2_s_in21k:\n\n    seed = 97000\n    train = False\n\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}]\n    }\n    \n    duration = 5\n    n_mels = 64\n    fmin = 50\n    fmax = 14000\n    n_fft = 1024\n    hop_length = 320\n    sr = 32000\n\n    target_columns = 'afrsil1 akekee akepa1 akiapo akikik amewig aniani apapan arcter \\\n                      barpet bcnher belkin1 bkbplo bknsti bkwpet blkfra blknod bongul \\\n                      brant brnboo brnnod brnowl brtcur bubsan buffle bulpet burpar buwtea \\\n                      cacgoo1 calqua cangoo canvas caster1 categr chbsan chemun chukar cintea \\\n                      comgal1 commyn compea comsan comwax coopet crehon dunlin elepai ercfra eurwig \\\n                      fragul gadwal gamqua glwgul gnwtea golphe grbher3 grefri gresca gryfra gwfgoo \\\n                      hawama hawcoo hawcre hawgoo hawhaw hawpet1 hoomer houfin houspa hudgod iiwi incter1 \\\n                      jabwar japqua kalphe kauama laugul layalb lcspet leasan leater1 lessca lesyel lobdow lotjae \\\n                      madpet magpet1 mallar3 masboo mauala maupar merlin mitpar moudov norcar norhar2 normoc norpin \\\n                      norsho nutman oahama omao osprey pagplo palila parjae pecsan peflov perfal pibgre pomjae puaioh \\\n                      reccar redava redjun redpha1 refboo rempar rettro ribgul rinduc rinphe rocpig rorpar rudtur ruff \\\n                      saffin sander semplo sheowl shtsan skylar snogoo sooshe sooter1 sopsku1 sora spodov sposan \\\n                      towsol wantat1 warwhe1 wesmea wessan wetshe whfibi whiter whttro wiltur yebcar yefcan zebdov'.split()\n\n   \n    base_model_name = \"tf_efficientnetv2_s_in21k\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 1\n    \n    ckpt_path = [\n        \"../input/birdclef-ensemble/tf_efficientnetv2_s_in21k_fold_0.bin\"\n    ]\n    \n    \nclass CFG_tf_efficientnetv2_m_in21k:\n\n    seed = 98000\n    train = False\n\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}]\n    }\n    \n    duration = 5\n    n_mels = 64\n    fmin = 50\n    fmax = 14000\n    n_fft = 1024\n    hop_length = 320\n    sr = 32000\n\n    target_columns = 'afrsil1 akekee akepa1 akiapo akikik amewig aniani apapan arcter \\\n                      barpet bcnher belkin1 bkbplo bknsti bkwpet blkfra blknod bongul \\\n                      brant brnboo brnnod brnowl brtcur bubsan buffle bulpet burpar buwtea \\\n                      cacgoo1 calqua cangoo canvas caster1 categr chbsan chemun chukar cintea \\\n                      comgal1 commyn compea comsan comwax coopet crehon dunlin elepai ercfra eurwig \\\n                      fragul gadwal gamqua glwgul gnwtea golphe grbher3 grefri gresca gryfra gwfgoo \\\n                      hawama hawcoo hawcre hawgoo hawhaw hawpet1 hoomer houfin houspa hudgod iiwi incter1 \\\n                      jabwar japqua kalphe kauama laugul layalb lcspet leasan leater1 lessca lesyel lobdow lotjae \\\n                      madpet magpet1 mallar3 masboo mauala maupar merlin mitpar moudov norcar norhar2 normoc norpin \\\n                      norsho nutman oahama omao osprey pagplo palila parjae pecsan peflov perfal pibgre pomjae puaioh \\\n                      reccar redava redjun redpha1 refboo rempar rettro ribgul rinduc rinphe rocpig rorpar rudtur ruff \\\n                      saffin sander semplo sheowl shtsan skylar snogoo sooshe sooter1 sopsku1 sora spodov sposan \\\n                      towsol wantat1 warwhe1 wesmea wessan wetshe whfibi whiter whttro wiltur yebcar yefcan zebdov'.split()\n\n   \n    base_model_name = \"tf_efficientnetv2_m_in21k\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 1\n    \n    ckpt_path = [\n        \"../input/birdclef-ensemble/tf_efficientnetv2_m_in21k_fold_0.bin\",\n        \"../input/birdclef-ensemble/tf_efficientnetv2_m_in21k_fold_1.bin\",\n        \"../input/birdclef-ensemble/tf_efficientnetv2_m_in21k_fold_2.bin\",\n        \"../input/birdclef-ensemble/tf_efficientnetv2_m_in21k_fold_3.bin\",\n        \"../input/birdclef-ensemble/tf_efficientnetv2_m_in21k_fold_4.bin\"\n    ]\n    \nclass CFG_tf_efficientnet_b0:\n\n    seed = 630\n    train = False\n\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}]\n    }\n    \n    duration = 5\n    n_mels = 256\n    fmin = 16\n    fmax = 16386\n    n_fft = 2048\n    hop_length = 512\n    sr = 32000\n\n    target_columns = 'afrsil1 akekee akepa1 akiapo akikik amewig aniani apapan arcter \\\n                      barpet bcnher belkin1 bkbplo bknsti bkwpet blkfra blknod bongul \\\n                      brant brnboo brnnod brnowl brtcur bubsan buffle bulpet burpar buwtea \\\n                      cacgoo1 calqua cangoo canvas caster1 categr chbsan chemun chukar cintea \\\n                      comgal1 commyn compea comsan comwax coopet crehon dunlin elepai ercfra eurwig \\\n                      fragul gadwal gamqua glwgul gnwtea golphe grbher3 grefri gresca gryfra gwfgoo \\\n                      hawama hawcoo hawcre hawgoo hawhaw hawpet1 hoomer houfin houspa hudgod iiwi incter1 \\\n                      jabwar japqua kalphe kauama laugul layalb lcspet leasan leater1 lessca lesyel lobdow lotjae \\\n                      madpet magpet1 mallar3 masboo mauala maupar merlin mitpar moudov norcar norhar2 normoc norpin \\\n                      norsho nutman oahama omao osprey pagplo palila parjae pecsan peflov perfal pibgre pomjae puaioh \\\n                      reccar redava redjun redpha1 refboo rempar rettro ribgul rinduc rinphe rocpig rorpar rudtur ruff \\\n                      saffin sander semplo sheowl shtsan skylar snogoo sooshe sooter1 sopsku1 sora spodov sposan \\\n                      towsol wantat1 warwhe1 wesmea wessan wetshe whfibi whiter whttro wiltur yebcar yefcan zebdov'.split()\n\n   \n    base_model_name = \"tf_efficientnet_b0_ns\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 1\n    \n    ckpt_path = [\n        \"../input/tf-efficientnet-b0-ns/fold-0_0.8157349896480331.bin\",\n        \"../input/tf-efficientnet-b0-ns/fold-1_0.8130277442702051.bin\",\n        \"../input/tf-efficientnet-b0-ns/fold-2_0.81753840842396.bin\",\n    ]\n    \nclass CFG_resnext50:\n\n    seed = 630\n    train = False\n\n    transforms = {\n        \"train\": [{\"name\": \"Normalize\"}],\n        \"valid\": [{\"name\": \"Normalize\"}]\n    }\n    \n    duration = 5\n    n_mels = 384\n    fmin = 300\n    fmax = 16000\n    n_fft = 2048\n    hop_length = 417\n    sr = 32000\n\n    target_columns = 'afrsil1 akekee akepa1 akiapo akikik amewig aniani apapan arcter \\\n                      barpet bcnher belkin1 bkbplo bknsti bkwpet blkfra blknod bongul \\\n                      brant brnboo brnnod brnowl brtcur bubsan buffle bulpet burpar buwtea \\\n                      cacgoo1 calqua cangoo canvas caster1 categr chbsan chemun chukar cintea \\\n                      comgal1 commyn compea comsan comwax coopet crehon dunlin elepai ercfra eurwig \\\n                      fragul gadwal gamqua glwgul gnwtea golphe grbher3 grefri gresca gryfra gwfgoo \\\n                      hawama hawcoo hawcre hawgoo hawhaw hawpet1 hoomer houfin houspa hudgod iiwi incter1 \\\n                      jabwar japqua kalphe kauama laugul layalb lcspet leasan leater1 lessca lesyel lobdow lotjae \\\n                      madpet magpet1 mallar3 masboo mauala maupar merlin mitpar moudov norcar norhar2 normoc norpin \\\n                      norsho nutman oahama omao osprey pagplo palila parjae pecsan peflov perfal pibgre pomjae puaioh \\\n                      reccar redava redjun redpha1 refboo rempar rettro ribgul rinduc rinphe rocpig rorpar rudtur ruff \\\n                      saffin sander semplo sheowl shtsan skylar snogoo sooshe sooter1 sopsku1 sora spodov sposan \\\n                      towsol wantat1 warwhe1 wesmea wessan wetshe whfibi whiter whttro wiltur yebcar yefcan zebdov'.split()\n\n   \n    base_model_name = \"resnext50_32x4d\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 3\n    \n    ckpt_path = [\n        \"../input/resnext50/resnext50_fold-0_0.7777777777777778.bin\",\n#         \"../input/resnext50/resnext50_fold-1_0.8084007574453433.bin\",\n#         \"../input/resnext50/resnext50_fold-2_0.8004904536696444.bin\",\n#         \"../input/resnext50/resnext50_fold-3_0.7966936334857543.bin\",\n        \"../input/resnext50/resnext50_fold-1_0.8105864037363778.bin\",\n        \"../input/resnext50/resnext50_fold-2_0.8004908835904627.bin\",\n        \"../input/resnext50/resnext50_fold-3_0.7987388334209142.bin\"\n        \n    ]","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.084623Z","iopub.execute_input":"2022-05-24T14:13:32.084946Z","iopub.status.idle":"2022-05-24T14:13:32.111828Z","shell.execute_reply.started":"2022-05-24T14:13:32.084906Z","shell.execute_reply":"2022-05-24T14:13:32.111068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config_eca_nfnet_l0 = CFG_eca_nfnet_l0()\nconfig_tf_efficientnetv2_s_in21k = CFG_tf_efficientnetv2_s_in21k()\nconfig_tf_efficientnetv2_m_in21k = CFG_tf_efficientnetv2_m_in21k()\nconfig_tf_efficientnet_b0 = CFG_tf_efficientnet_b0()\nconfig_resnext50 = CFG_resnext50()","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.113267Z","iopub.execute_input":"2022-05-24T14:13:32.113814Z","iopub.status.idle":"2022-05-24T14:13:32.125002Z","shell.execute_reply.started":"2022-05-24T14:13:32.113776Z","shell.execute_reply":"2022-05-24T14:13:32.12426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config_enesemble = [\n    config_eca_nfnet_l0,\n#     config_tf_efficientnetv2_s_in21k,\n    config_tf_efficientnetv2_m_in21k,\n    config_tf_efficientnet_b0,\n    config_resnext50\n]","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.128336Z","iopub.execute_input":"2022-05-24T14:13:32.128578Z","iopub.status.idle":"2022-05-24T14:13:32.134473Z","shell.execute_reply.started":"2022-05-24T14:13:32.128531Z","shell.execute_reply":"2022-05-24T14:13:32.133558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# define dataset","metadata":{}},{"cell_type":"code","source":"def compute_melspec(y, params):\n    \"\"\"\n    Computes a mel-spectrogram and puts it at decibel scale\n    Arguments:\n        y {np array} -- signal\n        params {AudioParams} -- Parameters to use for the spectrogram. Expected to have the attributes sr, n_mels, f_min, f_max\n    Returns:\n        np array -- Mel-spectrogram\n    \"\"\"\n    melspec = librosa.feature.melspectrogram(\n        y=y, sr=params.sr, n_mels=params.n_mels, n_fft=params.n_fft, hop_length=params.hop_length, fmin=params.fmin, fmax=params.fmax,\n    )\n\n    return melspec\n\n\ndef mono_to_color(X, eps=1e-6, mean=None, std=None):\n    \"\"\"\n    Converts a one channel array in [0, 255]\n    Arguments:\n        X {numpy array [H x W]} -- 2D array to convert\n    Keyword Arguments:\n        eps {float} -- To avoid dividing by 0 (default: {1e-6})\n        mean {None or np array} -- Mean for normalization (default: {None})\n        std {None or np array} -- Std for normalization (default: {None})\n    Returns:\n        numpy array [1 x H x W] -- RGB numpy array\n    \"\"\"\n    # X = np.stack([X, X, X], axis=-1)\n    X = np.expand_dims(X, axis=-1)\n\n    # Standardize\n    mean = mean or X.mean()\n    std = std or X.std()\n    X = (X - mean) / (std + eps)\n\n    # Normalize to [0, 255]\n    _min, _max = X.min(), X.max()\n\n    if (_max - _min) > eps:\n        V = np.clip(X, _min, _max)\n        V = 255 * (V - _min) / (_max - _min)\n        V = V.astype(np.uint8)\n    else:\n        V = np.zeros_like(X, dtype=np.uint8)\n\n    return V\n\ndef mono_to_color3(X, eps=1e-6, mean=None, std=None):\n    \"\"\"\n    Converts a one channel array to a 3 channel one in [0, 255]\n    Arguments:\n        X {numpy array [H x W]} -- 2D array to convert\n    Keyword Arguments:\n        eps {float} -- To avoid dividing by 0 (default: {1e-6})\n        mean {None or np array} -- Mean for normalization (default: {None})\n        std {None or np array} -- Std for normalization (default: {None})\n    Returns:\n        numpy array [3 x H x W] -- RGB numpy array\n    \"\"\"\n    X = np.stack([X, X, X], axis=-1)\n\n    # Standardize\n    mean = mean or X.mean()\n    std = std or X.std()\n    X = (X - mean) / (std + eps)\n\n    # Normalize to [0, 255]\n    _min, _max = X.min(), X.max()\n\n    if (_max - _min) > eps:\n        V = np.clip(X, _min, _max)\n        V = 255 * (V - _min) / (_max - _min)\n        V = V.astype(np.uint8)\n    else:\n        V = np.zeros_like(X, dtype=np.uint8)\n\n    return V","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.135874Z","iopub.execute_input":"2022-05-24T14:13:32.136457Z","iopub.status.idle":"2022-05-24T14:13:32.15093Z","shell.execute_reply.started":"2022-05-24T14:13:32.13641Z","shell.execute_reply":"2022-05-24T14:13:32.150224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataset(torchdata.Dataset):\n    def __init__(self, \n                 df: pd.DataFrame, \n                 clip: np.ndarray,\n                 config=None,\n                ):\n        \n        self.df = df\n        self.clip = clip\n        self.config = config\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx: int):\n\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        y = self.clip[self.config.sr * start_seconds : self.config.sr * end_seconds].astype(np.float32)\n        \n        image = compute_melspec(y, self.config)\n        image = librosa.power_to_db(image.astype(np.float32), ref=np.max)\n        \n        if config.in_channels == 3:\n            image = mono_to_color3(image)\n            image = image.astype(np.uint8)\n            image = albu_transforms2['valid'](image=image)['image'].T\n        else:\n            image = mono_to_color(image)\n            image = image.astype(np.uint8)\n            image = albu_transforms['valid'](image=image)['image'].T\n#         image = image.astype(np.uint8)\n\n#         image = albu_transforms['valid'](image=image)['image'].T\n        \n#         print(image.shape)\n            \n        return {\n            \"image\": image,\n            \"row_id\": row_id,\n        }","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.154529Z","iopub.execute_input":"2022-05-24T14:13:32.154918Z","iopub.status.idle":"2022-05-24T14:13:32.166163Z","shell.execute_reply.started":"2022-05-24T14:13:32.154881Z","shell.execute_reply":"2022-05-24T14:13:32.16527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# get models","metadata":{}},{"cell_type":"code","source":"models = []\n\nfor config in config_enesemble:\n    \n    config_models = []\n    \n    for ckpt_path in config.ckpt_path:\n    \n        model = TimmSED(\n            base_model_name=config.base_model_name,\n            config=config,\n            pretrained=config.pretrained,\n            num_classes=config.num_classes,\n            in_channels=config.in_channels\n        )\n\n        model.to(device)\n        model.load_state_dict(torch.load(ckpt_path, map_location='cuda:0'))\n        model.eval()\n        \n        config_models.append(model)\n    \n    if config.base_model_name==\"resnext50_32x4d\":\n        config.base_model_name = \"tf_efficientnet_b0_ns\"\n        for ckpt_path in [\"../input/eb0-final/fold-4_0.7996463306808134.bin\"]:\n    \n            model = TimmSED(\n                base_model_name=config.base_model_name,\n                config=config,\n                pretrained=config.pretrained,\n                num_classes=config.num_classes,\n                in_channels=config.in_channels\n            )\n\n            model.to(device)\n            model.load_state_dict(torch.load(ckpt_path, map_location='cuda:0'))\n            model.eval()\n\n            config_models.append(model)\n        \n    models.append((config, config_models))","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:32.167955Z","iopub.execute_input":"2022-05-24T14:13:32.168602Z","iopub.status.idle":"2022-05-24T14:13:46.397826Z","shell.execute_reply.started":"2022-05-24T14:13:32.168561Z","shell.execute_reply":"2022-05-24T14:13:46.39706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# prediction","metadata":{}},{"cell_type":"code","source":"all_audios = list(Path(\"../input/birdclef-2022/test_soundscapes/\").glob(\"*.ogg\"))#*10","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.399152Z","iopub.execute_input":"2022-05-24T14:13:46.399403Z","iopub.status.idle":"2022-05-24T14:13:46.404557Z","shell.execute_reply.started":"2022-05-24T14:13:46.399371Z","shell.execute_reply":"2022-05-24T14:13:46.40388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission = pd.read_csv('../input/birdclef-2022/sample_submission.csv')\n\nsample_submission.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.405717Z","iopub.execute_input":"2022-05-24T14:13:46.406122Z","iopub.status.idle":"2022-05-24T14:13:46.422762Z","shell.execute_reply.started":"2022-05-24T14:13:46.406085Z","shell.execute_reply":"2022-05-24T14:13:46.422027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def prediction_for_clip(\n    test_df: pd.DataFrame, \n    clip: np.ndarray, \n    models, \n    threshold=0.05, \n):\n    \n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    \n    # inference\n    prediction_dict = {}\n    \n    for config_models in models:\n        \n        config, models = config_models[0], config_models[1]\n        \n        dataset = TestDataset(\n            df=test_df, \n            clip=clip,\n            config=config,\n        )\n        \n        loader = torchdata.DataLoader(\n            dataset, \n            batch_size=12, \n            num_workers=8,\n            drop_last=False,\n            shuffle=False,\n            pin_memory=True\n        )\n        \n        for data in tqdm(loader):\n            \n            row_ids = data['row_id']\n            \n            for row_id in row_ids:\n                if row_id not in prediction_dict:\n                    prediction_dict[str(row_id)] = []\n            \n            image = data['image'].to(device)\n                \n            probas = []\n            \n            for model in models:\n\n                with torch.no_grad():\n                    output = model(image)\n#                     print(output['framewise_output'].shape)\n                    \n#                 for out_ in output['framewise_output']:\n                for row_id_idx, row_id in enumerate(row_ids):\n#                         print(row_ids, out_==output['framewise_output'][[row_id_idx]][0,:,:], torch.max(output['framewise_output'][[row_id_idx]], 1).values.detach().cpu().numpy().reshape(-1), torch.max(out_[[row_id_idx]], 0).values.detach().cpu().numpy().reshape(-1))\n                    prediction_dict[str(row_id)].append(torch.max(output['framewise_output'][[row_id_idx]], 1).values.detach().cpu().numpy().reshape(-1))\n#                     prediction_dict[str(row_id)].append(output['clipwise_output'][[row_id_idx]].detach().cpu().numpy().reshape(-1))\n#                     prediction_dict[str(row_id)].append(torch.max(output['framewise_output'][[row_id_idx]], 1).values.detach().cpu().numpy().reshape(-1))\n    \n    # ensemble\n    for row_id in list(prediction_dict.keys()):\n                \n        logits = np.array(prediction_dict[row_id]).mean(0)\n        events = logits >= threshold\n        labels = np.argwhere(events).reshape(-1).tolist()\n            \n        if len(labels) == 0:\n            prediction_dict[row_id] = {}\n            \n        else:\n            prediction_dict[row_id] = {}\n            \n            for label in labels:\n    \n                prediction_dict[row_id][config.target_columns[label]] = logits[label]\n             \n    return prediction_dict","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.424144Z","iopub.execute_input":"2022-05-24T14:13:46.424589Z","iopub.status.idle":"2022-05-24T14:13:46.438116Z","shell.execute_reply.started":"2022-05-24T14:13:46.424554Z","shell.execute_reply":"2022-05-24T14:13:46.437313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def crop_or_pad(y, length, sr, train=True, probs=None):\n    \"\"\"\n    Crops an array to a chosen length\n    Arguments:\n        y {1D np array} -- Array to crop\n        length {int} -- Length of the crop\n        sr {int} -- Sampling rate\n    Keyword Arguments:\n        train {bool} -- Whether we are at train time. If so, crop randomly, else return the beginning of y (default: {True})\n        probs {None or numpy array} -- Probabilities to use to chose where to crop (default: {None})\n    Returns:\n        1D np array -- Cropped array\n    \"\"\"\n    if len(y) <= length:\n        y = np.concatenate([y, np.zeros(length - len(y))])\n    else:\n        if not train:\n            start = 0\n        elif probs is None:\n            start = np.random.randint(len(y) - length)\n        else:\n            start = (\n                    np.random.choice(np.arange(len(probs)), p=probs) + np.random.random()\n            )\n            start = int(sr * (start))\n\n        y = y[start: start + length]\n\n    return y.astype(np.float32)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.43944Z","iopub.execute_input":"2022-05-24T14:13:46.439874Z","iopub.status.idle":"2022-05-24T14:13:46.450528Z","shell.execute_reply.started":"2022-05-24T14:13:46.439837Z","shell.execute_reply":"2022-05-24T14:13:46.449873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def prediction(\n    test_audios,\n    threshold=0.05, \n):\n    \n    warnings.filterwarnings(\"ignore\")\n    \n    prediction_dicts = {}\n    for audio_path in test_audios:\n        with timer(f\"Loading {str(audio_path)}\", logger):\n            clip, _ = librosa.load(audio_path, sr=32000)\n            \n        clip = crop_or_pad(clip, 32000*60, 32000, False)\n        \n        seconds = [i for i in range(5, 65, 5)]\n        name_ = \"_\".join(audio_path.name.split(\".\")[:-1])\n        row_ids = [name_+f\"_{second}\" for second in seconds]\n            \n        test_df = pd.DataFrame({\n            \"row_id\": row_ids,\n            \"seconds\": seconds\n        })\n        \n        with timer(f\"Prediction on {audio_path}\", logger):\n            \n            prediction_dict = prediction_for_clip(\n                test_df,\n                clip=clip,\n                models=models,\n                threshold=threshold, \n            )\n\n        prediction_dicts.update(prediction_dict)\n        \n    return prediction_dicts","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.452638Z","iopub.execute_input":"2022-05-24T14:13:46.453772Z","iopub.status.idle":"2022-05-24T14:13:46.463325Z","shell.execute_reply.started":"2022-05-24T14:13:46.45373Z","shell.execute_reply":"2022-05-24T14:13:46.462671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"threshold = 0.015 # N/A\n\nprediction_dicts = prediction(\n    test_audios=all_audios,\n    threshold=threshold, \n)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:13:46.466478Z","iopub.execute_input":"2022-05-24T14:13:46.467063Z","iopub.status.idle":"2022-05-24T14:14:35.586517Z","shell.execute_reply.started":"2022-05-24T14:13:46.467032Z","shell.execute_reply":"2022-05-24T14:14:35.585758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import copy\n\ndef post_processing(prediction_dicts):\n\n    processed_prediction_dicts = copy.deepcopy(prediction_dicts)\n\n    for row_id in prediction_dicts.keys():\n\n        second = int(row_id.split(\"_\")[-1])\n        prev_second = second - 5\n        next_second = second + 5\n\n        prev_row_id = \"_\".join(row_id.split(\"_\")[:-1] + [str(prev_second)])\n        next_row_id = \"_\".join(row_id.split(\"_\")[:-1] + [str(next_second)])\n\n        if prev_row_id in prediction_dicts:\n            for bird in prediction_dicts[prev_row_id].keys():\n                if bird in prediction_dicts[row_id].keys():\n                    processed_prediction_dicts[row_id][bird] += prediction_dicts[prev_row_id][bird]\n                else:\n                    processed_prediction_dicts[row_id][bird] = prediction_dicts[prev_row_id][bird]\n                    \n        if next_row_id in prediction_dicts:\n            for bird in prediction_dicts[next_row_id].keys():\n                if bird in prediction_dicts[row_id].keys():\n                    processed_prediction_dicts[row_id][bird] += prediction_dicts[next_row_id][bird]\n                else:\n                    processed_prediction_dicts[row_id][bird] = prediction_dicts[next_row_id][bird]\n                    \n                    \n#         if prev_row_id in prediction_dicts and next_row_id in prediction_dicts:\n#             for bird in prediction_dicts[prev_row_id].keys():\n#                 if bird in prediction_dicts[row_id].keys():\n#                     processed_prediction_dicts[row_id][bird] += prediction_dicts[prev_row_id][bird]\n#                 else:\n#                     processed_prediction_dicts[row_id][bird] = prediction_dicts[prev_row_id][bird]\n                    \n#                 if bird in prediction_dicts[next_row_id].keys():\n#                     processed_prediction_dicts[row_id][bird] += prediction_dicts[next_row_id][bird]\n#                 else:\n#                     print(prediction_dicts[next_row_id][bird])\n#                     processed_prediction_dicts[row_id][bird] = prediction_dicts[next_row_id][bird]\n                    \n#         elif prev_row_id in prediction_dicts and next_row_id not in prediction_dicts:\n#             for bird in prediction_dicts[row_id].keys():\n#                 if bird in prediction_dicts[prev_row_id].keys():\n#                     processed_prediction_dicts[row_id][bird] += prediction_dicts[prev_row_id][bird]\n#                 else:\n#                     print(prediction_dicts[prev_row_id][bird])\n#                     processed_prediction_dicts[row_id][bird] = prediction_dicts[prev_row_id][bird]\n                    \n#         elif prev_row_id not in prediction_dicts and next_row_id in prediction_dicts:\n#             for bird in prediction_dicts[row_id].keys():\n#                 if bird in prediction_dicts[next_row_id].keys():\n#                     processed_prediction_dicts[row_id][bird] += prediction_dicts[next_row_id][bird]\n#                 else:\n#                     print(prediction_dicts[next_row_id][bird])\n#                     processed_prediction_dicts[row_id][bird] = prediction_dicts[next_row_id][bird]\n\n#         if next_row_id in prediction_dicts:\n#             for bird in prediction_dicts[next_row_id].keys():\n#                 if bird in prediction_dicts[row_id].keys():\n#                     processed_prediction_dicts[row_id][bird] += prediction_dicts[next_row_id][bird]\n#     print(processed_prediction_dicts)\n    reformat_prediction_dicts = {}            \n    \n    for row_id in processed_prediction_dicts.keys():\n\n        if len(processed_prediction_dicts[row_id]) == 0:\n            reformat_prediction_dicts[row_id] = \"nocall\"\n\n        else:\n\n            bird_logit_pairs = []\n\n            for bird in processed_prediction_dicts[row_id].keys():\n                bird_logit_pairs.append((bird, processed_prediction_dicts[row_id][bird]))\n\n            bird_logit_pairs = sorted(bird_logit_pairs, key=lambda x : x[1], reverse=True)[:min(5, len(bird_logit_pairs))]\n            \n            voted_birds = [bird_logit_pair[0] for bird_logit_pair in bird_logit_pairs]\n            orig_birds = list(prediction_dicts[row_id].keys())\n            reformat_prediction_dicts[row_id] = \" \".join(list(set(voted_birds+orig_birds)))\n#             orig_birds = list(prediction_dicts[row_id].keys())\n# #             print(voted_birds,orig_birds)\n#             reformat_prediction_dicts[row_id] = \" \".join(list(orig_birds))\n            \n    return reformat_prediction_dicts\n            \npost_processed_prediction_dicts = post_processing(prediction_dicts)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:14:35.588184Z","iopub.execute_input":"2022-05-24T14:14:35.588754Z","iopub.status.idle":"2022-05-24T14:14:35.605446Z","shell.execute_reply.started":"2022-05-24T14:14:35.58871Z","shell.execute_reply":"2022-05-24T14:14:35.604666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"post_processed_prediction_dicts","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:14:35.606974Z","iopub.execute_input":"2022-05-24T14:14:35.607337Z","iopub.status.idle":"2022-05-24T14:14:35.622524Z","shell.execute_reply.started":"2022-05-24T14:14:35.607299Z","shell.execute_reply":"2022-05-24T14:14:35.621589Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for i in range(len(sample_submission)):\n    \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\n    if key in post_processed_prediction_dicts:\n        sample_submission.iat[i, 1] = (target_bird in post_processed_prediction_dicts[key])\n        \nsample_submission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:14:35.624314Z","iopub.execute_input":"2022-05-24T14:14:35.624582Z","iopub.status.idle":"2022-05-24T14:14:35.635446Z","shell.execute_reply.started":"2022-05-24T14:14:35.624548Z","shell.execute_reply":"2022-05-24T14:14:35.63469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-24T14:14:35.638183Z","iopub.execute_input":"2022-05-24T14:14:35.6384Z","iopub.status.idle":"2022-05-24T14:14:35.64796Z","shell.execute_reply.started":"2022-05-24T14:14:35.638376Z","shell.execute_reply":"2022-05-24T14:14:35.647022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}