{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":19391,"databundleVersionId":1025434,"sourceType":"competition"}],"dockerImageVersionId":30665,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import time\nimport numpy as np\nfrom torchvision import datasets\nfrom torchvision import transforms, models\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nfrom torchvision.transforms import v2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.datasets import ImageFolder\nimport matplotlib.pyplot as plt\nimport torch.optim as optim\nfrom itertools import product\nfrom torch.utils.data.sampler import SubsetRandomSampler\n\n%matplotlib inline\n\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:21.935691Z","iopub.execute_input":"2024-03-12T18:42:21.936638Z","iopub.status.idle":"2024-03-12T18:42:33.557906Z","shell.execute_reply.started":"2024-03-12T18:42:21.936596Z","shell.execute_reply":"2024-03-12T18:42:33.557060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Использование GPU по желанию\n\nif torch.cuda.is_available():\n  device = torch.device('cuda')\n  print('Работа на GPU')\nelse:\n  device = torch.device('cpu')\n  print('Работа на CPU')\n\n# Не забывайте про .to(device)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:36.231567Z","iopub.execute_input":"2024-03-12T18:42:36.232499Z","iopub.status.idle":"2024-03-12T18:42:36.289831Z","shell.execute_reply.started":"2024-03-12T18:42:36.232468Z","shell.execute_reply":"2024-03-12T18:42:36.288886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"common_transforms = v2.Compose([\n    v2.ToTensor(),\n    v2.Normalize(mean=[0.46, 0.44, 0.43], std=[0.29, 0.29, 0.29]),\n    v2.CenterCrop(100)\n])\n\ntrain_transforms = v2.Compose([\n    v2.RandomRotation(180),\n    v2.RandomHorizontalFlip(),\n])","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:38.124712Z","iopub.execute_input":"2024-03-12T18:42:38.125559Z","iopub.status.idle":"2024-03-12T18:42:38.133530Z","shell.execute_reply.started":"2024-03-12T18:42:38.125524Z","shell.execute_reply":"2024-03-12T18:42:38.132586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset = ImageFolder(root=\"/kaggle/input/cars3brands/middle_fmr\", transform=common_transforms)\nprint(f'Длина датасета: {len(dataset)}')\nprint(f'Размерность изображения {dataset[0][0].shape}')\nprint(dataset.classes)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:38.574777Z","iopub.execute_input":"2024-03-12T18:42:38.575609Z","iopub.status.idle":"2024-03-12T18:42:41.633512Z","shell.execute_reply.started":"2024-03-12T18:42:38.575576Z","shell.execute_reply":"2024-03-12T18:42:41.632467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.bar(dataset.classes, [(dataset.targets).count(i) for i in range(len(dataset.classes))])","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:27:14.919101Z","iopub.execute_input":"2024-03-12T18:27:14.919575Z","iopub.status.idle":"2024-03-12T18:27:15.197779Z","shell.execute_reply.started":"2024-03-12T18:27:14.919541Z","shell.execute_reply":"2024-03-12T18:27:15.196295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_size = 0.1\ntest_size = 0.15\n\ntrain_samples = len(dataset)\ntrain_indices = list(range(train_samples))\n\nsplit_value = int((1 - (val_size + test_size)) * train_samples)\nsplit_value_1 = split_value + int(np.floor(test_size * train_samples))\nnp.random.shuffle(train_indices)\n\ntrain_idx, val_idx, test_idx = train_indices[:split_value], train_indices[split_value:split_value_1], train_indices[split_value_1:]\n\ntrain_sampler = SubsetRandomSampler(train_idx)\ntest_sampler = SubsetRandomSampler(val_idx)\nval_sampler = SubsetRandomSampler(test_idx)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:45.499948Z","iopub.execute_input":"2024-03-12T18:42:45.500767Z","iopub.status.idle":"2024-03-12T18:42:45.509380Z","shell.execute_reply.started":"2024-03-12T18:42:45.500725Z","shell.execute_reply":"2024-03-12T18:42:45.508156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loader = DataLoader(dataset, batch_size=len(train_sampler), sampler=train_sampler)\nval_loader = DataLoader(dataset, batch_size=32, sampler=val_sampler)\ntest_loader = DataLoader(dataset, batch_size=32, sampler=test_sampler, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:45.922650Z","iopub.execute_input":"2024-03-12T18:42:45.923363Z","iopub.status.idle":"2024-03-12T18:42:45.928490Z","shell.execute_reply.started":"2024-03-12T18:42:45.923332Z","shell.execute_reply":"2024-03-12T18:42:45.927403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomTensorDataset(Dataset):\n    \"\"\"TensorDataset with support of transforms.\n    \"\"\"\n    def __init__(self, tensors, transform=None):\n        assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors)\n        self.tensors = tensors\n        self.transform = transform\n\n    def __getitem__(self, index):\n        x = self.tensors[0][index]\n\n        if self.transform:\n            x = self.transform(x)\n\n        y = self.tensors[1][index]\n\n        return x, y\n\n    def __len__(self):\n        return self.tensors[0].size(0)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:46.275697Z","iopub.execute_input":"2024-03-12T18:42:46.276451Z","iopub.status.idle":"2024-03-12T18:42:46.283473Z","shell.execute_reply.started":"2024-03-12T18:42:46.276413Z","shell.execute_reply":"2024-03-12T18:42:46.282536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for data in train_loader:\n    train_set = CustomTensorDataset(data, train_transforms)\ntrain_loader = DataLoader(train_set, batch_size=32)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:42:46.828172Z","iopub.execute_input":"2024-03-12T18:42:46.829066Z","iopub.status.idle":"2024-03-12T18:43:14.772855Z","shell.execute_reply.started":"2024-03-12T18:42:46.829030Z","shell.execute_reply":"2024-03-12T18:43:14.771709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"examples = next(iter(train_loader))\nlabels = examples[::-1][0]\nfor num, img  in enumerate(examples):\n   plt.imshow(img[0].permute(1,2,0))\n   plt.show()\n   print(f\"Label: {labels[num]}\")\n   break","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:27:45.600960Z","iopub.execute_input":"2024-03-12T18:27:45.601748Z","iopub.status.idle":"2024-03-12T18:27:45.968482Z","shell.execute_reply.started":"2024-03-12T18:27:45.601700Z","shell.execute_reply":"2024-03-12T18:27:45.967258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"examples = next(iter(test_loader))\nlabels = examples[::-1][0]\nfor num, img  in enumerate(examples):\n   plt.imshow(img[0].permute(1,2,0))\n   plt.show()\n   print(f\"Label: {labels[num]}\")\n   break","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:27:45.970506Z","iopub.execute_input":"2024-03-12T18:27:45.971398Z","iopub.status.idle":"2024-03-12T18:27:46.439669Z","shell.execute_reply.started":"2024-03-12T18:27:45.971353Z","shell.execute_reply":"2024-03-12T18:27:46.438365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def compute_accuracy(net, data_loader):\n    net.eval()\n    correct_pred = 0\n    num_examples = 0\n    with torch.no_grad():\n        for images, labels in data_loader:\n            images = images.to(device)\n            labels = labels.to(device)\n            outputs = net(images)\n            probas = F.softmax(outputs, dim=1)\n            _, predicted = torch.max(probas, 1)\n            num_examples += labels.size(0)\n            correct_pred += (predicted == labels).sum()\n\n        return (correct_pred.float()/num_examples * 100)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:43:29.136797Z","iopub.execute_input":"2024-03-12T18:43:29.137141Z","iopub.status.idle":"2024-03-12T18:43:29.144220Z","shell.execute_reply.started":"2024-03-12T18:43:29.137115Z","shell.execute_reply":"2024-03-12T18:43:29.143167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(num_epochs, model, optimizer, lr_sched):\n  train_acc = []\n  val_acc = []\n  for epoch in range(num_epochs):\n    model.train()\n    for i, (images, labels) in enumerate(train_loader):\n\n        images = images.to(device)\n        labels = labels.to(device)\n\n        outputs = model(images)\n        Loss = F.cross_entropy( outputs, labels)\n        optimizer.zero_grad()\n        Loss.backward()\n        optimizer.step()\n\n        ###\n        if not i % 50:\n            print ('Epoch: %03d/%03d | Batch %03d/%03d | Loss: %.4f'\n                   %(epoch+1, num_epochs, i,\n                     len(train_loader), Loss))\n\n    model.eval()\n    for i, (images, labels) in enumerate(val_loader):\n\n        images = images.to(device)\n        labels = labels.to(device)\n\n        outputs = model(images)\n        Loss = F.cross_entropy(outputs, labels)\n\n    acc1 = compute_accuracy(model, train_loader)\n    acc2 = compute_accuracy(model, val_loader)\n    train_acc.append(acc1.item())\n    val_acc.append(acc2.item())\n    print('Epoch: %03d/%03d training accuracy: %.2f%%' % (\n          epoch+1, num_epochs,\n          acc1))\n\n    print('Epoch: %03d/%03d validation accuracy: %.2f%%' % (\n          epoch+1, num_epochs,\n          acc2))\n    lr_sched.step()\n\n  return train_acc, val_acc","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:43:29.542623Z","iopub.execute_input":"2024-03-12T18:43:29.543256Z","iopub.status.idle":"2024-03-12T18:43:29.553231Z","shell.execute_reply.started":"2024-03-12T18:43:29.543224Z","shell.execute_reply":"2024-03-12T18:43:29.552242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rn50 = models.resnet50(pretrained=True).to(device)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T18:30:36.648307Z","iopub.execute_input":"2024-03-12T18:30:36.648793Z","iopub.status.idle":"2024-03-12T18:30:38.700100Z","shell.execute_reply.started":"2024-03-12T18:30:36.648757Z","shell.execute_reply":"2024-03-12T18:30:38.698583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2024-03-12T19:09:58.704025Z","iopub.execute_input":"2024-03-12T19:09:58.704645Z","iopub.status.idle":"2024-03-12T19:09:58.770572Z","shell.execute_reply.started":"2024-03-12T19:09:58.704611Z","shell.execute_reply":"2024-03-12T19:09:58.769403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"layers_to_unfreeze = 7\nfor k, child in enumerate(rn50.children()):\n  if k < layers_to_unfreeze:\n      for param in child.parameters():\n          param.requires_grad = False\n\nrn50.fc.out_features=4\n\noptimizer = optim.Adam(list(filter(lambda param: param.requires_grad, rn50.parameters())), lr=1e-4)\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2024-03-11T21:28:05.595534Z","iopub.execute_input":"2024-03-11T21:28:05.596571Z","iopub.status.idle":"2024-03-11T21:28:05.604120Z","shell.execute_reply.started":"2024-03-11T21:28:05.596535Z","shell.execute_reply":"2024-03-11T21:28:05.603207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc, val_acc = train(25, rn50, optimizer, scheduler)","metadata":{"execution":{"iopub.status.busy":"2024-03-11T21:28:07.280867Z","iopub.execute_input":"2024-03-11T21:28:07.281237Z","iopub.status.idle":"2024-03-11T21:32:06.779542Z","shell.execute_reply.started":"2024-03-11T21:28:07.281207Z","shell.execute_reply":"2024-03-11T21:32:06.778481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(train_acc)\nplt.plot(val_acc)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-11T21:32:06.781294Z","iopub.execute_input":"2024-03-11T21:32:06.781614Z","iopub.status.idle":"2024-03-11T21:32:07.011308Z","shell.execute_reply.started":"2024-03-11T21:32:06.781585Z","shell.execute_reply":"2024-03-11T21:32:07.010382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with torch.no_grad():\n    rn50.eval()\n    correct = 0\n    total = 0\n    correct = 0\n    total = 0\n    for images, labels in test_loader:\n          images, labels = images.to(device), labels.to(device)\n            # Расчет вывода модели\n            # С помощью torch.max можно получить индекс класса\n            # К total прибавляем количество данных в этом батче\n            # К correct прибавляем сумму совпадений между предсказанными классами и истинными\n          probs = rn50(images)\n\n          _, preds = torch.max(probs, axis=-1)\n          correct += (preds == labels).sum().item()\n          total += len(images)\n\n    print(f'Точность (accuracy) на тестовой выборке {(100 * correct / total)}')","metadata":{"execution":{"iopub.status.busy":"2024-03-11T21:32:28.196174Z","iopub.execute_input":"2024-03-11T21:32:28.196557Z","iopub.status.idle":"2024-03-11T21:32:30.875390Z","shell.execute_reply.started":"2024-03-11T21:32:28.196528Z","shell.execute_reply":"2024-03-11T21:32:30.874306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rn50_2 = models.resnet50(weights=\"ResNet50_Weights.DEFAULT\").to(device)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T19:19:34.911320Z","iopub.execute_input":"2024-03-12T19:19:34.911971Z","iopub.status.idle":"2024-03-12T19:19:35.449073Z","shell.execute_reply.started":"2024-03-12T19:19:34.911941Z","shell.execute_reply":"2024-03-12T19:19:35.448250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"layers_to_freeze = 7\nfor k, child in enumerate(rn50_2.children()):\n  if k < layers_to_freeze:\n      for param in child.parameters():\n          param.requires_grad = True\n\nrn50_2.fc.out_features=4\n\noptimizer = optim.Adam(list(filter(lambda param: param.requires_grad, rn50_2.parameters())), lr=1e-4)\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=6, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T19:21:25.259888Z","iopub.execute_input":"2024-03-12T19:21:25.260269Z","iopub.status.idle":"2024-03-12T19:21:25.268311Z","shell.execute_reply.started":"2024-03-12T19:21:25.260238Z","shell.execute_reply":"2024-03-12T19:21:25.267437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_acc, val_acc = train(30, rn50_2, optimizer, scheduler)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T19:21:26.761910Z","iopub.execute_input":"2024-03-12T19:21:26.762645Z","iopub.status.idle":"2024-03-12T19:28:13.668135Z","shell.execute_reply.started":"2024-03-12T19:21:26.762610Z","shell.execute_reply":"2024-03-12T19:28:13.667232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with torch.no_grad():\n    rn50_2.eval()\n    correct = 0\n    total = 0\n    correct = 0\n    total = 0\n    for images, labels in test_loader:\n          images, labels = images.to(device), labels.to(device)\n            # Расчет вывода модели\n            # С помощью torch.max можно получить индекс класса\n            # К total прибавляем количество данных в этом батче\n            # К correct прибавляем сумму совпадений между предсказанными классами и истинными\n          probs = rn50_2(images)\n\n          _, preds = torch.max(probs, axis=-1)\n          correct += (preds == labels).sum().item()\n          total += len(images)\n\n    print(f'Точность (accuracy) на тестовой выборке {(100 * correct / total)}')","metadata":{"execution":{"iopub.status.busy":"2024-03-12T19:28:13.670202Z","iopub.execute_input":"2024-03-12T19:28:13.670585Z","iopub.status.idle":"2024-03-12T19:28:15.721161Z","shell.execute_reply.started":"2024-03-12T19:28:13.670548Z","shell.execute_reply":"2024-03-12T19:28:15.720228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}