{"cells":[{"metadata":{},"cell_type":"markdown","source":"Special thanks to the authors of notebooks:\n    \n- **[[Training] Bird -- Simple BaseLine](https://www.kaggle.com/chanhu/training-bird-simple-baseline)**\n\n- **[Introduction to Sound Event Detection](https://www.kaggle.com/hidehisaarai1213/introduction-to-sound-event-detection)**\n\n\nand discussions:\n\n- **[[Competition Metrics]](https://www.kaggle.com/c/birdsong-recognition/discussion/160320)**\n- **[Cross Validation with Randomly Cropped Segments for Every Fold?](https://www.kaggle.com/c/birdsong-recognition/discussion/173587)**","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport sys\nimport random\nfrom pathlib import Path\nfrom typing import List, Tuple, Callable\n\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport librosa\nimport audioread\nimport soundfile as sf\n\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, Sampler, Subset\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import f1_score, average_precision_score\nfrom sklearn.exceptions import UndefinedMetricWarning\nimport warnings\n\n\nwarnings.filterwarnings(action=\"ignore\", category=UserWarning)\nwarnings.filterwarnings(action=\"ignore\", category=UndefinedMetricWarning)\nwarnings.filterwarnings(action=\"ignore\", category=RuntimeWarning)\n\n\nsys.path.append(\"../input/catalyst-git/catalyst\")\nsys.path.append(\"../input/efficientnetpytorch\")\n\n\nfrom catalyst import dl\nfrom efficientnet_pytorch import EfficientNet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ROOT = Path.cwd().parent\nINPUT_ROOT = ROOT / \"input\"\nRAW_DATA = INPUT_ROOT / \"birdsong-recognition\"\nTRAIN_AUDIO_DIR = RAW_DATA / \"train_audio\"\nTRAIN_RESAMPLED_AUDIO_DIRS = [\n    INPUT_ROOT / \"birdsong-resampled-train-audio-{:0>2}\".format(i)\n    for i in range(5)\n]\n\ntrain = pd.read_csv(TRAIN_RESAMPLED_AUDIO_DIRS[0] / \"train_mod.csv\")\nprint(\"Train shapes:\", train.shape)\n\n# global constans\nPERIOD = 5 # seconds to crop\nSAMPLE_RATE = 32_000\nFOLD_IDX = 0\nBATCH_SIZE = 48","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tmp_list = []\nfor audio_d in TRAIN_RESAMPLED_AUDIO_DIRS:\n    if not audio_d.exists():\n        continue\n    for ebird_d in audio_d.iterdir():\n        if ebird_d.is_file():\n            continue\n        for wav_f in ebird_d.iterdir():\n            tmp_list.append([ebird_d.name, wav_f.name, wav_f.as_posix()])\n            \ntrain_wav_path_exist = pd.DataFrame(tmp_list, columns=[\"ebird_code\", \"resampled_filename\", \"file_path\"])\n\ndel tmp_list\n\ntrain_all = pd.merge(train, train_wav_path_exist, on=[\"ebird_code\", \"resampled_filename\"], how=\"inner\")\n\nprint(train.shape)\nprint(train_wav_path_exist.shape)\nprint(train_all.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fold_method = StratifiedKFold(n_splits=5, random_state=2020, shuffle=True)\n\ntrain_all[\"fold\"] = -1\nfor fold_id, (train_index, val_index) in enumerate(fold_method.split(train_all, train_all[\"ebird_code\"])):\n    train_all.iloc[val_index, -1] = fold_id\n\ntrain_all[\"fold\"].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"BIRD_TO_CODE = {\n    \"aldfly\": 0,\n    \"ameavo\": 1,\n    \"amebit\": 2,\n    \"amecro\": 3,\n    \"amegfi\": 4,\n    \"amekes\": 5,\n    \"amepip\": 6,\n    \"amered\": 7,\n    \"amerob\": 8,\n    \"amewig\": 9,\n    \"amewoo\": 10,\n    \"amtspa\": 11,\n    \"annhum\": 12,\n    \"astfly\": 13,\n    \"baisan\": 14,\n    \"baleag\": 15,\n    \"balori\": 16,\n    \"banswa\": 17,\n    \"barswa\": 18,\n    \"bawwar\": 19,\n    \"belkin1\": 20,\n    \"belspa2\": 21,\n    \"bewwre\": 22,\n    \"bkbcuc\": 23,\n    \"bkbmag1\": 24,\n    \"bkbwar\": 25,\n    \"bkcchi\": 26,\n    \"bkchum\": 27,\n    \"bkhgro\": 28,\n    \"bkpwar\": 29,\n    \"bktspa\": 30,\n    \"blkpho\": 31,\n    \"blugrb1\": 32,\n    \"blujay\": 33,\n    \"bnhcow\": 34,\n    \"boboli\": 35,\n    \"bongul\": 36,\n    \"brdowl\": 37,\n    \"brebla\": 38,\n    \"brespa\": 39,\n    \"brncre\": 40,\n    \"brnthr\": 41,\n    \"brthum\": 42,\n    \"brwhaw\": 43,\n    \"btbwar\": 44,\n    \"btnwar\": 45,\n    \"btywar\": 46,\n    \"buffle\": 47,\n    \"buggna\": 48,\n    \"buhvir\": 49,\n    \"bulori\": 50,\n    \"bushti\": 51,\n    \"buwtea\": 52,\n    \"buwwar\": 53,\n    \"cacwre\": 54,\n    \"calgul\": 55,\n    \"calqua\": 56,\n    \"camwar\": 57,\n    \"cangoo\": 58,\n    \"canwar\": 59,\n    \"canwre\": 60,\n    \"carwre\": 61,\n    \"casfin\": 62,\n    \"caster1\": 63,\n    \"casvir\": 64,\n    \"cedwax\": 65,\n    \"chispa\": 66,\n    \"chiswi\": 67,\n    \"chswar\": 68,\n    \"chukar\": 69,\n    \"clanut\": 70,\n    \"cliswa\": 71,\n    \"comgol\": 72,\n    \"comgra\": 73,\n    \"comloo\": 74,\n    \"commer\": 75,\n    \"comnig\": 76,\n    \"comrav\": 77,\n    \"comred\": 78,\n    \"comter\": 79,\n    \"comyel\": 80,\n    \"coohaw\": 81,\n    \"coshum\": 82,\n    \"cowscj1\": 83,\n    \"daejun\": 84,\n    \"doccor\": 85,\n    \"dowwoo\": 86,\n    \"dusfly\": 87,\n    \"eargre\": 88,\n    \"easblu\": 89,\n    \"easkin\": 90,\n    \"easmea\": 91,\n    \"easpho\": 92,\n    \"eastow\": 93,\n    \"eawpew\": 94,\n    \"eucdov\": 95,\n    \"eursta\": 96,\n    \"evegro\": 97,\n    \"fiespa\": 98,\n    \"fiscro\": 99,\n    \"foxspa\": 100,\n    \"gadwal\": 101,\n    \"gcrfin\": 102,\n    \"gnttow\": 103,\n    \"gnwtea\": 104,\n    \"gockin\": 105,\n    \"gocspa\": 106,\n    \"goleag\": 107,\n    \"grbher3\": 108,\n    \"grcfly\": 109,\n    \"greegr\": 110,\n    \"greroa\": 111,\n    \"greyel\": 112,\n    \"grhowl\": 113,\n    \"grnher\": 114,\n    \"grtgra\": 115,\n    \"grycat\": 116,\n    \"gryfly\": 117,\n    \"haiwoo\": 118,\n    \"hamfly\": 119,\n    \"hergul\": 120,\n    \"herthr\": 121,\n    \"hoomer\": 122,\n    \"hoowar\": 123,\n    \"horgre\": 124,\n    \"horlar\": 125,\n    \"houfin\": 126,\n    \"houspa\": 127,\n    \"houwre\": 128,\n    \"indbun\": 129,\n    \"juntit1\": 130,\n    \"killde\": 131,\n    \"labwoo\": 132,\n    \"larspa\": 133,\n    \"lazbun\": 134,\n    \"leabit\": 135,\n    \"leafly\": 136,\n    \"leasan\": 137,\n    \"lecthr\": 138,\n    \"lesgol\": 139,\n    \"lesnig\": 140,\n    \"lesyel\": 141,\n    \"lewwoo\": 142,\n    \"linspa\": 143,\n    \"lobcur\": 144,\n    \"lobdow\": 145,\n    \"logshr\": 146,\n    \"lotduc\": 147,\n    \"louwat\": 148,\n    \"macwar\": 149,\n    \"magwar\": 150,\n    \"mallar3\": 151,\n    \"marwre\": 152,\n    \"merlin\": 153,\n    \"moublu\": 154,\n    \"mouchi\": 155,\n    \"moudov\": 156,\n    \"norcar\": 157,\n    \"norfli\": 158,\n    \"norhar2\": 159,\n    \"normoc\": 160,\n    \"norpar\": 161,\n    \"norpin\": 162,\n    \"norsho\": 163,\n    \"norwat\": 164,\n    \"nrwswa\": 165,\n    \"nutwoo\": 166,\n    \"olsfly\": 167,\n    \"orcwar\": 168,\n    \"osprey\": 169,\n    \"ovenbi1\": 170,\n    \"palwar\": 171,\n    \"pasfly\": 172,\n    \"pecsan\": 173,\n    \"perfal\": 174,\n    \"phaino\": 175,\n    \"pibgre\": 176,\n    \"pilwoo\": 177,\n    \"pingro\": 178,\n    \"pinjay\": 179,\n    \"pinsis\": 180,\n    \"pinwar\": 181,\n    \"plsvir\": 182,\n    \"prawar\": 183,\n    \"purfin\": 184,\n    \"pygnut\": 185,\n    \"rebmer\": 186,\n    \"rebnut\": 187,\n    \"rebsap\": 188,\n    \"rebwoo\": 189,\n    \"redcro\": 190,\n    \"redhea\": 191,\n    \"reevir1\": 192,\n    \"renpha\": 193,\n    \"reshaw\": 194,\n    \"rethaw\": 195,\n    \"rewbla\": 196,\n    \"ribgul\": 197,\n    \"rinduc\": 198,\n    \"robgro\": 199,\n    \"rocpig\": 200,\n    \"rocwre\": 201,\n    \"rthhum\": 202,\n    \"ruckin\": 203,\n    \"rudduc\": 204,\n    \"rufgro\": 205,\n    \"rufhum\": 206,\n    \"rusbla\": 207,\n    \"sagspa1\": 208,\n    \"sagthr\": 209,\n    \"savspa\": 210,\n    \"saypho\": 211,\n    \"scatan\": 212,\n    \"scoori\": 213,\n    \"semplo\": 214,\n    \"semsan\": 215,\n    \"sheowl\": 216,\n    \"shshaw\": 217,\n    \"snobun\": 218,\n    \"snogoo\": 219,\n    \"solsan\": 220,\n    \"sonspa\": 221,\n    \"sora\": 222,\n    \"sposan\": 223,\n    \"spotow\": 224,\n    \"stejay\": 225,\n    \"swahaw\": 226,\n    \"swaspa\": 227,\n    \"swathr\": 228,\n    \"treswa\": 229,\n    \"truswa\": 230,\n    \"tuftit\": 231,\n    \"tunswa\": 232,\n    \"veery\": 233,\n    \"vesspa\": 234,\n    \"vigswa\": 235,\n    \"warvir\": 236,\n    \"wesblu\": 237,\n    \"wesgre\": 238,\n    \"weskin\": 239,\n    \"wesmea\": 240,\n    \"wessan\": 241,\n    \"westan\": 242,\n    \"wewpew\": 243,\n    \"whbnut\": 244,\n    \"whcspa\": 245,\n    \"whfibi\": 246,\n    \"whtspa\": 247,\n    \"whtswi\": 248,\n    \"wilfly\": 249,\n    \"wilsni1\": 250,\n    \"wiltur\": 251,\n    \"winwre3\": 252,\n    \"wlswar\": 253,\n    \"wooduc\": 254,\n    \"wooscj2\": 255,\n    \"woothr\": 256,\n    \"y00475\": 257,\n    \"yebfly\": 258,\n    \"yebsap\": 259,\n    \"yehbla\": 260,\n    \"yelwar\": 261,\n    \"yerwar\": 262,\n    \"yetvir\": 263,\n}\nCODE_TO_BIRD = {v: k for k, v in BIRD_TO_CODE.items()}\nNUM_BIRDS = len(BIRD_TO_CODE)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def mono_to_color(\n    spect: np.ndarray,\n    mean: float = None,\n    std: float = None,\n    norm_max: float = None,\n    norm_min: float = None,\n    eps: float = 1e-6,\n) -> np.ndarray:\n    \"\"\"Convert single channel spectrogram to image like.\n\n    Args:\n        spect (np.ndarray): spectrogram\n        mean ([type], optional): mean to use for scaling.\n            If `None` then `spect` will be used for computations of mean value.\n            Default is `None`.\n        std ([type], optional): standart deviation to use for scaling.\n            If `None` then `spect` will be used for computations of std value.\n            Default is `None`.\n        norm_max ([type], optional): maximum value to use in `spect`,\n            values higher than this value will be replaced with this value.\n            If `None` then maximum value will be took from `spect`.\n            Default is `None`.\n        norm_min ([type], optional): minimum value to use in `spect`,\n            values lower than this value will be replaced with this value.\n            If `None` then minimum value will be took from `spect`.\n            Default is `None`.\n        eps ([type], optional): difference level beetween min and max value in\n            normalized values to use for replacing with `norm_min`/`norm_max` values.\n            Default is `1e-6`.\n\n    Returns:\n        image like spectrogram.\n    \"\"\"\n    spect = np.stack([spect, spect, spect], axis=-1)\n\n    # standardize\n    mean = mean or spect.mean()\n    spect = spect - mean\n\n    std = std or spect.std()\n    spect_std = spect / (std + eps)\n\n    _min, _max = spect_std.min(), spect_std.max()\n    norm_max = norm_max or _max\n    norm_min = norm_min or _min\n\n    if (_max - _min) > eps:\n        # normalize to [0, 255]\n        res = spect_std\n        res[res < norm_min] = norm_min\n        res[res > norm_max] = norm_max\n        res = 255 * (res - norm_min) / (norm_max - norm_min)\n        res = res.astype(np.uint8)\n    else:\n        res = np.zeros_like(spect_std, dtype=np.uint8)\n    return res","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def pad_waveform(waveform: np.ndarray, effective_length: int) -> np.ndarray:\n    \"\"\"Pad waveform (if length is less than :arg:`effective_length`)\n    with some random part of a waveform.\n\n    Args:\n        waveform (np.ndarray): raw waveform of a signal\n        effective_length (int): length of a segment to crop\n\n    Returns:\n        np.ndarray: padded waveform\n    \"\"\"\n    len_y = len(waveform)\n    if len_y < effective_length:\n        new_y = np.zeros(effective_length, dtype=waveform.dtype)\n        start = np.random.randint(effective_length - len_y)\n        new_y[start : start + len_y] = waveform\n        waveform = new_y\n    return waveform.astype(np.float32)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def random_crop(waveform: np.ndarray, effective_length: int) -> np.ndarray:\n    \"\"\"Perform random crop from waveform.\n\n    Args:\n        waveform (np.ndarray): raw waveform of a signal\n        effective_length (int): length of a segment to crop\n\n    Returns:\n        np.ndarray: cropped part of a signal\n    \"\"\"\n    len_y = len(waveform)\n    if len_y < effective_length:\n        waveform = pad_waveform(waveform, effective_length)\n    elif len_y > effective_length:\n        start = np.random.randint(len_y - effective_length)\n        waveform = waveform[start : start + effective_length].astype(np.float32)\n    else:\n        waveform = waveform.astype(np.float32)\n    return waveform","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class SpectrogramDataset(Dataset):\n    def __init__(\n        self,\n        file_list: List[List[str]],\n        img_size: int = 224,\n        waveform_transforms: Callable = None,\n        spectrogram_transforms: Callable = None,\n        melspectrogram_parameters: dict = {},\n    ):\n        self.file_list = file_list  # list of list: [file_path, ebird_code]\n        self.img_size = img_size\n        self.waveform_transforms = waveform_transforms\n        self.spectrogram_transforms = spectrogram_transforms\n        self.melspectrogram_parameters = melspectrogram_parameters\n\n    def __len__(self):\n        return len(self.file_list)\n\n    @staticmethod\n    def bird_code_to_label(bird: str) -> np.ndarray:\n        labels = np.zeros(NUM_BIRDS, dtype=\"f\")\n        labels[BIRD_TO_CODE[bird]] = 1\n        return labels\n\n    def __getitem__(self, idx: int):\n        wav_path, ebird_code = self.file_list[idx]\n\n        waveform, sr = sf.read(wav_path)\n        labels = self.bird_code_to_label(ebird_code)\n\n        if self.waveform_transforms:\n            waveform = self.waveform_transforms(waveform)\n            \n        waveform = random_crop(waveform, sr * PERIOD)\n\n        melspec = librosa.feature.melspectrogram(\n            waveform, sr=sr, **self.melspectrogram_parameters\n        )\n        melspec = librosa.power_to_db(melspec).astype(np.float32)\n\n        if self.spectrogram_transforms:\n            melspec = self.spectrogram_transforms(melspec)\n        else:\n            pass\n\n        image = mono_to_color(melspec)\n        height, width, _ = image.shape\n        image = cv2.resize(image, (int(width * self.img_size / height), self.img_size))\n        image = np.moveaxis(image, 2, 0)\n        image = (image / 255.0).astype(np.float32)\n\n        return image, labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MultilabelBalancedSampler(Sampler):\n    def __init__(self, targets, classes_num):\n\n        self.targets = targets\n        self.classes_num = classes_num\n\n        self.samples_num_per_class = np.sum(self.targets, axis=0)\n        self.max_num = np.max(self.samples_num_per_class)\n\n        self.indexes_per_class = []\n        # Training indexes of all sound classes. E.g.:\n        # [[0, 11, 12, ...], [3, 4, 15, 16, ...], [7, 8, ...], ...]\n        for k in range(self.classes_num):\n            self.indexes_per_class.append(np.where(self.targets[:, k] == 1)[0])\n\n        self.length = self.classes_num * self.max_num\n\n    def __iter__(self):\n        all_indexs = []\n\n        for k in range(self.classes_num):\n            if len(self.indexes_per_class[k]) == self.max_num:\n                all_indexs.append(self.indexes_per_class[k])\n            else:\n                gap = self.max_num - len(self.indexes_per_class[k])\n                random_choice = np.random.choice(\n                    self.indexes_per_class[k], int(gap), replace=True\n                )\n                all_indexs.append(\n                    np.array(list(random_choice) + list(self.indexes_per_class[k]))\n                )\n\n        l = np.stack(all_indexs).T\n        l = l.reshape(-1)\n        random.shuffle(l)\n        return iter(l)\n\n    def __len__(self):\n        return int(self.length)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MulticlassEfficientNet(nn.Module):\n    \"\"\"Multiclass efficientnet with pretrains\"\"\"\n\n    def __init__(self, pretrain: str, n_classes: int = 1):\n        \"\"\"\n        Args:\n            pretrain (str): one of:\n                - 'efficientnet-b0'\n                - 'efficientnet-b1'\n                - 'efficientnet-b2'\n                - 'efficientnet-b3'\n                - 'efficientnet-b4'\n                - 'efficientnet-b5'\n                - 'efficientnet-b6'\n                - 'efficientnet-b7'\n            n_classes (int, optional): number of classes to use,\n                default is `1`\n        \"\"\"\n        super().__init__()\n        self.backbone = EfficientNet.from_name(pretrain)\n        self.backbone._fc = nn.Linear(self.backbone._fc.in_features, n_classes)\n\n    def forward(self, batch):\n        return self.backbone(batch)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def sigmoid(x):\n    return 1 / (1 + np.exp(-x))\n\n\ndef softmax(x):\n    return np.exp(x) / np.sum(np.exp(x), axis=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class F1AverageMetric(dl.Callback):\n    def __init__(\n        self,\n        metric_name: str = \"f1\",\n        input_key: str = \"targets\",\n        output_key: str = \"logits\",\n        threshold: float = 0.5,\n        average: str = \"micro\",\n        activation: str = None,\n    ):\n        super().__init__(dl.CallbackOrder.Metric)\n        self.name = metric_name\n        self.inp = input_key\n        self.outp = output_key\n        self.target_container = None\n        self.preds_container = None\n        self.threshold = threshold\n        self.average = average\n        if activation == \"sigmoid\":\n            self.activation = sigmoid\n        elif activation == \"softmax\":\n            self.activation = softmax\n        else:\n            self.activation = lambda item: item\n\n    def on_loader_start(self, state: dl.IRunner) -> None:\n        self.target_container = []\n        self.preds_container = []\n        \n    def on_batch_end(self, state: dl.IRunner) -> None:\n        # collect scores\n        target = state.input[self.inp].detach().cpu().numpy()\n        self.target_container.append(target)\n\n        pred = state.output[self.outp].detach().cpu().numpy()\n        self.preds_container.append(pred)\n        \n    def on_loader_end(self, state: dl.IRunner) -> None:\n        y_pred = np.concatenate(self.preds_container, axis=0)\n        y_pred = self.activation(y_pred)\n        y_pred = np.where(y_pred > self.threshold, 1, 0)\n        \n        y_true = np.concatenate(self.target_container, axis=0)\n        score = f1_score(y_true, y_pred, average=self.average)\n        \n        state.loader_metrics[self.name] = score\n        # free memory\n        self.target_container = None\n        self.preds_container = None","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = train_all[train_all[\"fold\"] != FOLD_IDX][[\"file_path\", \"ebird_code\"]]\nvalid_df = train_all[train_all[\"fold\"] == FOLD_IDX][[\"file_path\", \"ebird_code\"]]\n\ntrain_targets = np.zeros((len(train_df), NUM_BIRDS), dtype=\"f\")\nfor idx, ebird_code in enumerate(train_df[\"ebird_code\"].values):\n    train_targets[idx, BIRD_TO_CODE[ebird_code]] = 1\n\ntrainset = SpectrogramDataset(\n    train_df.values.tolist(),\n    img_size=224,\n)\n# trainset = Subset(trainset, list(range(300)))\nprint(\"Train records:\", len(trainset))\n\nvalidset = SpectrogramDataset(\n    valid_df.values.tolist(),\n    img_size=224,\n)\n# validset = Subset(validset, list(range(300)))\nprint(\"Valid records:\", len(validset))\n\n\ndef valid_worker_init_fn(*args, **kwargs):\n    random.seed(42)\n    np.random.seed(42)\n\n\nloaders = {\n    \"train\": DataLoader(\n        trainset, batch_size=BATCH_SIZE, num_workers=2,\n#         sampler=MultilabelBalancedSampler(train_targets, NUM_BIRDS)\n    ),\n    \"valid\": DataLoader(\n        validset, batch_size=BATCH_SIZE * 2, num_workers=2,\n        worker_init_fn=valid_worker_init_fn\n    ),\n}\nprint(\"Batches in train:\", len(loaders[\"train\"]))\nprint(\"Batches in valid:\", len(loaders[\"valid\"]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# experiment definitions\nlogdir = \".\"\nnum_epochs = 10\nmodel = MulticlassEfficientNet(\"efficientnet-b1\", NUM_BIRDS)\noptimizer = optim.AdamW(model.parameters(), lr=1e-3)\ncriterion = nn.BCEWithLogitsLoss()\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)\n\n# training\nrunner = dl.SupervisedRunner()\nrunner.train(\n    logdir=logdir,\n    model=model,\n    num_epochs=num_epochs,\n    criterion=criterion,\n    optimizer=optimizer,\n    scheduler=scheduler,\n    loaders=loaders,\n    callbacks=[\n        F1AverageMetric(activation=\"sigmoid\"),\n        dl.CheckRunCallback(num_batch_steps=5, num_epoch_steps=num_epochs) # REMOVE THIS FOR FULL TRAINING\n    ],\n    main_metric=\"f1\",\n    minimize_metric=False,\n    verbose=True,\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}