{"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":"gpu","dataSources":[{"sourceId":33768,"databundleVersionId":3083964,"sourceType":"competition"}],"dockerImageVersionId":30674,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\n\nimport torchvision\nfrom torchvision import datasets, transforms\n\nimport pandas as pd\n\nimport datetime as dt\n\nfrom matplotlib import colors, pyplot as plt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-02T08:01:04.765065Z","iopub.execute_input":"2024-04-02T08:01:04.765448Z","iopub.status.idle":"2024-04-02T08:01:04.771185Z","shell.execute_reply.started":"2024-04-02T08:01:04.765419Z","shell.execute_reply":"2024-04-02T08:01:04.770259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path\n\nTRAIN_DIR = Path(\"/kaggle/input/classification-of-butterflies\").joinpath('train_butterflies').joinpath('train_split')\nTEST_DIR = Path(\"/kaggle/input/classification-of-butterflies\").joinpath('test_butterflies')\n\nNB_CLASSES = 50\nBATCH_SIZE = 20\nRESCALE_SIZE = 224\nDEVICE = torch.device(\"cpu\")","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:04.773049Z","iopub.execute_input":"2024-04-02T08:01:04.773755Z","iopub.status.idle":"2024-04-02T08:01:04.782093Z","shell.execute_reply.started":"2024-04-02T08:01:04.773729Z","shell.execute_reply":"2024-04-02T08:01:04.781253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize(224),\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:04.782990Z","iopub.execute_input":"2024-04-02T08:01:04.783243Z","iopub.status.idle":"2024-04-02T08:01:04.792472Z","shell.execute_reply.started":"2024-04-02T08:01:04.783222Z","shell.execute_reply":"2024-04-02T08:01:04.791744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import random_split\n\ndataset = datasets.ImageFolder(TRAIN_DIR, transform=transform)\n\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\n\ntrain, val = random_split(dataset, [train_size, val_size])\n","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:04.794251Z","iopub.execute_input":"2024-04-02T08:01:04.794515Z","iopub.status.idle":"2024-04-02T08:01:04.871964Z","shell.execute_reply.started":"2024-04-02T08:01:04.794473Z","shell.execute_reply":"2024-04-02T08:01:04.870892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from collections import Counter\n\nclass_cnt = dict(Counter(dataset.targets))","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:04.873079Z","iopub.execute_input":"2024-04-02T08:01:04.873401Z","iopub.status.idle":"2024-04-02T08:01:04.878447Z","shell.execute_reply.started":"2024-04-02T08:01:04.873370Z","shell.execute_reply":"2024-04-02T08:01:04.877525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.bar(class_cnt.keys(), class_cnt.values())\nplt.xlabel('Классы')\nplt.ylabel('Количество изображений')\nplt.title('Распределение классов')\nplt.xticks(rotation=90)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:04.879741Z","iopub.execute_input":"2024-04-02T08:01:04.880086Z","iopub.status.idle":"2024-04-02T08:01:05.220228Z","shell.execute_reply.started":"2024-04-02T08:01:04.880057Z","shell.execute_reply":"2024-04-02T08:01:05.219362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ButterflyDataset(Dataset):\n\n    def __init__(self, dataset):\n        super().__init__()\n        self.E = torch.eye(NB_CLASSES)\n        self.ds = dataset\n        self.len_ = len(dataset)\n\n    def __len__(self):\n        return self.len_\n\n    def __getitem__(self, index):\n        return (self.ds[index][0], self.E[self.ds[index][1]])","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:05.221373Z","iopub.execute_input":"2024-04-02T08:01:05.221659Z","iopub.status.idle":"2024-04-02T08:01:05.227629Z","shell.execute_reply.started":"2024-04-02T08:01:05.221634Z","shell.execute_reply":"2024-04-02T08:01:05.226784Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Trainer:\n\n    def __init__(\n        self,\n        loss_func,\n        optim = torch.optim.Adam,\n        model = torchvision.models.resnet34,\n        device: str = \"cpu\",\n        epoch_amount:int=1000,\n        batch_size:int = 50,\n        learning_rate: float = 1e-4,\n        permutate: bool = True\n    ) -> None:\n        self.device = torch.device(device)\n        self.epoch_amount = epoch_amount\n        self.loss = loss_func\n        self.dataset = ButterflyDataset\n        self.net = model\n        self.optim = optim\n        self.lr = learning_rate\n        self.shufle = permutate\n        self.batch_size = batch_size\n\n        self.train_loss = []\n        self.train_accuracy = []\n\n        self.validation_loss = []\n        self.validation_accuracy = []\n\n        self.best_model = model,\n        self.best_score = 1e20\n\n    def predict(self, X):\n        Model = self.best_model\n        Model.to(self.device)\n        Model.eval()\n        return Model(X)\n\n    def fit(\n            self,\n            train:torch.utils.data.dataset.Subset,\n            val:torch.utils.data.dataset.Subset\n        ):\n\n        Model = self.net(pretrained=True)\n        \n        for param in Model.parameters():\n            param.requires_grad = False\n\n\n        num_ftrs = Model.fc.in_features\n        Model.fc = nn.Linear(num_ftrs, NB_CLASSES)\n\n        Model.to(device=self.device)\n\n        opt = self.optim(Model.parameters(), lr=self.lr)\n\n        train_ds = self.dataset(train)\n        val_ds = self.dataset(val)\n\n        train_dl = DataLoader(train_ds, batch_size=self.batch_size)\n        val_dl = DataLoader(val_ds, shuffle=False)\n        for epoch in range(self.epoch_amount):\n            loss_tr, loss_v = 0, 0\n            start = dt.datetime.now()\n            \n            Model.train()\n            i = 0\n            for i, (data, classes) in enumerate(train_dl):\n                if (i % 10 == 0):\n                    print((i+1)*self.batch_size, \"images processed\")\n                data = data.to(self.device)\n                classes = classes.to(self.device)\n                opt.zero_grad()\n\n                y_pred = Model(data)\n\n                curr_loss = self.loss(y_pred, classes)\n\n\n                curr_loss.backward()\n                opt.step()\n                loss_tr += curr_loss\n            self.train_loss.append(loss_tr.item() / len(train_dl))\n\n            Model.eval()\n            with torch.no_grad():\n                for i, (data, classes) in enumerate(val_dl):\n                    if i % 200 == 0:\n                        print(i+1, \"images tested\")\n                    data = data.to(self.device)\n                    classes = classes.to(self.device)\n\n                    y_pred = Model(data)\n                    curr_loss = self.loss(y_pred, classes)\n                    loss_v += curr_loss\n            if (loss_v/len(val_dl) < self.best_score):\n                self.best_model = Model\n                self.best_score = loss_v/len(val_dl)\n\n            self.validation_loss.append(loss_v / len(val_dl))\n            print(f\"epoch: {epoch}\")\n            print(f\" {dt.datetime.now() - start} сек\")\n            print(f\"Loss_val: {loss_v / len(val_dl)}\")\n            print(f\"Loss_train: {loss_tr.item() / len(train_dl)}\")","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:05.229750Z","iopub.execute_input":"2024-04-02T08:01:05.230030Z","iopub.status.idle":"2024-04-02T08:01:05.249005Z","shell.execute_reply.started":"2024-04-02T08:01:05.230006Z","shell.execute_reply":"2024-04-02T08:01:05.248165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"params = {\n    'loss_func': nn.CrossEntropyLoss(),\n    'batch_size': 12,\n    'epoch_amount': 10,\n    'learning_rate': 0.0006,\n    'device': 'cuda:0'\n}","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:05.249988Z","iopub.execute_input":"2024-04-02T08:01:05.250217Z","iopub.status.idle":"2024-04-02T08:01:05.262582Z","shell.execute_reply.started":"2024-04-02T08:01:05.250197Z","shell.execute_reply":"2024-04-02T08:01:05.261786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# print(type(train))\n# print(torch.tensor(train[0][0]).shape)\nclf = Trainer(**params)\nclf.fit(train, val)","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:01:05.263614Z","iopub.execute_input":"2024-04-02T08:01:05.263861Z","iopub.status.idle":"2024-04-02T08:05:34.993580Z","shell.execute_reply.started":"2024-04-02T08:01:05.263839Z","shell.execute_reply":"2024-04-02T08:05:34.992635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predict_ds = datasets.ImageFolder(TEST_DIR, transform=transform)\n\ndata_pred = []\n\n# print(predict_ds[0])\n\nsample_name = [path.split('/')[-1].split('.')[0] for path, _ in predict_ds.samples]\n# print(sample_name)\nfor data, _ in predict_ds:\n    data_pred.append(data.clone().detach())\n\ndata_pred = torch.stack(data_pred, dim=0)\ndata_pred = data_pred.to(clf.device)\npred = clf.predict(data_pred)\n\nstr_nums = sorted([str(i) for i in range(NB_CLASSES)])\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\nprint(res)\ncnt_output = len(res)\nprint(cnt_output)\n\noutput = {\n    \"index\": sample_name,\n    \"label\": res,\n}\n\noutput = pd.DataFrame(output)\nprint(output)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:05:34.995070Z","iopub.execute_input":"2024-04-02T08:05:34.995437Z","iopub.status.idle":"2024-04-02T08:05:35.754956Z","shell.execute_reply.started":"2024-04-02T08:05:34.995404Z","shell.execute_reply":"2024-04-02T08:05:35.754086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"output.to_csv('res.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-04-02T08:05:35.755985Z","iopub.execute_input":"2024-04-02T08:05:35.756269Z","iopub.status.idle":"2024-04-02T08:05:35.762058Z","shell.execute_reply.started":"2024-04-02T08:05:35.756246Z","shell.execute_reply":"2024-04-02T08:05:35.761162Z"},"trusted":true},"execution_count":null,"outputs":[]}]}