{"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":"# 이름 : 전상혁\n# 학번 : 20163250\n--------------\n## Final Project \n\n### Project: Painting classification\n\n### Due date: 2021.06.17\n\n### 다음 링크로 접속하여 우선 팀 명을 바꿉니다. ex)20185141_용권순\nhttps://www.kaggle.com/competitions/2022-deep-learning-basics-challenge\n\n#### Data로 가서 Data를 모두 다운 받습니다. 그 다음은 Template code를 따라서 진행하시면 됩니다. \n>##### 최종실행 후  csv파일을 업로드 하시면 public결과가 보여집니다. \n\n---\n\n* 아래 여러 셀에서 코드를 완성하는 부분을 수행하고, 보고서에 설명을 최대한 자세하게 적어주세요. 기준은 본인이 이해하고 있다는 것을 표현할 수 있는 부분을 모두 적으시면 됩니다.\n  \n  \n> **제출방법**: \n* 보고서에는 코드 캡쳐 첨부이외에도, 각 코드를 작성하는 기반 이론, 방법론과 설명을 작성하세요.\n---------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T04:27:09.729446Z","iopub.status.busy":"2022-05-02T04:27:09.729037Z","iopub.status.idle":"2022-05-02T04:27:09.736951Z","shell.execute_reply":"2022-05-02T04:27:09.7359Z","shell.execute_reply.started":"2022-05-02T04:27:09.729396Z"}}},{"cell_type":"markdown","source":"## Final project 규칙\n\n- 학생들 간의 질문은 금지합니다 (교수 및 조교에게 질문하세요)\n- 대 원칙은 \"내가 이해한 것만 활용하고 작성한다\" 입니다\n- 사용하는 기법들과 코드는 모두 보고서에 설명되어야하며, 설명이 없는 경우 감점이나 0점 처리합니다\n    - 예를 들어서 검색한 끝에 model ensemble이라는 기법이 유용할 것 같아서, 참고하여 성능을 개선한 경우\n        1. 참고자료의 출처를 작성할 것\n        2. 기반 이론을 설명할 것\n        3. 사용한 코드 분석 및 기법을 설명할 것\n- 주석이 없는 경우 채점하지 않습니다\n- <p style=\"color:red;\">Pretrained network은 사용하지 않습니다. 본 프로젝트에서는, random 초기화한 parameter들을 직접 학습하는 과정만 허용합니다</p>\n\n    - 랜덤 초기화 기법은 특별한 제약이 없습니다\n- Competition 순위와 보고서는 각각 5:5로 점수가 반영됩니다.\n------------------------\n\n# 주의: 최종적으로 제출한 csv파일이 code에서 돌린 파일과 일치해야합니다. \n> + 기말 프로젝트 제출 시, model의 파라메터가 저장된 pt 파일, 보고서를 같이 제출합니다. \n> + 체점 과정 중 kaggle에 올라간 최종 csv파일과 제출한 모델을 사용하여 학생이 제출한 code로 csv생성 및 비교합니다(수기 변경 방지).\n> + kaggle에 올라간 최종 csv파일과 학생이 제출한 code로 생성한 csv파일이 다를 경우 감점 요소가 생길 수 있으니 주의해주시길 바랍니다.\n\n## 제출 하기 전 모든 셀을 정리해서 커널을 다시 실행하는 것을 권장 ","metadata":{}},{"cell_type":"markdown","source":"---\n","metadata":{}},{"cell_type":"markdown","source":"# 배경 설명\n\n> #### 여러분은 유명한 화가의 작품을 전시하는 유명한 미술관에 취업했습니다. \n>#### 최근 미술관이 대량의 작품을 입수하여, 각 화가들의 전시회를 열려고 합니다.   \n>#### 그러나 작품의 수가 너무나 많아서 사람이 분류하기에는 시간이 오래 걸릴것이라고 판단됩니다. \n>#### 이에 여러분은 딥러닝을 사용하여 효율적인 화가별 그림 분류 프로그램을 만들고자 합니다.\n\n# 목표: \n> ### 본 프로젝트의 완성본은, 새로운 그림(Image)입력하면 <p style=\"color:red\">해당 그림을 그린 화가를 예측합니다.</p>\n\n","metadata":{}},{"cell_type":"markdown","source":"-------------------------------\n------------------------------\n-----------------------------","metadata":{}},{"cell_type":"markdown","source":"## Step 0: Import library\n\n- 필요하다 생각되는 라이브러리를 미리 import합니다. (참고)\n- 필요 없는 라이브러리를 제거하거나 필요한 라이브러리를 추가하셔도 됩니다.","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom tqdm.auto import tqdm, trange\nimport random\nimport pandas as pd\nfrom PIL import Image\nfrom pathlib import Path\nfrom collections import OrderedDict\nfrom time import time, ctime, localtime\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.utils.data.sampler import SubsetRandomSampler\nfrom torch.utils.data import Dataset,DataLoader\n\nimport torchvision\nimport torchvision.transforms as transforms\n\nfrom torchvision import datasets\nfrom torchvision import models\n\n\nfrom sklearn.metrics import f1_score\nfrom sklearn.model_selection import train_test_split,train_test_split\nfrom sklearn.model_selection import StratifiedKFold,  KFold\n","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.17204Z","iopub.execute_input":"2022-06-17T12:21:55.172485Z","iopub.status.idle":"2022-06-17T12:21:55.182136Z","shell.execute_reply.started":"2022-06-17T12:21:55.172438Z","shell.execute_reply":"2022-06-17T12:21:55.181175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CUDA 사용 가능한지 확인\ntrain_on_gpu = torch.cuda.is_available()\n#train_on_gpu = False\n\nif not train_on_gpu:\n    device = 'cpu'\n    print('CUDA is not available.  Training on CPU ...')\nelse:\n    device = 'cuda'\n    print('CUDA is available!  Training on GPU ...')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.193839Z","iopub.execute_input":"2022-06-17T12:21:55.194611Z","iopub.status.idle":"2022-06-17T12:21:55.201542Z","shell.execute_reply.started":"2022-06-17T12:21:55.194561Z","shell.execute_reply":"2022-06-17T12:21:55.200555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"-----------------------------------","metadata":{}},{"cell_type":"markdown","source":"## Step 1: Preparing Dataset \n### 1-1: 경로 설정","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"# # obtain one batch of training images\n# dataiter = iter(train_loader)\n# images, labels = dataiter.next()\n# images = images.numpy() # convert images to numpy for display\n\n# # plot the images in the batch, along with the corresponding labels\n# fig = plt.figure(figsize=(25, 4))\n# # display 20 images\n# for idx in np.arange(20):\n#     ax = fig.add_subplot(2, int(20/2), idx+1, xticks=[], yticks=[])\n#     imshow(images[idx])\n#     ax.set_title(classes[labels[idx]])","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.214613Z","iopub.execute_input":"2022-06-17T12:21:55.215002Z","iopub.status.idle":"2022-06-17T12:21:55.220557Z","shell.execute_reply.started":"2022-06-17T12:21:55.214961Z","shell.execute_reply":"2022-06-17T12:21:55.219376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#본인 컴퓨터에 맞는 train folder의 위치를 입력합니다.(string)\ntrain_dir = '../input/2022-deep-learning-basics-challenge/painting_resize_256/train'   ","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.234754Z","iopub.execute_input":"2022-06-17T12:21:55.235308Z","iopub.status.idle":"2022-06-17T12:21:55.239384Z","shell.execute_reply.started":"2022-06-17T12:21:55.235271Z","shell.execute_reply":"2022-06-17T12:21:55.238559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 폴더의 목록(화가의 이름)을 가지고 옵니다. 총 class : 15개  \nclasses = []\n#class목록을 저장할 list \nfor i in range(len(glob.glob(train_dir+'/*'))):\n    classes.append(glob.glob(train_dir+'/*')[i].split('/')[-1])\nclass_num = len(classes)\nprint('Total Class num: ',class_num)\nprint('Class label:')\nfor i in range(class_num):print('{:5d}th : ' .format(i+1),classes[i])","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.262668Z","iopub.execute_input":"2022-06-17T12:21:55.263209Z","iopub.status.idle":"2022-06-17T12:21:55.285554Z","shell.execute_reply.started":"2022-06-17T12:21:55.263174Z","shell.execute_reply":"2022-06-17T12:21:55.284622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# #ABC 순서대로 정렬\n# classes = sorted(classes)\n# classes","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.288743Z","iopub.execute_input":"2022-06-17T12:21:55.289184Z","iopub.status.idle":"2022-06-17T12:21:55.29275Z","shell.execute_reply.started":"2022-06-17T12:21:55.289138Z","shell.execute_reply":"2022-06-17T12:21:55.291976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 1-2. 제대로 read 되는지 확인 (Transform적용)","metadata":{}},{"cell_type":"code","source":"#이미지 확인하기 위한 함수 정의\ndef check_Image(image_path,transform =None):\n    image = Image.open(image_path).convert(\"RGB\")\n    if transform ==None:\n        return image\n    else: return transform(image)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.324412Z","iopub.execute_input":"2022-06-17T12:21:55.325343Z","iopub.status.idle":"2022-06-17T12:21:55.334072Z","shell.execute_reply.started":"2022-06-17T12:21:55.325274Z","shell.execute_reply":"2022-06-17T12:21:55.332527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image = \"../input/2022-deep-learning-basics-challenge/painting_resize_256/train/Andy_Warhol/Andy_Warhol_103.jpg\"\ncheck_Image(image)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.347501Z","iopub.execute_input":"2022-06-17T12:21:55.348709Z","iopub.status.idle":"2022-06-17T12:21:55.400584Z","shell.execute_reply.started":"2022-06-17T12:21:55.348638Z","shell.execute_reply":"2022-06-17T12:21:55.399762Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#image가 어떤 식으로 transform 되는지 확인하고 싶을 때 사용하시면 됩니다. \ntransform = transforms.Compose([transforms.Grayscale(1)])\ncheck_Image(image,transform)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.402639Z","iopub.execute_input":"2022-06-17T12:21:55.402938Z","iopub.status.idle":"2022-06-17T12:21:55.429755Z","shell.execute_reply.started":"2022-06-17T12:21:55.402899Z","shell.execute_reply":"2022-06-17T12:21:55.428785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Step2: Generating DataLoader for Dataset","metadata":{}},{"cell_type":"code","source":"#train_transforms 규정\ntrain_transforms = transforms.Compose([\n    transforms.ToTensor(),\n    #RGB color dataset 쓰기 때문에 각 채녈 마다 mean,std 적용\n    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) \n\ntrain_data = datasets.ImageFolder(train_dir, transform = train_transforms)\n#classes ABC순으로 정렬 하기 위해 train_data.classes로 classes 정의\nclasses = train_data.classes","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.43192Z","iopub.execute_input":"2022-06-17T12:21:55.433087Z","iopub.status.idle":"2022-06-17T12:21:55.481628Z","shell.execute_reply.started":"2022-06-17T12:21:55.433016Z","shell.execute_reply":"2022-06-17T12:21:55.480825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.482923Z","iopub.execute_input":"2022-06-17T12:21:55.483325Z","iopub.status.idle":"2022-06-17T12:21:55.489885Z","shell.execute_reply.started":"2022-06-17T12:21:55.483294Z","shell.execute_reply":"2022-06-17T12:21:55.4889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T07:16:33.271344Z","iopub.status.busy":"2022-05-02T07:16:33.271002Z","iopub.status.idle":"2022-05-02T07:16:33.277614Z","shell.execute_reply":"2022-05-02T07:16:33.276446Z","shell.execute_reply.started":"2022-05-02T07:16:33.271298Z"}}},{"cell_type":"code","source":"# train, validation dataset spliting\n# trainig dataset의 20%를 validation으로 사용\nvalid_size = 0.2\n\nnum_train = len(train_data) # train_data의 수\nnum_train = int(num_train) # integer로 변환\nindices = list(range(num_train)) #0~3336 list\nnp.random.shuffle(indices) #list 값을 랜덤화 진행\nsplit = int(np.floor(valid_size * num_train)) #split = 667\n\n#train_idx -> 2670 valid_idx -> 667\ntrain_idx, valid_idx = indices[split:], indices[:split]\n\n\n\n# train sampler, valid sampler define\ntrain_sampler = SubsetRandomSampler(train_idx)\nvalid_sampler = SubsetRandomSampler(valid_idx)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.491754Z","iopub.execute_input":"2022-06-17T12:21:55.492088Z","iopub.status.idle":"2022-06-17T12:21:55.500891Z","shell.execute_reply.started":"2022-06-17T12:21:55.492058Z","shell.execute_reply":"2022-06-17T12:21:55.500362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_sampler)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.502187Z","iopub.execute_input":"2022-06-17T12:21:55.502619Z","iopub.status.idle":"2022-06-17T12:21:55.514584Z","shell.execute_reply.started":"2022-06-17T12:21:55.502589Z","shell.execute_reply":"2022-06-17T12:21:55.513833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(valid_sampler)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.515863Z","iopub.execute_input":"2022-06-17T12:21:55.516126Z","iopub.status.idle":"2022-06-17T12:21:55.526143Z","shell.execute_reply.started":"2022-06-17T12:21:55.516087Z","shell.execute_reply":"2022-06-17T12:21:55.525558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# batch size define\nbatch_size = 16","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.527515Z","iopub.execute_input":"2022-06-17T12:21:55.527916Z","iopub.status.idle":"2022-06-17T12:21:55.537252Z","shell.execute_reply.started":"2022-06-17T12:21:55.527873Z","shell.execute_reply":"2022-06-17T12:21:55.536298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# prepare data loaders (combine dataset and sampler)\ntrain_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,\n    sampler=train_sampler)\nvalid_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, \n    sampler=valid_sampler)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.539406Z","iopub.execute_input":"2022-06-17T12:21:55.539868Z","iopub.status.idle":"2022-06-17T12:21:55.54907Z","shell.execute_reply.started":"2022-06-17T12:21:55.539825Z","shell.execute_reply":"2022-06-17T12:21:55.548471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_loader)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.550944Z","iopub.execute_input":"2022-06-17T12:21:55.551482Z","iopub.status.idle":"2022-06-17T12:21:55.563545Z","shell.execute_reply.started":"2022-06-17T12:21:55.551447Z","shell.execute_reply":"2022-06-17T12:21:55.562651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(valid_loader)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.565589Z","iopub.execute_input":"2022-06-17T12:21:55.566049Z","iopub.status.idle":"2022-06-17T12:21:55.574997Z","shell.execute_reply.started":"2022-06-17T12:21:55.566005Z","shell.execute_reply":"2022-06-17T12:21:55.574466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Step 3: Generating Neural Network(model) \n - <p style=\"color:red;\">Pretrained network은 사용하지 않습니다. 본 프로젝트에서는, random 초기화한 parameter들을 직접 학습하는 과정만 허용합니다</p>\n - 모델을 선정한 이유를 간략하게 정리합니다.","metadata":{}},{"cell_type":"code","source":"# define the CNN architecture\nclass ConvNet(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # convolutional layer (sees 3x256x256 image tensor)\n        self.conv1 = nn.Conv2d(3,16,3,stride=1,padding=1)\n        # convolutional layer (sees 16x128x128 tensor)\n        self.conv2 = nn.Conv2d(16,32,3,stride=1,padding=1)\n        # convolutional layer (sees 32x64x64 tensor)\n        self.conv3 = nn.Conv2d(32,64,3,stride=1,padding=1)\n        # convolutional layer (sees 64x32x32 tensor)\n        self.conv4 = nn.Conv2d(64,128,3,stride=1,padding=1)\n        # convolutional layer (sees 128x16x16 tensor)\n        self.conv5 = nn.Conv2d(128,256,3,stride=1,padding=1)\n        # convolutional layer (sees 256x8x8 tensor)\n        self.conv6 = nn.Conv2d(256,512,3,stride=1,padding=1)\n        # max pooling layer\n        self.pool = nn.MaxPool2d(2,2)\n        # linear layer (512 * 4 * 4 -> 400)\n        self.fc1 = nn.Linear(512*4*4,400)\n\n        self.fc2 = nn.Linear(400,15)\n        \n        \n        # dropout layer (p=0.25)\n        self.dropout = nn.Dropout(0.5)\n        self.relu = nn.ReLU(True)\n\n    def forward(self, x):\n        # add sequence of convolutional and max pooling layers\n        x = self.pool(self.relu(self.conv1(x))) #torch.Size([16, 16, 128, 128])\n\n        x = self.pool(self.relu(self.conv2(x))) #torch.Size([16, 32, 64, 64])\n\n        x = self.pool(self.relu(self.conv3(x))) #torch.Size([16, 64, 32, 32])\n\n        x = self.pool(self.relu(self.conv4(x))) #torch.Size([16, 128, 16, 16])\n \n        x = self.pool(self.relu(self.conv5(x))) #torch.Size([16, 256, 8, 8])\n\n        x = self.pool(self.relu(self.conv6(x))) #torch.Size([16, 512, 4, 4])\n\n        # flatten image input\n        x = x.reshape(-1,512*4*4)\n        \n        # add dropout layer\n        x = self.dropout(x)\n        # add 1st hidden layer, with relu activation function\n        x = self.relu(self.fc1(x))     \n        \n        x = self.dropout(x)\n        # add 2nd hidden layer, with relu activation function\n        x = self.fc2(x)\n        \n        return x\n\n# create a complete CNN\nmodel = ConvNet()\n\n# move tensors to GPU if CUDA is available\nmodel.to(device)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.576575Z","iopub.execute_input":"2022-06-17T12:21:55.57684Z","iopub.status.idle":"2022-06-17T12:21:55.633829Z","shell.execute_reply.started":"2022-06-17T12:21:55.576811Z","shell.execute_reply":"2022-06-17T12:21:55.63296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T07:16:33.271344Z","iopub.status.busy":"2022-05-02T07:16:33.271002Z","iopub.status.idle":"2022-05-02T07:16:33.277614Z","shell.execute_reply":"2022-05-02T07:16:33.276446Z","shell.execute_reply.started":"2022-05-02T07:16:33.271298Z"}}},{"cell_type":"markdown","source":"## Step 4: Selecting Cost(Loss) Function & Optimizer\n> +  [loss function](http://pytorch.org/docs/stable/nn.html#loss-functions) 및 [optimizer](http://pytorch.org/docs/stable/optim.html)를 선택하여 코드를 완성하세요.\n  링크에서 다양한 Loss Function과 Optimize Function을 확인 할 수 있습니다","metadata":{}},{"cell_type":"code","source":"# loss function 지정(categorical cross-entropy)\ncriterion = nn.CrossEntropyLoss()\n\n# optimizer 지정\noptimizer = optim.Adam(model.parameters(), lr=0.0001, weight_decay=0.005)","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.635496Z","iopub.execute_input":"2022-06-17T12:21:55.635805Z","iopub.status.idle":"2022-06-17T12:21:55.640472Z","shell.execute_reply.started":"2022-06-17T12:21:55.635772Z","shell.execute_reply":"2022-06-17T12:21:55.639781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T07:16:33.271344Z","iopub.status.busy":"2022-05-02T07:16:33.271002Z","iopub.status.idle":"2022-05-02T07:16:33.277614Z","shell.execute_reply":"2022-05-02T07:16:33.276446Z","shell.execute_reply.started":"2022-05-02T07:16:33.271298Z"}}},{"cell_type":"markdown","source":"## Step 5: Train and validate the configured model\n### 학습 및 검증 과정을 진행합니다\n+ 학습 과정을 주석으로 설명하세요 \n+ Epoch별로 Loss, Accuracy를 출력하여 학습 진행 과정을 확인 할 수 있도록 합니다\n+ 출력 예시는 주어지나 정해진 형식은 없습니다\n+ 최적의 모델 파라메터를 저장합니다.\n\nFor example : \n```python\nStarted Training...\nEpoch: 1    Training Loss: 3.317162     Validation Loss: 4.162958\nEpoch: 2    Training Loss: 2.420140     Validation Loss: 4.182362\n...\n...\nFinished training\n```","metadata":{}},{"cell_type":"code","source":"print('Started Training...')\n\n# number of epochs to train the model\nn_epochs = 10\n\nvalid_loss_min = np.Inf # track change in validation loss\n\n# keep track of training and validation loss\ntrain_loss = torch.zeros(n_epochs)\nvalid_loss = torch.zeros(n_epochs)\n\ntrain_acc = torch.zeros(n_epochs)\nvalid_acc = torch.zeros(n_epochs)\n\nfor e in range(0, n_epochs):\n\n   \n    ###################\n    # train the model #\n    ###################\n    model.train()\n    for data, labels in train_loader:\n        # move tensors to GPU if CUDA is available\n        data, labels = data.to(device), labels.to(device)\n        # clear the gradients of all optimized variables\n        \n        optimizer.zero_grad()\n        # forward pass: compute predicted outputs by passing inputs to the model\n        logits = model(data)\n        # calculate the batch loss\n        loss = criterion(logits, labels)\n        # backward pass: compute gradient of the loss with respect to model parameters\n        loss.backward()\n        # perform a single optimization step (parameter update)\n        optimizer.step()\n        # update training loss\n        train_loss[e] += loss.item()\n        \n        ps = F.softmax(logits, dim=1)\n        top_p, top_class = ps.topk(1, dim=1)\n        equals = top_class == labels.reshape(top_class.shape)\n        train_acc[e] += torch.mean(equals.type(torch.float)).detach().cpu()\n    \n    train_loss[e] /= len(train_loader)\n    train_acc[e] /= len(train_loader)\n        \n        \n    ######################    \n    # validate the model #\n    ######################\n    with torch.no_grad(): \n        model.eval()\n        for data, labels in valid_loader:\n            # move tensors to GPU if CUDA is available\n            data, labels = data.to(device), labels.to(device)\n            # forward pass: compute predicted outputs by passing inputs to the model\n            logits = model(data)\n            # calculate the batch loss\n            loss = criterion(logits, labels)\n            # update average validation loss \n            valid_loss[e] += loss.item()\n\n            ps = F.softmax(logits, dim=1)\n            top_p, top_class = ps.topk(1, dim=1)\n            equals = top_class == labels.reshape(top_class.shape)\n            valid_acc[e] += torch.mean(equals.type(torch.float)).detach().cpu()\n    \n    # calculate average losses\n    valid_loss[e] /= len(valid_loader)\n    valid_acc[e] /= len(valid_loader)\n        \n    # print training/validation statistics \n    print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n        e, train_loss[e], valid_loss[e]))\n    \n     # print training/validation statistics \n    print('Epoch: {} \\tTraining accuracy: {:.6f} \\tValidation accuracy: {:.6f}'.format(\n        e, train_acc[e], valid_acc[e]))\n    \n    # save model if validation loss has decreased\n    if valid_loss[e] <= valid_loss_min:\n        print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(\n        valid_loss_min,\n        valid_loss[e]))\n        torch.save(model.state_dict(), 'model_cov.pt')\n        valid_loss_min = valid_loss[e]\n\nprint('Finished Training...')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:21:55.641576Z","iopub.execute_input":"2022-06-17T12:21:55.641913Z","iopub.status.idle":"2022-06-17T12:46:19.282707Z","shell.execute_reply.started":"2022-06-17T12:21:55.641874Z","shell.execute_reply":"2022-06-17T12:46:19.28179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T07:16:33.271344Z","iopub.status.busy":"2022-05-02T07:16:33.271002Z","iopub.status.idle":"2022-05-02T07:16:33.277614Z","shell.execute_reply":"2022-05-02T07:16:33.276446Z","shell.execute_reply.started":"2022-05-02T07:16:33.271298Z"}}},{"cell_type":"markdown","source":"## Step 6: Analyze the  training/validation results\n+ 위에서 구한 학습 결과를 분석합니다. \n+ 수업에서 배운 그래프를 활용하시는 것을 적극 추천드립니다.\n+ 만족할만한 결과가 나올 때 까지 Hyper Parameter Tuning을 진행합니다. ","metadata":{}},{"cell_type":"code","source":"# loss graph \nplt.plot(train_loss, label = 'training loss')\nplt.plot(valid_loss, label = 'validation loss')\nplt.legend()","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.28442Z","iopub.execute_input":"2022-06-17T12:46:19.284662Z","iopub.status.idle":"2022-06-17T12:46:19.511829Z","shell.execute_reply.started":"2022-06-17T12:46:19.284632Z","shell.execute_reply":"2022-06-17T12:46:19.511006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# accuracy graph\nplt.plot(train_acc, label = 'training accuracy')\nplt.plot(valid_acc, label = 'validation accuracy')\nplt.legend()","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.513182Z","iopub.execute_input":"2022-06-17T12:46:19.513598Z","iopub.status.idle":"2022-06-17T12:46:19.723801Z","shell.execute_reply.started":"2022-06-17T12:46:19.513551Z","shell.execute_reply":"2022-06-17T12:46:19.723005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# save optimizer\ntorch.save(optimizer.state_dict(), 'opt_statedict.pt')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.725199Z","iopub.execute_input":"2022-06-17T12:46:19.725511Z","iopub.status.idle":"2022-06-17T12:46:19.790166Z","shell.execute_reply.started":"2022-06-17T12:46:19.72547Z","shell.execute_reply":"2022-06-17T12:46:19.789167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# save checkpoint\ncheckpoint = {'model_cov': model.state_dict(),\n             'optimizer_state_dict': optimizer.state_dict()}\n\ntorch.save(checkpoint, 'checkpoint.pt')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.791569Z","iopub.execute_input":"2022-06-17T12:46:19.792087Z","iopub.status.idle":"2022-06-17T12:46:19.882324Z","shell.execute_reply.started":"2022-06-17T12:46:19.792041Z","shell.execute_reply":"2022-06-17T12:46:19.881451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model, 'model.pt')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.885526Z","iopub.execute_input":"2022-06-17T12:46:19.885846Z","iopub.status.idle":"2022-06-17T12:46:19.921003Z","shell.execute_reply.started":"2022-06-17T12:46:19.885804Z","shell.execute_reply":"2022-06-17T12:46:19.920403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"--------------------------","metadata":{"execution":{"iopub.execute_input":"2022-05-02T07:16:33.271344Z","iopub.status.busy":"2022-05-02T07:16:33.271002Z","iopub.status.idle":"2022-05-02T07:16:33.277614Z","shell.execute_reply":"2022-05-02T07:16:33.276446Z","shell.execute_reply.started":"2022-05-02T07:16:33.271298Z"}}},{"cell_type":"markdown","source":"## Step 7: Define Test Data Set\n> Test data를 위한 Custom Test Dataset을 제공해드립니다.   \n> 필요한 부분을 채워 사용하시거나 직접 코드를 작성하셔도 됩니다.","metadata":{"execution":{"iopub.execute_input":"2022-04-29T07:02:16.640927Z","iopub.status.busy":"2022-04-29T07:02:16.640238Z","iopub.status.idle":"2022-04-29T07:02:16.644942Z","shell.execute_reply":"2022-04-29T07:02:16.644001Z","shell.execute_reply.started":"2022-04-29T07:02:16.640891Z"}}},{"cell_type":"code","source":"'''Custom Dataset을 제작하기 위해서는 3가지를 반드시 포함해야합니다. \n1.def __init__()      :초기화 함수입니다. Dataset을 상속받아 imagepath와 transform을 지정합니다.\n2.def __len__()       :dataset의 총 길이를 return하는 함수입니다. \n3.def __getitem__()   :index(idx)에 해당하는 data sample을 return 하는 함수입니다. \n'''\nclass test_Dataset(Dataset): #test_set을 class로 정의합니다.\n    def __init__(self,imgpath,transform=None):\n        \n        self.imgpath = imgpath\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.imgpath)\n    \n    def __getitem__(self,idx):\n        if self.transform !=None:\n            x = self.transform(Image.open(self.imgpath[idx]).convert('RGB'))\n        else: x = Image.open(self.imgpath[idx]).convert('RGB')\n        return x","metadata":{"tags":[],"execution":{"iopub.status.busy":"2022-06-17T12:46:19.922637Z","iopub.execute_input":"2022-06-17T12:46:19.923166Z","iopub.status.idle":"2022-06-17T12:46:19.932156Z","shell.execute_reply.started":"2022-06-17T12:46:19.923125Z","shell.execute_reply":"2022-06-17T12:46:19.931276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dir = '../input/2022-deep-learning-basics-challenge/painting_resize_256/test'\n#test_transform 정의 \ntest_transform = torchvision.transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])\n\ntest_set  = sorted(glob.glob(test_dir+'/*')) #모든 파일을 읽어서 정리합니다. \ntest_data = test_Dataset(test_set,test_transform)\n\n#Data Loader 작성 , (tip: test이므로 Shuffle을 할 필요가 없습니다. )\ntest_Dataloader = torch.utils.data.DataLoader(test_data, batch_size=len(test_data))","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:19.933576Z","iopub.execute_input":"2022-06-17T12:46:19.934018Z","iopub.status.idle":"2022-06-17T12:46:20.162499Z","shell.execute_reply.started":"2022-06-17T12:46:19.933987Z","shell.execute_reply":"2022-06-17T12:46:20.161654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test data 수 체크\nprint(\"test_data_len:\", test_data.__len__())","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:20.163728Z","iopub.execute_input":"2022-06-17T12:46:20.164465Z","iopub.status.idle":"2022-06-17T12:46:20.169047Z","shell.execute_reply.started":"2022-06-17T12:46:20.164412Z","shell.execute_reply":"2022-06-17T12:46:20.168225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"----------------","metadata":{}},{"cell_type":"markdown","source":"## Step 8(Final): Predict with Test Data\n### Step 8-1: Predict \n+ test data를 우리의 모델로 예측합니다.","metadata":{}},{"cell_type":"code","source":"#class 재 확인 15개인지 확인하십시오 \nprint('Total Class num: ',class_num)\nprint('Class label:')\nfor i in range(class_num):print('{:5d}th : ' .format(i+1),classes[i])","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:20.170281Z","iopub.execute_input":"2022-06-17T12:46:20.170509Z","iopub.status.idle":"2022-06-17T12:46:20.188981Z","shell.execute_reply.started":"2022-06-17T12:46:20.170482Z","shell.execute_reply":"2022-06-17T12:46:20.188323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 불러오기\n#최적의 모델 로드해서 predict를 진행합니다.\n\nmodel.load_state_dict(torch.load('model_cov.pt'))\nmodel.eval()","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:20.190269Z","iopub.execute_input":"2022-06-17T12:46:20.190945Z","iopub.status.idle":"2022-06-17T12:46:20.211925Z","shell.execute_reply.started":"2022-06-17T12:46:20.190897Z","shell.execute_reply":"2022-06-17T12:46:20.211002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# obtain one batch of test images\ndataiter = iter(test_Dataloader)\nimages = dataiter.next()\nimages.numpy()\n\n# move model inputs to cuda, if GPU available\nif train_on_gpu:\n    images = images.cuda()\n\n# get sample outputs\noutput = model(images)\n# convert output probabilities to predicted class\n_, preds_tensor = torch.max(output, 1)\npred = np.squeeze(preds_tensor.numpy()) if not train_on_gpu else np.squeeze(preds_tensor.cpu().numpy())","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:46:20.213954Z","iopub.execute_input":"2022-06-17T12:46:20.214518Z","iopub.status.idle":"2022-06-17T12:47:09.603624Z","shell.execute_reply.started":"2022-06-17T12:46:20.214478Z","shell.execute_reply":"2022-06-17T12:47:09.602747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#pred 확인\npred","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:47:09.604991Z","iopub.execute_input":"2022-06-17T12:47:09.606007Z","iopub.status.idle":"2022-06-17T12:47:09.615632Z","shell.execute_reply.started":"2022-06-17T12:47:09.605974Z","shell.execute_reply":"2022-06-17T12:47:09.614733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 8-2 : Making csv file with our predict result\n+ csv파일로 만드는 예시를 보여드립니다. ","metadata":{}},{"cell_type":"code","source":"name=[]                                     # 그림의 Id를 담을 list 생성 \ncategory =[]                                # 그림의 Category를 담을 list 생성\nfor i in range(test_data.__len__()):        #\n    name.append(test_set[i].split('/')[-1]) # 파일 이름에서 label만 가지고 옵니다. \n    category.append(classes[pred[i]])       # pred에 해당하는 class를 category에 집어 넣습니다. \n    \n    \ntm = localtime()\ncsv_file_name = f\"{tm.tm_mday}day_{tm.tm_hour}h_{tm.tm_min}m_{tm.tm_sec}s\"\n\n#파일의 이름은 마음대로 설정할 수 있습니다. 경로를 쓰지 않으면 현재 디렉토리에 알아서 생성됩니다. \npd.DataFrame({'Id':name,'Category':category}).to_csv(f'predict_{csv_file_name}.csv',index=False)                                                ","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:47:09.617225Z","iopub.execute_input":"2022-06-17T12:47:09.617797Z","iopub.status.idle":"2022-06-17T12:47:09.638863Z","shell.execute_reply.started":"2022-06-17T12:47:09.61776Z","shell.execute_reply":"2022-06-17T12:47:09.63805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#predict 하기 위해서 model 전체를 저장합니다. 체점을 위해서 필요한 과정입니다.\ntorch.save(model,f'./pt/model_{csv_file_name}.pt') ","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:47:09.639922Z","iopub.execute_input":"2022-06-17T12:47:09.640231Z","iopub.status.idle":"2022-06-17T12:47:09.664199Z","shell.execute_reply.started":"2022-06-17T12:47:09.640203Z","shell.execute_reply":"2022-06-17T12:47:09.663331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(name[:5])\nprint(category[:5])","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:50:02.913142Z","iopub.execute_input":"2022-06-17T12:50:02.9146Z","iopub.status.idle":"2022-06-17T12:50:02.920801Z","shell.execute_reply.started":"2022-06-17T12:50:02.914538Z","shell.execute_reply":"2022-06-17T12:50:02.919821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 잘 생성됬는지 확인 , 따로 경로를 설정하지 않았다면,현재 디렉토리에 자동으로 생성됩니다. \npd.read_csv(f'./predict_{csv_file_name}.csv')","metadata":{"execution":{"iopub.status.busy":"2022-06-17T12:50:04.916185Z","iopub.execute_input":"2022-06-17T12:50:04.917504Z","iopub.status.idle":"2022-06-17T12:50:04.942649Z","shell.execute_reply.started":"2022-06-17T12:50:04.91743Z","shell.execute_reply":"2022-06-17T12:50:04.941805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 생성한 csv파일을 kaggle에 등록하시면 됩니다.\n\n","metadata":{}}]}