{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":25954,"databundleVersionId":2091745,"sourceType":"competition"},{"sourceId":1297722,"sourceType":"datasetVersion","datasetId":750498},{"sourceId":2130303,"sourceType":"datasetVersion","datasetId":1278322}],"dockerImageVersionId":31193,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":140.670377,"end_time":"2024-11-25T21:19:44.704503","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-11-25T21:17:24.034126","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"копирование и установка пакета","metadata":{}},{"cell_type":"code","source":"import shutil\nimport os\n\nshutil.copytree('../input/resnest50-fast-package/resnest-0.0.6b20200701/resnest', 'resnet', dirs_exist_ok=True)\nos.system('pip install \"./resnet\" --no-deps')\nimport os\nimport numpy as np\nimport pandas as pd\nimport librosa\nimport torch\nimport math\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset\nfrom resnest.torch import resnest50\nfrom sklearn.preprocessing import LabelEncoder","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:43.309442Z","iopub.execute_input":"2025-11-24T17:44:43.309666Z","iopub.status.idle":"2025-11-24T17:44:51.944001Z","shell.execute_reply.started":"2025-11-24T17:44:43.309642Z","shell.execute_reply":"2025-11-24T17:44:51.943436Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Получение входных данных","metadata":{}},{"cell_type":"code","source":"PATH_TEST = \"../input/birdclef-2021/test_soundscapes\"\nPATH_TRAIN = \"../input/birdclef-2021/train_soundscapes\"\n\nmeta = pd.read_csv(\"../input/birdclef-2021/test.csv\")\n\naudio_root = PATH_TEST\nif meta.shape[0] < 5:\n    meta = pd.read_csv(\"../input/birdclef-2021/train_soundscape_labels.csv\")\n    audio_root = PATH_TRAIN\n\nprint(meta.shape)\ndisplay(meta.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:51.945044Z","iopub.execute_input":"2025-11-24T17:44:51.945427Z","iopub.status.idle":"2025-11-24T17:44:51.982022Z","shell.execute_reply.started":"2025-11-24T17:44:51.945383Z","shell.execute_reply":"2025-11-24T17:44:51.981512Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"кеши","metadata":{}},{"cell_type":"code","source":"audio_buf = {}\nsections_buf = {}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:51.982702Z","iopub.execute_input":"2025-11-24T17:44:51.982961Z","iopub.status.idle":"2025-11-24T17:44:51.986543Z","shell.execute_reply.started":"2025-11-24T17:44:51.982938Z","shell.execute_reply":"2025-11-24T17:44:51.985859Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Функции чтения аудиофайлов","metadata":{}},{"cell_type":"code","source":"def load_full_clip(ds, idx, target_rate=None):\n    tag = f\"{idx}_{ds}\"\n    if tag in audio_buf:\n        return audio_buf[tag]\n\n    file_found = None\n    for fname in os.listdir(audio_root):\n        if fname.startswith(tag):\n            file_found = os.path.join(audio_root, fname)\n            break\n\n    if file_found is None:\n        raise RuntimeError(\"Файл не найден: \" + tag)\n\n    audio, sr = librosa.load(file_found, sr=None, res_type=\"kaiser_fast\")\n\n    if target_rate and sr != target_rate:\n        audio = librosa.resample(audio, sr, target_rate)\n        sr = target_rate\n\n    audio_buf[tag] = (audio, sr)\n    return audio, sr\n\n\ndef load_fragment(ds, idx, sec, win=5, target_rate=None):\n    key = f\"{idx}_{ds}_{sec}\"\n    if key in sections_buf:\n        return sections_buf[key]\n\n    wav, rate = load_full_clip(ds, idx, target_rate)\n    end = int(sec) * rate\n    start = end - win * rate\n    frag = wav[start:end]\n\n    sections_buf[key] = (frag, rate)\n    return frag, rate","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:51.987210Z","iopub.execute_input":"2025-11-24T17:44:51.987443Z","iopub.status.idle":"2025-11-24T17:44:52.000939Z","shell.execute_reply.started":"2025-11-24T17:44:51.987418Z","shell.execute_reply":"2025-11-24T17:44:52.000319Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"СПЕКТРОГРАММЫ","metadata":{}},{"cell_type":"code","source":"def mel_transform(signal, sr):\n    mel = librosa.feature.melspectrogram(\n        y=signal,\n        sr=sr,\n        n_mels=128,\n        fmin=0,\n        fmax=sr / 2,\n        n_fft=sr // 10,\n        hop_length=sr // 40,\n    )\n    return librosa.power_to_db(mel).astype(np.float32)\n\n\ndef norm_to_uint(img):\n    eps = 1e-6\n    x = (img - img.mean()) / (img.std() + eps)\n    mn, mx = x.min(), x.max()\n    if mx - mn < eps:\n        return np.zeros_like(x, dtype=np.uint8)\n    x = np.clip(x, mn, mx)\n    x = ((x - mn) / (mx - mn) * 255).astype(np.uint8)\n    return x\n\n\ndef stack_rgb(x):\n    return np.repeat(x[np.newaxis, :, :], 3, axis=0).astype(np.float32) / 255.0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:52.002710Z","iopub.execute_input":"2025-11-24T17:44:52.002903Z","iopub.status.idle":"2025-11-24T17:44:52.013329Z","shell.execute_reply.started":"2025-11-24T17:44:52.002889Z","shell.execute_reply":"2025-11-24T17:44:52.012647Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"DATASET","metadata":{}},{"cell_type":"code","source":"class BirdClips(Dataset):\n    def __init__(self, table):\n        self.tbl = table\n        self.target_sr = 32000\n        self.win_len = 5\n        self.cache = {}\n\n    def __len__(self):\n        return len(self.tbl)\n\n    def _make_img(self, audio):\n        return stack_rgb(norm_to_uint(mel_transform(audio, self.target_sr)))\n\n    def __getitem__(self, idx):\n        if idx in self.cache:\n            return self.cache[idx]\n\n        rid = self.tbl.loc[idx, \"row_id\"]\n        clip, ds, sec = rid.split(\"_\")[:3]\n\n        audio, _ = load_fragment(ds, clip, int(sec), win=self.win_len, target_rate=self.target_sr)\n        img = self._make_img(audio)\n\n        self.cache[idx] = img\n        return img\n\n\ndataset = BirdClips(meta)\n\nprint(dataset[0].shape)\n\nfig, axes = plt.subplots(9, 1, figsize=(10, 20))\nfor i in range(9):\n    axes[i].imshow(np.transpose(dataset[i], (1, 2, 0)))\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:44:52.014113Z","iopub.execute_input":"2025-11-24T17:44:52.014384Z","iopub.status.idle":"2025-11-24T17:45:06.519880Z","shell.execute_reply.started":"2025-11-24T17:44:52.014360Z","shell.execute_reply":"2025-11-24T17:45:06.518941Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"МЕТАДАННЫЕ И МОДЕЛЬ","metadata":{}},{"cell_type":"code","source":"labels_df = pd.read_csv(\"../input/birdclef-2021/train_metadata.csv\")\nencoder = LabelEncoder().fit(sorted(labels_df[\"primary_label\"].unique()))\nn_classes = len(encoder.classes_)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(device)\n\n\ndef init_model(weights_path):\n    net = resnest50(pretrained=False)\n    net.fc = torch.nn.Linear(net.fc.in_features, n_classes)\n\n    saved = torch.load(weights_path, map_location=\"cpu\")\n\n\n    fixed = {}\n    for k, v in saved.items():\n        nk = k.replace(\"model.\", \"\")\n        fixed[nk] = v\n\n    net.load_state_dict(fixed)\n    net.to(device)\n    net.eval()\n    return net\n\n\nnet = init_model(\"../input/kkiller-birdclef-models-public/birdclef_resnest50_fold0_epoch_10_f1_val_06471_20210417161101.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:45:06.520603Z","iopub.execute_input":"2025-11-24T17:45:06.521017Z","iopub.status.idle":"2025-11-24T17:45:08.963910Z","shell.execute_reply.started":"2025-11-24T17:45:06.520989Z","shell.execute_reply":"2025-11-24T17:45:08.963098Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Функции обработки выходных данных модели","metadata":{}},{"cell_type":"code","source":"@torch.no_grad()\ndef pick_labels(logits):\n    thr = 0.1\n    idx_sorted = (-logits).argsort(1)\n    cnt = (logits > thr).sum(1)\n    return [i[:c].cpu().numpy().tolist() for i, c in zip(idx_sorted, cnt)]\n\n\ndef decode_predictions(arr):\n    return [\n        \" \".join(encoder.inverse_transform(x)) if x else \"nocall\"\n        for x in arr\n    ]\n\n\ndef forward_batch(batch):\n    tens = torch.from_numpy(batch).to(device)\n    out = torch.sigmoid(net(tens))\n    return decode_predictions(pick_labels(out))\n\n\n# тестовое выполнение\nsample = np.stack([dataset[200 + i] for i in range(10)])\npreds = forward_batch(sample)\n\nfor i, p in enumerate(preds):\n    print(f\"{i*5}-{i*5+5} sec:\", p)\n\n\ndef full_predict(ds):\n    bs = 64\n    L = len(ds)\n    result = []\n    for start in range(0, L, bs):\n        items = [ds[i] for i in range(start, min(start + bs, L))]\n        arr = np.stack(items)\n        result.extend(forward_batch(arr))\n    return result\n\n\nfinal_preds = full_predict(dataset)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:45:08.964769Z","iopub.execute_input":"2025-11-24T17:45:08.965022Z","iopub.status.idle":"2025-11-24T17:45:58.854751Z","shell.execute_reply.started":"2025-11-24T17:45:08.964986Z","shell.execute_reply":"2025-11-24T17:45:58.854183Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"SUBMISSION","metadata":{}},{"cell_type":"code","source":"def prepare_submit(ref_df, pr):\n    out = pd.DataFrame({\n        \"row_id\": ref_df[\"row_id\"],\n        \"birds\": pr\n    })\n    return out\n\n\nsubmission = prepare_submit(meta, final_preds)\nprint(submission.head())\nsubmission.to_csv(\"submission.csv\", index=False)\n","metadata":{"papermill":{"duration":0.02471,"end_time":"2024-11-25T21:19:42.031450","exception":false,"start_time":"2024-11-25T21:19:42.006740","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2025-11-24T17:45:58.855569Z","iopub.execute_input":"2025-11-24T17:45:58.855832Z","iopub.status.idle":"2025-11-24T17:45:58.869544Z","shell.execute_reply.started":"2025-11-24T17:45:58.855809Z","shell.execute_reply":"2025-11-24T17:45:58.868841Z"}},"outputs":[],"execution_count":null}]}