{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":99895,"databundleVersionId":11971489,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install efficientnet_pytorch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:11:10.892433Z","iopub.execute_input":"2025-06-04T14:11:10.892994Z","iopub.status.idle":"2025-06-04T14:12:46.094674Z","shell.execute_reply.started":"2025-06-04T14:11:10.892974Z","shell.execute_reply":"2025-06-04T14:12:46.093449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_PATH = '../input/itmo-acoustic-event-detectin-2025/'\ntrain_meta_fname = 'train.csv'\ntest_meta_fname = 'sample_submission.csv'\ntrain_data_folder = 'audio_train/train' # Путь к папке с обучающими wav файлами\ntest_data_folder = 'audio_test/test'   # Путь к папке с тестовыми wav файлами","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:12:46.096589Z","iopub.execute_input":"2025-06-04T14:12:46.096948Z","iopub.status.idle":"2025-06-04T14:12:46.102046Z","shell.execute_reply.started":"2025-06-04T14:12:46.096911Z","shell.execute_reply":"2025-06-04T14:12:46.101244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport os\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\nimport torchaudio\nimport torchvision\nfrom torchaudio import transforms\nfrom efficientnet_pytorch import EfficientNet\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score\nfrom tqdm import tqdm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:12:46.102881Z","iopub.execute_input":"2025-06-04T14:12:46.103088Z","iopub.status.idle":"2025-06-04T14:12:49.672426Z","shell.execute_reply.started":"2025-06-04T14:12:46.103074Z","shell.execute_reply":"2025-06-04T14:12:49.671818Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# set seeds\nimport random\nimport numpy as np\n\nrandom.seed(42)\nnp.random.seed(42)\ntorch.manual_seed(42)\ntorch.cuda.manual_seed(42)\ntorch.backends.cudnn.deterministic = True","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:00.086246Z","iopub.execute_input":"2025-06-04T14:13:00.086929Z","iopub.status.idle":"2025-06-04T14:13:00.092766Z","shell.execute_reply.started":"2025-06-04T14:13:00.086908Z","shell.execute_reply":"2025-06-04T14:13:00.092247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train = pd.read_csv(os.path.join(DATA_PATH, train_meta_fname))\ndf_test = pd.read_csv(os.path.join(DATA_PATH, test_meta_fname))\ndf_train.head(2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:00.425714Z","iopub.execute_input":"2025-06-04T14:13:00.426185Z","iopub.status.idle":"2025-06-04T14:13:00.450359Z","shell.execute_reply.started":"2025-06-04T14:13:00.426161Z","shell.execute_reply":"2025-06-04T14:13:00.449635Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_classes = df_train.label.nunique()\nprint(n_classes)\nclasses_dict = {cl:i for i,cl in enumerate(df_train.label.unique())}\ndf_train['label_encoded'] = df_train.label.map(classes_dict)\ndf_train.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:00.796213Z","iopub.execute_input":"2025-06-04T14:13:00.796650Z","iopub.status.idle":"2025-06-04T14:13:00.807809Z","shell.execute_reply.started":"2025-06-04T14:13:00.796634Z","shell.execute_reply":"2025-06-04T14:13:00.807136Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# https://github.com/lukemelas/EfficientNet-PyTorch\nclass BaseLineModel(nn.Module):\n    \n    def __init__(self, sample_rate=16000, n_classes=41):\n        super().__init__()\n        self.ms = torchaudio.transforms.MelSpectrogram(sample_rate)\n#         self.bn1 = nn.BatchNorm2d(1)\n        \n        self.cnn1 = nn.Conv2d(in_channels=1, out_channels=10, kernel_size=3, padding=1)\n        self.cnn3 = nn.Conv2d(in_channels=10, out_channels=3, kernel_size=3, padding=1)\n        \n        self.features = EfficientNet.from_pretrained('efficientnet-b0')\n        # use it as features\n#         for param in self.features.parameters():\n#             param.requires_grad = False\n            \n        self.lin1 = nn.Linear(1000, 333)\n        \n        self.lin2 = nn.Linear(333, 111)\n                \n        self.lin3 = nn.Linear(111, n_classes)\n        \n    def forward(self, x):\n        x = self.ms(x)\n#         x = self.bn1(x)\n                \n        x = F.relu(self.cnn1(x))\n        x = F.relu(self.cnn3(x))\n        \n        x = self.features(x)\n\n        x = x.view(x.shape[0], -1)\n        x = F.relu(x)\n        \n        x = F.relu(self.lin1(x))\n        x = F.relu(self.lin2(x))\n        x = self.lin3(x)\n        return x\n    \n    def inference(self, x):\n        x = self.forward(x)\n        x = F.softmax(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:23.775686Z","iopub.execute_input":"2025-06-04T14:13:23.775966Z","iopub.status.idle":"2025-06-04T14:13:23.782723Z","shell.execute_reply.started":"2025-06-04T14:13:23.775945Z","shell.execute_reply":"2025-06-04T14:13:23.782055Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def sample_or_pad(waveform, wav_len=32000):\n    m, n = waveform.shape\n    if n < wav_len:\n        padded_wav = torch.zeros(1, wav_len)\n        padded_wav[:, :n] = waveform\n        return padded_wav\n    elif n > wav_len:\n        offset = np.random.randint(0, n - wav_len)\n        sampled_wav = waveform[:, offset:offset+wav_len]\n        return sampled_wav\n    else:\n        return waveform\n        \nclass EventDetectionDataset(Dataset):\n    def __init__(self, data_path, x, y=None):\n        self.x = x\n        self.y = y\n        self.data_path = data_path\n    \n    def __len__(self):\n        return len(self.x)\n\n    def __getitem__(self, idx):\n        path2wav = os.path.join(self.data_path, self.x[idx])\n        waveform, sample_rate = torchaudio.load(path2wav)\n        waveform = sample_or_pad(waveform)\n        if self.y is not None:\n            return waveform, self.y[idx]\n        return waveform\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:27.246573Z","iopub.execute_input":"2025-06-04T14:13:27.247309Z","iopub.status.idle":"2025-06-04T14:13:27.253167Z","shell.execute_reply.started":"2025-06-04T14:13:27.247283Z","shell.execute_reply":"2025-06-04T14:13:27.252433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(df_train.fname.values, df_train.label_encoded.values, \n                                                  test_size=0.2, random_state=42)\ntrain_loader = DataLoader(\n                        EventDetectionDataset(os.path.join(DATA_PATH, train_data_folder), X_train, y_train),\n                        batch_size=41\n                )\nval_loader = DataLoader(\n                        EventDetectionDataset(os.path.join(DATA_PATH, train_data_folder), X_val, y_val),\n                        batch_size=41\n                )\ntest_loader = DataLoader(\n                        EventDetectionDataset(os.path.join(DATA_PATH, test_data_folder), df_test.fname.values, None),\n                        batch_size=41, shuffle=False\n                )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:27.567857Z","iopub.execute_input":"2025-06-04T14:13:27.568534Z","iopub.status.idle":"2025-06-04T14:13:27.577319Z","shell.execute_reply.started":"2025-06-04T14:13:27.568512Z","shell.execute_reply":"2025-06-04T14:13:27.576496Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def eval_model(model, eval_dataset):\n    model.eval()\n    forecast, true_labs = [], []\n    with torch.no_grad():\n        for wavs, labs in tqdm(eval_dataset):\n            wavs, labs = wavs.cuda(), labs.detach().numpy()\n            true_labs.append(labs)\n            outputs = model.inference(wavs)\n            \n            outputs = outputs.detach().cpu().numpy().argmax(axis=1)\n            forecast.append(outputs)\n    forecast = [x for sublist in forecast for x in sublist]\n    true_labs = [x for sublist in true_labs for x in sublist]\n    return f1_score(forecast, true_labs, average='macro')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:30.893475Z","iopub.execute_input":"2025-06-04T14:13:30.894033Z","iopub.status.idle":"2025-06-04T14:13:30.899129Z","shell.execute_reply.started":"2025-06-04T14:13:30.894012Z","shell.execute_reply":"2025-06-04T14:13:30.898252Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ncriterion = nn.CrossEntropyLoss()\nmodel = BaseLineModel()\nmodel = model.cuda()\nlr = 1e-3\n\noptimizer = torch.optim.Adam(model.parameters(), lr=lr)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:34.372130Z","iopub.execute_input":"2025-06-04T14:13:34.372699Z","iopub.status.idle":"2025-06-04T14:13:35.424290Z","shell.execute_reply.started":"2025-06-04T14:13:34.372678Z","shell.execute_reply":"2025-06-04T14:13:35.423704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_epoch = 70\nbest_f1 = 0\nfor epoch in range(n_epoch):\n    model.train()\n    for wavs, labs in tqdm(train_loader):\n        optimizer.zero_grad()\n        wavs, labs = wavs.cuda(), labs.cuda()\n        outputs = model(wavs)\n        loss = criterion(outputs, labs)\n        loss.backward()\n        optimizer.step()\n#     if epoch % 10 == 0:\n    f1 = eval_model(model, val_loader)\n    f1_train = eval_model(model, train_loader)\n    print(f'epoch: {epoch}, f1_test: {f1}, f1_train: {f1_train}')\n    if f1 > best_f1:\n        best_f1 = f1\n        torch.save(model.state_dict(), '../baseline_fulldiv.pt')\n        \n    lr = lr * 0.95\n    for param_group in optimizer.param_groups:\n        param_group['lr'] = lr","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T11:49:27.860739Z","iopub.execute_input":"2025-06-04T11:49:27.861327Z","iopub.status.idle":"2025-06-04T12:59:01.060446Z","shell.execute_reply.started":"2025-06-04T11:49:27.861307Z","shell.execute_reply":"2025-06-04T12:59:01.059731Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# make a model\nmodel_name = 'baseline_fulldiv.pt'\nmodel = BaseLineModel().cuda()\nmodel.load_state_dict(torch.load(os.path.join('..', model_name)))\nmodel.eval()\nforecast = []\nwith torch.no_grad():\n    for wavs in tqdm(test_loader):\n        wavs = wavs.cuda()\n        outputs = model.inference(wavs)\n        outputs = outputs.detach().cpu().numpy().argmax(axis=1)\n        forecast.append(outputs)\nforecast = [x for sublist in forecast for x in sublist]\ndecoder = {classes_dict[cl]:cl for cl in classes_dict}\nforecast = pd.Series(forecast).map(decoder)\ndf_test['label'] = forecast\ndf_test.to_csv(f'{model_name}.csv', index=None)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:13:47.298507Z","iopub.execute_input":"2025-06-04T14:13:47.298769Z","iopub.status.idle":"2025-06-04T14:13:47.479554Z","shell.execute_reply.started":"2025-06-04T14:13:47.298751Z","shell.execute_reply":"2025-06-04T14:13:47.478580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# При сохранении модели\ntorch.save(model.state_dict(), 'baseline_model.pt') # Просто имя файла\n\n# При загрузке модели (для предсказания)\nmodel_name = 'baseline_model.pt' # Убедись, что это имя совпадает с тем, как ты сохранила\nmodel.load_state_dict(torch.load(model_name)) # Просто имя файла\n\n# При сохранении сабмишна\ndf_test.to_csv('submission.csv', index=None) # Просто имя файла, например, submission.csv\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T14:07:58.583497Z","iopub.execute_input":"2025-06-04T14:07:58.583742Z","iopub.status.idle":"2025-06-04T14:07:58.592753Z","shell.execute_reply.started":"2025-06-04T14:07:58.583723Z","shell.execute_reply":"2025-06-04T14:07:58.591943Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}