-
2021 ML Dev-Matching | 미술 작품 분류하기 : 출제자가 추천한 우수 코드 C취업 이야기/데브매칭 문제 해설 2021. 7. 6. 09:32
목차
- 환경설정
- 데이터
- 데이터 lookup 테이블 만들기
- EDA
- Dataset & DataLoader
- train / valid 나누기
- get_loader
- 모델
- conv 모델
- efficientnet1
- timm
- 훈련
- 초기세팅
- criterion
- get_model
- get_optimizer
- get_scheduler
- train
- validate
- pseudo_labeling
- run
- 데이터 불러오기
- 훈련 진행
- 추론
- 앙상블
- kfold 훈련
- soft voting
2021 Dev-Matching: 머신러닝 과제테스트¶
☺️ 문제를 어떤 관점에서 정의하였는지 ☺️
문제는 이미지 분류 과제입니다. 주어진 데이터는 이미지고, 7가지 클래스로 분류하면 됩니다. 이미지는 데이터의 50% 이상이 노이즈이기 때문에, 딥러닝 모델이 유용합니다. 다만 어떤 관점에서 정의했냐고 말하기에는 너무나 명확한 문제라고 생각하기 때문에 문제 해결 과정을 적겠습니다.
8시간이라는 제한된 시간안에 밑바닥부터 코드를 작성해야 했기에, 일단 다른 것은 다 제쳐두고, 이미지 분류라는 과제를 해결하기 위한 베이스라인 코드를 구축하는 것부터 해결하고자 하였습니다. 환경설정, 데이터, 모델, 훈련을 위한 세팅 함수들을 하나씩 작성해나가면서 훈련 프로세스를 구축하였고, 빠른 실험을 위해 config만 수정하면 바로 새로운 실험을 실행할 수 있도록 하였습니다.
저는 문제 해결의 관점으로 다음의 3가지만 생각하였습니다
- 데이터
- 모델
- 앙상블
데이터의 경우 가볍게 EDA(Exploratory Data Analysis, 탐색적 데이터 분석)를 해본 결과 미술관에 전시될 그림들로 구성되어있었습니다. 리얼리즘과 추상화의 중간 즈음에 위치한 그림들로 대부분의 이미지들은 중앙에 위치하고 있고, 몇몇 누락된 이미지들을 제외하면 깔끔한 데이터라고 생각합니다. 무엇보다 불균형이 약간 있지만 크게 문제될 수준은 아니라고 보았습니다.
데이터에서는 특별히 손볼 것이 없다고 생각하여, 사용하는 모델에 맞춰 이미지 사이즈를 조정하는 것과 선형공선성을 막기 위한 normalization 정도만 진행하였습니다. 다양한 색을 augmentation으로 변형하여 넣어준다면 효과적일 수도 있다는 생각이 들었지만 넘어갔습니다.
모델에서는 SOTA(State-of-the-art)모델을 사용하는 것에 중점을 두었습니다. ViT(Vision Transformer)모델의 경우 기존 Convolution filter를 사용하던 모델에 비해 성능이 높고 가볍기 때문에 해당 모델을 중점으로 채용하였고 앙상블을 위해 Convolution filter를 사용한 다른 좋은 성능의 모델들도 사용하였습니다.
빠른 실험을 위해 timm 라이브러리를 사용하였습니다.
앙상블의 경우 빠르고 간단한 KFold 앙상블과, pseudo labeling 앙상블을 고려하였습니다.
정해진 시간 안에 끝내야 하는 만큼 간단하고 효과적인 요소들만 사용하였습니다.
☺️ 문제 해결 위해 만든 모델에 대한 설명과 그 모델을 선택한 이유 ☺️
처음에는 베이스라인 코드를 밑바닥부터 작성한만큼 에러를 잡기 위해 간단한 convnet모델로 출발하였습니다. 아주 작은 모델로 모델 학습이 진행되는지 알아보고자 테스트하였습니다.
그다음으로는 이전 SOTA였던 EfficientNet01을 불러와 작고 가볍지만 pretrained된 모델에서 성능 향상이 일어나는지 확인하였습니다. 성능은 확실히 증가하였고, 전체 훈련 프로세스 과정에 이상이 없다는 것을 확인한 후 바로 timm 모델을 사용하였습니다.
ViT(Vision Transformer)를 사용한 이유는 간단합니다. 가벼우며 성능이 매우 강력하기 때문입니다. 처음부터 자체적으로 훈련시킨다면 inductive bias가 약한 모델인만큼 사용하기 어렵겠지만 timm 라이브러리에서 pretrained된 모델을 얼마든지 가져다 쓸 수 있는 환경이기 때문에 가볍게 가져다가 사용하였습니다.
이외에 앙상블을 위해 convolution filter를 사용한 모델들 중 강력한 모델로 알려진 모델들을 가져다가 훈련시켰습니다.
In [1]:import os import gc import copy import numpy as np import pandas as pd import easydict from tqdm import notebook # 이미지 from PIL import Image # 시각화 import matplotlib.pyplot as plt # PyTorch import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader import torch.nn as nn import torch.nn.functional as F from torch.optim import Adam, AdamW from torch.optim.lr_scheduler import ReduceLROnPlateau from torchvision import transforms
In [2]:!pip install timm import timm
Requirement already satisfied: timm in /usr/local/lib/python3.7/dist-packages (0.4.9) Requirement already satisfied: torch>=1.4 in /usr/local/lib/python3.7/dist-packages (from timm) (1.8.1+cu101) Requirement already satisfied: torchvision in /usr/local/lib/python3.7/dist-packages (from timm) (0.9.1+cu101) Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch>=1.4->timm) (3.7.4.3) Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from torch>=1.4->timm) (1.19.5) Requirement already satisfied: pillow>=4.1.1 in /usr/local/lib/python3.7/dist-packages (from torchvision->timm) (7.1.2)In [3]:config = {} # 설정 config['seed'] = 42 config['device'] = "cuda" if torch.cuda.is_available() else "cpu" # 데이터 config['num_workers'] = 1 config['pin_memory'] = True # 모델 config['hidden_dim'] = 128 config['dropout'] = 0.1 # 훈련 config['n_epochs'] = 20 config['batch_size'] = 64 config['lr'] = 0.0001 config['clip_grad'] = 10 config['log_steps'] = 50 config['patience'] = 5 args = easydict.EasyDict(config)
데이터 lookup 테이블 만들기¶
- PATH 설정
- label2idx, idx2label
- train_df
- test_df
In [4]:PROJECT_PATH = "/content/drive/MyDrive/테스트" # 데이터셋 패스 설정 TRAIN_PATH = os.path.join(PROJECT_PATH, 'train') TEST_PATH = os.path.join(PROJECT_PATH, 'test')
In [5]:# label2idx label2idx = {'dog': 0, 'elephant': 1, 'giraffe': 2, 'guitar': 3, 'horse': 4, 'house': 5, 'person': 6} idx2label = {v: k for k, v in label2idx.items()}
In [6]:# train_df 만들기 labels = [] for path in os.walk(TRAIN_PATH): label_type = path[0].split('/')[-1] if label_type == 'train': continue base_path = path[0] images = path[2] idx = label2idx[label_type] for image in images: img_path = os.path.join(base_path, image) label = {'img_path': img_path, 'label': idx} labels.append(label) train_df = pd.DataFrame(labels) train_df = train_df.sort_values(['label', 'img_path']) train_df = train_df.reset_index(drop=True) train_df.head(5)
Out[6]:img_path label 0 /content/drive/MyDrive/테스트/train/dog/pic_001.jpg 0 1 /content/drive/MyDrive/테스트/train/dog/pic_002.jpg 0 2 /content/drive/MyDrive/테스트/train/dog/pic_003.jpg 0 3 /content/drive/MyDrive/테스트/train/dog/pic_004.jpg 0 4 /content/drive/MyDrive/테스트/train/dog/pic_005.jpg 0 In [7]:# test_df 만들기 labels = [] for path in os.walk(TEST_PATH): base_path = path[0] images = path[2] for image in images: img_path = os.path.join(base_path, image) label = {'img_path': img_path, 'label': -1} labels.append(label) test_df = pd.DataFrame(labels) test_df = test_df.sort_values(['img_path']) test_df = test_df.reset_index(drop=True) test_df.head(5)
Out[7]:img_path label 0 /content/drive/MyDrive/테스트/test/0001.jpg -1 1 /content/drive/MyDrive/테스트/test/0002.jpg -1 2 /content/drive/MyDrive/테스트/test/0003.jpg -1 3 /content/drive/MyDrive/테스트/test/0004.jpg -1 4 /content/drive/MyDrive/테스트/test/0005.jpg -1 EDA¶
- 실제 사진이 아닌, 미술작품들
- 각 라벨별로 누락된 이미지들이 있음
In [8]:image = plt.imread(train_df['img_path'][0]) plt.imshow(image);
In [9]:image = plt.imread(test_df['img_path'][0]) plt.imshow(image);
In [10]:train_df.groupby('label').count()
Out[10]:img_path label 0 329 1 205 2 235 3 134 4 151 5 245 6 399 In [11]:test_df.count()
Out[11]:img_path 350 label 350 dtype: int64Dataset & DataLoader¶
In [12]:class ArtDataset(Dataset): def __init__(self, df, transform=None): self.df = df self.transform = transform def __getitem__(self, idx): data = self.df.iloc[idx] # 이미지 img_path = data['img_path'] image = Image.open(img_path) if self.transform: image = self.transform(image) # 라벨 label = data['label'] return image, label def __len__(self): return len(self.df)
In [13]:transform = transforms.Compose([transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]) dataset = ArtDataset(train_df, transform) dataset[7]
Out[13]:(tensor([[[ 1.6495, 1.6838, 1.7009, ..., 0.8276, 0.6734, 0.7419], [ 1.6838, 1.7865, 1.8722, ..., 0.8276, 0.6563, 0.6563], [ 1.6838, 1.9235, 2.0605, ..., 0.9474, 0.6563, 0.6049], ..., [-1.3644, -1.6042, -1.6555, ..., -1.6213, -1.6727, -1.7069], [-1.2959, -1.5699, -1.7754, ..., -1.7925, -1.8782, -1.8268], [-1.4158, -1.7069, -1.7583, ..., -1.9980, -2.0152, -1.9809]], [[ 1.7458, 1.7983, 1.8508, ..., 0.2227, 0.2227, 0.3102], [ 1.7808, 1.8859, 2.0259, ..., 0.0826, 0.0651, 0.0651], [ 1.7633, 2.0259, 2.2185, ..., 0.1527, -0.0399, -0.1099], ..., [-1.4580, -1.7031, -1.7731, ..., -1.6856, -1.6155, -1.6506], [-1.3704, -1.6681, -1.8782, ..., -1.8256, -1.8081, -1.7556], [-1.4930, -1.8081, -1.8606, ..., -2.0357, -1.9482, -1.9132]], [[ 1.4548, 1.4722, 1.5245, ..., -1.3861, -1.2467, -1.1247], [ 1.5245, 1.5942, 1.6988, ..., -1.5953, -1.4559, -1.4210], [ 1.5942, 1.7685, 1.9080, ..., -1.5081, -1.5256, -1.5430], ..., [-1.1596, -1.3687, -1.3687, ..., -1.1596, -1.3339, -1.3687], [-1.1247, -1.3339, -1.5081, ..., -1.4559, -1.6127, -1.5604], [-1.2467, -1.4733, -1.4907, ..., -1.6650, -1.7522, -1.7173]]]), 0)
In [14]:loader = DataLoader(dataset, shuffle=True, batch_size=32) for x, y in loader: print(x, y) break
tensor([[[[ 1.1187, 1.1187, 1.1358, ..., 0.6734, 0.5878, 0.7419], [ 1.1187, 1.1358, 1.1358, ..., 0.6906, 0.5878, 0.7591], [ 1.1358, 1.1358, 1.1358, ..., 0.6906, 0.5707, 0.7933], ..., [ 0.2796, 0.2967, 0.3309, ..., -2.1179, -1.9295, -1.8610], [ 0.2967, 0.3309, 0.3309, ..., -2.0837, -1.8953, -1.8953], [-0.2684, 0.0056, 0.4679, ..., -1.9809, -1.8439, -1.8953]], [[ 1.2731, 1.2731, 1.2906, ..., 0.8179, 0.7304, 0.6779], [ 1.2731, 1.2906, 1.2906, ..., 0.8354, 0.7479, 0.7304], [ 1.2906, 1.2906, 1.2906, ..., 0.8179, 0.7829, 0.7829], ..., [ 0.3627, 0.3452, 0.3803, ..., -1.9482, -2.0007, -1.9307], [ 0.3102, 0.3102, 0.3803, ..., -1.9482, -1.9482, -1.9482], [-0.2675, -0.0224, 0.5203, ..., -1.9132, -1.8957, -1.9482]], [[ 1.6291, 1.6291, 1.6465, ..., 1.0714, 0.9494, 0.8971], [ 1.6291, 1.6465, 1.6465, ..., 1.0888, 1.0017, 0.9668], [ 1.6465, 1.6465, 1.6465, ..., 1.1237, 1.0539, 1.0539], ..., [ 0.4962, 0.4962, 0.5485, ..., -1.7522, -1.7522, -1.6824], [ 0.4265, 0.4439, 0.4962, ..., -1.5953, -1.7522, -1.7522], [-0.1487, 0.1128, 0.6356, ..., -1.5779, -1.6999, -1.7522]]], [[[ 0.6392, 0.8789, 0.9988, ..., -0.4054, -0.4397, -0.4397], [ 0.7933, 0.8447, 0.9646, ..., -0.4226, -0.4226, -0.4226], [ 0.5364, 0.6049, 0.8104, ..., -0.4054, -0.4054, -0.4054], ..., [ 1.5125, 1.5468, 1.5468, ..., -0.4397, -0.4226, -0.4226], [ 1.4269, 1.4783, 1.5125, ..., -0.4397, -0.4226, -0.4226], [ 1.3584, 1.3413, 1.3413, ..., -0.4397, -0.4397, -0.4397]], [[-0.2150, -0.0399, 0.0301, ..., 0.2227, 0.2227, 0.2227], [-0.2500, -0.0574, 0.1352, ..., 0.2402, 0.2402, 0.2402], [-0.6702, -0.4076, -0.0399, ..., 0.2577, 0.2577, 0.2577], ..., [ 2.0259, 2.0609, 2.0609, ..., 0.2052, 0.2052, 0.2052], [ 1.8333, 1.8859, 1.9209, ..., 0.2052, 0.2227, 0.2227], [ 1.7633, 1.7458, 1.7108, ..., 0.2052, 0.2052, 0.2052]], [[-0.3230, -0.1835, -0.1835, ..., 1.6640, 1.6117, 1.6117], [-0.3578, -0.2532, -0.1138, ..., 1.6291, 1.6291, 1.6291], [-0.7238, -0.6018, -0.3230, ..., 1.6465, 1.6465, 1.6465], ..., [ 2.3960, 2.4308, 2.4657, ..., 1.6814, 1.7511, 1.7511], [ 2.2391, 2.2914, 2.3263, ..., 1.6465, 1.6988, 1.6988], [ 2.1694, 2.1520, 2.1346, ..., 1.6465, 1.6814, 1.6814]]], [[[ 0.1254, 0.1083, 0.1254, ..., -1.3302, -1.3815, -1.4329], [ 0.0912, 0.0912, 0.1254, ..., -1.2788, -1.3302, -1.3815], [ 0.0912, 0.0912, 0.0912, ..., -1.3302, -1.3473, -1.3815], ..., [-1.5357, -1.6898, -1.5357, ..., -1.5699, -1.6384, -1.6898], [-1.5699, -1.6384, -1.5870, ..., -1.5185, -1.6213, -1.6727], [-1.5357, -1.6042, -1.5699, ..., -1.4843, -1.5870, -1.6384]], [[ 0.8179, 0.8529, 0.8704, ..., -0.9328, -0.9853, -1.0378], [ 0.8179, 0.8179, 0.8704, ..., -0.9328, -0.9153, -0.9678], [ 0.8179, 0.8179, 0.8354, ..., -1.0203, -0.9503, -0.9853], ..., [-1.2304, -1.3529, -1.2129, ..., -1.4580, -1.3704, -1.4230], [-1.2654, -1.3354, -1.2829, ..., -1.4055, -1.3529, -1.4055], [-1.2304, -1.3004, -1.2654, ..., -1.3704, -1.3179, -1.3704]], [[ 1.6988, 1.6291, 1.5768, ..., -0.9853, -0.9330, -0.9853], [ 1.6814, 1.6465, 1.6117, ..., -0.9678, -0.9678, -1.0201], [ 1.6988, 1.6814, 1.6117, ..., -1.0027, -1.0550, -1.0898], ..., [-1.2467, -1.3513, -1.1421, ..., -0.9156, -1.1596, -1.2119], [-1.2467, -1.3164, -1.2293, ..., -1.0898, -1.0898, -1.1421], [-1.2119, -1.2816, -1.2119, ..., -1.0550, -1.0550, -1.1073]]], ..., [[[ 1.1529, 1.1529, 1.1700, ..., 0.1254, 0.1254, 0.3138], [ 1.3070, 1.2728, 1.1187, ..., 0.3309, 0.4337, 0.5193], [ 1.3413, 1.3070, 1.1015, ..., 0.5536, 0.6563, 0.5364], ..., [ 2.2489, 2.2489, 2.2489, ..., 2.0948, 2.0777, 2.0948], [ 2.2489, 2.2489, 2.2489, ..., 2.1975, 2.2147, 2.2147], [ 2.2489, 2.2489, 2.2489, ..., 2.1975, 2.2147, 2.2147]], [[ 0.1527, 0.1702, 0.2402, ..., -0.9503, -0.9503, -0.7577], [ 0.2577, 0.2752, 0.1877, ..., -0.8102, -0.6702, -0.5826], [ 0.2927, 0.3102, 0.1176, ..., -0.6702, -0.4951, -0.6176], ..., [ 2.4111, 2.4111, 2.4111, ..., 2.4286, 2.4286, 2.4286], [ 2.3936, 2.3936, 2.3936, ..., 2.3585, 2.3585, 2.3585], [ 2.4286, 2.4286, 2.4286, ..., 2.3936, 2.3761, 2.3761]], [[-0.6367, -0.6193, -0.6018, ..., -1.4384, -1.4559, -1.2641], [-0.5147, -0.5147, -0.6193, ..., -1.2990, -1.2467, -1.1596], [-0.4798, -0.4798, -0.6715, ..., -1.1247, -1.0898, -1.2119], ..., [ 2.5529, 2.5529, 2.5529, ..., 2.6400, 2.6226, 2.6400], [ 2.6226, 2.6226, 2.6226, ..., 2.6400, 2.6400, 2.6400], [ 2.6400, 2.6400, 2.6400, ..., 2.6400, 2.6400, 2.6400]]], [[[-2.0837, -2.1179, -2.0837, ..., -1.8097, -1.4500, -1.1589], [-2.0494, -2.1008, -2.1008, ..., -1.7069, -1.3815, -0.9877], [-2.0494, -2.0152, -2.0323, ..., -1.8439, -1.8097, -1.7069], ..., [-0.4397, -1.1418, -1.2617, ..., -2.0494, -1.8782, -1.7754], [-0.3883, -0.6965, -0.8507, ..., -1.9295, -1.9295, -1.8439], [-0.9877, -1.3473, -1.4672, ..., -1.8610, -1.8610, -1.7925]], [[-2.0007, -2.0357, -2.0007, ..., -1.6506, -1.2829, -0.9853], [-1.9657, -2.0182, -2.0182, ..., -1.5455, -1.2129, -0.8102], [-1.9657, -1.9307, -1.9482, ..., -1.6856, -1.6506, -1.5455], ..., [-0.1625, -0.8803, -1.0028, ..., -1.6681, -1.7556, -1.6506], [-0.1800, -0.5126, -0.6702, ..., -1.7906, -1.7906, -1.7031], [-0.7927, -1.1779, -1.3004, ..., -1.7206, -1.7206, -1.6506]], [[-1.7696, -1.8044, -1.7696, ..., -1.3687, -1.0376, -0.7413], [-1.7347, -1.7870, -1.7870, ..., -1.2641, -0.9678, -0.5670], [-1.7347, -1.6999, -1.7173, ..., -1.4036, -1.4036, -1.2990], ..., [-0.0267, -0.7064, -0.8284, ..., -1.5430, -1.5430, -1.4384], [-0.0267, -0.3055, -0.4275, ..., -1.4733, -1.4733, -1.3861], [-0.6367, -0.9678, -1.0550, ..., -1.4036, -1.4036, -1.3339]]], [[[ 0.1597, 0.1426, 0.2796, ..., 1.0673, 1.0844, 1.1187], [-0.3541, -0.1999, 0.0056, ..., 1.2557, 1.3242, 1.3584], [-0.8335, -1.1247, -0.8164, ..., 1.3584, 1.4098, 1.4440], ..., [ 1.1700, 1.0159, 0.9303, ..., 0.6906, 0.3138, -0.6623], [ 0.9817, 0.7933, 0.7419, ..., 1.1187, 0.9817, 0.7077], [ 1.0159, 0.9303, 0.8104, ..., 1.1187, 1.1015, 1.3070]], [[ 0.2227, 0.1702, 0.2577, ..., 1.1856, 1.1856, 1.2206], [-0.3550, -0.2500, -0.0749, ..., 1.3081, 1.3782, 1.4132], [-0.9153, -1.2129, -0.9328, ..., 1.3431, 1.4657, 1.5007], ..., [ 1.0805, 0.9230, 0.8179, ..., 0.6429, 0.2577, -0.7402], [ 0.8354, 0.6429, 0.5903, ..., 1.0455, 0.8704, 0.5903], [ 0.8704, 0.7829, 0.6604, ..., 1.0455, 0.9930, 1.2031]], [[-0.1661, -0.1661, -0.0615, ..., 1.1411, 1.1411, 1.1759], [-0.5844, -0.4624, -0.2707, ..., 1.2805, 1.3502, 1.3851], [-1.0027, -1.2990, -1.0027, ..., 1.3851, 1.4374, 1.4722], ..., [ 1.0714, 0.9494, 0.9145, ..., 0.8274, 0.5485, -0.4450], [ 0.8797, 0.7228, 0.6879, ..., 1.1237, 1.0017, 0.7228], [ 0.9145, 0.8622, 0.7576, ..., 1.1062, 1.1237, 1.3328]]]]) tensor([6, 0, 5, 6, 6, 6, 3, 2, 0, 1, 5, 0, 6, 4, 5, 0, 6, 0, 3, 3, 0, 2, 3, 3, 4, 4, 1, 0, 1, 6, 3, 1])
train / valid 나누기¶
pandas DataFrame을 기준으로 stratifiedKFold를 적용한다
In [15]:from sklearn.model_selection import StratifiedKFold def split_df(df, kfold_n=5): kfold = StratifiedKFold(n_splits=kfold_n) # 클래스 비율 고려하여 Fold별로 데이터 나눔 X = df.img_path.values y = df.label.values datas = [] for i, (train_index, valid_index) in enumerate(kfold.split(X, y)): train_df = df.iloc[train_index].copy().reset_index(drop=True) valid_df = df.iloc[valid_index].copy().reset_index(drop=True) datas.append((train_df, valid_df)) return datas
In [16]:datas = split_df(train_df)
In [17]:# 첫번째 데이터셋 train datas[0][0].groupby('label').count()
Out[17]:img_path label 0 263 1 164 2 188 3 107 4 121 5 196 6 319 In [18]:# 첫번째 데이터셋 valid datas[0][1].groupby('label').count()
Out[18]:img_path label 0 66 1 41 2 47 3 27 4 30 5 49 6 80 get_loader¶
In [19]:def get_loader(train_data, valid_data, transform): train_dataset = ArtDataset(train_data, transform) valid_dataset = ArtDataset(valid_data, transform) train_loader = DataLoader(train_dataset, shuffle=True, num_workers=args.num_workers, batch_size=args.batch_size, pin_memory=args.pin_memory) valid_loader = DataLoader(valid_dataset, shuffle=False, num_workers=args.num_workers, batch_size=args.batch_size, pin_memory=args.pin_memory) return train_loader, valid_loader
In [20]:for X, y in loader: print(X.size(), y.size()) break
>torch.Size([32, 3, 224, 224]) torch.Size([32])conv 모델¶
간단한 convolution 모델을 사용해서 테스트하는 용도
In [21]:class ConvNet(nn.Module): def __init__(self, args, class_n=7): super().__init__() self.model = nn.Sequential( # [32, 3, 224, 224] -> [32, 32, 55, 55] nn.Conv2d(in_channels=3, out_channels=32, kernel_size=8, stride=4), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d((2, 2)), # [32, 64, 55, 55] -> [32, 64, 27, 27] # [32, 32, 27, 27] -> [32, 64, 11, 11] nn.Conv2d(in_channels=32, out_channels=64, kernel_size=7, stride=2), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d((2, 2)), # [32, 64, 11, 11] -> [32, 64, 5, 5] ) self.fc = nn.Linear(1600, class_n) def forward(self, x): x = self.model(x) x = x.view(x.size(0), -1) return self.fc(x)
In [22]:model = ConvNet(args) model(X)
Out[22]:tensor([[ 0.9441, 0.3273, -0.6121, -1.1562, -1.1537, -0.2866, -0.3136], [ 0.0923, 0.5396, -0.3335, -0.2363, -0.3932, -0.4474, 0.0705], [ 1.1090, -0.0963, -0.3213, -0.8175, 0.0193, -0.1474, 0.2303], [ 0.2213, 0.5964, 0.1489, -0.2720, -0.7719, -0.3505, -0.3247], [ 0.3219, 1.3156, 0.1622, -1.7833, -0.5985, -0.6310, -1.0919], [ 0.6533, 0.4952, -0.2269, -1.0678, -0.2662, -0.7674, -0.3342], [ 0.5027, 0.1173, 0.1857, 0.0938, -0.4946, 0.8828, 0.1678], [ 0.6146, 0.3164, 0.5716, -0.8988, -0.5872, -0.4984, -0.7020], [ 0.8043, 0.7840, 0.3966, -0.5947, -0.4601, 0.3243, 0.0259], [ 1.0216, 0.4896, 0.2961, -0.5511, -0.4961, 0.1674, 0.0173], [ 0.2953, 0.8990, -0.0758, -1.0837, -0.4858, -0.1145, 0.3061], [ 0.4921, 0.3758, 0.5821, -0.8128, -1.1178, -0.5434, -0.3811], [ 0.9240, 0.8390, -0.2498, -0.8254, -0.8668, -0.4110, -0.0476], [ 1.7050, 0.8061, 0.0745, -1.4041, -1.5088, 0.4276, 0.0937], [ 0.4990, 0.2662, 0.1519, -1.1867, -0.9486, -1.2554, -0.0370], [ 0.9249, 0.7384, -0.2740, -0.4297, -1.1963, -0.0577, -0.1950], [ 0.6903, 1.0579, -0.3505, -0.5165, -0.5967, -0.1050, -0.4528], [ 0.7049, 0.4872, 0.3703, -0.6034, -0.9301, 0.2915, 0.0649], [ 0.7048, 0.7583, 0.3892, -0.7462, -0.4054, 0.1733, -0.2026], [ 0.9102, -0.2895, 0.1764, -1.3334, -1.1267, -0.7388, -0.3778], [ 0.6860, 0.9166, 0.2442, -0.5162, -0.4703, 0.0927, -0.6246], [ 0.5346, -0.3926, 0.6689, -0.8792, -0.7831, -0.3497, 0.0800], [ 0.8854, 0.6109, -0.3990, -1.1772, -0.1643, -0.3895, -0.6607], [ 1.3579, 0.5562, 0.4058, -0.9862, -1.3069, 0.0973, -0.5180], [ 0.5796, 0.8724, 0.6406, -0.8832, -0.5234, -0.4178, -0.2793], [ 1.1863, 0.6524, 0.3318, -0.7983, -0.7219, -0.2296, -0.0742], [ 0.4154, 0.5497, 0.1223, -0.9258, 0.0560, 0.0630, -0.0349], [ 1.0239, 0.2273, 0.2094, -1.0673, -0.4870, 0.0552, -0.2058], [ 0.6459, 0.5558, 0.1114, -1.1328, -0.7657, 0.2688, -0.2605], [ 0.7271, 0.3053, -0.1695, -0.8216, -0.6764, -0.0481, -0.0794], [ 0.2739, 0.3990, 0.3245, -0.8883, -0.3505, 0.0920, 0.1564], [ 1.4383, 0.4677, 0.1684, -1.4680, -0.7739, 0.3378, -0.0589]], grad_fn=<AddmmBackward>)
efficientnet1¶
In [23]:class Eff01(nn.Module): def __init__(self, args, class_n=7): super().__init__() self.model = timm.create_model('efficientnet_b1', pretrained=True, num_classes=class_n) def forward(self, x): x = self.model(x) return x
In [24]:model = Eff01(args) model(X)
Out[24]:tensor([[ 3.9316e-01, -1.8075e+00, -6.8078e-01, 1.3850e+00, -1.6314e+00, 4.2127e+00, 8.1528e-01], [ 1.7965e+00, 7.2678e+00, -4.4178e+00, 3.0586e-01, 1.9594e+00, 1.6846e+00, -6.7419e-01], [-2.7659e+00, -1.9599e+00, -2.3481e+00, -4.4121e+00, 8.8137e-02, 3.4413e+00, -3.1732e+00], [-2.1057e+00, -2.9621e+00, -2.7104e+00, -3.4373e+00, 2.9861e+00, 2.3211e+00, -4.8303e+00], [ 5.2630e+00, 8.9739e+00, 3.2290e+00, 5.1347e+00, -2.9204e+00, 5.2858e+00, -4.6337e+00], [ 2.9802e+00, 6.9154e+00, -4.1486e+00, -4.6411e+00, -3.9898e+00, 4.4854e+00, 3.2991e+00], [ 2.5207e+00, 1.6186e+00, 2.0065e+00, 3.0777e+00, 1.5605e+00, -3.3963e-01, -8.9962e-01], [-2.4768e+00, 4.9098e+00, -7.2241e+00, -1.5993e+00, -2.9143e+00, -5.8529e+00, -5.0937e+00], [-6.0758e+00, 7.5426e-01, -2.3609e+00, -2.4397e+00, -5.7454e+00, 2.9179e+00, -2.9950e+00], [ 1.4790e+00, 6.0400e+00, 1.0130e+00, 1.6859e+00, 1.0481e+00, -2.8229e+00, 2.9617e-02], [ 5.7227e-01, -2.2472e+00, -2.3249e+00, -3.1104e+00, -1.1003e+00, -2.7433e+00, -3.7159e+00], [-2.2360e-01, 2.4394e-01, 4.0713e+00, -9.7840e-01, -1.8921e+00, 1.4798e+00, -1.5911e+00], [-1.4358e+00, 1.8061e+00, 1.8506e+00, -2.6608e+00, 4.8493e+00, 9.6075e-01, -5.7549e-01], [ 1.3821e+00, 4.6102e+00, -5.7297e-01, -2.3651e+00, 3.2042e+00, 2.1695e-01, -2.7694e+00], [-2.1986e+00, -1.3774e+00, -2.0758e+00, -2.2942e+00, -6.2637e+00, 3.4803e+00, -9.1589e+00], [-1.0898e+00, 3.8918e+00, -5.0518e+00, -7.5061e+00, 1.0734e+00, 3.0160e+00, -2.0883e+00], [-3.8563e+00, 4.9663e+00, -1.8223e-01, 3.4113e+00, 6.0263e-01, 2.2603e+00, 4.2581e+00], [ 5.6363e+00, -2.7442e-02, -1.2771e+00, 2.7350e+00, 5.1099e-01, 4.8014e+00, 2.6841e+00], [ 1.5867e+00, 8.0267e+00, 3.5557e+00, -2.1183e-03, -2.8267e-01, -2.8626e+00, 2.4946e+00], [ 6.7608e-01, 3.2706e+00, -1.2610e+00, 3.0974e+00, -2.9917e+00, 3.7218e+00, -6.0823e-01], [ 1.8446e+00, 3.5921e+00, 3.1441e+00, -2.8459e+00, -1.0907e+00, -1.2436e+00, -3.9847e+00], [ 2.0054e+00, 4.8740e+00, 4.1562e+00, 7.2944e-01, 4.3491e-01, 1.6272e+00, 3.8274e-01], [-3.8758e+00, 2.1684e+00, 1.8707e+00, -6.0805e+00, -1.8065e+00, -1.1074e+00, -4.8875e+00], [ 5.3469e-01, 3.1542e+00, 1.5800e+00, 3.5849e-01, -5.1072e-01, 2.5812e+00, 3.3352e-01], [-1.2886e+00, 6.4772e+00, 8.9048e-01, -3.9631e-01, -1.3061e+00, 8.1103e+00, -3.2352e-01], [-1.2911e-01, 9.9117e-01, 2.9715e-02, 5.2929e+00, 1.9702e+00, 2.3241e+00, 7.3989e+00], [-4.0124e+00, -4.2550e+00, 8.7637e-01, -8.5220e+00, 1.9189e+00, -8.4398e-02, -3.6078e+00], [ 2.8761e+00, 1.7192e+00, 6.2730e+00, -3.0518e-01, -6.0232e-01, -1.1055e+00, -3.1051e+00], [-2.1232e+00, 4.9213e-01, 4.0293e+00, 1.0153e+00, 3.6330e+00, 3.2296e+00, -3.1552e+00], [-4.8670e+00, 2.8554e+00, 3.5081e+00, -4.5551e+00, -5.0727e-01, 3.7878e+00, -4.3766e+00], [-2.5460e-01, -1.3759e+00, -1.8093e+00, 8.9533e-01, 3.3150e-03, 2.9745e+00, 2.5689e+00], [ 7.1304e-01, 1.9664e+00, 2.8399e-01, -8.2121e-01, -3.6928e+00, -7.3601e+00, -5.2162e+00]], grad_fn=<AddmmBackward>)
timm¶
timm이 제공하는 다양한 모델을 마음대로 가져다쓰기 위한 모델
In [25]:class Timm(nn.Module): def __init__(self, args, class_n=7): super().__init__() self.model = timm.create_model(args.timm_model, pretrained=True, num_classes=class_n) def forward(self, x): x = self.model(x) return x
훈련¶
초기 세팅¶
In [90]:config = {} # 설정 config['seed'] = 42 config['device'] = "cuda" if torch.cuda.is_available() else "cpu" config['model_path'] = os.path.join(PROJECT_PATH, 'model') # 데이터 config['num_workers'] = 1 config['pin_memory'] = False # 모델 config['dropout'] = 0.1 # 훈련 config['n_epochs'] = 20 config['lr'] = 0.0001 config['batch_size'] = 32 config['clip_grad'] = 10 config['log_steps'] = 1 config['patience'] = 10 config['model'] = 'timm' config['timm_model'] = 'vit_deit_base_distilled_patch16_224' config['optimizer'] = 'adam' config['scheduler'] = 'plateau' config['load'] = False config['model_name'] = "" config['kfold'] = 1 config['pseudo_labeling'] = False config['pseudo_iter_n'] = 2 args = easydict.EasyDict(config)
criterion¶
In [27]:criterion = nn.CrossEntropyLoss()
get_model¶
In [28]:def get_model(args): """ Load model and move tensors to a given devices. """ if args.model == 'convnet': model = ConvNet(args) if args.model == 'eff1': model = Eff01(args) if args.model == 'eff3': model = Eff03(args) if args.model == 'timm': model = Timm(args) model.to(args.device) return model
get_optimizer¶
In [29]:def get_optimizer(model, args): if args.optimizer == 'adam': optimizer = Adam(model.parameters(), lr=args.lr, weight_decay=0.0) # 모든 parameter들의 grad값을 0으로 초기화 optimizer.zero_grad() return optimizer
get_scheduler¶
In [73]:def get_scheduler(optimizer, args): if args.scheduler == 'plateau': scheduler = ReduceLROnPlateau(optimizer, patience=3, factor=0.5, mode='max', verbose=True) return scheduler
train¶
In [31]:def train(args, model, train_loader, optimizer): model.train() corrects = 0 for step, (images, labels) in enumerate(train_loader): images = images.to(args.device) labels = labels.to(args.device) outputs = model(images) if args.timm_model == 'vit_deit_base_distilled_patch16_224': outputs = outputs[0] loss = criterion(outputs, labels) loss.backward() optimizer.step() optimizer.zero_grad() if step % args.log_steps == 0: print(f"Training steps: {step} Loss: {str(loss.item())}") _, preds = torch.max(outputs, 1) corrects += torch.sum(preds == labels.data) acc = corrects / args.train_len return acc
validate¶
In [32]:def validate(args, model, valid_loader): model.eval() corrects = 0 for images, labels in valid_loader: images = images.to(args.device) labels = labels.to(args.device) outputs = model(images) _, preds = torch.max(outputs, 1) corrects += torch.sum(preds == labels.data) acc = corrects / args.valid_len print(f'VALID ACC : {acc}\n') return acc, outputs
pseudo_labeling¶
In [103]:def pseudo_labeling(args, model, train_data): # train_data에 새로운 df new_train_data = copy.deepcopy(test_df) test_dataset = ArtDataset(test_df, transform) test_loader = DataLoader(test_dataset, shuffle=False, num_workers=args.num_workers, batch_size=args.batch_size, pin_memory=args.pin_memory) model.eval() answers = [] for images, labels in test_loader: images = images.to(args.device) labels = labels.to(args.device) outputs = model(images) _, preds = torch.max(outputs, 1) answers.extend(list(preds.cpu().numpy())) new_train_data.label = answers new_train_data = pd.concat([train_data, new_train_data]).reset_index(drop=True) return new_train_data
run¶
In [123]:def run(args, train_data, valid_data): """데이터셋을 주면 처음부터 끝까지 훈련 사이클을 실행""" # 캐시 메모리 비우기 및 가비지 컬렉터 가동! torch.cuda.empty_cache() gc.collect() # 데이터 로드 args.train_len = len(train_data) args.valid_len = len(valid_data) transform = transforms.Compose([transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]) train_loader, valid_loader = get_loader(train_data, valid_data, transform) if args.load: model = torch.load(os.path.join(args.model_path, args.model_name)) else: model = get_model(args) optimizer = get_optimizer(model, args) scheduler = get_scheduler(optimizer, args) early_stopping_counter = 0 best_acc = -1 if args.pseudo_labeling: iter_n = args.pseudo_iter_n else: iter_n = 1 # pseudo labeling을 위한 iteration for iter_i in range(iter_n): for epoch in notebook.tqdm(range(args.n_epochs)): print(f'Epoch {epoch + 1}/{args.n_epochs}') ### TRAIN train_acc = train(args, model, train_loader, optimizer) ### VALID valid_acc, outputs = validate(args, model, valid_loader) ### model save and early stopping if valid_acc > best_acc: best_acc = valid_acc early_stopping_counter = 0 # 모델 저장! if args.model == 'timm': save_name = f"{args.timm_model}_fold{args.kfold}_{str(best_acc.item())[:4]}" else: save_name = f"{args.model}_fold{args.kfold}_{str(best_acc.item())[:4]}" torch.save(model, os.path.join(args.model_path, save_name)) print(f'model saved! {save_name}') else: early_stopping_counter += 1 if early_stopping_counter >= args.patience: print(f'EarlyStopping counter: {early_stopping_counter} out of {args.patience}') break # scheduler if args.scheduler == 'plateau': scheduler.step(best_acc) # Pseudo Labeling if args.pseudo_labeling: print('pseudo labeing ongoing!') train_data = pseudo_labeling(args, model, train_data) # make a loader with new train data train_loader, _ = get_loader(train_data, valid_data, transform)
데이터 불러오기¶
In [105]:datas = split_df(train_df) # 하나의 fold만 사용 train_data = datas[args.kfold - 1][0] valid_data = datas[args.kfold - 1][1]
훈련 진행¶
In [107]:args.lr = 0.0001 args.load = False args.model_name = '' args.batch_size = 16 args.log_steps = 20 args.patience = 10
In [ ]:timm.list_models(pretrained=True)
In [109]:args.timm_model = 'vit_deit_base_distilled_patch16_224' # args.timm_model = 'ecaresnet50t' # args.timm_model = 'seresnext50_32x4d' # args.timm_model = 'tf_efficientnet_b3_ns' # args.timm_model = 'eca_nfnet_l0' # args.timm_model = 'resnest50d' # args.timm_model = 'regnety_016'
In [121]:# pseudo labeling args.pseudo_labeling = True args.pseudo_iter_n = 3 args.n_epochs = 3
In [124]:run(args, train_data, valid_data)
Epoch 1/3 Training steps: 0 Loss: 1.9610543251037598 Training steps: 20 Loss: 0.11243961751461029 Training steps: 40 Loss: 0.31864628195762634 Training steps: 60 Loss: 0.04142267629504204 Training steps: 80 Loss: 0.014966970309615135 VALID ACC : 0.9764705896377563 model saved! vit_deit_base_distilled_patch16_224_fold1_0.97 Epoch 2/3 Training steps: 0 Loss: 0.006128528621047735 Training steps: 20 Loss: 0.04373385012149811 Training steps: 40 Loss: 0.010203133337199688 Training steps: 60 Loss: 0.28457173705101013 Training steps: 80 Loss: 0.24638208746910095 VALID ACC : 0.979411780834198 model saved! vit_deit_base_distilled_patch16_224_fold1_0.97 Epoch 3/3 Training steps: 0 Loss: 0.11676128208637238 Training steps: 20 Loss: 0.0013939981581643224 Training steps: 40 Loss: 0.003479683306068182 Training steps: 60 Loss: 0.007280834950506687 Training steps: 80 Loss: 0.0033565755002200603 VALID ACC : 0.958823561668396 pseudo labeing ongoing! Epoch 1/3 Training steps: 0 Loss: 0.04027740657329559 Training steps: 20 Loss: 0.12000448256731033 Training steps: 40 Loss: 0.017177144065499306 Training steps: 60 Loss: 0.2898399531841278 Training steps: 80 Loss: 0.005810225382447243 Training steps: 100 Loss: 0.12840282917022705 VALID ACC : 0.9323529601097107 Epoch 2/3 Training steps: 0 Loss: 0.1331356167793274 Training steps: 20 Loss: 0.08409298211336136 Training steps: 40 Loss: 0.018287230283021927 Training steps: 60 Loss: 0.0019370263908058405 Training steps: 80 Loss: 0.0035161140840500593 Training steps: 100 Loss: 0.0007211645133793354 VALID ACC : 0.9382352828979492 Epoch 3/3 Training steps: 0 Loss: 0.0049949875101447105 Training steps: 20 Loss: 0.0009458191343583167 Training steps: 40 Loss: 0.00010684832523111254 Training steps: 60 Loss: 0.0020058471709489822 Training steps: 80 Loss: 0.0013503937516361475 Training steps: 100 Loss: 0.0018512691603973508 VALID ACC : 0.9352941513061523 Epoch 6: reducing learning rate of group 0 to 5.0000e-05. pseudo labeing ongoing! Epoch 1/3 Training steps: 0 Loss: 0.0003172778233420104 Training steps: 20 Loss: 0.0002910386538133025 Training steps: 40 Loss: 0.0008431083406321704 Training steps: 60 Loss: 0.0006055183475837111 Training steps: 80 Loss: 0.00013664942525792867 Training steps: 100 Loss: 0.0006959352176636457 Training steps: 120 Loss: 9.717841749079525e-05 VALID ACC : 0.979411780834198 Epoch 2/3 Training steps: 0 Loss: 0.00014311331324279308 Training steps: 20 Loss: 0.0005445697461254895 Training steps: 40 Loss: 0.000317348021781072 Training steps: 60 Loss: 0.00019007959053851664 Training steps: 80 Loss: 0.0006655334727838635 Training steps: 100 Loss: 0.00010388605733169243 Training steps: 120 Loss: 0.00014714842836838216 VALID ACC : 0.979411780834198 Epoch 3/3 Training steps: 0 Loss: 0.0006675210315734148 Training steps: 20 Loss: 0.0002456515794619918 Training steps: 40 Loss: 0.0003927541838493198 Training steps: 60 Loss: 8.302312926389277e-05 Training steps: 80 Loss: 8.846087439451367e-05 Training steps: 100 Loss: 0.00022786625777371228 Training steps: 120 Loss: 7.981226372066885e-05 VALID ACC : 0.979411780834198 pseudo labeing ongoing!
추론¶
In [39]:test_dataset = ArtDataset(test_df, transform) test_loader = DataLoader(test_dataset, shuffle=False, num_workers=args.num_workers, batch_size=args.batch_size, pin_memory=args.pin_memory)
In [125]:torch.cuda.empty_cache() gc.collect()
Out[125]:385
In [126]:infer_model_name = 'timm_0.99' infer_model_name = 'ecaresnet50t_0.98' infer_model_name = 'vit_deit_base_distilled_patch16_224_0.97' model = torch.load(os.path.join(args.model_path, infer_model_name))
In [127]:model.eval() answers = [] for images, labels in test_loader: images = images.to(args.device) labels = labels.to(args.device) outputs = model(images) _, preds = torch.max(outputs, 1) answers.extend(list(preds.cpu().numpy()))
In [129]:print(answers)
>[2, 3, 3, 3, 3, 3, 4, 4, 3, 1, 6, 2, 0, 2, 3, 1, 2, 0, 6, 3, 3, 5, 2, 3, 0, 5, 1, 2, 0, 5, 4, 5, 6, 2, 0, 5, 5, 4, 2, 1, 4, 0, 2, 3, 1, 3, 0, 5, 5, 2, 6, 5, 4, 1, 5, 0, 4, 5, 1, 1, 5, 0, 6, 1, 1, 2, 4, 1, 1, 3, 1, 3, 0, 1, 1, 6, 2, 0, 3, 4, 1, 6, 1, 6, 6, 4, 3, 6, 1, 2, 2, 5, 1, 0, 5, 6, 3, 3, 1, 6, 5, 6, 5, 0, 3, 2, 5, 3, 0, 4, 4, 6, 2, 5, 4, 2, 0, 0, 5, 6, 4, 2, 2, 6, 4, 1, 5, 6, 0, 4, 1, 1, 6, 4, 4, 2, 5, 3, 5, 0, 4, 3, 1, 5, 1, 5, 4, 0, 2, 5, 6, 1, 6, 3, 2, 2, 0, 1, 4, 5, 2, 0, 6, 1, 3, 4, 1, 5, 6, 2, 1, 5, 3, 0, 0, 3, 2, 5, 3, 4, 2, 0, 3, 6, 0, 3, 3, 2, 0, 4, 4, 2, 2, 4, 4, 6, 6, 6, 3, 2, 5, 5, 4, 6, 2, 1, 3, 6, 0, 2, 3, 1, 1, 3, 1, 5, 2, 2, 0, 0, 0, 1, 2, 2, 6, 4, 3, 1, 5, 4, 3, 5, 0, 0, 4, 3, 0, 1, 4, 1, 6, 1, 2, 1, 6, 0, 5, 4, 6, 3, 4, 2, 5, 3, 1, 4, 2, 3, 4, 0, 6, 0, 2, 0, 1, 0, 1, 4, 0, 1, 1, 5, 6, 4, 6, 2, 4, 4, 3, 3, 6, 4, 0, 3, 1, 3, 0, 0, 5, 2, 5, 5, 2, 5, 0, 6, 5, 1, 5, 1, 5, 3, 0, 3, 3, 1, 6, 5, 0, 4, 0, 4, 3, 4, 4, 2, 5, 1, 2, 0, 6, 6, 1, 3, 3, 0, 0, 5, 2, 4, 6, 2, 6, 3, 6, 0, 4, 6, 2, 0, 2, 0, 5, 5, 1, 6, 3, 3, 5, 1]In [130]:label2idx
Out[130]:{'dog': 0, 'elephant': 1, 'giraffe': 2, 'guitar': 3, 'horse': 4, 'house': 5, 'person': 6}
In [131]:submission_path = os.path.join(PROJECT_PATH, 'submission.csv') submission_df = pd.DataFrame({'answer_value': answers}) submission_df.to_csv(submission_path)
In [132]:submission_df.value_counts()
Out[132]:answer_value 3 53 1 53 0 52 5 50 2 50 4 47 6 45 dtype: int64
kfold 훈련¶
In [68]:args.timm_model = 'vit_deit_base_distilled_patch16_224' # args.timm_model = 'ecaresnet50t' # args.timm_model = 'seresnext50_32x4d' # args.timm_model = 'tf_efficientnet_b3_ns' # args.timm_model = 'eca_nfnet_l0' # args.timm_model = 'resnest50d' # args.timm_model = 'regnety_016'
In [72]:args.lr = 0.0001 args.load = False args.model_name = '' args.batch_size = 16 args.log_steps = 20 args.patience = 5
In [74]:kfold_n = 5 datas = split_df(train_df) for fold in range(1, kfold_n + 1): args.kfold = fold # 하나의 fold만 사용 train_data = datas[args.kfold - 1][0] valid_data = datas[args.kfold - 1][1] run(args, train_data, valid_data)
Epoch 1/20 Training steps: 0 Loss: 2.070225954055786 Training steps: 20 Loss: 0.09332413226366043 Training steps: 40 Loss: 0.22841119766235352 Training steps: 60 Loss: 0.04848042130470276 Training steps: 80 Loss: 0.17917747795581818 VALID ACC : 0.979411780834198 model saved! vit_deit_base_distilled_patch16_224_fold1_0.97 Epoch 2/20 Training steps: 0 Loss: 0.013894079253077507 Training steps: 20 Loss: 0.11277658492326736 Training steps: 40 Loss: 0.06558889150619507 Training steps: 60 Loss: 0.12228739261627197 Training steps: 80 Loss: 0.015994392335414886 VALID ACC : 0.9764705896377563 Epoch 3/20 Training steps: 0 Loss: 0.007395995780825615 Training steps: 20 Loss: 0.0025502904318273067 Training steps: 40 Loss: 0.0007685854798182845 Training steps: 60 Loss: 0.0006357259699143469 Training steps: 80 Loss: 0.0006690919981338084 VALID ACC : 0.979411780834198 Epoch 4/20 Training steps: 0 Loss: 0.0008087260066531599 Training steps: 20 Loss: 0.0012696878984570503 Training steps: 40 Loss: 0.0009208667906932533 Training steps: 60 Loss: 0.0008509294711984694 Training steps: 80 Loss: 0.0008439231896772981 VALID ACC : 0.9823529720306396 model saved! vit_deit_base_distilled_patch16_224_fold1_0.98 Epoch 5/20 Training steps: 0 Loss: 0.0004001033375971019 Training steps: 20 Loss: 0.00033618463203310966 Training steps: 40 Loss: 0.0004378109297249466 Training steps: 60 Loss: 0.00022693183564115316 Training steps: 80 Loss: 0.0003972008707933128 VALID ACC : 0.9852941632270813 model saved! vit_deit_base_distilled_patch16_224_fold1_0.98 Epoch 6/20 Training steps: 0 Loss: 0.0001803989871405065 Training steps: 20 Loss: 0.00019188910664524883 Training steps: 40 Loss: 0.00015008499030955136 Training steps: 60 Loss: 0.00031750480411574244 Training steps: 80 Loss: 0.00015961111057549715 VALID ACC : 0.9852941632270813 Epoch 7/20 Training steps: 0 Loss: 0.0003038535942323506 Training steps: 20 Loss: 0.00013863165804650635 Training steps: 40 Loss: 0.0002890844480134547 Training steps: 60 Loss: 0.00029595577507279813 Training steps: 80 Loss: 0.00019118939235340804 VALID ACC : 0.9852941632270813 Epoch 8/20 Training steps: 0 Loss: 0.00021021650172770023 Training steps: 20 Loss: 0.00018152184202335775 Training steps: 40 Loss: 0.00023899308871477842 Training steps: 60 Loss: 0.000142873395816423 Training steps: 80 Loss: 0.00011664496560115367 VALID ACC : 0.9852941632270813 Epoch 9/20 Training steps: 0 Loss: 0.00021138088777661324 Training steps: 20 Loss: 0.00028158232453279197 Training steps: 40 Loss: 0.00019580998923629522 Training steps: 60 Loss: 0.00010884227231144905 Training steps: 80 Loss: 0.00013760558795183897 VALID ACC : 0.9852941632270813 Epoch 9: reducing learning rate of group 0 to 5.0000e-05. Epoch 10/20 Training steps: 0 Loss: 0.00022388184152077883 Training steps: 20 Loss: 0.00010977809870382771 Training steps: 40 Loss: 0.00017114584625232965 Training steps: 60 Loss: 0.00014162009756546468 Training steps: 80 Loss: 7.580553938169032e-05 VALID ACC : 0.9852941632270813 EarlyStopping counter: 5 out of 5 Epoch 1/20 Training steps: 0 Loss: 2.125271797180176 Training steps: 20 Loss: 0.1512129306793213 Training steps: 40 Loss: 0.021708954125642776 Training steps: 60 Loss: 0.11550218611955643 Training steps: 80 Loss: 0.08638344705104828 VALID ACC : 0.9558823704719543 model saved! vit_deit_base_distilled_patch16_224_fold2_0.95 Epoch 2/20 Training steps: 0 Loss: 0.011126736178994179 Training steps: 20 Loss: 0.004127616062760353 Training steps: 40 Loss: 0.008746129460632801 Training steps: 60 Loss: 0.002552709076553583 Training steps: 80 Loss: 0.005797188729047775 VALID ACC : 0.9676470756530762 model saved! vit_deit_base_distilled_patch16_224_fold2_0.96 Epoch 3/20 Training steps: 0 Loss: 0.002060434315353632 Training steps: 20 Loss: 0.0007710144273005426 Training steps: 40 Loss: 0.0009948632214218378 Training steps: 60 Loss: 0.0002511692000553012 Training steps: 80 Loss: 0.0007774809491820633 VALID ACC : 0.9735294580459595 model saved! vit_deit_base_distilled_patch16_224_fold2_0.97 Epoch 4/20 Training steps: 0 Loss: 0.0007255766540765762 Training steps: 20 Loss: 0.0005823898245580494 Training steps: 40 Loss: 0.0002615299599710852 Training steps: 60 Loss: 0.0008422219543717802 Training steps: 80 Loss: 0.00038621696876361966 VALID ACC : 0.9764705896377563 model saved! vit_deit_base_distilled_patch16_224_fold2_0.97 Epoch 5/20 Training steps: 0 Loss: 0.0003897449350915849 Training steps: 20 Loss: 0.00023776116722729057 Training steps: 40 Loss: 0.00044705800246447325 Training steps: 60 Loss: 0.0005612970562651753 Training steps: 80 Loss: 0.00017410620057489723 VALID ACC : 0.9852941632270813 model saved! vit_deit_base_distilled_patch16_224_fold2_0.98 Epoch 6/20 Training steps: 0 Loss: 0.0002749292179942131 Training steps: 20 Loss: 0.0002847451833076775 Training steps: 40 Loss: 0.00047713532694615424 Training steps: 60 Loss: 0.0004889280535280704 Training steps: 80 Loss: 0.00030827586306259036 VALID ACC : 0.9852941632270813 Epoch 7/20 Training steps: 0 Loss: 0.00025418432778678834 Training steps: 20 Loss: 0.00016597700596321374 Training steps: 40 Loss: 0.00019834867271129042 Training steps: 60 Loss: 0.0003435465332586318 Training steps: 80 Loss: 0.0001903756201500073 VALID ACC : 0.9852941632270813 Epoch 8/20 Training steps: 0 Loss: 0.00014426129928324372 Training steps: 20 Loss: 0.00022852919937577099 Training steps: 40 Loss: 0.0002765594981610775 Training steps: 60 Loss: 0.000177494584931992 Training steps: 80 Loss: 0.0002137339033652097 VALID ACC : 0.9852941632270813 Epoch 9/20 Training steps: 0 Loss: 0.00018333044135943055 Training steps: 20 Loss: 0.00010870480036828667 Training steps: 40 Loss: 0.00012791194603778422 Training steps: 60 Loss: 0.00012232620792929083 Training steps: 80 Loss: 9.94913061731495e-05 VALID ACC : 0.9852941632270813 Epoch 9: reducing learning rate of group 0 to 5.0000e-05. Epoch 10/20 Training steps: 0 Loss: 0.00013787909119855613 Training steps: 20 Loss: 0.00010700257553253323 Training steps: 40 Loss: 5.6122637033695355e-05 Training steps: 60 Loss: 0.00016332794621121138 Training steps: 80 Loss: 6.30063223070465e-05 VALID ACC : 0.9882352948188782 model saved! vit_deit_base_distilled_patch16_224_fold2_0.98 Epoch 11/20 Training steps: 0 Loss: 9.694581967778504e-05 Training steps: 20 Loss: 0.00010940924403257668 Training steps: 40 Loss: 0.00017602772277314216 Training steps: 60 Loss: 0.00010274062515236437 Training steps: 80 Loss: 8.837206405587494e-05 VALID ACC : 0.9882352948188782 Epoch 12/20 Training steps: 0 Loss: 0.0001780791935743764 Training steps: 20 Loss: 0.00010090007708640769 Training steps: 40 Loss: 0.00012891730875708163 Training steps: 60 Loss: 7.917111361166462e-05 Training steps: 80 Loss: 0.0002364671090617776 VALID ACC : 0.9882352948188782 Epoch 13/20 Training steps: 0 Loss: 8.280579640995711e-05 Training steps: 20 Loss: 7.735982217127457e-05 Training steps: 40 Loss: 9.142953786067665e-05 Training steps: 60 Loss: 0.00010475851740920916 Training steps: 80 Loss: 5.940067785559222e-05 VALID ACC : 0.9882352948188782 Epoch 14/20 Training steps: 0 Loss: 9.359944669995457e-05 Training steps: 20 Loss: 6.828831828897819e-05 Training steps: 40 Loss: 7.491827273042873e-05 Training steps: 60 Loss: 9.29912130231969e-05 Training steps: 80 Loss: 0.0001112468889914453 VALID ACC : 0.9882352948188782 Epoch 14: reducing learning rate of group 0 to 2.5000e-05. Epoch 15/20 Training steps: 0 Loss: 0.0001017541071632877 Training steps: 20 Loss: 0.00010287428449373692 Training steps: 40 Loss: 7.4692492489703e-05 Training steps: 60 Loss: 5.7015880884137005e-05 Training steps: 80 Loss: 0.0001095659754355438 VALID ACC : 0.9882352948188782 EarlyStopping counter: 5 out of 5 Epoch 1/20 Training steps: 0 Loss: 1.9553475379943848 Training steps: 20 Loss: 0.360125869512558 Training steps: 40 Loss: 0.11961036920547485 Training steps: 60 Loss: 0.013302672654390335 Training steps: 80 Loss: 0.2760090231895447 VALID ACC : 0.9647058844566345 model saved! vit_deit_base_distilled_patch16_224_fold3_0.96 Epoch 2/20 Training steps: 0 Loss: 0.005790058057755232 Training steps: 20 Loss: 0.011808047071099281 Training steps: 40 Loss: 0.012922742404043674 Training steps: 60 Loss: 0.0027748234570026398 Training steps: 80 Loss: 0.0008948363829404116 VALID ACC : 0.9764705896377563 model saved! vit_deit_base_distilled_patch16_224_fold3_0.97 Epoch 3/20 Training steps: 0 Loss: 0.0015448693884536624 Training steps: 20 Loss: 0.0006571502890437841 Training steps: 40 Loss: 0.0027235643938183784 Training steps: 60 Loss: 0.014082379639148712 Training steps: 80 Loss: 0.11243818700313568 VALID ACC : 0.9617647528648376 Epoch 4/20 Training steps: 0 Loss: 0.0008669137023389339 Training steps: 20 Loss: 0.15325620770454407 Training steps: 40 Loss: 0.024426553398370743 Training steps: 60 Loss: 0.003827356733381748 Training steps: 80 Loss: 0.022955361753702164 VALID ACC : 0.9441176652908325 Epoch 5/20 Training steps: 0 Loss: 0.0011019408702850342 Training steps: 20 Loss: 0.001850143657065928 Training steps: 40 Loss: 0.000597894424572587 Training steps: 60 Loss: 0.000499193905852735 Training steps: 80 Loss: 0.0005587120540440083 VALID ACC : 0.9676470756530762 Epoch 6/20 Training steps: 0 Loss: 0.0008818659116514027 Training steps: 20 Loss: 0.0005890672327950597 Training steps: 40 Loss: 0.000380369572667405 Training steps: 60 Loss: 0.00021075723634567112 Training steps: 80 Loss: 0.0003150541160721332 VALID ACC : 0.9735294580459595 Epoch 6: reducing learning rate of group 0 to 5.0000e-05. Epoch 7/20 Training steps: 0 Loss: 0.00035146938171237707 Training steps: 20 Loss: 0.0002934508374892175 Training steps: 40 Loss: 0.000293821154627949 Training steps: 60 Loss: 0.00024732472957111895 Training steps: 80 Loss: 0.0001991338504012674 VALID ACC : 0.9735294580459595 EarlyStopping counter: 5 out of 5 Epoch 1/20 Training steps: 0 Loss: 2.0614306926727295 Training steps: 20 Loss: 0.21165452897548676 Training steps: 40 Loss: 0.15650087594985962 Training steps: 60 Loss: 0.09856440871953964 Training steps: 80 Loss: 0.25801852345466614 VALID ACC : 0.9528023600578308 model saved! vit_deit_base_distilled_patch16_224_fold4_0.95 Epoch 2/20 Training steps: 0 Loss: 0.003911319188773632 Training steps: 20 Loss: 0.013249287381768227 Training steps: 40 Loss: 0.0009106044308282435 Training steps: 60 Loss: 0.0026690915692597628 Training steps: 80 Loss: 0.01531395222991705 VALID ACC : 0.9498525261878967 Epoch 3/20 Training steps: 0 Loss: 0.0017143264412879944 Training steps: 20 Loss: 0.002851467579603195 Training steps: 40 Loss: 0.005741201341152191 Training steps: 60 Loss: 0.011219356209039688 Training steps: 80 Loss: 0.002695375354960561 VALID ACC : 0.9646017551422119 model saved! vit_deit_base_distilled_patch16_224_fold4_0.96 Epoch 4/20 Training steps: 0 Loss: 0.000511382007971406 Training steps: 20 Loss: 0.0013728523626923561 Training steps: 40 Loss: 0.0010254302760586143 Training steps: 60 Loss: 0.0003245208063162863 Training steps: 80 Loss: 0.0008100293343886733 VALID ACC : 0.9793510437011719 model saved! vit_deit_base_distilled_patch16_224_fold4_0.97 Epoch 5/20 Training steps: 0 Loss: 0.0006320927059277892 Training steps: 20 Loss: 0.0003737296792678535 Training steps: 40 Loss: 0.00028914542053826153 Training steps: 60 Loss: 0.0009214243618771434 Training steps: 80 Loss: 0.0002785417309496552 VALID ACC : 0.976401150226593 Epoch 6/20 Training steps: 0 Loss: 0.000439854251453653 Training steps: 20 Loss: 0.00021529578953050077 Training steps: 40 Loss: 0.00015027981135062873 Training steps: 60 Loss: 0.00014621201262343675 Training steps: 80 Loss: 0.0001887156249722466 VALID ACC : 0.976401150226593 Epoch 7/20 Training steps: 0 Loss: 0.00013472522550728172 Training steps: 20 Loss: 0.00019639963284134865 Training steps: 40 Loss: 0.00017765158554539084 Training steps: 60 Loss: 0.0002927388995885849 Training steps: 80 Loss: 0.0001379675231873989 VALID ACC : 0.976401150226593 Epoch 8/20 Training steps: 0 Loss: 0.00033308877027593553 Training steps: 20 Loss: 0.00018385719158686697 Training steps: 40 Loss: 0.0002205742202932015 Training steps: 60 Loss: 0.0002880125539377332 Training steps: 80 Loss: 0.00019521107606124133 VALID ACC : 0.976401150226593 Epoch 8: reducing learning rate of group 0 to 5.0000e-05. Epoch 9/20 Training steps: 0 Loss: 0.0002322245854884386 Training steps: 20 Loss: 0.00014505763829220086 Training steps: 40 Loss: 0.00020668211800511926 Training steps: 60 Loss: 0.00011255430581513792 Training steps: 80 Loss: 0.00016966232215054333 VALID ACC : 0.976401150226593 EarlyStopping counter: 5 out of 5 Epoch 1/20 Training steps: 0 Loss: 2.1110196113586426 Training steps: 20 Loss: 0.1107415184378624 Training steps: 40 Loss: 0.09970464557409286 Training steps: 60 Loss: 0.012141451239585876 Training steps: 80 Loss: 0.011343749240040779 VALID ACC : 0.9262536764144897 model saved! vit_deit_base_distilled_patch16_224_fold5_0.92 Epoch 2/20 Training steps: 0 Loss: 0.01333638560026884 Training steps: 20 Loss: 0.005270378198474646 Training steps: 40 Loss: 0.0025757476687431335 Training steps: 60 Loss: 0.007112572900950909 Training steps: 80 Loss: 0.0005468337913043797 VALID ACC : 0.9587020874023438 model saved! vit_deit_base_distilled_patch16_224_fold5_0.95 Epoch 3/20 Training steps: 0 Loss: 0.000730900326743722 Training steps: 20 Loss: 0.0010238775284960866 Training steps: 40 Loss: 0.000511404185090214 Training steps: 60 Loss: 0.00064817228121683 Training steps: 80 Loss: 0.00030412187334150076 VALID ACC : 0.9557521939277649 Epoch 4/20 Training steps: 0 Loss: 0.0005783180240541697 Training steps: 20 Loss: 0.00042364178807474673 Training steps: 40 Loss: 0.0002950250345747918 Training steps: 60 Loss: 0.0002105626481352374 Training steps: 80 Loss: 0.00021895382087677717 VALID ACC : 0.9557521939277649 Epoch 5/20 Training steps: 0 Loss: 0.0002488949103280902 Training steps: 20 Loss: 0.00030456739477813244 Training steps: 40 Loss: 0.0004265912575647235 Training steps: 60 Loss: 0.0003578931500669569 Training steps: 80 Loss: 0.0007239663973450661 VALID ACC : 0.9557521939277649 Epoch 6/20 Training steps: 0 Loss: 0.0002544424496591091 Training steps: 20 Loss: 0.0001761214662110433 Training steps: 40 Loss: 0.00019317405531182885 Training steps: 60 Loss: 0.00023175563546828926 Training steps: 80 Loss: 0.00015963845362421125 VALID ACC : 0.9557521939277649 Epoch 6: reducing learning rate of group 0 to 5.0000e-05. Epoch 7/20 Training steps: 0 Loss: 0.00016027921810746193 Training steps: 20 Loss: 0.00013730306818615645 Training steps: 40 Loss: 9.590276749804616e-05 Training steps: 60 Loss: 0.00013750368088949472 Training steps: 80 Loss: 7.908276893431321e-05 VALID ACC : 0.9557521939277649 EarlyStopping counter: 5 out of 5
soft voting¶
In [133]:torch.cuda.empty_cache() gc.collect()
Out[133]:369
In [165]:models = [ # "vit_deit_base_distilled_patch16_224_fold1_pseudo_0.97", "vit_deit_base_distilled_patch16_224_0.97", "vit_deit_base_distilled_patch16_224_0.99", "vit_deit_base_distilled_patch16_224_fold1_0.98", "vit_deit_base_distilled_patch16_224_fold2_0.98", "vit_deit_base_distilled_patch16_224_fold3_0.97", "vit_deit_base_distilled_patch16_224_fold4_0.97", "vit_deit_base_distilled_patch16_224_fold5_0.95"] models = [torch.load(os.path.join(args.model_path, model)).eval() for model in models]
In [166]:args.batch_size = 2 test_dataset = ArtDataset(test_df, transform) test_loader = DataLoader(test_dataset, shuffle=False, num_workers=args.num_workers, batch_size=args.batch_size, pin_memory=args.pin_memory)
In [167]:answers = [] for images, labels in test_loader: images = images.to(args.device) labels = labels.to(args.device) predicts = torch.zeros(images.size(0), 7) for model in models: outputs = model(images) outputs = F.softmax(outputs.cpu(), dim=1) predicts += outputs # prediction들의 average 계산 predict_avg = predicts / len(models) _, preds = torch.max(predict_avg, 1) answers.extend(list(preds.cpu().numpy()))
In [168]:print(answers)
[2, 3, 3, 3, 3, 3, 4, 4, 3, 1, 6, 2, 6, 2, 3, 1, 2, 0, 6, 3, 3, 5, 2, 3, 0, 5, 1, 2, 0, 5, 1, 5, 6, 2, 0, 5, 5, 4, 2, 1, 4, 0, 2, 3, 1, 3, 0, 5, 5, 2, 6, 5, 4, 1, 5, 0, 4, 5, 1, 0, 5, 0, 6, 1, 1, 2, 4, 1, 1, 3, 1, 3, 0, 1, 1, 6, 2, 0, 3, 4, 1, 6, 1, 6, 6, 4, 3, 6, 1, 2, 2, 5, 1, 0, 5, 6, 3, 3, 1, 6, 5, 6, 6, 0, 3, 2, 5, 3, 0, 0, 4, 6, 2, 5, 4, 2, 0, 0, 5, 6, 4, 2, 2, 6, 4, 1, 5, 6, 0, 4, 1, 1, 6, 4, 4, 2, 5, 6, 5, 0, 4, 3, 1, 5, 1, 5, 4, 0, 2, 5, 6, 1, 6, 3, 2, 2, 0, 1, 4, 5, 2, 4, 6, 2, 3, 4, 1, 5, 6, 2, 1, 5, 3, 4, 0, 3, 2, 5, 3, 4, 2, 0, 3, 6, 0, 3, 3, 2, 0, 4, 4, 2, 2, 4, 4, 6, 6, 6, 3, 2, 5, 5, 4, 6, 2, 1, 3, 6, 0, 2, 3, 1, 1, 3, 1, 5, 2, 2, 0, 0, 0, 1, 2, 2, 6, 6, 3, 2, 5, 4, 3, 5, 0, 0, 4, 5, 0, 6, 4, 1, 6, 1, 2, 1, 6, 0, 5, 4, 6, 3, 4, 2, 5, 3, 1, 4, 2, 3, 4, 0, 6, 0, 2, 0, 1, 0, 1, 4, 0, 1, 1, 5, 6, 4, 6, 2, 4, 4, 3, 6, 6, 4, 0, 3, 1, 3, 0, 0, 5, 2, 5, 5, 2, 5, 0, 6, 5, 1, 5, 1, 5, 3, 0, 3, 3, 1, 6, 5, 0, 4, 0, 4, 3, 4, 4, 2, 5, 1, 2, 0, 6, 6, 1, 3, 3, 0, 0, 5, 2, 4, 6, 6, 6, 3, 6, 0, 4, 6, 4, 0, 2, 0, 5, 5, 1, 6, 3, 3, 5, 1]
In [169]:submission_path = os.path.join(PROJECT_PATH, 'submission.csv') submission_df = pd.DataFrame({'answer_value': answers}) submission_df.to_csv(submission_path)
In [170]:submission_df.value_counts()
Out[170]:answer_value 6 52 0 51 5 50 3 50 2 50 1 50 4 47 dtype: int64
In [149]:submission_df.value_counts()
Out[149]:answer_value 6 52 2 51 5 50 3 50 1 50 0 50 4 47 dtype: int64
'취업 이야기 > 데브매칭 문제 해설' 카테고리의 다른 글
2021 앱 Dev-Matching | K-MOOC 강좌정보 서비스 (0) 2021.07.20 2021 ML Dev-Matching | 미술 작품 분류하기 : 우수 코드 공개 (0) 2021.07.06 2021 ML Dev-Matching | 미술 작품 분류하기 : 출제자가 추천한 우수 코드 B (0) 2021.07.06 2021 ML Dev-Matching | 미술 작품 분류하기 : 출제자가 추천한 우수 코드 A (0) 2021.07.06 '2021 Dev-Matching: 웹 백엔드 개발자(상반기)' 기출 문제 해설 (0) 2021.04.26