{"metadata":{"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":8900,"databundleVersionId":862232,"sourceType":"competition"},{"sourceId":2645,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":1911,"modelId":257},{"sourceId":637131,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":480369,"modelId":496047}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false},"colab":{"provenance":[],"gpuType":"T4"},"accelerator":"GPU","widgets":{"application/vnd.jupyter.widget-state+json":{"047a708faadf4b39884f330909f3fed5":{"model_module":"@jupyter-widgets/controls","model_name":"HBoxModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_fa1bbe9d9f744706b6d84e76e3e90e1e","IPY_MODEL_1c550de5a369463db51052b5d07fd4c8","IPY_MODEL_f47906928731454da3a105462ddcdea2"],"layout":"IPY_MODEL_dc6cd95a6dae4b8a8832929603253218"}},"fa1bbe9d9f744706b6d84e76e3e90e1e":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2f5a201695594bd983579192f4bcc8d3","placeholder":"​","style":"IPY_MODEL_2d1ca9a1e8cb432392f693ca15f6af11","value":"Downloading 3 files: 100%"}},"1c550de5a369463db51052b5d07fd4c8":{"model_module":"@jupyter-widgets/controls","model_name":"FloatProgressModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_2e606636d23640d6b2f25865e9ae2606","max":3,"min":0,"orientation":"horizontal","style":"IPY_MODEL_df95070ff40e43668f5b4c9afdf40132","value":3}},"f47906928731454da3a105462ddcdea2":{"model_module":"@jupyter-widgets/controls","model_name":"HTMLModel","model_module_version":"1.5.0","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_19a93920ba5d47e2bc0414d08c2d58d7","placeholder":"​","style":"IPY_MODEL_e798c74cd8b741e293d736a8f64929fa","value":" 3/3 [00:01&lt;00:00,  1.90s/it]"}},"dc6cd95a6dae4b8a8832929603253218":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2f5a201695594bd983579192f4bcc8d3":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2d1ca9a1e8cb432392f693ca15f6af11":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2e606636d23640d6b2f25865e9ae2606":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"df95070ff40e43668f5b4c9afdf40132":{"model_module":"@jupyter-widgets/controls","model_name":"ProgressStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"19a93920ba5d47e2bc0414d08c2d58d7":{"model_module":"@jupyter-widgets/base","model_name":"LayoutModel","model_module_version":"1.2.0","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e798c74cd8b741e293d736a8f64929fa":{"model_module":"@jupyter-widgets/controls","model_name":"DescriptionStyleModel","model_module_version":"1.5.0","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}}}}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from google.colab import files\n\nuploaded = files.upload()\n\nfor fn in uploaded.keys():\n  print('User uploaded file \"{name}\" with length {length} bytes'.format(\n      name=fn, length=len(uploaded[fn])))\n\n# Then move kaggle.json into the folder where the API expects to find it.\n!mkdir -p ~/.kaggle/ && mv kaggle.json ~/.kaggle/ && chmod 600 ~/.kaggle/kaggle.json","metadata":{"id":"0HtGf0HEXEa5","outputId":"01aa0277-e67b-4b37-fd8b-e851b2db9606"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nfrom torchvision import models\nfrom torch.utils.data import Dataset, DataLoader\nimport cv2\nimport librosa\nimport librosa.display\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom tqdm import tqdm\nimport kagglehub\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Настройки для воспроизводимости\ntorch.manual_seed(42)\nnp.random.seed(42)","metadata":{"execution":{"iopub.status.busy":"2025-11-10T09:46:29.577967Z","iopub.execute_input":"2025-11-10T09:46:29.578379Z","iopub.status.idle":"2025-11-10T09:46:29.702898Z","shell.execute_reply.started":"2025-11-10T09:46:29.578341Z","shell.execute_reply":"2025-11-10T09:46:29.701235Z"},"trusted":true,"id":"CE-U941LZvi1"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Загрузка и анализ данных","metadata":{"id":"xzaspv8lZvi2"}},{"cell_type":"code","source":"audio_dataset_path = kagglehub.competition_download(\"freesound-audio-tagging\")\nefficientnet_weights_path = kagglehub.model_download(\n    \"tensorflow/efficientnet/TensorFlow2/b0-classification/1\"\n)","metadata":{"id":"oaeTHBd-eK61","outputId":"c5984d7b-f3ef-4a4c-8ab8-da36b6c807c5"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data_path = '/root/.cache/kagglehub/competitions/freesound-audio-tagging/audio_train/'\ntest_data_path = '/root/.cache/kagglehub/competitions/freesound-audio-tagging/audio_test/'\n\ntrain_df = pd.read_csv('/root/.cache/kagglehub/competitions/freesound-audio-tagging/train.csv')\ntest_df = pd.read_csv('/root/.cache/kagglehub/competitions/freesound-audio-tagging/sample_submission.csv')\n\nprint(\"Размер тренировочных данных:\", train_df.shape)\nprint(\"Размер тестовых данных:\", test_df.shape)\n\n# Анализ классов\nprint(\"\\nПервые 5 записей тренировочного набора:\")\nprint(train_df.head())\n\nunique_classes = train_df.label.unique()\nprint(f\"\\nУникальные классы ({len(unique_classes)}):\")\nprint(unique_classes)\n\n# Визуализация распределения классов\nplt.figure(figsize=(12, 6))\ntrain_df['label'].value_counts().plot(kind='bar')\nplt.title('Распределение классов в тренировочных данных')\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.show()\n\n# Создание кодировщика меток\nclass_encoder = {label: idx for idx, label in enumerate(unique_classes)}\ndecoder = {idx: label for label, idx in class_encoder.items()}\nnum_classes = len(unique_classes)\n\nprint(f\"\\nКодировщик классов (первые 10):\")\nfor i, (label, idx) in enumerate(list(class_encoder.items())[:10]):\n    print(f\"  {label} -> {idx}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T09:05:44.801325Z","iopub.execute_input":"2025-11-10T09:05:44.801787Z","iopub.status.idle":"2025-11-10T09:05:45.595251Z","shell.execute_reply.started":"2025-11-10T09:05:44.80175Z","shell.execute_reply":"2025-11-10T09:05:45.594013Z"},"id":"fw9c3_2_Zvi3","outputId":"439c9fe1-685e-4e8f-c259-422d95b782d9"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Настройка устройства и параметров","metadata":{"id":"2QY6rswkZvi4"}},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Используемое устройство: {device}\")\n\nif torch.cuda.is_available():\n    print(f\"GPU: {torch.cuda.get_device_name()}\")\n    print(f\"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB\")\n\n# Параметры обучения\nbatch_size = 64\nnum_epochs = 5\nlearning_rate = 0.001","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T09:24:29.801876Z","iopub.execute_input":"2025-11-10T09:24:29.802254Z","iopub.status.idle":"2025-11-10T09:24:29.810578Z","shell.execute_reply.started":"2025-11-10T09:24:29.802223Z","shell.execute_reply":"2025-11-10T09:24:29.809311Z"},"id":"Efo38vSvZvi4","outputId":"64971f60-3f00-4de8-a610-b17182a2e538"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Создание датасета и аугментация данных","metadata":{"id":"dWzWICfLZvi4"}},{"cell_type":"code","source":"class AudioDataset(Dataset):\n    def __init__(self, data, base_path, is_test=False):\n        self.data = data\n        self.base_path = base_path\n        self.is_test = is_test\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, index):\n        filename = self.data.fname.values[index]\n        file_label = self.data.label.values[index]\n\n        full_path = (test_data_path if self.is_test else train_data_path) + filename\n\n        try:\n            # Загрузка аудио\n            audio_signal, _ = librosa.load(full_path)\n\n            # MEL-спектрограмма\n            mel_spectrogram = librosa.feature.melspectrogram(y=audio_signal)\n            log_mel = librosa.power_to_db(mel_spectrogram, ref=np.max)\n\n            # Изменение размера\n            resized_spectrogram = cv2.resize(log_mel, (128, 128))\n\n        except Exception as error:\n            print(f\"Ошибка обработки файла {full_path}: {error}\")\n            resized_spectrogram = np.zeros(shape=(128, 128))\n\n        # Создание трехканального изображения\n        processed_data = np.stack([resized_spectrogram] * 3)\n        processed_tensor = torch.tensor(processed_data, dtype=torch.float32)\n\n        if not self.is_test:\n            encoded_label = class_encoder[file_label]\n            return processed_tensor, encoded_label\n        else:\n            return processed_tensor","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T09:12:18.020366Z","iopub.execute_input":"2025-11-10T09:12:18.020766Z","iopub.status.idle":"2025-11-10T09:12:36.935846Z","shell.execute_reply.started":"2025-11-10T09:12:18.020731Z","shell.execute_reply":"2025-11-10T09:12:36.93407Z"},"id":"ShSgXcosZvi5"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_train, x_validation, y_train, y_validation = train_test_split(train_df, train_df,\n                                 test_size=0.2, shuffle=True, random_state=5)\ntrain_dataset = AudioDataset(x_train, train_data_path)\nval_dataset = AudioDataset(x_validation, train_data_path)\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)","metadata":{"id":"GbP42SKu3LI3"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Подготовка данных для обучения","metadata":{"id":"Qgu1R7DgZvi6"}},{"cell_type":"code","source":"# Стратифицированное разделение данных\ntrain_split, val_split = train_test_split(\n    train_df,\n    test_size=0.2,\n    shuffle=True,\n    random_state=42,\n    stratify=train_df.label.values\n)\n\nprint(f\"Тренировочные данные: {len(train_split)} samples\")\nprint(f\"Валидационные данные: {len(val_split)} samples\")\n\n# Создание датасетов и загрузчиков\ntraining_dataset = AudioDataset(train_split, train_data_path)\nvalidation_dataset = AudioDataset(val_split, train_data_path)\n\ntraining_loader = DataLoader(\n    training_dataset,\n    batch_size=batch_size,\n    shuffle=True,\n    num_workers=4,\n    pin_memory=True\n)\n\nvalidation_loader = DataLoader(\n    validation_dataset,\n    batch_size=batch_size,\n    shuffle=False,\n    num_workers=4,\n    pin_memory=True\n)\n\nprint(f\"Количество батчей в тренировочном загрузчике: {len(training_loader)}\")\nprint(f\"Количество батчей в валидационном загрузчике: {len(validation_loader)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T10:08:37.413985Z","iopub.execute_input":"2025-11-10T10:08:37.414399Z","iopub.status.idle":"2025-11-10T10:08:37.44263Z","shell.execute_reply.started":"2025-11-10T10:08:37.414364Z","shell.execute_reply":"2025-11-10T10:08:37.440997Z"},"id":"AbS_PZRwZvi6","outputId":"fa71a475-d73b-4f4f-ce5d-a8b4fff6385e"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Загрузка модели","metadata":{"id":"eno32owGZvi5"}},{"cell_type":"code","source":"# Загружаем предобученную модель без весов\nmodel = models.efficientnet_b0(weights=None)\n\n# При прямой загрузке весов был timeout error, поэтому загружаем вручную\nweight_path = '/efficientnet_b0_rwightman-7f5810bc.pth'\nstate_dict = torch.load(weight_path, map_location='cpu')\nmodel.load_state_dict(state_dict)\n\n# Изменяем классификатор на подходящий\nmodel.classifier[1] = torch.nn.Linear(1280, 41)\nmodel = model.to(device)\n\n# Подбираем оптимизатор и критерий останова под задачу классификации\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\ncriterion = torch.nn.CrossEntropyLoss()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T10:07:06.78922Z","iopub.execute_input":"2025-11-10T10:07:06.790295Z","iopub.status.idle":"2025-11-10T10:07:06.969023Z","shell.execute_reply.started":"2025-11-10T10:07:06.79025Z","shell.execute_reply":"2025-11-10T10:07:06.967886Z"},"id":"UkqBTsKvZvi5"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Функции для обучения и валидации","metadata":{"id":"BDT3ZBSSZvi6"}},{"cell_type":"code","source":"def train_epoch(model, loader, optimizer, criterion, device, scheduler=None):\n    model.train()\n    total_loss = 0\n    correct = 0\n    total_samples = 0\n\n    progress_bar = tqdm(loader, desc='Training', leave=False)\n\n    for batch_data, batch_labels in progress_bar:\n        batch_data, batch_labels = batch_data.to(device), batch_labels.to(device)\n        batch_size = batch_data.size(0)\n\n        optimizer.zero_grad()\n        predictions = model(batch_data)\n        loss = criterion(predictions, batch_labels)\n        loss.backward()\n\n        # Gradient clipping\n        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n        optimizer.step()\n\n        if scheduler:\n            scheduler.step()\n\n        total_loss += loss.item() * batch_size\n        correct += (predictions.argmax(1) == batch_labels).sum().item()\n        total_samples += batch_size\n\n        # Обновление progress bar\n        progress_bar.set_postfix({\n            'Loss': f'{loss.item():.4f}',\n            'Acc': f'{(predictions.argmax(1) == batch_labels).float().mean().item():.4f}'\n        })\n\n    return total_loss / total_samples, correct / total_samples\n\ndef validate_epoch(model, loader, criterion, device):\n    model.eval()\n    total_loss = 0\n    correct = 0\n    total_samples = 0\n\n    all_predictions = []\n    all_labels = []\n\n    with torch.no_grad():\n        progress_bar = tqdm(loader, desc='Validation', leave=False)\n        for batch_data, batch_labels in progress_bar:\n            batch_data, batch_labels = batch_data.to(device), batch_labels.to(device)\n            batch_size = batch_data.size(0)\n\n            predictions = model(batch_data)\n            loss = criterion(predictions, batch_labels)\n\n            total_loss += loss.item() * batch_size\n            correct += (predictions.argmax(1) == batch_labels).sum().item()\n            total_samples += batch_size\n\n            all_predictions.extend(predictions.argmax(1).cpu().numpy())\n            all_labels.extend(batch_labels.cpu().numpy())\n\n            progress_bar.set_postfix({\n                'Loss': f'{loss.item():.4f}',\n                'Acc': f'{(predictions.argmax(1) == batch_labels).float().mean().item():.4f}'\n            })\n\n    return total_loss / total_samples, correct / total_samples, all_predictions, all_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T10:10:04.23462Z","iopub.execute_input":"2025-11-10T10:10:04.236001Z","iopub.status.idle":"2025-11-10T10:10:04.250878Z","shell.execute_reply.started":"2025-11-10T10:10:04.235939Z","shell.execute_reply":"2025-11-10T10:10:04.24969Z"},"id":"HfA2AMATZvi6"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Обучение","metadata":{"id":"xVzyO5U9Zvi7"}},{"cell_type":"code","source":"# Для отслеживания метрик\ntrain_losses = []\nval_losses = []\ntrain_accuracies = []\nval_accuracies = []\nlearning_rates = []\n\nbest_accuracy = 0\nbest_epoch = 0\n\n# Обучение модели\nfor epoch in range(num_epochs):\n    print(f\"\\nЭпоха {epoch+1}/{num_epochs}\")\n    print(\"-\" * 50)\n\n    # Тренировочная фаза\n    train_loss, train_acc = train_epoch(\n        model, training_loader, optimizer,\n        criterion, device\n    )\n\n    # Валидационная фаза\n    val_loss, val_acc, val_preds, val_labels = validate_epoch(\n        model, validation_loader, criterion, device\n    )\n\n    # Сохранение метрик\n    train_losses.append(train_loss)\n    val_losses.append(val_loss)\n    train_accuracies.append(train_acc)\n    val_accuracies.append(val_acc)\n\n    # Сохранение лучшей модели\n    if val_acc > best_accuracy:\n        best_accuracy = val_acc\n        best_epoch = epoch\n        torch.save({\n            'epoch': epoch,\n            'model_state_dict': model.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'val_accuracy': val_acc,\n            'train_accuracy': train_acc,\n        }, 'best_audio_model.pth')\n        print(f\"Новая лучшая модель сохранена. Точность: {val_acc:.4f}\")\n\n    print(f\"Train Loss: {train_loss:.4f}, Train Accuracy: {train_acc:.4f}\")\n    print(f\"Val Loss: {val_loss:.4f}, Val Accuracy: {val_acc:.4f}\")\n    print(f\"Best Accuracy: {best_accuracy:.4f} (epoch {best_epoch+1})\")\n\n# Загрузка лучшей модели для инференса\ncheckpoint = torch.load('best_audio_model.pth')\nmodel.load_state_dict(checkpoint['model_state_dict'])\nprint(f\"\\nЗагружена лучшая модель из эпохи {checkpoint['epoch']+1}\")\nprint(f\"Лучшая точность на валидации: {checkpoint['val_accuracy']:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T10:31:56.20703Z","iopub.execute_input":"2025-11-10T10:31:56.207485Z"},"id":"oD9m2F_TZvi7","outputId":"696b471b-5ab4-46b8-e922-af680d7c3790"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Визуализация результатов обучения","metadata":{"id":"oIhuhKsCsr3l"}},{"cell_type":"code","source":"# Графики обучения\nfig, axes = plt.subplots(1, 2, figsize=(18, 5))\n\n# Loss\naxes[0].plot(train_losses, label='Train Loss', linewidth=2)\naxes[0].plot(val_losses, label='Val Loss', linewidth=2)\naxes[0].set_title('Функция потерь')\naxes[0].set_xlabel('Эпоха')\naxes[0].set_ylabel('Loss')\naxes[0].legend()\naxes[0].grid(True, alpha=0.3)\n\n# Accuracy\naxes[1].plot(train_accuracies, label='Train Accuracy', linewidth=2)\naxes[1].plot(val_accuracies, label='Val Accuracy', linewidth=2)\naxes[1].set_title('Точность')\naxes[1].set_xlabel('Эпоха')\naxes[1].set_ylabel('Accuracy')\naxes[1].legend()\naxes[1].grid(True, alpha=0.3)\n\nplt.tight_layout()\nplt.show()","metadata":{"id":"OHIvFzXAsu_w","outputId":"3b127a8c-3e67-4ad4-a01b-599e4bad5ef5"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Тестирование","metadata":{"id":"5EcPpHmD7n8h"}},{"cell_type":"code","source":"def predict_with_tta(model, loader, device, n_augmentations=3):\n    model.eval()\n    all_predictions = []\n\n    with torch.no_grad():\n        progress_bar = tqdm(loader, desc='TTA Prediction')\n        for batch_data in progress_bar:\n            batch_data = batch_data.to(device)\n            batch_predictions = []\n\n            # Предсказание на оригинальных данных\n            pred = model(batch_data)\n            batch_predictions.append(pred)\n\n            # TTA - горизонтальное отражение и небольшие трансформации\n            for i in range(n_augmentations - 1):\n                # Разные виды аугментаций для TTA\n                if i == 0:\n                    augmented_batch = torch.flip(batch_data, dims=[-1])  # Flip time dimension\n                elif i == 1:\n                    # Небольшое добавление шума\n                    noise = torch.randn_like(batch_data) * 0.01\n                    augmented_batch = batch_data + noise\n                else:\n                    # Комбинация\n                    augmented_batch = torch.flip(batch_data, dims=[-1])\n                    noise = torch.randn_like(augmented_batch) * 0.005\n                    augmented_batch = augmented_batch + noise\n\n                pred_aug = model(augmented_batch)\n                batch_predictions.append(pred_aug)\n\n            # Усреднение предсказаний\n            avg_prediction = torch.stack(batch_predictions).mean(0)\n            all_predictions.append(avg_prediction.cpu())\n\n    return torch.cat(all_predictions)\n\n# Создание тестового датасета и загрузчика\ntest_dataset = AudioDataset(test_df, test_data_path, is_test=True)\ntest_loader = DataLoader(\n    test_dataset,\n    batch_size=batch_size,\n    shuffle=False,\n    num_workers=2\n)\n\n# Предсказание с TTA\nprint(\"Генерация предсказаний с Test Time Augmentation...\")\ntest_predictions = predict_with_tta(model, test_loader, device, n_augmentations=3)\n\n# Применение softmax для получения вероятностей\nprobability_predictions = F.softmax(test_predictions, dim=1).numpy()\n\nprint(f\"Размерность предсказаний: {probability_predictions.shape}\")","metadata":{"id":"-qnW4n0g7p6V","outputId":"fe51a4db-cc95-4bff-f3f5-b6fe55f8662f"},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Создание файла для отправки","metadata":{"id":"5CGN2_WO7vE4"}},{"cell_type":"code","source":"# Создание submission файла\nsubmission_result = test_df.copy()\n\n# Заполнение предсказаниями\nfor i in range(len(test_df)):\n    class_probabilities = probability_predictions[i, :]\n    predicted_class_index = np.argmax(class_probabilities)\n    submission_result.label[i] = decoder[predicted_class_index]\n\n# Сохранение результатов\nsubmission_result.to_csv('submission.csv', index=False, header=True)\n\nprint(\"Первые 10 предсказаний:\")\nprint(submission_result.head(10))\n\n# Анализ распределения предсказаний\nplt.figure(figsize=(12, 6))\nsubmission_result['label'].value_counts().plot(kind='bar')\nplt.title('Распределение предсказанных классов')\nplt.xticks(rotation=45)\nplt.tight_layout()\nplt.show()\n\nprint(f\"\\nФайл с результатами сохранен как 'submission.csv'\")\nprint(f\"Всего предсказаний: {len(submission_result)}\")","metadata":{"id":"V24Glhrb7135","outputId":"364cda95-92cf-418e-ee5e-bdd4e0b48aa5"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from google.colab import files\n\n# Скачать submission.csv\nfiles.download('submission.csv')","metadata":{"id":"8JMCvZgwOo2T","outputId":"5945a961-5a3c-45a5-90a1-2df2d8a10de4"},"outputs":[],"execution_count":null}]}