{"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":"!pip install ../input/torchlibrosa/torchlibrosa-0.0.5-py3-none-any.whl > /dev/null","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","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\nfrom sklearn.model_selection import StratifiedKFold, GroupKFold\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\nimport matplotlib.pyplot as plt","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed: int = 56):\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)  \n    torch.backends.cudnn.deterministic = True  \n    torch.backends.cudnn.benchmark = True  ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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(56)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def init_layer(layer):\n    nn.init.xavier_uniform_(layer.weight)\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    (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    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    return output\n\n\nclass AttBlockV2(nn.Module):\n    def __init__(self, in_features: int, out_features: int, activation=\"linear\"):\n        super().__init__()\n        self.activation = activation\n        self.att = nn.Conv1d(in_channels=in_features, out_channels=out_features, kernel_size=1,\n                             stride=1, padding=0, bias=True)\n        self.cla = nn.Conv1d(in_channels=in_features, out_channels=out_features, kernel_size=1,\n                             stride=1, padding=0, bias=True)\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        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__(self, base_model_name: str, pretrained=False, num_classes=24, in_channels=1):\n        super().__init__()\n        self.spec_augmenter = SpecAugmentation(time_drop_width=64//2, time_stripes_num=2,\n                                               freq_drop_width=8//2, freq_stripes_num=2)\n        self.bn0 = nn.BatchNorm2d(CFG.n_mels)\n        base_model = timm.create_model(base_model_name, pretrained=pretrained, in_chans=in_channels)\n        layers = list(base_model.children())[:-2]\n        self.encoder = nn.Sequential(*layers)\n        if hasattr(base_model, \"fc\"):\n            in_features = base_model.fc.in_features\n        else:\n            in_features = base_model.classifier.in_features\n        self.fc1 = nn.Linear(in_features, in_features, bias=True)\n        self.att_block = AttBlockV2(in_features, num_classes, activation=\"sigmoid\")\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        x = input_data \n        frames_num = x.shape[2]\n        x = x.transpose(1, 3)\n        x = self.bn0(x)\n        x = x.transpose(1, 3)\n        if self.training:\n            if random.random() < 0.25:\n                x = self.spec_augmenter(x)\n        x = x.transpose(2, 3)\n        x = self.encoder(x)\n        x = torch.mean(x, dim=3)\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.48, 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.48, 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        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 = {'framewise_output': framewise_output, 'clipwise_output': clipwise_output,\n                       'logit': logit, 'framewise_logit': framewise_logit, }\n\n        return output_dict","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mean = (0.485, 0.456, 0.406) # RGB\nstd = (0.229, 0.224, 0.225) # RGB\n\nalbu_transforms = {'train' : A.Compose([A.HorizontalFlip(p=0.4),\n                                        A.OneOf([A.Cutout(max_h_size=5, max_w_size=16),\n                                                 A.CoarseDropout(max_holes=4),], p=0.4),\n                                        A.Normalize(mean, std),]),\n                   'valid' : A.Compose([A.Normalize(mean, std),]), }","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CFG:\n    EXP_ID = '018' \n    seed = 56\n    epochs = 25\n    train = True\n    folds = [5, 11, 14, 22, 30]\n    img_size = 224\n    main_metric = \"epoch_f1_at_03\"\n    minimize_metric = False\n    transforms = {\"train\": [{\"name\": \"Normalize\"}], \"valid\": [{\"name\": \"Normalize\"}]}\n    period = 5\n    n_mels = 224\n    fmin = 20\n    fmax = 16000\n    n_fft = 2048\n    hop_length = 512\n    sample_rate = 32000\n    melspectrogram_parameters = {\"mels\": 224, \"fmin\": 20, \"fmax\": 16000 }\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    loader_params = {\"train\": {\"batch_size\": 16, \"num_workers\": 0, \"shuffle\": True },\n                     \"valid\": {\"batch_size\": 32, \"num_workers\": 0, \"shuffle\": False }}\n\n    base_model_name = \"tf_efficientnet_b0_ns\"\n    pooling = \"max\"\n    pretrained = False\n    num_classes = 152\n    in_channels = 3\n\n    N_FOLDS = 32\n    LR = 1e-3\n    T_max=10\n    min_lr=1e-6","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"AUDIO_PATH = '../input/birdclef-2022/train_audio'\nCLASSES = sorted(os.listdir(AUDIO_PATH))\nNUM_CLASSES = len(CLASSES)\nclass AudioParams:\n    sr = 32000\n    duration = 5\n    n_mels = 224\n    fmin = 20\n    fmax = 16000","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def compute_melspec(y, params):\n    melspec = librosa.feature.melspectrogram(y=y, sr=params.sr, n_mels=params.n_mels, \n                                             fmin=params.fmin, fmax=params.fmax, )\n    melspec = librosa.power_to_db(melspec).astype(np.float32)\n    return melspec\n\n\ndef mono_to_color(X, eps=1e-6, mean=None, std=None):\n    X = np.stack([X, X, X], axis=-1)\n    mean = mean or X.mean()\n    std = std or X.std()\n    X = (X - mean) / (std + eps)\n    _min, _max = X.min(), X.max()\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    return V\n\nclass TestDataset(torchdata.Dataset):\n    def __init__(self, df: pd.DataFrame, clip: np.ndarray):\n        self.df = df\n        self.clip = np.concatenate([clip, clip, clip])\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        image = self.clip[SR*start_seconds:SR*end_seconds].astype(np.float32)\n        image = np.nan_to_num(image)\n        image = compute_melspec(image, AudioParams)\n        image = mono_to_color(image)\n        image = image.astype(np.uint8)\n        image = albu_transforms['valid'](image=image)['image'].T\n        return {\"image\": image, \"row_id\": row_id, }","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_paths = ['../input/birdies/fold-5.bin','../input/birdies/fold-11.bin',\n               '../input/birdies/fold-14.bin','../input/birdies/fold-22.bin','../input/birdies/fold-30.bin']\n\nmodels = []\nfor p in model_paths:\n    model = TimmSED(base_model_name=CFG.base_model_name, pretrained=CFG.pretrained,\n                    num_classes=CFG.num_classes, in_channels=CFG.in_channels)\n    model.to(device)\n    model.load_state_dict(torch.load(p))\n    model.eval()\n    models.append(model)\n    \nprint()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGET_SR = 32000\nDATADIR = Path(\"../input/birdclef-2022/test_soundscapes/\")\n\nall_audios = list(DATADIR.glob(\"*.ogg\"))\nsample_submission = pd.read_csv('../input/birdclef-2022/sample_submission.csv')\nsample_submission","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def prediction_for_clip(test_df: pd.DataFrame, clip: np.ndarray, models, \n                        threshold=0.0405, threshold_long=None):\n    dataset = TestDataset(df=test_df, clip=clip,)\n    loader = torchdata.DataLoader(dataset, batch_size=1, shuffle=False)\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    \n    prediction_dict = {}\n    for data in tqdm(loader):\n        row_id = data['row_id'][0]\n        image = data['image'].to(device)\n        with torch.no_grad():\n            probas = []\n            probas_long = []\n            for model in models:\n                with torch.cuda.amp.autocast():\n                    output = model(image)\n                probas.append(output['clipwise_output'].detach().cpu().numpy().reshape(-1))\n            probas = np.array(probas)\n          \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\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\n\n\ndef prediction(test_audios, threshold=0.0405, threshold_long=None):\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, always_2d=True)\n            clip = np.mean(clip, 1)\n            \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({\"row_id\": row_ids, \"seconds\": seconds })\n        with timer(f\"Prediction on {audio_path}\", logger):\n            prediction_dict = prediction_for_clip(test_df, clip=clip, models=models,\n                                                  threshold=threshold, threshold_long=threshold_long)\n        prediction_dicts.update(prediction_dict)\n    return prediction_dicts\n\nthreshold = 0.0405\nthreshold_long = None # 0.05\n\nprediction_dicts = prediction(test_audios=all_audios, threshold=threshold, threshold_long=threshold_long)\nprint(prediction_dicts)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for 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)\nsample_submission","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}