{"cells":[{"metadata":{},"cell_type":"markdown","source":"## About\n\nThis code enables to train a 5-fold ResNext-50 in the kaggle kernels. There is unfortunately some timeout issues.\n\nThe 5 fold blend with our [post-processing method](https://www.kaggle.com/theoviel/inference-theo) achieves private LB 0.675 (3rd place)\n\n\nCode is a bit dirty, the clean version is available on [GitHub](https://github.com/TheoViel/kaggle_birdcall_identification)"},{"metadata":{},"cell_type":"markdown","source":"## Initialization"},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!pip install audiomentations pysndfx","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import os\nimport sys\n\nsys.path = [\n    '../input/bird-outputs/src/src/',\n] + sys.path\n\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nfrom sklearn.model_selection import *\n\npd.options.display.max_rows = 500\npd.options.display.max_columns = 500","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data"},{"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\"\nTEST_AUDIO_DIR = RAW_DATA / \"test_audio\"\n\nTRAIN_RESAMPLED_AUDIO_DIRS = [\n  INPUT_ROOT / \"birdsong-resampled-train-audio-{:0>2}\".format(i)  for i in range(5)\n]\n\ntrain = pd.read_csv(TRAIN_RESAMPLED_AUDIO_DIRS[0] / \"train_mod.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"resampled_infos = []\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            resampled_infos.append([ebird_d.name, wav_f.name, wav_f.as_posix()])\n            \ntrain_resampled_infos = pd.DataFrame(resampled_infos, columns=[\"ebird_code\", \"resampled_filename\", \"file_path\"])\n\ntrain_all = pd.merge(train, train_resampled_infos, on=[\"ebird_code\", \"resampled_filename\"], how=\"inner\")\ndf_train = train_all.copy()\n\nprint(f\"Successfully loaded {len(train_all)} resampled audios out of {len(train)}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_extra = pd.read_csv(INPUT_ROOT / \"xenoexternalwav0/train_extended.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EXTRA_RESAMPLED_AUDIO_DIRS = [INPUT_ROOT / f\"xenoexternalwav{i // 3}/external-xeno-wav-{i}\"  for i in range(5)]\n\nresampled_infos = []\nfor audio_d in EXTRA_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            resampled_infos.append([wav_f.name, wav_f.as_posix()])\n            \nextra_resampled_infos = pd.DataFrame(resampled_infos, columns=[\"ebird_code\", \"file_path\"]).sort_values(\"ebird_code\").reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_extra_ = pd.merge(df_extra, extra_resampled_infos, on=[\"ebird_code\"], how=\"left\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"paths = []\nfor c, file in df_extra_[[\"file_path\", \"filename\"]].values:\n    path = f\"{c}/{file[:-4]}.wav\"\n    paths.append(path)\ndf_extra[\"file_path\"] = paths","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# df_extra = df_extra[df_extra['duration'] < 200]  # remove long samples to save time","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Params"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import os\nimport torch\nimport warnings\nimport numpy as np\n\n\nwarnings.simplefilter(action=\"ignore\", category=UserWarning)\nwarnings.simplefilter(action=\"ignore\", category=FutureWarning)\n\nSEED = 2020\n\nDATA_PATH = \"../input/birdsong-recognition/\"\nAUDIO_PATH = \"../input/birdsong-recognition/train_audio/\"\n\nBACKGROUND_PATH = \"../input/bird-backgrounds/\"\n\nMEAN = np.array([0.485, 0.456, 0.406])\nSTD = np.array([0.229, 0.224, 0.225])\n\nNUM_WORKERS = 4\nVAL_BS = 32\n\nDEVICE = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\n\n\nCLASSES = sorted(os.listdir(AUDIO_PATH))\nNUM_CLASSES = len(CLASSES)\n\nCP_TODAY = \"\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Utils"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import os\nimport torch\nimport random\nimport numpy as np\nimport torch.nn as nn\nfrom sklearn.metrics import f1_score\n\n\ndef seed_everything(seed):\n    \"\"\"\n    Seeds basic parameters for reproductibility of results\n    \n    Arguments:\n        seed {int} -- Number of the seed\n    \"\"\"\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True  # False\n\n\ndef save_model_weights(model, filename, verbose=1, cp_folder=\"\"):\n    \"\"\"\n    Saves the weights of a PyTorch model\n    \n    Arguments:\n        model {torch module} -- Model to save the weights of\n        filename {str} -- Name of the checkpoint\n    \n    Keyword Arguments:\n        verbose {int} -- Whether to display infos (default: {1})\n        cp_folder {str} -- Folder to save to (default: {''})\n    \"\"\"\n    if verbose:\n        print(f\"\\n -> Saving weights to {os.path.join(cp_folder, filename)}\\n\")\n    torch.save(model.state_dict(), os.path.join(cp_folder, filename))\n\n\ndef load_model_weights(model, filename, verbose=1, cp_folder=\"\"):\n    \"\"\"\n    Loads the weights of a PyTorch model. The exception handles cpu/gpu incompatibilities\n    \n    Arguments:\n        model {torch module} -- Model to load the weights to\n        filename {str} -- Name of the checkpoint\n    \n    Keyword Arguments:\n        verbose {int} -- Whether to display infos (default: {1})\n        cp_folder {str} -- Folder to load from (default: {''})\n    \n    Returns:\n        torch module -- Model with loaded weights\n    \"\"\"\n    if verbose:\n        print(f\"\\n -> Loading weights from {os.path.join(cp_folder,filename)}\\n\")\n    try:\n        model.load_state_dict(os.path.join(cp_folder, filename), strict=strict)\n    except BaseException:\n        model.load_state_dict(\n            torch.load(os.path.join(cp_folder, filename), map_location=\"cpu\"),\n            strict=True,\n        )\n    return model\n\n\ndef count_parameters(model, all=False):\n    \"\"\"\n    Count the parameters of a model\n    \n    Arguments:\n        model {torch module} -- Model to count the parameters of\n    \n    Keyword Arguments:\n        all {bool} -- Whether to include not trainable parameters in the sum (default: {False})\n    \n    Returns:\n        int -- Number of parameters\n    \"\"\"\n    if all:\n        return sum(p.numel() for p in model.parameters())\n    else:\n        return sum(p.numel() for p in model.parameters() if p.requires_grad)\n\n\nONE_HOT = np.eye(NUM_CLASSES)\n\n\ndef f1(truth, pred, threshold=0.5, avg=\"samples\"):\n\n    if len(truth.shape) == 1:\n        truth = ONE_HOT[truth]\n\n    pred = (pred > threshold).astype(int)\n\n    return f1_score(truth, pred, average=avg)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Transforms"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import cv2\nimport pysndfx\nimport numpy as np\nfrom audiomentations import *\n\n\ndef mono_to_color(X, eps=1e-6, mean=None, std=None):\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\n\n\ndef resize(image, size=None):\n    if size is not None:\n        h, w, _ = image.shape\n        new_w, new_h = int(w * size / h), size\n        image = cv2.resize(image, (new_w, new_h))\n\n    return image\n\n\ndef normalize(image, mean=None, std=None):\n    image = image / 255.0\n    if mean is not None and std is not None:\n        image = (image - mean) / std\n    return np.moveaxis(image, 2, 0).astype(np.float32)\n\n\ndef crop_or_pad(y, length, sr, train=True, probs=None):\n    # if len(y) > 0:\n    # y, _ = librosa.effects.trim(y) # trim, top_db=default(60)\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)\n\n\ndef get_wav_transforms():\n    transforms = Compose(\n        [\n            AddGaussianSNR(max_SNR=0.5, p=0.5),\n            AddBackgroundNoise(\n                sounds_path=BACKGROUND_PATH, min_snr_in_db=0, max_snr_in_db=2, p=0.5\n            ),\n        ]\n    )\n\n    return transforms\n\n\nclass AudioAugmentation:\n    def __init__(self, p_effects=0.5, p_noise=0.5):\n        self.p_effects = p_effects\n\n        self.noise_transfos = Compose(\n            [\n                AddGaussianSNR(max_SNR=0.5, p=p_noise),\n                AddBackgroundNoise(\n                    sounds_path=BACKGROUND_PATH, min_snr_in_db=0, max_snr_in_db=2, p=p_noise\n                ),\n            ]\n        )\n\n    def __call__(self, y, sr):\n        y = self.noise_transfos(y, sr)\n\n        if np.random.uniform() < self.p_effects:\n            effects_chain = (\n                pysndfx.AudioEffectsChain()\n                .reverb(\n                    reverberance=random.randrange(50),\n                    room_scale=random.randrange(50),\n                    stereo_depth=random.randrange(50),\n                )\n                .pitch(shift=random.randrange(-300, 300))\n                .overdrive(gain=random.randrange(2, 20))\n            )\n\n            y = effects_chain(y)\n\n        return y\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dataset"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import os\nimport pickle\nimport librosa\nimport soundfile\nimport numpy as np\nfrom torch.utils.data import Dataset\n\n\nONE_HOT = np.eye(len(CLASSES))\nCONF_PATH = \"../input/bird-outputs/preds_oof_2.pkl\"\nassert os.path.isfile(CONF_PATH)\n\n\ndef compute_melspec(y, params):\n    melspec = librosa.feature.melspectrogram(\n        y,\n        sr=params.sr,\n        n_mels=params.n_mels,\n        fmin=params.fmin,\n        fmax=params.fmax,\n    )\n\n    melspec = librosa.power_to_db(melspec).astype(np.float32)\n    return melspec\n\n\nclass BirdDataset(Dataset):\n    def __init__(self, df, params, audio_path=\"\", train=True, use_conf=False):\n        self.train = train\n        self.params = params\n        self.audio_path = audio_path\n\n        self.wav_transfos = get_wav_transforms() if train else None\n        # self.wav_transfos = AudioAugmentation(p_effects=0.5, p_noise=0.5) if train else None\n\n        self.spec_transfos = None\n\n        self.y = np.array([CLASSES.index(c) for c in df[\"ebird_code\"]])\n        self.paths = df[\"file_path\"].values\n\n        self.sample_len = params.duration * params.sr\n\n        self.use_conf = use_conf\n        if use_conf:\n            with open(CONF_PATH, \"rb\") as file:\n                self.confidences = pickle.load(file)\n\n    def __len__(self):\n        return len(self.paths)\n\n    def __getitem__(self, idx: int):\n        y, sr = soundfile.read(self.audio_path + self.paths[idx])\n\n        if self.use_conf:\n            name = \"/\".join(self.paths[idx].split('/')[-2:])\n            confs = self.confidences[name][:, self.y[idx]]\n            if len(confs):\n                confs = confs / np.sum(confs)\n            else:\n                confs = None\n        else:\n            confs = None\n\n        y = crop_or_pad(\n            y, self.sample_len, sr=self.params.sr, train=self.train, probs=confs\n        )\n\n        if self.wav_transfos is not None:\n            y = self.wav_transfos(y, self.params.sr)\n\n        melspec = compute_melspec(y, self.params)\n\n        if self.spec_transfos is not None:\n            melspec = self.spec_transfos(melspec)\n\n        image = mono_to_color(melspec)\n        image = resize(image, self.params.img_size)\n        image = normalize(image, mean=None, std=None)\n\n        return image, ONE_HOT[self.y[idx]]\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import torch\n\n\ndef get_model(name, use_msd=False, num_classes=1):\n\n    model = torch.hub.load('pytorch/vision:v0.6.0', name, pretrained=True)\n            \n    nb_ft = model.fc.in_features\n    del model.fc\n    model.fc = nn.Linear(nb_ft, num_classes)\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import gc\nimport time\nimport torch\nimport numpy as np\nimport torch.nn as nn\n\nfrom tqdm import tqdm\nfrom torch.optim import Adam\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data.sampler import RandomSampler\nfrom transformers import get_linear_schedule_with_warmup\nfrom torchvision.models.inception import InceptionOutputs\n\n# from util import f1\nfrom training.mixup import mixup_data\n# from params import NUM_WORKERS, NUM_CLASSES\nfrom training.specaugment import SpecAugmentation\n\n\ndef smooth_label(y , alpha=0.01):\n    y = y * (1 - alpha)\n    y[y == 0] = alpha\n    return y\n\n    \ndef fit(\n    model,\n    train_dataset,\n    val_dataset,\n    epochs=50,\n    batch_size=32,\n    val_bs=32,\n    warmup_prop=0.1,\n    lr=1e-3,\n    alpha=0.4,\n    mixup_proba=0.0,\n    specaugment_proba=0.0,\n    label_smoothing=0.0,\n    verbose=1,\n    verbose_eval=1,\n):\n    \"\"\"\n    Usual torch fit function\n    \n    Arguments:\n        model {torch model} -- Model to train\n        train_dataset {torch dataset} -- Dataset to train with\n        val_dataset {torch dataset} -- Dataset to validate with\n    \n    Keyword Arguments:\n        epochs {int} -- Number of epochs (default: {50})\n        batch_size {int} -- Training batch size (default: {32})\n        val_bs {int} -- Validation batch size (default: {32})\n        warmup_prop {float} -- Warmup proportion (default: {0.1})\n        lr {float} -- Start (or maximum) learning rate (default: {1e-3})\n        alpha {float} -- alpha value for mixup (default: {0.4})\n        mixup_proba {float} -- Probability to apply mixup (default: {0.})\n        specaugment_proba {float} -- Probability to apply specaugment (default: {0.})\n        verbose {int} -- Period (in epochs) to display logs at (default: {1})\n        verbose_eval {int} -- Period (in epochs) to perform evaluation at (default: {1})\n\n    Returns:\n        numpy array -- Predictions at the last epoch\n    \"\"\"\n\n    avg_val_loss = 0.\n    avg_loss = 0.\n    score = 0.\n\n    optimizer = Adam(model.parameters(), lr=lr)\n\n    loss_fct = nn.BCEWithLogitsLoss(reduction=\"mean\").cuda()\n\n    spec_augmenter = SpecAugmentation(\n        time_drop_width=16, time_stripes_num=2, freq_drop_width=8, freq_stripes_num=2\n    )\n\n    train_loader = DataLoader(\n        train_dataset,\n        batch_size=batch_size,\n        shuffle=True,\n        drop_last=True,\n        pin_memory=True,\n        num_workers=NUM_WORKERS,\n    )\n    val_loader = DataLoader(\n        val_dataset, batch_size=val_bs, shuffle=False, pin_memory=True, num_workers=NUM_WORKERS\n    )\n\n    num_warmup_steps = int(warmup_prop * epochs * len(train_loader))\n    num_training_steps = int(epochs * len(train_loader))\n    scheduler = get_linear_schedule_with_warmup(\n        optimizer, num_warmup_steps, num_training_steps\n    )\n\n    for epoch in range(epochs):\n        model.train()\n        start_time = time.time()\n        optimizer.zero_grad()\n\n        avg_loss = 0\n        for step, (x, y_batch) in enumerate(train_loader):\n            if specaugment_proba:\n                if np.random.rand() < specaugment_proba:\n                    x = spec_augmenter(x)\n\n            if np.random.rand() < mixup_proba:\n                x, y_a, y_b, _ = mixup_data(x.cuda(), y_batch.cuda(), alpha=alpha)\n                y_batch = torch.clamp(y_a + y_b, 0, 1)\n\n            # if label_smoothing:\n            #     y_batch = smooth_label(y_batch, alpha=label_smoothing)\n\n            y_pred = model(x.cuda())\n\n            # if type(y_pred) == InceptionOutputs:\n            #     y_pred = y_pred.logits\n\n            loss = loss_fct(y_pred, y_batch.cuda().float())\n\n            loss.backward()\n            avg_loss += loss.item() / len(train_loader)\n\n            optimizer.step()\n            optimizer.zero_grad()\n            scheduler.step()\n\n        if (epoch + 1) % verbose_eval == 0 or (epoch + 1 == epochs):\n            model.eval()\n\n            avg_val_loss = 0.0\n            with torch.no_grad():\n                preds = np.empty((0, NUM_CLASSES))\n                for x, y_batch in val_loader:\n                    y_pred = model(x.cuda()).detach()\n                    loss = loss_fct(y_pred, y_batch.cuda().float())\n                    avg_val_loss += loss.item() / len(val_loader)\n\n                    preds = np.concatenate([preds, torch.sigmoid(y_pred).cpu().numpy()])\n\n            micro_f1 = f1(val_dataset.y, preds, avg=\"micro\")\n            samples_f1 = f1(val_dataset.y, preds)\n\n        elapsed_time = time.time() - start_time\n        if (epoch + 1) % verbose == 0:\n            elapsed_time = elapsed_time * verbose\n            lr = scheduler.get_lr()[0]\n            print(\n                f\"Epoch {epoch + 1}/{epochs} \\t lr={lr:.1e} \\t t={elapsed_time:.0f}s  \\t loss={avg_loss:.4f} \\t \",\n                end=\"\",\n            )\n            if (epoch + 1) % verbose_eval == 0 or (epoch + 1 == epochs):\n                print(\n                    f\"val_loss={avg_val_loss:.4f} \\t micro_f1={micro_f1:.3f} \\t samples_f1={samples_f1:.3f}\"\n                )\n            else:\n                print(\"\")\n\n    torch.cuda.empty_cache()\n    return preds\n\n\ndef predict(model, dataset, batch_size=64):\n    \"\"\"\n    Usual torch predict function\n\n    Arguments:\n        model {torch model} -- Model to predict with\n        dataset {torch dataset} -- Dataset to predict with on\n\n    Keyword Arguments:\n        batch_size {int} -- Batch size (default: {32})\n\n    Returns:\n        numpy array -- Predictions\n    \"\"\"\n    model.eval()\n    preds = np.empty((0, NUM_CLASSES))\n\n    loader = DataLoader(\n        dataset, batch_size=batch_size, shuffle=False, pin_memory=True, num_workers=NUM_WORKERS\n    )\n    with torch.no_grad():\n        for x, _ in loader:\n            y_pred = model(x.cuda()).detach()\n            preds = np.concatenate([preds, torch.sigmoid(y_pred).cpu().numpy()])\n\n    return preds\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Main"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def train(config, df_train, df_val, fold):\n\n    print(f\"    -> {len(df_train)} training birds\")\n    print(f\"    -> {len(df_val)} validation birds\")\n\n    seed_everything(config.seed)\n\n    model = get_model(\n        config.selected_model, use_msd=config.use_msd, num_classes=NUM_CLASSES\n    ).cuda()\n    model.zero_grad()\n\n    train_dataset = BirdDataset(\n        df_train, AudioParams, audio_path=\"\", use_conf=config.use_conf\n    )\n    val_dataset = BirdDataset(df_val, AudioParams, audio_path=\"\", train=False)\n\n    n_parameters = count_parameters(model)\n    print(f\"    -> {n_parameters} trainable parameters\\n\")\n\n    pred_val = fit(\n        model,\n        train_dataset,\n        val_dataset,\n        epochs=config.epochs,\n        batch_size=config.batch_size,\n        val_bs=config.val_bs,\n        lr=config.lr,\n        warmup_prop=config.warmup_prop,\n        alpha=config.alpha,\n        mixup_proba=config.mixup_proba,\n        specaugment_proba=config.specaugment_proba,\n        label_smoothing=config.label_smoothing,\n        verbose_eval=config.verbose_eval,\n    )\n\n    if config.save:\n        save_model_weights(\n            model,\n            f\"{config.selected_model}_{config.name}_{fold}.pt\",\n            cp_folder=CP_TODAY,\n        )\n\n    return pred_val\n\n\ndef k_fold(config, df, df_extra=None):\n\n    skf = StratifiedKFold(n_splits=config.k, random_state=config.random_state)\n    splits = list(skf.split(X=df, y=df[\"ebird_code\"]))\n\n    pred_oof = np.zeros((len(df), NUM_CLASSES))\n\n    for i, (train_idx, val_idx) in enumerate(splits):\n        if i in config.selected_folds:\n            print(f\"\\n-------------   Fold {i + 1} / {config.k}  -------------\\n\")\n\n            df_train = df.iloc[train_idx].copy()\n            df_val = df.iloc[val_idx].copy()\n\n            if df_extra is not None:\n                df_train = pd.concat((df_train, df_extra), 0).reset_index(drop=True)\n\n            pred_val = train(config, df_train, df_val, i)\n            pred_oof[val_idx] = pred_val\n\n    return pred_oof","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Config:\n    # General\n    seed = 2020\n    verbose = 1\n    verbose_eval = 31\n    save = True\n\n    # k-fold\n    k = 5\n    random_state = 42\n    selected_folds = [0] \n\n    # Model\n    selected_model = 'resnext50_32x4d'\n    \n    use_msd = False\n    use_conf = False\n    \n    img_size = None\n    batch_size = 64\n    epochs = 30\n    lr = 1e-3\n    warmup_prop = 0.05\n    val_bs = 64\n\n    label_smoothing = 0.\n    specaugment_proba = 0.\n    mixup_proba = 0.5\n    alpha = 5\n\n    name = \"extra\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class AudioParams:\n    sr = 32000\n    duration = 5\n    img_size = None\n\n    # Melspectrogram\n    n_mels = 128\n    fmin = 20\n    fmax = 16000","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_oof = k_fold(Config, df_train, df_extra)","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}