모든 데이터 분석은 google colab pro에서 진행했습니다.
우선 관련함수들을 import하도록 하겠습니다.
관련 데이터는 torchvision에 있는 cifar100 dataset을 이용하도록 합니다. dsets.CIFAR100으로 로드가 가능합니다.
import torch
import torchvision
from torch.utils.data import TensorDataset, DataLoader
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.functional as F
import torch.nn as nn
import matplotlib.pyplot as plt
torch.cuda.is_availbale()은 cuda라는 그래픽을 사용할 수 있는지 물어보는 것 입니다. 저희는 GPU를 이용해서 학습할 것이니 사용해주도록 합니다. print에서 cpu라고 뜬다면 colab의 메뉴바의 런타임 - 런타임 유형 변경에서 gpu로 변경해주시면 됩니다.
import dirve는 google 자신의 drive를 가상드라이브로 이용해서 데이터 저장이나 데이터로드를 가능하도록 해줍니다. colab을 이용할 경우 런타임이 4시간 정도 돌리면 사용량으로 인해서 자동으로 끊기고 colab pro를 이용해도 끊길 때가 있으니 꼭 설정해주도록 합니다.
USE_CUDA = torch.cuda.is_available() # GPU를 사용가능하면 True, 아니라면 False를 리턴
device = torch.device("cuda" if USE_CUDA else "cpu") # GPU 사용 가능하면 사용하고 아니면 CPU 사용
print("다음 기기로 학습합니다:", device)
from google.colab import drive
drive.mount('/content/jdrive')
데이터를 로드해주도록 합니다. batchsize는 보통 2의 배수로 로드합니다. 대부분의 논문에서는 256으로 사용하는 것 같지만 막상 training 해보면 그렇게까지 잘 되는 것 같지는 않습니다. 우선 여기서는 batchsize는 64로 로드하도록 합니다.
batch_size = 64
cifar100_trainset = dsets.CIFAR100(root='./data',
train=True,
download=True,
transform=transforms.ToTensor())
cifar100_testset = dsets.CIFAR100(root='./data',
train=False,
download=True,
transform=transforms.ToTensor())
cifar100_trainloader = torch.utils.data.DataLoader(dataset = cifar100_trainset,
batch_size=batch_size,
shuffle=True,
drop_last=True)
cifar100_testloader = torch.utils.data.DataLoader(dataset=cifar100_testset,
batch_size=batch_size,
shuffle=False,
drop_last=True)
모델을 로드하는 방식은 두 가지가 있습니다. pytorch에서 지원해주는 model을 사용하는 것과 직접 작성한 모델을 사용하는 법이 있습니다. pytorch에서 지원해주는 model을 사용하는 경우입니다. pretrained 같은 경우 pytorch에서 이미지 1000개를 가지고 미리 train시켜 weight값을 initialize해준 상태입니다. 이렇게 train시켜 놓으면 조금 더 나은 결과값을 기대해볼 수 있습니다. 하지만 CNN모델은 존재하지 않고 Resnet부터 존재하니 우선 코드를 작성해서 사용해주도록 합니다.
기본 CNN 모델입니다.
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.keep_prob = 0.5
# image shape (? ,3, 28 , 28)
#conv ( ?, 32, 28, 28 ,)
#pool ( ?, 32, 14, 14 )
self.layer1 = torch.nn.Sequential(
torch.nn.Conv2d(3,32, kernel_size = 3, stride = 1, padding =1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2))
###image (?,32,14,14,)
# conv (?,64,14,14)
# pool (?, 64,7 ,7)
self.layer2 = torch.nn.Sequential(
torch.nn.Conv2d(32,64, kernel_size = 3, stride = 1, padding =1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2))
# L3 ImgIn shape=(?, 64, 7, 7, )
# Conv ->(?, 128,7, 7, )
# Pool ->(?, 128,4, 4, )
self.layer3 = torch.nn.Sequential(
torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2, padding=1))
# L4 FC 128x4x4 inputs -> 625 outputs pooling이 진행되면서 3200이 된걸로 보입니다...
self.fc1 = torch.nn.Linear(3200, 625, bias=True)
torch.nn.init.xavier_uniform_(self.fc1.weight)
self.layer4 = torch.nn.Sequential(
self.fc1,
torch.nn.ReLU(),
torch.nn.Dropout(p=1 - self.keep_prob))
# L5 Final FC 625 inputs -> 100 outputs
self.fc2 = torch.nn.Linear(625, 100, bias=True)
#가중치 초기화
torch.nn.init.xavier_uniform_(self.fc2.weight)
def forward(self, x):
out = self.layer1(x)
out = self.layer2(out)
out = self.layer3(out)
out = out.view(out.size(0), -1) # Flatten them for FC
out = self.layer4(out)
out = self.fc2(out)
return out
model = CNN().to(device)
이제 모델을 이용해 학습해주도록 합시다.
training은 항상 train 시간이 좀 더 걸려도 dataset에 대한 train set에 대한 loss와 valid set에 대한 loss를 따로 계산해주는 것이 좋은 것 같습니다. train loss는 시간이 지나면 계속 떨어지지만 valid loss는 증가하지 않거나 오히려 떨어지는 것을 볼 수 있습니다.
그리고 optimizer같은 경우는 여러가지가 있지만 colab으로 돌릴경우 adam이나 adamw를 사용하는게 좋습니다. adam같은 경우 sgd를 사용하는 경우보다 빠르게 최종치에 도달하는 경향을 보입니다.
criterion = torch.nn.CrossEntropyLoss().to(device) # 비용 함수에 소프트맥스 함수 포함되어져 있음.
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
total_batch = len(cifar100_trainloader)
t_loss = []
t_accuracy = []
vl_loss = []
vl_accuracy =[]
train_loss = 0
correct = 0
total = 0
test_loss=0
vl_correct = 0
vl_total=0
for epoch in range(20):
model.train()
model.training = True
for inputs, targets in cifar100_trainloader:
inputs = inputs.to(device)
targets = targets.to(device)
optimizer.zero_grad()
predictions = model(inputs)
loss = criterion(predictions, targets)
loss.backward()
optimizer.step()
with torch.no_grad():
train_loss += loss.item()
train_loss1 = loss.item()
_, predicted = torch.max(predictions, 1)
total += targets.size(0)
correct += predicted.eq(targets.data).cpu().sum()
acc = 100.*correct/total
model.eval()
model.training = False
with torch.no_grad():
for inputs, targets in cifar100_testloader:
inputs = inputs.to(device)
targets = targets.to(device)
predictions = model(inputs)
loss = criterion(predictions, targets)
test_loss += loss.item()
test_loss1 = loss.item()
_, predicted = torch.max(predictions, 1)
vl_total += targets.size(0)
vl_correct += predicted.eq(targets.data).cpu().sum()
test_acc = 100.*vl_correct/vl_total
t_loss.append(train_loss1)
t_accuracy.append(acc)
vl_loss.append(test_loss1)
vl_accuracy.append(test_acc)
print('epoch:{4:<3} tr_loss:{0:0.4f} tr_accuracy:{1:0.2f}% val_loss:{2:0.4f} val_accuracy:{3:0.2f}%'.format(train_loss1,acc,test_loss1,test_acc,epoch+1))
모델을 학습시켰으면 그래프를 통해 가시화시켜줍니다.
plt.plot(t_loss, '-bx')
plt.plot(vl_loss, '-rx')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(['Training', 'Validation'])
plt.title('Loss vs. No. of epochs')j
plt.plot(t_accuracy, '-rx')
plt.plot(vl_accuracy,'-bx')
plt.xlabel('Epoch')
plt.ylabel('Acuracy')
plt.legend(['Training', 'Validation'])
plt.title('Accuracy vs. No. of epochs')
accuracy가 40%정도 나오는 모습을 확인했습니다. 이상으로 cifar-100 cnn으로 구현하기를 마치겠습니다.