{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"},{"sourceId":15444,"sourceType":"datasetVersion","datasetId":11102},{"sourceId":1664300,"sourceType":"datasetVersion","datasetId":985472}],"dockerImageVersionId":30043,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"![cifar10](https://miro.medium.com/max/709/1*LyV7_xga4jUHdx4_jHk1PQ.png)","metadata":{}},{"cell_type":"markdown","source":"<a id=\"2\"></a>\n# Import Libaries","metadata":{}},{"cell_type":"code","source":"# 載入必要的套件\nimport os\nimport torch\nimport torchvision\nimport tarfile\nfrom torchvision.datasets.utils import download_url\nfrom torch.utils.data import random_split\nfrom torchvision.datasets import ImageFolder\nfrom torchvision.transforms import ToTensor,ToPILImage\nimport matplotlib.pyplot as plt\nfrom torch.utils.data.dataloader import DataLoader\nfrom torchvision.utils import make_grid\nimport torch.nn as nn\nimport torch.nn.functional as F","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-06-10T08:09:06.314661Z","iopub.execute_input":"2021-06-10T08:09:06.314956Z","iopub.status.idle":"2021-06-10T08:09:07.808795Z","shell.execute_reply.started":"2021-06-10T08:09:06.314926Z","shell.execute_reply":"2021-06-10T08:09:07.807846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"3\"></a>\n# Exploring the Data","metadata":{}},{"cell_type":"code","source":"# 將cifar10解壓縮\nwith tarfile.open('../input/cifar10/cifar10.tgz', 'r:gz') as tar:\n    tar.extractall(path='./input')","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:10:53.319155Z","iopub.execute_input":"2021-06-10T07:10:53.319511Z","iopub.status.idle":"2021-06-10T07:11:17.561875Z","shell.execute_reply.started":"2021-06-10T07:10:53.319466Z","shell.execute_reply":"2021-06-10T07:11:17.560826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#列出所有類別\nprint(os.listdir('./input/cifar10'))\nclasses= os.listdir('./input/cifar10/train')\nprint(classes)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:11:37.015003Z","iopub.execute_input":"2021-06-10T07:11:37.015409Z","iopub.status.idle":"2021-06-10T07:11:37.023516Z","shell.execute_reply.started":"2021-06-10T07:11:37.015376Z","shell.execute_reply":"2021-06-10T07:11:37.021878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#確認有訓練資料\ncat_files= os.listdir('./input/cifar10/train/cat')\nprint('training example for cats:',len(cat_files))\nprint(cat_files[:5])","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:12:16.469922Z","iopub.execute_input":"2021-06-10T07:12:16.470389Z","iopub.status.idle":"2021-06-10T07:12:16.48365Z","shell.execute_reply.started":"2021-06-10T07:12:16.470335Z","shell.execute_reply":"2021-06-10T07:12:16.482215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"automobile_files= os.listdir('./input/cifar10/train/automobile')\nprint('training example for automobiles:',len(automobile_files))\nprint(automobile_files[:5])","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:12:38.429056Z","iopub.execute_input":"2021-06-10T07:12:38.429442Z","iopub.status.idle":"2021-06-10T07:12:38.443085Z","shell.execute_reply.started":"2021-06-10T07:12:38.42941Z","shell.execute_reply":"2021-06-10T07:12:38.441575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#確認有測試資料\ncat_files= os.listdir('./input/cifar10/test/cat')\nprint('of test example for cats:',len(cat_files))\nprint(cat_files[:5])","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:12:47.740108Z","iopub.execute_input":"2021-06-10T07:12:47.740526Z","iopub.status.idle":"2021-06-10T07:12:47.750657Z","shell.execute_reply.started":"2021-06-10T07:12:47.740463Z","shell.execute_reply":"2021-06-10T07:12:47.749141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#建立dataset 並確認\ndata_dir = './input/cifar10'\ndataset = ImageFolder(data_dir+'/train', transform=ToTensor())\nimg, label= dataset[0]\nprint(dataset.classes)\nprint(img.shape,label)\nimg","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:14:39.944066Z","iopub.execute_input":"2021-06-10T07:14:39.944477Z","iopub.status.idle":"2021-06-10T07:14:40.369513Z","shell.execute_reply.started":"2021-06-10T07:14:39.944444Z","shell.execute_reply":"2021-06-10T07:14:40.368312Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_image(img,label):\n    print('Label: ', dataset.classes[label],\"(\"+str(label)+\")\")\n    plt.imshow(img.permute(1,2,0))","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:15:34.003953Z","iopub.execute_input":"2021-06-10T07:15:34.004334Z","iopub.status.idle":"2021-06-10T07:15:34.013683Z","shell.execute_reply.started":"2021-06-10T07:15:34.004303Z","shell.execute_reply":"2021-06-10T07:15:34.012547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_image(dataset[200][0],dataset[200][1])","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:15:34.883261Z","iopub.execute_input":"2021-06-10T07:15:34.883651Z","iopub.status.idle":"2021-06-10T07:15:35.087164Z","shell.execute_reply.started":"2021-06-10T07:15:34.883597Z","shell.execute_reply":"2021-06-10T07:15:35.085995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"4\"></a>\n## Training and Validation Datasets","metadata":{}},{"cell_type":"code","source":"#裁切訓練集與驗證集\nval_size = 5000\ntrain_size = len(dataset) - val_size\ntrain_ds, val_ds = random_split(dataset,[train_size, val_size])\nlen(train_ds), len(val_ds)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:17:20.255973Z","iopub.execute_input":"2021-06-10T07:17:20.256333Z","iopub.status.idle":"2021-06-10T07:17:20.2741Z","shell.execute_reply.started":"2021-06-10T07:17:20.256288Z","shell.execute_reply":"2021-06-10T07:17:20.2726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#建立DataLoader\nbatch_size=128\ntrain_dl = DataLoader(train_ds,batch_size,shuffle=True,num_workers=4,pin_memory=True )\nval_dl = DataLoader(val_ds, batch_size, num_workers=4, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:20:12.857362Z","iopub.execute_input":"2021-06-10T07:20:12.857794Z","iopub.status.idle":"2021-06-10T07:20:12.865769Z","shell.execute_reply.started":"2021-06-10T07:20:12.857749Z","shell.execute_reply":"2021-06-10T07:20:12.863865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#展示一批次圖片\ndef show_images_batch(d1):\n    for images, labels in d1:\n        fig, ax= plt.subplots(figsize=(16,8))\n        ax.set_xticks([])\n        ax.set_yticks([])\n        ax.imshow(make_grid(images, nrow=16).permute(1,2,0))\n        break ","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:20:14.813865Z","iopub.execute_input":"2021-06-10T07:20:14.814197Z","iopub.status.idle":"2021-06-10T07:20:14.822748Z","shell.execute_reply.started":"2021-06-10T07:20:14.814167Z","shell.execute_reply":"2021-06-10T07:20:14.821392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_images_batch(train_dl) # training data single batch images","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:20:15.859185Z","iopub.execute_input":"2021-06-10T07:20:15.859591Z","iopub.status.idle":"2021-06-10T07:20:21.403657Z","shell.execute_reply.started":"2021-06-10T07:20:15.859542Z","shell.execute_reply":"2021-06-10T07:20:21.402204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_images_batch(val_dl) # validation data single batch images","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:20:39.787743Z","iopub.execute_input":"2021-06-10T07:20:39.78812Z","iopub.status.idle":"2021-06-10T07:20:40.931022Z","shell.execute_reply.started":"2021-06-10T07:20:39.788085Z","shell.execute_reply":"2021-06-10T07:20:40.929728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#定義準確率計算方式\ndef accuracy(outputs,labels):\n    _,preds= torch.max(outputs, dim=1)\n    return torch.tensor(torch.sum(preds==labels).item()/len(preds))\n\nclass ImageClassificationBase(nn.Module):\n    #訓練環節\n    def training_step(self,batch):\n        images,labels= batch \n        images, labels = images.cuda(), labels.cuda()\n        out= self(images)  #預測\n        loss= F.cross_entropy(out,labels) #計算loss\n        return loss\n    \n    #驗證環節\n    def validation_step(self,batch):\n        images, labels = batch\n        images, labels = images.cuda(), labels.cuda()\n        out = self(images)  # 預測\n        loss= F.cross_entropy(out,labels) # 計算loss\n        acc= accuracy(out,labels)\n        return {'val_loss':loss.detach(), 'val_acc':acc}\n    \n    #驗證結束\n    def validation_epoch_end(self, outputs):\n        batch_losses = [x['val_loss'] for x in outputs]\n        epoch_loss= torch.stack(batch_losses).mean() # epoch_loss為batch_losses的平均\n        batch_accs = [x['val_acc'] for x in outputs]\n        epoch_acc = torch.stack(batch_accs).mean()\n        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}\n    \n    #訓練結束\n    def epoch_end(self,epoch,result):\n        print(\"Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}\".format(\n            epoch, result['train_loss'], result['val_loss'], result['val_acc']))","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:28:39.883999Z","iopub.execute_input":"2021-06-10T07:28:39.884352Z","iopub.status.idle":"2021-06-10T07:28:39.902337Z","shell.execute_reply.started":"2021-06-10T07:28:39.884323Z","shell.execute_reply":"2021-06-10T07:28:39.900952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#捲機神經網路\nclass Cifar10CnnModel(ImageClassificationBase):\n    def __init__(self):\n        super().__init__()\n        self.network = nn.Sequential(\n            nn.Conv2d(3, 32, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2), # output: 64 x 16 x 16\n\n            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2), # output: 128 x 8 x 8\n\n            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2), # output: 256 x 4 x 4\n\n            nn.Flatten(), \n            nn.Linear(256*4*4, 1024),\n            nn.ReLU(),\n            nn.Linear(1024, 512),\n            nn.ReLU(),\n            nn.Linear(512, 10))\n        \n    def forward(self, xb):\n        return self.network(xb)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:28:40.564519Z","iopub.execute_input":"2021-06-10T07:28:40.564932Z","iopub.status.idle":"2021-06-10T07:28:40.581471Z","shell.execute_reply.started":"2021-06-10T07:28:40.564885Z","shell.execute_reply":"2021-06-10T07:28:40.580586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model= Cifar10CnnModel().cuda()\nmodel","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:29:01.513332Z","iopub.execute_input":"2021-06-10T07:29:01.513771Z","iopub.status.idle":"2021-06-10T07:29:01.585263Z","shell.execute_reply.started":"2021-06-10T07:29:01.513735Z","shell.execute_reply":"2021-06-10T07:29:01.58391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#預測測試\nfor images, labels in train_dl:\n    images, labels = images.cuda(), labels.cuda()\n    print('images.shape:', images.shape)\n    out = model(images)\n    print('out.shape:',out.shape)\n    print('out[0]',out[0])\n    break","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:29:31.294215Z","iopub.execute_input":"2021-06-10T07:29:31.294648Z","iopub.status.idle":"2021-06-10T07:29:32.403197Z","shell.execute_reply.started":"2021-06-10T07:29:31.294615Z","shell.execute_reply":"2021-06-10T07:29:32.401134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"[i+1 for i in range(4)]\n\n","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:32:18.47231Z","iopub.execute_input":"2021-06-10T07:32:18.472674Z","iopub.status.idle":"2021-06-10T07:32:18.484409Z","shell.execute_reply.started":"2021-06-10T07:32:18.472641Z","shell.execute_reply":"2021-06-10T07:32:18.483347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"6\"></a>\n# Training the Model","metadata":{}},{"cell_type":"code","source":"#測試時不需要跟新權重，關閉更新權重以加速訓練\n@torch.no_grad() \ndef evaluate(model, val_loader):\n    model.eval() #切換模型至測試模式\n    outputs = [model.validation_step(batch) for batch in val_loader] #python語法糖\n    return model.validation_epoch_end(outputs)\n  \ndef fit(epochs, lr, model, train_loader, val_loader, opt_func= torch.optim.SGD):\n    history=[]\n    optimizer= opt_func(model.parameters(),lr) # 宣告優化器\n    for epoch in range(epochs):\n        model.train() # 切換模型至訓練模式\n        train_losses=[]\n        for batch in train_loader:\n            loss= model.training_step(batch)\n            train_losses.append(loss)\n            loss.backward() #compute  gradients\n            optimizer.step()\n            optimizer.zero_grad() # zero the gradients\n\n        result= evaluate(model,val_loader)\n        result['train_loss'] = torch.stack(train_losses).mean().item()\n        model.epoch_end(epoch, result)\n        history.append(result)\n    return history\n            ","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:37:17.216108Z","iopub.execute_input":"2021-06-10T07:37:17.216494Z","iopub.status.idle":"2021-06-10T07:37:17.228535Z","shell.execute_reply.started":"2021-06-10T07:37:17.216454Z","shell.execute_reply":"2021-06-10T07:37:17.227491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"evaluate(model,val_dl)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:37:23.448152Z","iopub.execute_input":"2021-06-10T07:37:23.448471Z","iopub.status.idle":"2021-06-10T07:37:25.278256Z","shell.execute_reply.started":"2021-06-10T07:37:23.448441Z","shell.execute_reply":"2021-06-10T07:37:25.277212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#設定超參數\nnum_epochs = 5\nopt_func = torch.optim.Adam\nlr = 0.001","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:38:08.906935Z","iopub.execute_input":"2021-06-10T07:38:08.907342Z","iopub.status.idle":"2021-06-10T07:38:08.913444Z","shell.execute_reply.started":"2021-06-10T07:38:08.907302Z","shell.execute_reply":"2021-06-10T07:38:08.911978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = fit(num_epochs, lr, model, train_dl, val_dl, opt_func)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:38:12.171772Z","iopub.execute_input":"2021-06-10T07:38:12.17218Z","iopub.status.idle":"2021-06-10T07:39:48.962764Z","shell.execute_reply.started":"2021-06-10T07:38:12.172151Z","shell.execute_reply":"2021-06-10T07:39:48.960796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#繪製準確率圖表\ndef plot_accuracies(history):\n    accuracies=[x['val_acc'] for x in history]\n    plt.plot(accuracies,'-x')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.title('Accuracy vs No of epochs')","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:40:58.218381Z","iopub.execute_input":"2021-06-10T07:40:58.218795Z","iopub.status.idle":"2021-06-10T07:40:58.226005Z","shell.execute_reply.started":"2021-06-10T07:40:58.218758Z","shell.execute_reply":"2021-06-10T07:40:58.224416Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10,6))\nplot_accuracies(history)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:40:59.577513Z","iopub.execute_input":"2021-06-10T07:40:59.578Z","iopub.status.idle":"2021-06-10T07:40:59.882093Z","shell.execute_reply.started":"2021-06-10T07:40:59.577969Z","shell.execute_reply":"2021-06-10T07:40:59.880772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#繪製loss圖表\ndef plot_losses(history):\n    train_losses = [x.get('train_loss') for x in history]\n    val_losses = [x['val_loss'] for x in history]\n    plt.plot(train_losses, '-bx')\n    plt.plot(val_losses, '-rx')\n    plt.xlabel('epoch')\n    plt.ylabel('loss')\n    plt.legend(['Training', 'Validation'])\n    plt.title('Loss vs. No. of epochs');","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:41:19.232046Z","iopub.execute_input":"2021-06-10T07:41:19.232402Z","iopub.status.idle":"2021-06-10T07:41:19.241938Z","shell.execute_reply.started":"2021-06-10T07:41:19.232371Z","shell.execute_reply":"2021-06-10T07:41:19.240147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10,6))\nplot_losses(history)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:41:20.21134Z","iopub.execute_input":"2021-06-10T07:41:20.211735Z","iopub.status.idle":"2021-06-10T07:41:20.415494Z","shell.execute_reply.started":"2021-06-10T07:41:20.211703Z","shell.execute_reply":"2021-06-10T07:41:20.414028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"7\"></a>\n# Testing with individual images","metadata":{}},{"cell_type":"code","source":"test_dataset = ImageFolder(data_dir+'/test', transform=ToTensor())\ntest_dataset","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:42:44.781822Z","iopub.execute_input":"2021-06-10T07:42:44.782173Z","iopub.status.idle":"2021-06-10T07:42:44.856477Z","shell.execute_reply.started":"2021-06-10T07:42:44.782142Z","shell.execute_reply":"2021-06-10T07:42:44.853588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_image(img, model):\n    xb = img.unsqueeze(0).cuda()\n    yb = model(xb)\n    _, preds= torch.max(yb, dim=1)\n    return dataset.classes[preds[0].item()]","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:43:21.907607Z","iopub.execute_input":"2021-06-10T07:43:21.908047Z","iopub.status.idle":"2021-06-10T07:43:21.914896Z","shell.execute_reply.started":"2021-06-10T07:43:21.908017Z","shell.execute_reply":"2021-06-10T07:43:21.913385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#查看測試資料\nimg,label= test_dataset[5]\nplt.imshow(img.permute(1,2,0))\nprint('Label:', dataset.classes[label], ', Predicted:', predict_image(img, model))","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:43:52.388941Z","iopub.execute_input":"2021-06-10T07:43:52.389366Z","iopub.status.idle":"2021-06-10T07:43:52.561901Z","shell.execute_reply.started":"2021-06-10T07:43:52.389295Z","shell.execute_reply":"2021-06-10T07:43:52.560319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#測試結果\ntest_loader = DataLoader(test_dataset,batch_size)\ntest_result = evaluate(model, test_loader)\ntest_result","metadata":{"execution":{"iopub.status.busy":"2021-06-10T07:44:19.647263Z","iopub.execute_input":"2021-06-10T07:44:19.64778Z","iopub.status.idle":"2021-06-10T07:44:24.422758Z","shell.execute_reply.started":"2021-06-10T07:44:19.647716Z","shell.execute_reply":"2021-06-10T07:44:24.421492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}