{"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  resnest > /dev/null","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport librosa as lb\nimport pandas as pd\nfrom pathlib import Path\n\nimport torch\nfrom  torch.utils.data import Dataset, DataLoader\n\nfrom tqdm.notebook import tqdm\n\nfrom resnest.torch import resnest50","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_CLASSES = 24\nSR = 16_000\nDURATION =  60\nDATA_ROOT = Path(\"../input/rfcx-species-audio-detection\")\nTRAIN_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/train\")\nTEST_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/test\")\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MelSpecComputer:\n    def __init__(self, sr, n_mels, fmin, fmax):\n        self.sr = sr\n        self.n_mels = n_mels\n        self.fmin = fmin\n        self.fmax = fmax\n\n    def __call__(self, y):\n\n        melspec = lb.feature.melspectrogram(\n            y, sr=self.sr, n_mels=self.n_mels, fmin=self.fmin, fmax=self.fmax,\n        )\n\n        melspec = lb.power_to_db(melspec).astype(np.float32)\n        return melspec\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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 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, is_train=True):\n    if len(y) < length:\n        y = np.concatenate([y, np.zeros(length - len(y))])\n    elif len(y) > length:\n        if not is_train:\n            start = 0\n        else:\n            start = np.random.randint(len(y) - length)\n\n        y = y[start:start + length]\n\n    y = y.astype(np.float32, copy=False)\n\n    return y","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class RFCXDataset(Dataset):\n\n    def __init__(self, data, sr, n_mels=128, fmin=0, fmax=None,  is_train=False,\n                 num_classes=NUM_CLASSES, root=None, duration=DURATION):\n\n        self.data = data\n        \n        self.sr = sr\n        self.n_mels = n_mels\n        self.fmin = fmin\n        self.fmax = fmax or self.sr//2\n\n        self.is_train = is_train\n\n        self.num_classes = num_classes\n        self.duration = duration\n        self.audio_length = self.duration*self.sr\n        \n        self.root =  root or (TRAIN_AUDIO_ROOT if self.is_train else TEST_AUDIO_ROOT)\n\n        self.wav_transfos = get_wav_transforms() if self.is_train else None\n\n        self.mel_spec_computer = MelSpecComputer(sr=self.sr, n_mels=self.n_mels, fmin=self.fmin, fmax=self.fmax)\n\n\n    def __len__(self):\n        return len(self.data)\n    \n    def read_index(self, idx, fill_val=1.0, offset=None, use_offset=True):\n        d = self.data.iloc[idx]\n        record, species = d[\"recording_id\"], d[\"species_id\"]\n        try:\n            if use_offset and (self.duration < d[\"duration\"]+1):\n                offset = offset or np.random.uniform(1, int(d[\"duration\"]-self.duration))\n\n            y, _ = lb.load(self.root.joinpath(record).with_suffix(\".flac\").as_posix(),\n                           sr=self.sr, duration=self.duration, offset=offset)\n            \n            if self.wav_transfos is not None:\n                y = self.wav_transfos(y, self.sr)\n            y = crop_or_pad(y, self.audio_length, sr=self.sr)\n            t = np.zeros(self.num_classes)\n            t[species] = fill_val\n        except Exception as e:\n#             print(e)\n            raise ValueError()  from  e\n            y = np.zeros(self.audio_length)\n            t = np.zeros(self.num_classes)\n        \n        return y,t\n            \n        \n\n    def __getitem__(self, idx):\n\n        y, t = self.read_index(idx)\n        \n        \n        melspec = self.mel_spec_computer(y) \n        image = mono_to_color(melspec)\n        image = normalize(image, mean=None, std=None)\n\n        return image, t","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_duration(audio_name, root=TEST_AUDIO_ROOT):\n    return lb.get_duration(filename=root.joinpath(audio_name).with_suffix(\".flac\"))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = pd.DataFrame({\n    \"recording_id\": [path.stem for path in Path(TEST_AUDIO_ROOT).glob(\"*.flac\")],\n})\ndata[\"species_id\"] = [[] for _ in range(len(data))]\n\nprint(data.shape)\ndata[\"duration\"] = data[\"recording_id\"].apply(get_duration)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data[\"duration\"].hist()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ds = RFCXDataset(data=data, sr=SR, duration=10)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x, y = ds[0]\nx.shape, y.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_BATCH_SIZE = 40\nTEST_NUM_WORKERS = 2","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data = RFCXDataset(data=data, sr=SR)\ntest_loader = DataLoader(test_data, batch_size=TEST_BATCH_SIZE, num_workers=TEST_NUM_WORKERS)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nnet = resnest50(pretrained=True).to(device)\nn_features = net.fc.in_features\nnet.fc = torch.nn.Linear(n_features, NUM_CLASSES)\nnet = net.to(device)\nnet.load_state_dict(torch.load(\"../input/kkiller-rfcx-species-detection-public-checkpoints/rfcx_resnest50.pth\", map_location=device))\nnet = net.eval()\nnet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = []\nnet.eval()\nwith torch.no_grad():\n    for (xb, yb) in  tqdm(test_loader):\n        xb, yb = xb.to(device), yb.to(device)\n        o = net(xb)\n        o = torch.sigmoid(o) \n        preds.append(o.detach().cpu().numpy())\npreds = np.vstack(preds)\npreds.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.DataFrame(preds, columns=[f\"s{i}\" for i in range(24)])\nsub[\"recording_id\"] = data[\"recording_id\"].values[:len(sub)]\nsub = sub[[\"recording_id\"] + [f\"s{i}\" for i in range(24)]]\nprint(sub.shape)\nsub.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}