{"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 notebook uses model which was trained here:\nhttps://www.kaggle.com/takamichitoda/birdclef-starter-train-precomputed-spectrogram?scriptVersionId=59442176","metadata":{}},{"cell_type":"code","source":"!pip install /kaggle/input/timm-pytorch-image-models/pytorch-image-models-master/\n!pip install --no-deps /kaggle/input/evaluations/","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\nimport os\nimport librosa\nimport psutil\nimport random\n\nimport numpy as np\nimport pandas as pd\nimport soundfile as sf\n\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm as tqdm_notebook\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import precision_recall_fscore_support\nfrom sklearn.metrics import f1_score\nfrom sklearn.metrics import average_precision_score\n\nimport torch\nimport torch.nn as nn\nfrom torch.nn import functional as F\nfrom torch.optim import Adam\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nfrom torchvision import transforms\nimport timm\nfrom pathlib import Path\n\nfrom evaluations.kaggle_2020 import row_wise_micro_averaged_f1_score\n\ndevice = torch.device(\"cuda\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class config:\n    INPUT_ROOT = \"/kaggle/input/birdclef-2021\"\n    WORK_ROOT = \"/kaggle/working\"\n    SAMPLING_RATE = 32000\n    FMIN = 20\n    FMAX = 16000\n    N_FFT = 2048\n    SPEC_HEIGHT = 128\n    SPEC_WIDTH= 40  # 5s * sr / N_FFT / 2\n    #SPEC_WIDTH = 313\n    IMAGE_WIDTH = 313\n    SEED = 416\n    BATCH_SIZE = 256\n    MODEL_NAME = \"resnet18\"\n    LEAENING_RATE = 1e-3\n    T_MAX = 10\n    NUM_EPOCHS = 10\n    N_ACCUMULATE = 1\n    DATA_N_LIMIT = 100","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def set_seed(seed):\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.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_metadata_df = pd.read_csv(f\"{config.INPUT_ROOT}/train_metadata.csv\")\nprimary_labels = train_metadata_df[\"primary_label\"].unique()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST = (len(list(Path(f\"{config.INPUT_ROOT}/test_soundscapes/\").glob(\"*.ogg\"))) != 0)\nif TEST:\n    DATADIR = Path(f\"{config.INPUT_ROOT}/test_soundscapes/\")\n    test_df = pd.read_csv(f\"{config.INPUT_ROOT}/test.csv\")\n    test_df[\"birds\"] = \"nocall\"\nelse:\n    DATADIR = Path(f\"{config.INPUT_ROOT}/train_soundscapes/\")\n    test_df = pd.read_csv(f\"{config.INPUT_ROOT}/train_soundscape_labels.csv\")\n    \nall_audios = list(DATADIR.glob(\"*.ogg\"))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MODEL_HEADER_INFO = {\n    \"resnet18\": (-2, 512)\n}\n\ndef interpolate(x: torch.Tensor, ratio: int):\n    x = x.transpose(1, 2)\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    upsampled = upsampled.transpose(1, 2)\n    return upsampled\n\n\nclass BirdCLEFNet(nn.Module):\n    def __init__(self, model_name):\n        super(BirdCLEFNet, self).__init__()\n        self.model_name = model_name\n        self.n_label = 397\n\n        base_model = timm.create_model(model_name, pretrained=False)\n        h_idx, n_dense = MODEL_HEADER_INFO[model_name]        \n        self.model_head = nn.Sequential(*list(base_model.children())[:h_idx])\n                \n        self.fc_a = nn.Conv1d(n_dense, self.n_label, 1)\n        self.fc_b = nn.Conv1d(n_dense, self.n_label, 1)\n\n    def forward(self, x):  # input x: (batch, channel, Hz, time)\n        frames_num = x.shape[3]\n        x = x.transpose(3, 2)  # (batch, channel, time, Hz)\n        h = self.model_head(x)  # (batch, unit, time, Hz)\n        \n        h = F.relu(h)\n        ti_pool = torch.mean(h, dim=3)  # (batch, unit, time)\n\n        # channel smoothing\n        x1 = F.max_pool1d(ti_pool, kernel_size=3, stride=1, padding=1)\n        x2 = F.avg_pool1d(ti_pool, kernel_size=3, stride=1, padding=1)\n        ti_pool = x1 + x2\n        \n        xa = self.fc_a(ti_pool)  # (batch, n_class, time)\n        xb = self.fc_b(ti_pool)  # (batch, n_class, time)\n        xb = torch.softmax(xb, dim=2)\n\n        # time pool\n        clipwise_output = torch.sum(xa * xb, dim=2)\n        segmentwise_output= interpolate(xa, 32)\n\n        return {\n            \"clipwise_output\": clipwise_output,\n            \"segmentwise_output\": segmentwise_output,\n        }","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mono_to_color(\n    X: np.ndarray, mean=None, std=None,\n    norm_max=None, norm_min=None, eps=1e-6\n):\n    # Stack X as [X,X,X]\n    X = np.stack([X, X, X], axis=-1)\n\n    # Standardize\n    mean = mean or X.mean()\n    X = X - mean\n    std = std or X.std()\n    Xstd = X / (std + eps)\n    _min, _max = Xstd.min(), Xstd.max()\n    norm_max = norm_max or _max\n    norm_min = norm_min or _min\n    if (_max - _min) > eps:\n        # Normalize to [0, 255]\n        V = Xstd\n        V[V < norm_min] = norm_min\n        V[V > norm_max] = norm_max\n        V = 255 * (V - norm_min) / (norm_max - norm_min)\n        V = V.astype(np.uint8)\n    else:\n        # Just zero\n        V = np.zeros_like(Xstd, dtype=np.uint8)\n    return V\n\nclass TestDataset(torch.utils.data.Dataset):\n    def __init__(self, all_audios):\n        self.all_audios = all_audios\n        \n        self.to_tensor = transforms.ToTensor()\n        self.norm = transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))\n\n    def __len__(self):\n        return len(self.all_audios)\n    \n    def __getitem__(self, idx):\n        audio_path = self.all_audios[idx]\n        audio_id, site, _ = audio_path.name.split(\"_\")\n        clip, samplerate = sf.read(audio_path)\n        \n        mel_specs, row_ids = [], []\n        for tail_s in range(5, 605, 5):\n            head_s = tail_s - 5\n            _clip = clip[head_s*config.SAMPLING_RATE:tail_s*config.SAMPLING_RATE]\n            mel_spec = librosa.feature.melspectrogram(y=_clip, \n                                                      sr=config.SAMPLING_RATE, \n                                                      n_fft=config.N_FFT, \n                                                      n_mels=config.SPEC_HEIGHT, \n                                                      fmin=config.FMIN, \n                                                      fmax=config.FMAX)\n            mel_spec = librosa.power_to_db(mel_spec, ref=np.max)\n            \n            mel_spec = mono_to_color(mel_spec)\n            mel_spec = self.to_tensor(mel_spec)\n            mel_spec = self.norm(mel_spec)\n            \n            mel_specs.append(mel_spec)\n            row_ids.append(f\"{audio_id}_{site}_{tail_s}\")\n            \n        mel_specs = torch.stack(mel_specs)\n        return mel_specs, row_ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = BirdCLEFNet(config.MODEL_NAME)\nmodel.to(device)\nmodel.eval()\npath = \"/kaggle/input/birdclef-starter-train-precomputed-spectrogram/birdclefnet_f0_last_model.bin\"\nckpt = torch.load(path, map_location=\"cpu\")\nmodel.load_state_dict(ckpt)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"THRESHOLD = 0.5\n\nres_dfs = []\ndset = TestDataset(all_audios)\nfor mel_specs, row_ids in tqdm_notebook(dset):\n    X = mel_specs.to(device)\n    with torch.no_grad():\n        outputs = model(X)\n    clipwise_output = outputs[\"clipwise_output\"].sigmoid().cpu()\n    \n    predict_labels = [list(primary_labels[posi.numpy()]) for posi in clipwise_output > THRESHOLD]\n    predict_labels = [\" \".join(i) if len(i) != 0 else \"nocall\" for i in predict_labels]\n    \n    res_df = pd.DataFrame(zip(row_ids, predict_labels), columns=[\"row_id\", \"birds\"])\n    res_dfs.append(res_df)\n    \nsubmission_df = pd.concat(res_dfs, axis=0)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rows = []\nfor row_id in test_df[\"row_id\"]:\n    row = submission_df.query(f\"row_id=='{row_id}'\")\n    rows.append(row)\nsubmission_df = pd.concat(rows).reset_index(drop=True)\nsubmission_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_true = test_df[\"birds\"].tolist()\ny_pred = submission_df[\"birds\"].tolist()\nlocal_score = row_wise_micro_averaged_f1_score(y_true, y_pred)\nprint(local_score)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=None)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.read_csv(\"submission.csv\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}