{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Cài đặt thư viện","metadata":{}},{"cell_type":"markdown","source":"## Cài đặt các thư viện chung","metadata":{}},{"cell_type":"code","source":"import time\nimport os\nimport copy\nimport functools\nimport pandas as pd\nimport numpy as np\n\n# Thư viện dựng biểu đồ và hình ảnh\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, confusion_matrix\nfrom collections import OrderedDict\n\nfrom tqdm import tqdm\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-10T18:45:40.884032Z","iopub.execute_input":"2021-07-10T18:45:40.884463Z","iopub.status.idle":"2021-07-10T18:45:40.890437Z","shell.execute_reply.started":"2021-07-10T18:45:40.884426Z","shell.execute_reply":"2021-07-10T18:45:40.889498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Cài đặt thư viện torch và torchvision","metadata":{}},{"cell_type":"code","source":"import cv2\nimport torch\nimport torchvision\n\n\nfrom torch import optim, nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import datasets, models, transforms\n\n#Albumentations là công cụ hữu ích trong thị giác máy tính giúp tăng hiệu suất xử lý cho mạng CNN\nimport albumentations as AL\nfrom albumentations.pytorch import ToTensorV2","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:40.948815Z","iopub.execute_input":"2021-07-10T18:45:40.949378Z","iopub.status.idle":"2021-07-10T18:45:40.955359Z","shell.execute_reply.started":"2021-07-10T18:45:40.949331Z","shell.execute_reply":"2021-07-10T18:45:40.954642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Tải dữ liệu","metadata":{}},{"cell_type":"code","source":"dataset = \"../input/plant-pathology-2020-fgvc7\"\ntrain = pd.read_csv(os.path.join(dataset,\"train.csv\"))\ntest = pd.read_csv(os.path.join(dataset,\"test.csv\"))\nprint(f\"Số lượng dữ liệu huấn luyện: {train.shape[0]}\")\nprint(f\"Số lượng dữ liệu dự đoán: {test.shape[0]}\")","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:41.014591Z","iopub.execute_input":"2021-07-10T18:45:41.015142Z","iopub.status.idle":"2021-07-10T18:45:41.03434Z","shell.execute_reply.started":"2021-07-10T18:45:41.015092Z","shell.execute_reply":"2021-07-10T18:45:41.033473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Minh họa dữ liệu","metadata":{}},{"cell_type":"markdown","source":"## Phân nhóm các loại bệnh với số lượng tương ứng","metadata":{}},{"cell_type":"code","source":"# Dùng hàm agg của pandas để tích hợp số lượng cho từng loại bệnh\nquantities = train[train.columns[1:5]].agg(['sum']).loc['sum']","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:41.056365Z","iopub.execute_input":"2021-07-10T18:45:41.056846Z","iopub.status.idle":"2021-07-10T18:45:41.066933Z","shell.execute_reply.started":"2021-07-10T18:45:41.056818Z","shell.execute_reply":"2021-07-10T18:45:41.066039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Minh họa dữ liệu phân nhóm bằng Pie Chart","metadata":{}},{"cell_type":"code","source":"# Tạo figure với kích thước và tỷ lệ\nfig, ax = plt.subplots(figsize=(10, 5), subplot_kw=dict(aspect=\"equal\"))\n\n# Mảng các số lượng của từng loại bệnh\nnumbers = quantities.tolist()\n\n# Mảng các tên của loại bệnh\ntypes = quantities.keys().tolist()\n\n# Hàm format nhãn khi xuất hiện trên chart (% và số lượng)\ndef formatting(v, data):\n    absolute = int(round(v/100.*np.sum(data)))\n    return \"{:.1f}%\\n{:d}\".format(v, absolute)\n\n# Tạo pie chart \nwedges, texts, autotexts = ax.pie(numbers, autopct=lambda v: formatting(v, numbers),\n                                  textprops=dict(color=\"w\"))\n\n# Đây là 1 labelled pie chart nên phải có legend với các số liệu cấu hình cấu hình\nax.legend(wedges, types,\n          title=\"Types\",\n          loc=\"center left\",\n          fontsize=12,\n          bbox_to_anchor=(1, 0, 0.5, 1)).get_title().set_fontsize('12')\n\n# Cài đặt cấu hình cho chữ trên pie chart\nplt.setp(autotexts, size=12, weight=\"bold\")\n\nax.set_title(\"Number of diseases by type pie chart\", size=8, loc='center')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:41.119855Z","iopub.execute_input":"2021-07-10T18:45:41.120345Z","iopub.status.idle":"2021-07-10T18:45:41.256685Z","shell.execute_reply.started":"2021-07-10T18:45:41.120314Z","shell.execute_reply":"2021-07-10T18:45:41.25594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Minh họa dữ liệu từ tập ảnh","metadata":{}},{"cell_type":"code","source":"images = os.path.join(dataset,\"images\")\n\nnumber_per_type = 3\n\n# hàm chuyển đổi của reduce, bao gồm giá trí hiện tại và bộ chứa\ndef get_diseased_by_type(accum, cur):\n    # lấy các hình ảnh có bệnh tương ứng với cột\n    mask = train[cur] == 1\n    \n    # lấy 4 indexes của các hình ảnh có bệnh tương ứng với cột\n    indexes = train[cur][mask].sample(n=number_per_type).keys()\n    \n    # lấy tên hình tương ứng với index\n    images = [i + \".jpg\" for i in train['image_id'][indexes]]\n    \n    accum.append(images)\n    \n    return accum\n\n# lấy danh sách các bệnh\ntypes = train.columns[1:5].tolist()\n\n# Tương ứng với mỗi bệnh sẽ lấy {number_per_type} hình trong tập dữ liệu train\nsamples = functools.reduce(get_diseased_by_type, types, [])\n\nfig = plt.figure(figsize=(20, 20))\ni=1\nfor type_index in range(len(types)):\n    samples_by_type = samples[type_index]\n    for image_name in samples_by_type:\n        ax = fig.add_subplot(len(types), number_per_type, i)\n        img = mpimg.imread(os.path.join(images, image_name))\n        imgplot = plt.imshow(img)\n        ax.set_title(types[type_index])\n        plt.axis('off')\n        i+=1","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:41.257859Z","iopub.execute_input":"2021-07-10T18:45:41.258268Z","iopub.status.idle":"2021-07-10T18:45:47.959957Z","shell.execute_reply.started":"2021-07-10T18:45:41.258229Z","shell.execute_reply":"2021-07-10T18:45:47.959098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Xử lý và phân chia dữ liệu","metadata":{}},{"cell_type":"markdown","source":"## Tạo dữ liệu cross-validation từ tập train","metadata":{}},{"cell_type":"code","source":"# Từ tên của hình ảnh để lấy ra đường dẫn tuyệt đối của ảnh trong thư mục input\ndef get_absolute_path(image_name):\n    return os.path.join(dataset, \"images\", image_name + \".jpg\")\n\ntrain_images = train[\"image_id\"].map(get_absolute_path)\ntrain_labels = train[train.columns[1:5]]\n\n# tách ra từ dữ liệu train để làm dữ liệu cross-validation với tỷ lệ (train, valid) = (80, 20)\ntrain_images, val_images, train_labels, val_labels = train_test_split(train_images, train_labels, test_size = 0.2, random_state=16)\n\n# Mỗi tập dữ liệu sinh ra sau khi tách vẫn dữ nguyên index trong dataframe ban đầu nên ta cần reset index của nó (bắt đầu từ 0)\n# drop=True để remove cột index cũ\ntrain_images.reset_index(drop=True,inplace=True)\ntrain_labels.reset_index(drop=True,inplace=True)\nval_images.reset_index(drop=True,inplace=True)\nval_labels.reset_index(drop=True,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:47.961457Z","iopub.execute_input":"2021-07-10T18:45:47.961891Z","iopub.status.idle":"2021-07-10T18:45:47.97764Z","shell.execute_reply.started":"2021-07-10T18:45:47.961858Z","shell.execute_reply":"2021-07-10T18:45:47.976766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Định nghĩa các transform để xử lý dữ liệu ảnh theo các tùy chọn để tăng hiệu quả cho mô hình","metadata":{}},{"cell_type":"code","source":"# Sử dụng các transforms của pytorch\ndata_transforms = {\n    'train': transforms.Compose([\n        transforms.ToTensor(),\n        \n        # ngẫu nhiên crop một vị trí của hình và resize nó với 1 kích thước cho trước\n        transforms.RandomResizedCrop(size=(256, 256)),\n        \n        # Lật hình theo hướng horizontal\n        transforms.RandomHorizontalFlip(p=0.5),\n        \n        # Lật hình theo hướng vertical\n        transforms.RandomVerticalFlip(p=0.5),\n        \n        # Rotate hình với ngẫu nhiên góc đó, vị trí và tỷ lệ phóng\n        transforms.RandomAffine(degrees=(0, 180)),\n        \n        \n        \n        # giá trị trung bình mean=[0.485, 0.456, 0.406] (thường dùng)\n        # giá trị độ lệch chuẩn st=[0.229, 0.224, 0.225] (thường dùng)\n        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    ]),\n    'val': transforms.Compose([\n        transforms.ToTensor(),\n        transforms.RandomResizedCrop(size=(256, 256)),\n        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n    ]),\n}\n\n# Sử dụng các transforms của Albumentations\n# mytransform = {\n#     \"train\": AL.Compose([\n#     AL.RandomResizedCrop(height=256, width=256, p=1.0),\n#     AL.Flip(),\n#     AL.ShiftScaleRotate(rotate_limit=1.0, p=0.8),\n#     AL.Normalize(p=1.0),\n#     ToTensorV2(p=1.0),\n#     ]),\n#     \"validation\": AL.Compose([\n#     AL.RandomResizedCrop(height=256, width=256, p=1.0),\n#     AL.Normalize(p=1.0),\n#     ToTensorV2(p=1.0),\n#     ]),\n# }\n","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:47.979026Z","iopub.execute_input":"2021-07-10T18:45:47.979451Z","iopub.status.idle":"2021-07-10T18:45:47.997141Z","shell.execute_reply.started":"2021-07-10T18:45:47.979421Z","shell.execute_reply":"2021-07-10T18:45:47.996102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Class ImageDataset để thực hiện xử lý dữ liệu với các transform","metadata":{}},{"cell_type":"code","source":"class ImageDataset(Dataset):\n    \n    def __init__(self, images, labels=None, transforms=None):\n        self.images = images\n        self.labels = labels\n        self.transforms=transforms\n        \n    def __getitem__(self, idx):\n        # đọc hình ảnh với vị trí idx trong tập ảnh\n        image = cv2.imread(self.images[idx])\n        \n        # chuyển đổi ảnh sang hệ số màu RGB\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        # transform hình ảnh\n        transformed = image if transforms is None else self.transforms(image)\n        \n        if self.labels is None:\n            return transformed\n        else:\n            label = None if self.labels is None else torch.argmax(torch.tensor(self.labels.iloc[idx]))\n            return transformed, label\n\n    def __len__(self):\n        return self.images.shape[0]","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:47.998226Z","iopub.execute_input":"2021-07-10T18:45:47.998741Z","iopub.status.idle":"2021-07-10T18:45:48.017032Z","shell.execute_reply.started":"2021-07-10T18:45:47.998711Z","shell.execute_reply":"2021-07-10T18:45:48.015945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Mô hình huấn luyện","metadata":{}},{"cell_type":"markdown","source":"## Các cấu hình","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 64 #4\nNUM_EPOCHS = 15 #10\ndevice = \"cuda\"\nTRAIN_SIZE = train_labels.shape[0]\nVALID_SIZE = val_labels.shape[0]\nlearning_rate = 5e-5\n\n# pre-trained model sử dụng\nmodel_name = \"resnet\"\n\n# số loại bệnh\nnum_classes = 4\n\n# chỉ tối ưu các trọng số của fined-tune network\nfeature_extract = True","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.018845Z","iopub.execute_input":"2021-07-10T18:45:48.019535Z","iopub.status.idle":"2021-07-10T18:45:48.035496Z","shell.execute_reply.started":"2021-07-10T18:45:48.019488Z","shell.execute_reply":"2021-07-10T18:45:48.034542Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Chọn mô hình pre-trained","metadata":{}},{"cell_type":"code","source":"# Liệu rằng chúng ta có nên tối ưu trọng số của cả mô hình gồm pre-train và fined-tune network,\n# Nếu feature_extracting = True, nghĩa là chỉ cập nhật fined-tune network\ndef set_parameter_requires_grad(model, feature_extracting):\n    if feature_extracting:\n        for param in model.parameters():\n            param.requires_grad = False\n\n# Khởi tạo mô hình mạng sử dụng\ndef initialize_model(model_name, num_classes, feature_extract=True, use_pretrained=True):\n    model_ft = None\n\n    if model_name == \"resnet\":\n        \"\"\" Resnet50\n        \"\"\"\n        model_ft = models.resnet50(pretrained=use_pretrained)\n        set_parameter_requires_grad(model_ft, feature_extract)\n        # Bởi vì lớp fully connected cuối cùng của Resnet18 có dạng Linear(in_features=512, out_features=1000, bias=True)\n        # nên chúng ta phải thay đổi lớp cuối cùng này với {out_feature} bằng {num_classes}\n        in_features = model_ft.fc.in_features\n        # Lớp fined-tune, sẽ được cập nhật trong số trong khi train\n        model_ft.fc = nn.Linear(in_features, num_classes)\n\n    elif model_name == \"densenet\":\n        \"\"\" Densenet\n        \"\"\"\n        model_ft = models.densenet121(pretrained=use_pretrained)\n        set_parameter_requires_grad(model_ft, feature_extract)\n        num_ftrs = model_ft.classifier.in_features\n        model_ft.classifier = nn.Linear(num_ftrs, num_classes)\n\n    else:\n        print(\"Invalid model name, exiting...\")\n        exit()\n\n    return model_ft\n","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.037036Z","iopub.execute_input":"2021-07-10T18:45:48.037469Z","iopub.status.idle":"2021-07-10T18:45:48.048547Z","shell.execute_reply.started":"2021-07-10T18:45:48.037425Z","shell.execute_reply":"2021-07-10T18:45:48.047685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Tạo mô hình pre-trained","metadata":{}},{"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n# Initialize the model for this run\nmodel_ft = initialize_model(model_name, num_classes, feature_extract, use_pretrained=True)\n\n# Print the model we just instantiated\nprint(model_ft)","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.050726Z","iopub.execute_input":"2021-07-10T18:45:48.051182Z","iopub.status.idle":"2021-07-10T18:45:48.799049Z","shell.execute_reply.started":"2021-07-10T18:45:48.051137Z","shell.execute_reply":"2021-07-10T18:45:48.798245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Tạo trình tối ưu (optimizer)","metadata":{}},{"cell_type":"code","source":"# nạp mô hình vào GPU\nmodel_ft = model_ft.to(device)\n\n# feature_extract == True, nghĩa là chỉ lấy những parameters cần cập nhật, ngược lại thì sẽ cập nhật trọng số của cả network\nif feature_extract:\n    params_to_update = []\n    for name,param in model_ft.named_parameters():\n        if param.requires_grad == True:\n            params_to_update.append(param)\n            print(\"\\t\",name)\nelse:\n    # lấy tất cả param của mạng\n    params_to_update = model_ft.parameters()\n    for name,param in model_ft.named_parameters():\n        if param.requires_grad == True:\n            print(\"\\t\",name)\n\n\n# Sử dụng stomach GD optimizer\noptimizer_ft = optim.SGD(params_to_update, lr=learning_rate, momentum=0.9)\n","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.800494Z","iopub.execute_input":"2021-07-10T18:45:48.800998Z","iopub.status.idle":"2021-07-10T18:45:48.817411Z","shell.execute_reply.started":"2021-07-10T18:45:48.80095Z","shell.execute_reply":"2021-07-10T18:45:48.816235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Tạo CrossEntropyLoss","metadata":{}},{"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.818815Z","iopub.execute_input":"2021-07-10T18:45:48.819099Z","iopub.status.idle":"2021-07-10T18:45:48.826659Z","shell.execute_reply.started":"2021-07-10T18:45:48.81907Z","shell.execute_reply":"2021-07-10T18:45:48.825889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Hàm huấn luyện","metadata":{}},{"cell_type":"code","source":"def train(model, dataloaders, criterion, optimizer, num_epochs=15):\n    since = time.time()\n    \n    train_loss_history = []\n    val_loss_history = []\n    val_acc_history = []\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n        \n        # Mỗi epoch sẽ chạy trên phase train và phase validation\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # load dữ liệu từ dataloader theo batch_size\n            for inputs, labels in dataloaders[phase]:\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n\n                # reset độ dốc để tránh cộng dồn\n                optimizer.zero_grad()\n\n                # Chỉ cập nhật trọng số trong quá trình train\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    loss = criterion(outputs, labels)\n\n                    # Lấy vị trí của giá trị cao nhất\n                    _, preds = torch.max(outputs, 1)\n\n                    if phase == 'train':\n                        \n                        # lan truyền giá trị lỗi đến các trọng số trong mạng\n                        loss.backward()\n                        \n                        # cập nhật lại các trọng số\n                        optimizer.step()\n\n                # Cộng dồn giá trị lỗi trên mỗi batch\n                running_loss += loss.item() * inputs.size(0)\n                \n                # Cộng dồn độ chính xác trên mỗi batch\n                running_corrects += torch.sum(preds == labels.data)\n\n            # Tính lỗi trung bình trên mỗi item trên mỗi phase, mỗi epoch\n            epoch_loss = running_loss / len(dataloaders[phase].dataset)\n            \n            # Tính độ chính xác trên mỗi phase, mỗi epoch\n            epoch_acc = running_corrects.double().item() / len(dataloaders[phase].dataset)\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))\n            \n            if phase == 'train':\n                train_loss_history.append(epoch_loss)\n                \n            if phase == 'val':\n                val_loss_history.append(epoch_loss)\n                val_acc_history.append(epoch_acc)\n                \n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n            \n\n        print(f\"######## End epoch {epoch} ##########\")\n\n    time_elapsed = time.time() - since\n    print('Thời gian huấn luyện: {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    print('Độ chính xác tốt nhất trên tập validation: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model, train_loss_history, val_loss_history, val_acc_history","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.827891Z","iopub.execute_input":"2021-07-10T18:45:48.828368Z","iopub.status.idle":"2021-07-10T18:45:48.844094Z","shell.execute_reply.started":"2021-07-10T18:45:48.828324Z","shell.execute_reply":"2021-07-10T18:45:48.84314Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n\n\n\n# Huấn luyện mô hình","metadata":{}},{"cell_type":"markdown","source":"## Nạp dữ liệu vào Pytorch Dataloader","metadata":{}},{"cell_type":"code","source":"train_data_loader = DataLoader(ImageDataset(train_images, train_labels, data_transforms[\"train\"]), batch_size=BATCH_SIZE, shuffle=True)\nval_data_loader = DataLoader(ImageDataset(val_images, val_labels, data_transforms[\"val\"]), batch_size=BATCH_SIZE, shuffle=True)\n\ndataloaders_dict = {\"train\": train_data_loader, \"val\": val_data_loader}","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.845366Z","iopub.execute_input":"2021-07-10T18:45:48.845816Z","iopub.status.idle":"2021-07-10T18:45:48.864576Z","shell.execute_reply.started":"2021-07-10T18:45:48.845775Z","shell.execute_reply":"2021-07-10T18:45:48.863625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Thực thi huấn luyện","metadata":{}},{"cell_type":"code","source":"# Train and evaluate\nmodel_ft, train_loss, val_loss, val_acc = train(model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=NUM_EPOCHS)","metadata":{"execution":{"iopub.status.busy":"2021-07-10T18:45:48.866381Z","iopub.execute_input":"2021-07-10T18:45:48.866934Z","iopub.status.idle":"2021-07-10T20:44:26.843303Z","shell.execute_reply.started":"2021-07-10T18:45:48.866767Z","shell.execute_reply":"2021-07-10T20:44:26.84228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Minh họa lỗi","metadata":{}},{"cell_type":"code","source":"metrics = [{\"label\": \"Training Loss\", \"value\": train_loss},\n           {\"label\": \"Validation Loss\", \"value\": val_loss},\n           {\"label\": \"Validation Accuracy\", \"value\": val_acc}]\nfig = plt.figure(figsize=(20, 5))\n\nfor i, m in enumerate(metrics):\n    fig.add_subplot(1, 3, i+1)\n    plt.title(f\"{m['label']} vs. Number of Training Epochs\")\n    plt.xlabel(\"Training Epochs\")\n    plt.ylabel(f\"{m['label']}\")\n    plt.plot(range(1,NUM_EPOCHS+1), m['value'])\n\nplt.show()\n   \n    ","metadata":{"execution":{"iopub.status.busy":"2021-07-10T20:44:26.84517Z","iopub.execute_input":"2021-07-10T20:44:26.845623Z","iopub.status.idle":"2021-07-10T20:44:27.500492Z","shell.execute_reply.started":"2021-07-10T20:44:26.845575Z","shell.execute_reply":"2021-07-10T20:44:27.499477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dự đoán","metadata":{}},{"cell_type":"code","source":"softmax = nn.Softmax(dim=1)\n\ndef test_function(model, loader):\n    predictions = []\n    \n    progress = tqdm(loader, desc=\"Testing\")\n    #print(progress)\n    #inputs, labels\n    with torch.no_grad():\n        for  _, images in enumerate(progress):\n            images = images.to(device)\n            model.eval()\n            probs = softmax(model(images)).tolist()\n            predictions.extend(probs)\n    return predictions\n\ntest_images = test[\"image_id\"].map(get_absolute_path)\ntest_loader = DataLoader(ImageDataset(test_images, None, data_transforms[\"val\"]), batch_size=BATCH_SIZE)\npredictions = np.array(test_function(model_ft, test_loader))\nprint(predictions)\n","metadata":{"execution":{"iopub.status.busy":"2021-07-10T20:44:27.50197Z","iopub.execute_input":"2021-07-10T20:44:27.502551Z","iopub.status.idle":"2021-07-10T20:52:04.060303Z","shell.execute_reply.started":"2021-07-10T20:44:27.502505Z","shell.execute_reply":"2021-07-10T20:52:04.059351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submit","metadata":{}},{"cell_type":"code","source":"submission = pd.read_csv(os.path.join(dataset,\"sample_submission.csv\"))\nsubmission.loc[:, submission.columns[1:5]] = predictions\nsubmission.to_csv(\"submission_2.csv\", index=False)","metadata":{},"execution_count":null,"outputs":[]}]}