{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.13"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":8900,"databundleVersionId":862232,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":956.230086,"end_time":"2025-10-18T19:50:01.539116","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2025-10-18T19:34:05.309030","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"4271b567","cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport librosa\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom torchvision import models\nfrom IPython.display import Audio, display","metadata":{"execution":{"iopub.status.busy":"2025-10-18T22:13:49.948577Z","iopub.execute_input":"2025-10-18T22:13:49.949180Z","iopub.status.idle":"2025-10-18T22:13:53.426363Z","shell.execute_reply.started":"2025-10-18T22:13:49.949155Z","shell.execute_reply":"2025-10-18T22:13:53.425517Z"},"papermill":{"duration":11.319242,"end_time":"2025-10-18T19:34:20.128827","exception":false,"start_time":"2025-10-18T19:34:08.809585","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"87419717-8461-477e-b377-b2d6cb934c9e","cell_type":"code","source":"# Функция оценки MAP@3\ndef compute_map_at_3(true_labels, pred_probs):\n    top3 = np.argsort(pred_probs, axis=1)[:, ::-1][:, :3]\n    scores = []\n    for i, true in enumerate(true_labels):\n        if true in top3[i]:\n            rank = np.where(top3[i] == true)[0][0] + 1\n            scores.append(1.0 / rank)\n        else:\n            scores.append(0.0)\n    return np.mean(scores)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.427793Z","iopub.execute_input":"2025-10-18T22:13:53.428499Z","iopub.status.idle":"2025-10-18T22:13:53.433161Z","shell.execute_reply.started":"2025-10-18T22:13:53.428479Z","shell.execute_reply":"2025-10-18T22:13:53.432553Z"}},"outputs":[],"execution_count":null},{"id":"0d0b5523-23ba-498c-8c48-dac16b49f604","cell_type":"code","source":"# Пути к данным\nTRAIN_AUDIO_DIR = \"../input/freesound-audio-tagging/audio_train/\"\nTEST_AUDIO_DIR = \"../input/freesound-audio-tagging/audio_test/\"\nTRAIN_CSV_PATH = \"../input/freesound-audio-tagging/train.csv\"\nSAMPLE_SUB_PATH = \"../input/freesound-audio-tagging/sample_submission.csv\"\n\n# Загрузка меток\nlabels_df = pd.read_csv(TRAIN_CSV_PATH)\nprint(\"Пример обучающих данных:\")\nprint(labels_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.433725Z","iopub.execute_input":"2025-10-18T22:13:53.433935Z","iopub.status.idle":"2025-10-18T22:13:53.470963Z","shell.execute_reply.started":"2025-10-18T22:13:53.433919Z","shell.execute_reply":"2025-10-18T22:13:53.470257Z"}},"outputs":[],"execution_count":null},{"id":"8eb1f54d-bf2c-433e-8df8-9a50c8d74602","cell_type":"code","source":"SR = 22050          # Частота дискретизации\nDURATION = 5.0      # Длительность в секундах\nN_MELS = 128        # Количество мел-фильтров\nFMAX = 11025        # Максимальная частота\nIMG_H, IMG_W = 128, 128  # Размер изображения спектрограммы","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.480409Z","iopub.execute_input":"2025-10-18T22:13:53.480598Z","iopub.status.idle":"2025-10-18T22:13:53.498452Z","shell.execute_reply.started":"2025-10-18T22:13:53.480576Z","shell.execute_reply":"2025-10-18T22:13:53.497866Z"}},"outputs":[],"execution_count":null},{"id":"ed7df326-fa0b-4368-9c84-1f35d135cbf9","cell_type":"code","source":"class FreesoundDataset(Dataset):\n    def __init__(self, metadata, audio_dir, label_map=None, is_test=False):\n        self.meta = metadata\n        self.audio_dir = audio_dir\n        self.label_map = label_map\n        self.is_test = is_test\n\n    def __len__(self):\n        return len(self.meta)\n\n    def __getitem__(self, idx):\n        fname = self.meta.iloc[idx][\"fname\"]\n        full_path = os.path.join(self.audio_dir, fname)\n\n        waveform, _ = librosa.load(full_path, sr=SR, duration=DURATION)\n        if len(waveform) < SR * DURATION:\n            waveform = np.pad(waveform, (0, int(SR * DURATION - len(waveform))), mode=\"constant\")\n\n        # Преобразование в мел-спектрограмму\n        mel_spec = librosa.feature.melspectrogram(y=waveform, sr=SR, n_mels=N_MELS, fmax=FMAX)\n        mel_db = librosa.power_to_db(mel_spec, ref=np.max)\n\n        # Приведение к фиксированному размеру\n        try:\n            resized = cv2.resize(mel_db, (IMG_W, IMG_H))\n        except:\n            resized = np.zeros((IMG_H, IMG_W))\n\n        # Трёхканальное изображение для EfficientNet\n        image = np.stack([resized] * 3, axis=0).astype(np.float32)\n\n        if self.is_test:\n            return torch.tensor(image)\n        else:\n            label_str = self.meta.iloc[idx][\"label\"]\n            label_id = self.label_map[label_str]\n            return torch.tensor(image), label_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.472634Z","iopub.execute_input":"2025-10-18T22:13:53.472891Z","iopub.status.idle":"2025-10-18T22:13:53.479682Z","shell.execute_reply.started":"2025-10-18T22:13:53.472874Z","shell.execute_reply":"2025-10-18T22:13:53.478871Z"}},"outputs":[],"execution_count":null},{"id":"160ba2a6","cell_type":"code","source":"# Определяем cpu или gpu\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Используемое устройство: {DEVICE}\")","metadata":{"execution":{"iopub.status.busy":"2025-10-18T22:13:53.499054Z","iopub.execute_input":"2025-10-18T22:13:53.499243Z","iopub.status.idle":"2025-10-18T22:13:53.550276Z","shell.execute_reply.started":"2025-10-18T22:13:53.499224Z","shell.execute_reply":"2025-10-18T22:13:53.549639Z"},"papermill":{"duration":0.064662,"end_time":"2025-10-18T19:34:20.197211","exception":false,"start_time":"2025-10-18T19:34:20.132549","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"id":"2857d50c-6623-4a34-9581-dc0cfb8b96fd","cell_type":"code","source":"#Пример звука из датасета\nsample_file = labels_df.iloc[0][\"fname\"]\nsample_label = labels_df.iloc[0][\"label\"]\nprint(f\"\\nМетка примера: {sample_label}\")\ndisplay(Audio(filename=os.path.join(TRAIN_AUDIO_DIR, sample_file)))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.550998Z","iopub.execute_input":"2025-10-18T22:13:53.551221Z","iopub.status.idle":"2025-10-18T22:13:53.596079Z","shell.execute_reply.started":"2025-10-18T22:13:53.551202Z","shell.execute_reply":"2025-10-18T22:13:53.595086Z"}},"outputs":[],"execution_count":null},{"id":"429dfea7-c829-469f-b090-ffe9ad2160ad","cell_type":"code","source":"verified_df = labels_df[labels_df[\"manually_verified\"] == 1].reset_index(drop=True)\nprint(f\"Количество записей с проверенными метками: {len(verified_df)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.597050Z","iopub.execute_input":"2025-10-18T22:13:53.597368Z","iopub.status.idle":"2025-10-18T22:13:53.603781Z","shell.execute_reply.started":"2025-10-18T22:13:53.597341Z","shell.execute_reply":"2025-10-18T22:13:53.603071Z"}},"outputs":[],"execution_count":null},{"id":"4332a53d-f1a9-479d-8267-72c891155148","cell_type":"code","source":"# Метки\nclass_names = sorted(verified_df[\"label\"].unique())\nnum_classes = len(class_names)\nprint(f\"Количество уникальных меток: {num_classes}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.604821Z","iopub.execute_input":"2025-10-18T22:13:53.605178Z","iopub.status.idle":"2025-10-18T22:13:53.611043Z","shell.execute_reply.started":"2025-10-18T22:13:53.605154Z","shell.execute_reply":"2025-10-18T22:13:53.610323Z"}},"outputs":[],"execution_count":null},{"id":"23351331-55ce-4c08-9edf-16a6819be544","cell_type":"code","source":"label2id = {}\nid2label = {}\nfor i, cls in enumerate(class_names):\n    label2id[cls] = i\n    id2label[i] = cls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.612785Z","iopub.execute_input":"2025-10-18T22:13:53.613179Z","iopub.status.idle":"2025-10-18T22:13:53.620920Z","shell.execute_reply.started":"2025-10-18T22:13:53.613163Z","shell.execute_reply":"2025-10-18T22:13:53.620080Z"}},"outputs":[],"execution_count":null},{"id":"4cea1277-509d-4834-89cb-d9d3bb871ea5","cell_type":"code","source":"# Разделение на обучающую и валидационную выборки\ntrain_split, val_split = train_test_split(\n    verified_df,\n    test_size=0.2,\n    stratify=verified_df[\"label\"],\n    random_state=42\n)\nprint(f\"Обучающих примеров: {len(train_split)}\")\nprint(f\"Валидационных примеров: {len(val_split)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.621744Z","iopub.execute_input":"2025-10-18T22:13:53.622020Z","iopub.status.idle":"2025-10-18T22:13:53.640807Z","shell.execute_reply.started":"2025-10-18T22:13:53.622004Z","shell.execute_reply":"2025-10-18T22:13:53.640108Z"}},"outputs":[],"execution_count":null},{"id":"6732bebf-7e6a-44f1-a49c-27909a62e0c6","cell_type":"code","source":"# Создание загрузчиков\nBATCH_SIZE = 32\ntrain_dataset = FreesoundDataset(train_split, TRAIN_AUDIO_DIR, label2id)\nval_dataset = FreesoundDataset(val_split, TRAIN_AUDIO_DIR, label2id)\n\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.641545Z","iopub.execute_input":"2025-10-18T22:13:53.641880Z","iopub.status.idle":"2025-10-18T22:13:53.652023Z","shell.execute_reply.started":"2025-10-18T22:13:53.641822Z","shell.execute_reply":"2025-10-18T22:13:53.651383Z"}},"outputs":[],"execution_count":null},{"id":"3b0856a7-60b2-4ff2-b247-c02f27a19f48","cell_type":"code","source":"# Инициализация модели\nmodel = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.DEFAULT)\nmodel.classifier[1] = nn.Linear(model.classifier[1].in_features, num_classes)\nmodel = model.to(DEVICE)\n\n# Оптимизатор и функция потерь\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', patience=3, factor=0.5)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:53.652609Z","iopub.execute_input":"2025-10-18T22:13:53.652812Z","iopub.status.idle":"2025-10-18T22:13:54.067468Z","shell.execute_reply.started":"2025-10-18T22:13:53.652798Z","shell.execute_reply":"2025-10-18T22:13:54.066869Z"}},"outputs":[],"execution_count":null},{"id":"0d681830-0fad-4c80-a3bb-6dc037fa966b","cell_type":"code","source":"# Обучение\nbest_score = 0.0\nEPOCHS = 15\n\nfor epoch in range(EPOCHS):\n    model.train()\n    for inputs, targets in train_loader:\n        inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        optimizer.step()\n\n    # Валидация\n    model.eval()\n    all_preds = []\n    all_targets = []\n    with torch.no_grad():\n        for inputs, targets in val_loader:\n            inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)\n            logits = model(inputs)\n            probs = F.softmax(logits, dim=1).cpu().numpy()\n            all_preds.append(probs)\n            all_targets.append(targets.cpu().numpy())\n\n    all_preds = np.vstack(all_preds)\n    all_targets = np.concatenate(all_targets)\n    val_metric = compute_map_at_3(all_targets, all_preds)\n    print(f\"Эпоха {epoch + 1}/{EPOCHS} — MAP@3 на валидации: {val_metric:.4f}\")\n\n    if val_metric > best_score:\n        best_score = val_metric\n        torch.save(model.state_dict(), \"model.pth\")\n\n    scheduler.step(val_metric)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:13:54.068211Z","iopub.execute_input":"2025-10-18T22:13:54.068424Z","iopub.status.idle":"2025-10-18T22:26:40.382508Z","shell.execute_reply.started":"2025-10-18T22:13:54.068408Z","shell.execute_reply":"2025-10-18T22:26:40.381798Z"}},"outputs":[],"execution_count":null},{"id":"fe08cf18-5f8a-43e0-8438-4ee526dc2ec5","cell_type":"code","source":"# Подготовка тестовых данных\ntest_meta = pd.read_csv(SAMPLE_SUB_PATH)\ntest_dataset = FreesoundDataset(test_meta, TEST_AUDIO_DIR, is_test=True)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=0)\n\nmodel.load_state_dict(torch.load(\"model.pth\"))\nmodel.eval()\n\ntest_probs = []\nwith torch.no_grad():\n    for inputs in test_loader:\n        inputs = inputs.to(DEVICE)\n        logits = model(inputs)\n        probs = F.softmax(logits, dim=1).cpu().numpy()\n        test_probs.append(probs)\n\ntest_probs = np.vstack(test_probs)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:26:40.383511Z","iopub.execute_input":"2025-10-18T22:26:40.384166Z","iopub.status.idle":"2025-10-18T22:30:53.832113Z","shell.execute_reply.started":"2025-10-18T22:26:40.384144Z","shell.execute_reply":"2025-10-18T22:30:53.831264Z"}},"outputs":[],"execution_count":null},{"id":"986bdcbe-7eef-4520-a92d-7bd9c4a7f7b1","cell_type":"code","source":"# Формирование решения в формате csv\npredictions = []\nfor i, row in test_meta.iterrows():\n    ids = np.argsort(test_probs[i])[::-1][:3]\n    labels = [id2label[idx] for idx in ids]\n    predictions.append({\"fname\": row[\"fname\"], \"label\": \" \".join(labels)})\n\nsubmission_df = pd.DataFrame(predictions)\nsubmission_df.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-18T22:30:53.833114Z","iopub.execute_input":"2025-10-18T22:30:53.833726Z","iopub.status.idle":"2025-10-18T22:30:54.295639Z","shell.execute_reply.started":"2025-10-18T22:30:53.833698Z","shell.execute_reply":"2025-10-18T22:30:54.294885Z"}},"outputs":[],"execution_count":null},{"id":"90732cc0-669d-4446-b005-c9721ceacf63","cell_type":"code","source":"print(\"\\nПримеры меток на тестовом наборе:\")\nexamples = submission_df.iloc[20:26]\nfor _, ex in examples.iterrows():\n    print(f\"\\nФайл: {ex['fname']}\")\n    print(f\"Предсказанные метки: {ex['label']}\")\n    display(Audio(filename=os.path.join(TEST_AUDIO_DIR, ex[\"fname\"])))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-19T09:52:39.969415Z","iopub.execute_input":"2025-10-19T09:52:39.969748Z","iopub.status.idle":"2025-10-19T09:52:40.039329Z","shell.execute_reply.started":"2025-10-19T09:52:39.969723Z","shell.execute_reply":"2025-10-19T09:52:40.038362Z"}},"outputs":[],"execution_count":null}]}