{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!pip uninstall torch --y\n!pip uninstall torchaudio --y","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2020-08-11T09:45:24.805587Z","iopub.status.busy":"2020-08-11T09:45:24.80465Z","iopub.status.idle":"2020-08-11T09:45:28.87251Z","shell.execute_reply":"2020-08-11T09:45:28.871377Z"},"papermill":{"duration":4.091991,"end_time":"2020-08-11T09:45:28.872641","exception":false,"start_time":"2020-08-11T09:45:24.78065","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Newest torch required for tracing. Torchaudio for data loading\n!pip install ../input/pytorch-160-with-torchvision-070/torch-1.6.0cu101-cp37-cp37m-linux_x86_64.whl\n!pip install ../input/torchaudio/torchaudio-0.6.0-cp37-cp37m-manylinux1_x86_64.whl\n# !pip install ../input/bird-panns/torchlibrosa-master/torchlibrosa-master/ > /dev/null\n\nimport os\nimport gc\nimport time\nimport math\nimport shutil\nimport random\nimport warnings\nimport typing as tp\nfrom pathlib import Path\nfrom contextlib import contextmanager\n\nimport yaml\nfrom joblib import delayed, Parallel\n\nimport cv2\nimport librosa\nimport audioread\nimport soundfile as sf\n\nimport numpy as np\nimport pandas as pd\n\nfrom fastprogress import progress_bar\nfrom sklearn.metrics import f1_score\nfrom sklearn.model_selection import StratifiedKFold\n\nimport torch\nimport torchaudio\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.nn import Conv2d, Module, Linear, BatchNorm2d, ReLU\nfrom torch.nn.modules.utils import _pair\nimport torch.utils.data as data\nfrom torchlibrosa.stft import Spectrogram, LogmelFilterBank\nfrom torchlibrosa.augmentation import SpecAugmentation\n#from efficientnet_pytorch import EfficientNet\n\n\npd.options.display.max_rows = 500\npd.options.display.max_columns = 500","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"args = {\n    'n_mels': 224,\n    'hop_length': 384,\n    'std_sr': 32000,\n    'threshold': .5,\n    'model': '../input/birdweights/c3_10_42.pt',  # c2__17.pt c2_9_18.pt, c2_0_41.pt\n}\nmodel = torch.jit.load(args['model'], map_location='cpu').cuda()\nmodel.eval();\n\nroot = os.path.join('../input', \"birdsong-recognition\")\n# TRAIN_AUDIO_DIR = RAW_DATA / \"train_audio\"\ntest_dir = os.path.join(root, 'test_audio')\nprint(test_dir)\n\nif os.path.isdir(test_dir):\n    print('Running actual submission!')\n    test_df = pd.read_csv(os.path.join(root, 'test.csv'))\n    sub = pd.read_csv(\"../input/birdsong-recognition/sample_submission.csv\")\nelse:\n    print('Running debug submission')\n    test_dir = os.path.join('../input', 'birdcall-check', 'test_audio')\n    test_df = pd.read_csv(os.path.join('../input', 'birdcall-check', 'test.csv'))\n    sub = pd.read_csv('../input/inference-pytorch-birdcall-resnet-baseline/submission.csv')\n    print('Naturally no test dir found')\nsub.to_csv(\"submission.csv\", index=False)  # this will be overwritten if everything goes well. Hmnmm. will it?","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"execution":{"iopub.execute_input":"2020-08-11T09:45:29.471784Z","iopub.status.busy":"2020-08-11T09:45:29.470935Z","iopub.status.idle":"2020-08-11T09:45:29.474035Z","shell.execute_reply":"2020-08-11T09:45:29.474607Z"},"papermill":{"duration":0.04791,"end_time":"2020-08-11T09:45:29.474766","exception":false,"start_time":"2020-08-11T09:45:29.426856","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"BIRD_CODE = {\n    'aldfly': 0, 'ameavo': 1, 'amebit': 2, 'amecro': 3, 'amegfi': 4,\n    'amekes': 5, 'amepip': 6, 'amered': 7, 'amerob': 8, 'amewig': 9,\n    'amewoo': 10, 'amtspa': 11, 'annhum': 12, 'astfly': 13, 'baisan': 14,\n    'baleag': 15, 'balori': 16, 'banswa': 17, 'barswa': 18, 'bawwar': 19,\n    'belkin1': 20, 'belspa2': 21, 'bewwre': 22, 'bkbcuc': 23, 'bkbmag1': 24,\n    'bkbwar': 25, 'bkcchi': 26, 'bkchum': 27, 'bkhgro': 28, 'bkpwar': 29,\n    'bktspa': 30, 'blkpho': 31, 'blugrb1': 32, 'blujay': 33, 'bnhcow': 34,\n    'boboli': 35, 'bongul': 36, 'brdowl': 37, 'brebla': 38, 'brespa': 39,\n    'brncre': 40, 'brnthr': 41, 'brthum': 42, 'brwhaw': 43, 'btbwar': 44,\n    'btnwar': 45, 'btywar': 46, 'buffle': 47, 'buggna': 48, 'buhvir': 49,\n    'bulori': 50, 'bushti': 51, 'buwtea': 52, 'buwwar': 53, 'cacwre': 54,\n    'calgul': 55, 'calqua': 56, 'camwar': 57, 'cangoo': 58, 'canwar': 59,\n    'canwre': 60, 'carwre': 61, 'casfin': 62, 'caster1': 63, 'casvir': 64,\n    'cedwax': 65, 'chispa': 66, 'chiswi': 67, 'chswar': 68, 'chukar': 69,\n    'clanut': 70, 'cliswa': 71, 'comgol': 72, 'comgra': 73, 'comloo': 74,\n    'commer': 75, 'comnig': 76, 'comrav': 77, 'comred': 78, 'comter': 79,\n    'comyel': 80, 'coohaw': 81, 'coshum': 82, 'cowscj1': 83, 'daejun': 84,\n    'doccor': 85, 'dowwoo': 86, 'dusfly': 87, 'eargre': 88, 'easblu': 89,\n    'easkin': 90, 'easmea': 91, 'easpho': 92, 'eastow': 93, 'eawpew': 94,\n    'eucdov': 95, 'eursta': 96, 'evegro': 97, 'fiespa': 98, 'fiscro': 99,\n    'foxspa': 100, 'gadwal': 101, 'gcrfin': 102, 'gnttow': 103, 'gnwtea': 104,\n    'gockin': 105, 'gocspa': 106, 'goleag': 107, 'grbher3': 108, 'grcfly': 109,\n    'greegr': 110, 'greroa': 111, 'greyel': 112, 'grhowl': 113, 'grnher': 114,\n    'grtgra': 115, 'grycat': 116, 'gryfly': 117, 'haiwoo': 118, 'hamfly': 119,\n    'hergul': 120, 'herthr': 121, 'hoomer': 122, 'hoowar': 123, 'horgre': 124,\n    'horlar': 125, 'houfin': 126, 'houspa': 127, 'houwre': 128, 'indbun': 129,\n    'juntit1': 130, 'killde': 131, 'labwoo': 132, 'larspa': 133, 'lazbun': 134,\n    'leabit': 135, 'leafly': 136, 'leasan': 137, 'lecthr': 138, 'lesgol': 139,\n    'lesnig': 140, 'lesyel': 141, 'lewwoo': 142, 'linspa': 143, 'lobcur': 144,\n    'lobdow': 145, 'logshr': 146, 'lotduc': 147, 'louwat': 148, 'macwar': 149,\n    'magwar': 150, 'mallar3': 151, 'marwre': 152, 'merlin': 153, 'moublu': 154,\n    'mouchi': 155, 'moudov': 156, 'norcar': 157, 'norfli': 158, 'norhar2': 159,\n    'normoc': 160, 'norpar': 161, 'norpin': 162, 'norsho': 163, 'norwat': 164,\n    'nrwswa': 165, 'nutwoo': 166, 'olsfly': 167, 'orcwar': 168, 'osprey': 169,\n    'ovenbi1': 170, 'palwar': 171, 'pasfly': 172, 'pecsan': 173, 'perfal': 174,\n    'phaino': 175, 'pibgre': 176, 'pilwoo': 177, 'pingro': 178, 'pinjay': 179,\n    'pinsis': 180, 'pinwar': 181, 'plsvir': 182, 'prawar': 183, 'purfin': 184,\n    'pygnut': 185, 'rebmer': 186, 'rebnut': 187, 'rebsap': 188, 'rebwoo': 189,\n    'redcro': 190, 'redhea': 191, 'reevir1': 192, 'renpha': 193, 'reshaw': 194,\n    'rethaw': 195, 'rewbla': 196, 'ribgul': 197, 'rinduc': 198, 'robgro': 199,\n    'rocpig': 200, 'rocwre': 201, 'rthhum': 202, 'ruckin': 203, 'rudduc': 204,\n    'rufgro': 205, 'rufhum': 206, 'rusbla': 207, 'sagspa1': 208, 'sagthr': 209,\n    'savspa': 210, 'saypho': 211, 'scatan': 212, 'scoori': 213, 'semplo': 214,\n    'semsan': 215, 'sheowl': 216, 'shshaw': 217, 'snobun': 218, 'snogoo': 219,\n    'solsan': 220, 'sonspa': 221, 'sora': 222, 'sposan': 223, 'spotow': 224,\n    'stejay': 225, 'swahaw': 226, 'swaspa': 227, 'swathr': 228, 'treswa': 229,\n    'truswa': 230, 'tuftit': 231, 'tunswa': 232, 'veery': 233, 'vesspa': 234,\n    'vigswa': 235, 'warvir': 236, 'wesblu': 237, 'wesgre': 238, 'weskin': 239,\n    'wesmea': 240, 'wessan': 241, 'westan': 242, 'wewpew': 243, 'whbnut': 244,\n    'whcspa': 245, 'whfibi': 246, 'whtspa': 247, 'whtswi': 248, 'wilfly': 249,\n    'wilsni1': 250, 'wiltur': 251, 'winwre3': 252, 'wlswar': 253, 'wooduc': 254,\n    'wooscj2': 255, 'woothr': 256, 'y00475': 257, 'yebfly': 258, 'yebsap': 259,\n    'yehbla': 260, 'yelwar': 261, 'yerwar': 262, 'yetvir': 263\n}\n\nINV_BIRD_CODE = {v: k for k, v in BIRD_CODE.items()}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torchaudio.transforms import *\nfmin, fmax = 25, 11000\nf1 = MelSpectrogram(sample_rate=args['std_sr'], n_fft=1024, hop_length=args['hop_length'], f_min=fmin, f_max=fmax, n_mels=args['n_mels']).cuda()\nf2 = MelSpectrogram(sample_rate=args['std_sr'], n_fft=2048, hop_length=args['hop_length'], f_min=fmin, f_max=fmax, n_mels=args['n_mels']).cuda()\nf3 = MelSpectrogram(sample_rate=args['std_sr'], n_fft=4096, hop_length=args['hop_length'], f_min=fmin, f_max=fmax, n_mels=args['n_mels']).cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class TestDataset(data.Dataset):\n    def __init__(self, df, spectrogram):\n        self.df = df\n        self.spectrogram = spectrogram\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def normalize(self, spect):\n        spect = spect.contiguous()\n        miu = spect.view(spect.size(0), -1).mean(-1).unsqueeze(-1).unsqueeze(-1)\n        std = spect.view(spect.size(0), -1).std(-1).unsqueeze(-1).unsqueeze(-1) + 1e-8\n        return (spect - miu) / std / 2\n    \n    def __getitem__(self, idx):\n        sample = self.df.loc[idx, :]\n        site = sample.site\n        row_id = sample.row_id\n        \n        if site == \"site_3\":\n            y = self.spectrogram\n            len_y = y.shape[-1]\n            start = 0\n            end = args['std_sr'] * 5 // args['hop_length']\n            y_all = []\n            while len_y > start:\n                y_batch = self.normalize(y[:, :, start:end])\n                if end >= len_y:\n                    clip_length = args['std_sr'] * 5 // args['hop_length']\n                    y_batch = self.normalize(y[:, :, -clip_length:])\n                    y_all.append(y_batch)\n                    break\n                start = end\n                end = end + args['std_sr'] * 5 // args['hop_length']\n                y_all.append(y_batch)\n            y_all = torch.stack(y_all)\n            return y_all, row_id, site\n        else:\n            end_seconds = int(sample.seconds)\n            start_seconds = int(end_seconds - 5)\n            \n            start_index = args['std_sr'] * start_seconds // args['hop_length']\n            end_index = args['std_sr'] * end_seconds // args['hop_length']\n            \n            # Hmmm. so assuming the final index will always be less than length of whole sound file\n            y = self.spectrogram[:, :, start_index:end_index]\n            y = self.normalize(y)\n        return y, row_id, site\n    \n\ndef prediction_for_clip(dataset, threshold=0.5):\n    loader = data.DataLoader(dataset, batch_size=1, shuffle=False)\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    \n    model.eval()\n    prediction_dict = {}\n    for image, row_id, site in loader:\n        site = site[0]\n        row_id = row_id[0]\n        image = image.to(device).float()\n        if site in {\"site_1\", \"site_2\"}:\n            # print(row_id, image.shape)\n            image = image.to(device).float()\n            with torch.no_grad():\n                prediction = model(image)\n                proba = prediction.view(-1).sigmoid().cpu().numpy()\n\n            events = proba >= threshold\n            labels = np.argwhere(events).reshape(-1).tolist()\n        else:\n            # print(row_id, image.shape)\n            # to avoid prediction on large batch\n            image = image.squeeze(0)\n            batch_size = 16\n            whole_size = image.size(0)\n            if whole_size % batch_size == 0:\n                n_iter = whole_size // batch_size\n            else:\n                n_iter = whole_size // batch_size + 1\n                \n            all_events = set()\n            for batch_i in range(n_iter):\n                batch = image[batch_i * batch_size:(batch_i + 1) * batch_size]\n                if batch.ndim == 3:\n                    batch = batch.unsqueeze(0)\n\n                batch = batch.to(device)\n                with torch.no_grad():\n                    prediction = model(batch)\n                    proba = prediction.view(batch.size(0), -1).sigmoid().cpu().numpy()\n                    \n                events = proba >= threshold\n                for i in range(len(events)):\n                    event = events[i, :]\n                    labels = np.argwhere(event).reshape(-1).tolist()\n                    for label in labels:\n                        all_events.add(label)\n                        \n            labels = list(all_events)\n        if len(labels) == 0:\n            prediction_dict[row_id] = \"nocall\"\n        else:\n            labels_str_list = list(map(lambda x: INV_BIRD_CODE[x], labels))\n            label_string = \" \".join(labels_str_list)\n            prediction_dict[row_id] = label_string\n    return prediction_dict\n\n\nunique_audio_id = test_df.audio_id.unique()\nwarnings.filterwarnings(\"ignore\")\nprediction_dfs = []\nfor audio_id in progress_bar(unique_audio_id):\n    # Load the spectrogram\n    signal, sample_rate = torchaudio.load(os.path.join(test_dir, audio_id+'.mp3'))\n\n    signal = signal.mean(0).cuda()\n    signal = torchaudio.transforms.Resample(orig_freq=sample_rate, new_freq=args['std_sr'])(signal)\n    spectrogram = torch.log((torch.stack([f1(signal), f2(signal), f3(signal)], axis=0)) + 1e-8).half().float().cpu()\n\n    test_df_for_audio_id = test_df.query(\n        f\"audio_id == '{audio_id}'\").reset_index(drop=True)\n    dataset = TestDataset(test_df_for_audio_id, spectrogram)\n    prediction_dict = prediction_for_clip(dataset=dataset, threshold=args['threshold'])\n    row_id = list(prediction_dict.keys())\n    birds = list(prediction_dict.values())\n    prediction_df = pd.DataFrame({\n        \"row_id\": row_id,\n        \"birds\": birds\n    })\n    prediction_dfs.append(prediction_df)\n\nprediction_df = pd.concat(prediction_dfs, axis=0, sort=False).reset_index(drop=True)\nprediction_df['birds'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"prediction_df.to_csv('submission.csv', index=False)\nprediction_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"for i in range(len(prediction_df)):\n    if 'site_3' in prediction_df['row_id'].values[i]:\n        prediction_df.birds.values[i] = 'nocall'\nprediction_df.to_csv('submission.csv', index=False)\nprediction_df","execution_count":null}],"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}