{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":33768,"databundleVersionId":3083964,"sourceType":"competition"}],"dockerImageVersionId":30919,"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        break\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,"execution":{"iopub.status.busy":"2025-03-10T16:13:23.034853Z","iopub.execute_input":"2025-03-10T16:13:23.035329Z","iopub.status.idle":"2025-03-10T16:13:25.470714Z","shell.execute_reply.started":"2025-03-10T16:13:23.035291Z","shell.execute_reply":"2025-03-10T16:13:25.469900Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import DataLoader\nimport numpy as np\nfrom torch.optim.lr_scheduler import StepLR\nimport matplotlib.pyplot as plt\nfrom torchvision import models\nfrom torch import nn\n\nfrom tqdm import tqdm\nfrom IPython.display import clear_output\n\nfrom collections import defaultdict\nimport time","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:25.471831Z","iopub.execute_input":"2025-03-10T16:13:25.472198Z","iopub.status.idle":"2025-03-10T16:13:25.476877Z","shell.execute_reply.started":"2025-03-10T16:13:25.472171Z","shell.execute_reply":"2025-03-10T16:13:25.475933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 128\n\n\n# Путь к папке с данными\ndata_dir_train = '/kaggle/input/classification-of-butterflies/train_butterflies/train_split'\ndata_dir_test = '/kaggle/input/classification-of-butterflies/test_butterflies'\n# Преобразования для изображений\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),  # Изменение размера изображений\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomVerticalFlip(p=0.5),\n    transforms.RandomRotation(10),\n    transforms.ToTensor(),  # Преобразование в тензор\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # Нормализация\n])\n\n# Создание датасета с помощью ImageFolder\n\ntrain_dataset = datasets.ImageFolder(root=data_dir_train, transform=transform)\ntest_dataset = datasets.ImageFolder(root=data_dir_test, transform=transform)\n\n# Разделение на обучающую и тестовую выборки\ntrain_size = int(0.8 * len(train_dataset))  # 80% данных для обучения\nvalid_size = len(train_dataset) - train_size  # 20% данных для тестирования\ntrain_dataset, valid_dataset = torch.utils.data.random_split(train_dataset, [train_size, valid_size])\n\n# Создание DataLoader\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\nvalid_loader = DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=False)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n# Пример использования\nfor images, labels in train_loader:\n    print(images.shape)  # Размер батча: (batch_size, channels, height, width)\n    print(labels)  # Метки классов\n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:25.478798Z","iopub.execute_input":"2025-03-10T16:13:25.479046Z","iopub.status.idle":"2025-03-10T16:13:25.915305Z","shell.execute_reply.started":"2025-03-10T16:13:25.479025Z","shell.execute_reply":"2025-03-10T16:13:25.914294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\ndevice","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:25.916808Z","iopub.execute_input":"2025-03-10T16:13:25.917107Z","iopub.status.idle":"2025-03-10T16:13:25.922492Z","shell.execute_reply.started":"2025-03-10T16:13:25.917073Z","shell.execute_reply":"2025-03-10T16:13:25.921742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_resnet18 = models.resnet18(pretrained=False)\nmodel_resnet18.fc = nn.Linear(512, 50)\nmodel_resnet18 = model_resnet18.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:25.923347Z","iopub.execute_input":"2025-03-10T16:13:25.923632Z","iopub.status.idle":"2025-03-10T16:13:26.123078Z","shell.execute_reply.started":"2025-03-10T16:13:25.923604Z","shell.execute_reply":"2025-03-10T16:13:26.122016Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in train_loader:\n    print(model_resnet18(i[0].to(device)).shape)\n    break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:26.124015Z","iopub.execute_input":"2025-03-10T16:13:26.124419Z","iopub.status.idle":"2025-03-10T16:13:26.502525Z","shell.execute_reply.started":"2025-03-10T16:13:26.124383Z","shell.execute_reply":"2025-03-10T16:13:26.501477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_resnet18","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:26.503625Z","iopub.execute_input":"2025-03-10T16:13:26.503993Z","iopub.status.idle":"2025-03-10T16:13:26.510563Z","shell.execute_reply.started":"2025-03-10T16:13:26.503958Z","shell.execute_reply":"2025-03-10T16:13:26.509744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_learning_curves(history):\n    '''\n    Функция для вывода графиков лосса и метрики во время обучения.\n    '''\n    fig = plt.figure(figsize=(20, 7))\n\n    plt.subplot(1,2,1)\n    plt.title('Лосс', fontsize=15)\n    plt.plot(history['loss']['train'], label='train')\n    plt.plot(history['loss']['val'], label='val')\n    plt.ylabel('лосс', fontsize=15)\n    plt.xlabel('эпоха', fontsize=15)\n    plt.legend()\n\n    plt.subplot(1,2,2)\n    plt.title('Точность', fontsize=15)\n    plt.plot(history['acc']['train'], label='train')\n    plt.plot(history['acc']['val'], label='val')\n    plt.ylabel('лосс', fontsize=15)\n    plt.xlabel('эпоха', fontsize=15)\n    plt.legend()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:26.512837Z","iopub.execute_input":"2025-03-10T16:13:26.513121Z","iopub.status.idle":"2025-03-10T16:13:26.530100Z","shell.execute_reply.started":"2025-03-10T16:13:26.513090Z","shell.execute_reply":"2025-03-10T16:13:26.529161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(\n    model,\n    criterion,\n    optimizer,\n    scheduler,\n    train_batch_gen,\n    val_batch_gen,\n    num_epochs=10\n):\n    '''\n    Функция для обучения модели и вывода лосса и метрики во время обучения.\n    '''\n\n    history = defaultdict(lambda: defaultdict(list))\n\n    for epoch in range(num_epochs):\n        train_loss = 0\n        train_acc = 0\n        val_loss = 0\n        val_acc = 0\n\n        start_time = time.time()\n\n        # устанавливаем поведение dropout / batch_norm  в обучение\n        model.train(True)\n        model.to(device)\n\n        # на каждой \"эпохе\" делаем полный проход по данным\n        for X_batch, y_batch in tqdm(train_batch_gen):\n            # обучаемся на текущем батче\n            X_batch = X_batch.to(device)\n            y_batch = y_batch.to(device)\n\n            logits = model(X_batch)\n\n            loss = criterion(logits, y_batch.long().to(device))\n\n            loss.backward()\n            optimizer.step()\n            optimizer.zero_grad()\n\n            train_loss += np.sum(loss.detach().cpu().numpy())\n            y_pred = logits.max(1)[1].detach().cpu().numpy()\n            train_acc += np.mean(y_batch.cpu().numpy() == y_pred)\n        scheduler.step()\n\n        # подсчитываем лоссы и сохраням в \"историю\"\n        train_loss /= len(train_batch_gen)\n        train_acc /= len(train_batch_gen)\n        history['loss']['train'].append(train_loss)\n        history['acc']['train'].append(train_acc)\n\n        # устанавливаем поведение dropout / batch_norm в режим тестирования\n        model.train(False)\n\n        # полностью проходим по валидационному датасету\n        for X_batch, y_batch in tqdm(val_batch_gen):\n            X_batch = X_batch.to(device)\n            y_batch = y_batch.to(device)\n\n            logits = model(X_batch)\n            loss = criterion(logits, y_batch.long().to(device))\n            val_loss += np.sum(loss.detach().cpu().numpy())\n            y_pred = logits.max(1)[1].detach().cpu().numpy()\n            val_acc += np.mean(y_batch.cpu().numpy() == y_pred)\n\n        # подсчитываем лоссы и сохраням в \"историю\"\n        val_loss /= len(val_batch_gen)\n        val_acc /= len(val_batch_gen)\n        history['loss']['val'].append(val_loss)\n        history['acc']['val'].append(val_acc)\n\n        clear_output()\n\n        # печатаем результаты после каждой эпохи\n        print(\"Epoch {} of {} took {:.3f}s\".format(\n            epoch + 1, num_epochs, time.time() - start_time))\n        print(\"  training loss (in-iteration): \\t{:.6f}\".format(train_loss))\n        print(\"  validation loss (in-iteration): \\t{:.6f}\".format(val_loss))\n        print(\"  training accuracy: \\t\\t\\t{:.2f} %\".format(train_acc * 100))\n        print(\"  validation accuracy: \\t\\t\\t{:.2f} %\".format(val_acc * 100))\n\n        plot_learning_curves(history)\n\n    return model, history","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:26.531502Z","iopub.execute_input":"2025-03-10T16:13:26.531865Z","iopub.status.idle":"2025-03-10T16:13:26.549698Z","shell.execute_reply.started":"2025-03-10T16:13:26.531819Z","shell.execute_reply":"2025-03-10T16:13:26.548773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model_resnet18.parameters(), lr=3e-4)\nscheduler = StepLR(optimizer, step_size=3, gamma=0.2)\n\nclf_model, history = train(\n    model_resnet18, criterion, optimizer,\n    scheduler, train_loader, valid_loader,\n    num_epochs=12\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:13:26.550567Z","iopub.execute_input":"2025-03-10T16:13:26.550810Z","iopub.status.idle":"2025-03-10T16:17:37.949087Z","shell.execute_reply.started":"2025-03-10T16:13:26.550789Z","shell.execute_reply":"2025-03-10T16:17:37.948312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"################################\n# thx to Сергей Панин (pan1ns) #\n################################\n\n\ntest_dataset = datasets.ImageFolder(root=data_dir_test, transform=transform)\n\n\nsample_name = [path.split('/')[-1].split('.')[0] for path, _ in test_dataset.samples]\n\ndata_pred = []\nfor data, _ in test_dataset:\n    data_pred.append(data.clone().detach())\n\ndata_pred = torch.stack(data_pred, dim=0)\ndata_pred = data_pred.to(device)\npred = clf_model(data_pred)\n\nstr_nums = sorted([str(i) for i in range(50)])\n\nto_real_index = {i : int(str_nums[i]) for i in range(50)}\n\nres = [to_real_index[torch.argmax(item).item()] for item in pred]\n\ncnt_output = len(res)\n\noutput = {\n    \"index\": sample_name,\n    \"label\": res,\n}\n\noutput = pd.DataFrame(output)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:17:37.949964Z","iopub.execute_input":"2025-03-10T16:17:37.950267Z","iopub.status.idle":"2025-03-10T16:17:38.962761Z","shell.execute_reply.started":"2025-03-10T16:17:37.950233Z","shell.execute_reply":"2025-03-10T16:17:38.962068Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output.to_csv('submission_resnet18_reindexed.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-10T16:17:38.963589Z","iopub.execute_input":"2025-03-10T16:17:38.963835Z","iopub.status.idle":"2025-03-10T16:17:38.969183Z","shell.execute_reply.started":"2025-03-10T16:17:38.963814Z","shell.execute_reply":"2025-03-10T16:17:38.968253Z"}},"outputs":[],"execution_count":null}]}