{"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/birdthirdlibs/timm-0.4.5-py3-none-any.whl","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport torch\nimport argparse\nimport random\nimport numpy as np\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params = {\n    'encoder' : {'tf_efficientnet_b0_ns':['../input/birdeb2baseline/fold_0_epoch_25.pth']},\n    'root_dir':'../input/birdclef-2021',\n    'sample_rate': 32000,\n    'window_size' : 2048,\n    'hop_size' : 512,\n    'mel_bins' : 128,\n    'fmin' : 20,\n    'fmax' : 16000,\n    'classes_num' : 397,\n    \"period\": 5,\n    'tta':1,\n    'batch_size':16,\n    'workers':16,\n}","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes = sorted(os.listdir(f\"{params['root_dir']}/train_short_audio/\"))\nclasses_maps = {idx:cls_ for idx, cls_ in enumerate(classes)}\ndef pred2label(preds):\n    labels = []\n    for p in preds:\n        idxs = np.argwhere(p).reshape(-1).tolist()\n        if len(idxs) == 0:\n            labels.append(\"nocall\")\n            continue\n        label = list(map(lambda x: classes_maps[x], idxs))\n        label = \" \".join(label)\n        labels.append(label)\n    return labels","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mono_to_color(X, eps=1e-6, mean=None, std=None):\n    \"\"\"\n    Converts a one channel array to a 3 channel one in [0, 255]\n\n    Arguments:\n        X {numpy array [H x W]} -- 2D array to convert\n\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\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\n    \ndef normalize(image, mean=None, std=None):\n    \"\"\"\n    Normalizes an array in [0, 255] to the format adapted to neural network\n\n    Arguments:\n        image {np array [3 x H x W]} -- [description]\n\n    Keyword Arguments:\n        mean {None or np array} -- Mean for normalization, expected of size 3 (default: {None})\n        std {None or np array} -- Std for normalization, expected of size 3 (default: {None})\n\n    Returns:\n        np array [H x W x 3] -- Normalized array\n    \"\"\"\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)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import librosa\nimport soundfile\nfrom torch.utils.data import Dataset, DataLoader\nclass TestDataset(Dataset):\n    def __init__(self, filepath, params,transforms = None):\n        audio, sr = soundfile.read(filepath)\n        if sr != params['sample_rate']:\n            audio = librosa.resample(audio, sr, params.sr,res_type=\"kaiser_fast\")\n        row_id, site, _ = filepath.split('/')[-1].split('_')\n        row_id = row_id+'_'+site+'_{}'\n        audio_len = len(audio)\n        step = params['period'] * params['sample_rate']\n        cnt = 0\n        audios = []\n        row_ids = []\n        for i in range(0, audio_len,  step):\n            cnt += 1\n            start = i\n            end = start + step\n            if end > audio_len:\n                break\n            audios.append(audio[start:end])\n            row_ids.append(row_id.format(cnt*5))\n\n        self.params = params\n        self.audios = audios\n        self.row_ids = row_ids\n        self.transforms = transforms\n\n    def __len__(self):\n        return len(self.row_ids)\n\n    def __getitem__(self, idx):\n        audio = self.audios[idx]\n        row_id = self.row_ids[idx]\n        if self.transforms:\n            audio = self.transforms(samples=audio, sample_rate=sr)\n        \n        melspec = librosa.feature.melspectrogram(audio, sr=self.params['sample_rate'], n_mels=self.params['mel_bins'], \n                                                 fmin=self.params['fmin'], fmax=self.params['fmax'])\n        melspec = librosa.power_to_db(melspec).astype(np.float32)\n        \n        image = mono_to_color(melspec)\n        image = normalize(image, mean=None, std=None)\n        return image, row_id","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn as nn\nfrom timm import create_model\nclass BirdAudioClassifier(nn.Module):\n    def __init__(self,encoder,classes_num):\n        super().__init__()\n        self.encoder = create_model(model_name = encoder,num_classes = classes_num,in_chans = 3)    \n    def forward(self, input):\n        x = self.encoder(input)\n        return x","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def createModels(params):\n    models = []\n    for modeName in params['encoder'].keys():\n        model = BirdAudioClassifier(modeName,params['classes_num'])\n        model.cuda()\n        for modelPath in params['encoder'][modeName]:\n            model.load_state_dict(torch.load(modelPath))\n            models.append(model)\n            print(modeName + ' ' + modelPath + 'Load Done!!!')\n    return models","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def modelpredict(model,input):\n    with torch.no_grad():\n        pred = model(input.cuda())\n        pred = torch.sigmoid(pred).cpu().numpy()\n    return pred","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def infetenceOneFile(filepath,model,params):\n    preds = np.empty((0, params['classes_num']))\n    row_ids = []\n    testDataset = TestDataset(filepath, params)\n    tst_loader = DataLoader(testDataset, batch_size=params['batch_size'], shuffle=False, num_workers=params['workers'],   pin_memory=True)\n    for idx, (img, row_id) in enumerate(tst_loader):\n        row_ids += row_id\n        pred = modelpredict(model,img)\n        preds = np.concatenate([preds,pred])\n    return preds,row_ids","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\nfrom tqdm.notebook import tqdm\nsubmission = {\"row_id\":[], \"birds\":[]}\nmodels = createModels(params)\nroot_dir = params['root_dir']\nif len(glob.glob(os.path.join(f'{root_dir}/test_soundscapes/', '*.ogg'))):\n    testpath = f'{root_dir}/test_soundscapes/'\nelse:\n    testpath = f'{root_dir}/train_soundscapes/'\n\nfor filepath in tqdm(sorted(glob.glob(os.path.join(testpath, '*.ogg')))):\n    preds = []\n    for model in models:\n        model.eval()\n        for i in range(params['tta']):\n            pred,row_ids = infetenceOneFile(filepath,model,params)\n            preds.append(pred)\n    preds = np.array(preds)\n    preds = np.sum(preds,axis=0)\n    preds /= (len(models) * params['tta'])\n    preds = preds > 0.5\n    submission[\"birds\"] = np.append(submission[\"birds\"], pred2label(preds))\n    submission[\"row_id\"] = np.append(submission[\"row_id\"], row_ids)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame(submission)\nsubmission.head()\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{},"execution_count":null,"outputs":[]}]}