앞장에서는 수행한 Retaining시에 Batch size가 8이상 크면 컴퓨터의 사양에 따라서 메모리가 부족한 경우도 생길 수도 있습니다. 혹은 이미 생겨서 그 크기를 조정한 경우도 있을 수 있습니다. 즉, 네트워크와 입력 dataset이 크면 학습에 큰 컴퓨터 자원이 소모됩니다.
따라서, pretrained된 network는 거의 모든 부분을 그대로 사용하고, 학습이 필요한 부분은 마지막 Fully connnected layer일 뿐이니, 마지막 layer 앞전 값을 입력으로 하고 마지막 단만을 학습하는 방법을 생각할 수 있습니다.
이번 장에서는 이부분을 구현하도록 하겠습니다.
일단, 밑의 명령어를 수행시켜서, 실행디렉토리 밑에 꽃 이미지 압축파일을 풀어 놓습니다.
In [1]:
!if [ ! -d "/tmp/flower_photos" ]; then curl http://download.tensorflow.org/example_images/flower_photos.tgz | tar xz -C /tmp ;rm /tmp/flower_photos/LICENSE.txt; fi
In [2]:
%matplotlib inline
In [3]:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from torchvision import datasets, transforms
from torch.autograd import Variable
import matplotlib.pyplot as plt
import numpy as np
is_cuda = torch.cuda.is_available() # cuda 사용가능시, True
traindir = '/tmp/flower_photos'
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
batch_size = 1
train_loader = torch.utils.data.DataLoader(
datasets.ImageFolder(traindir,
transforms.Compose([
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalize,])),
batch_size=batch_size,
shuffle=True)
cls_num = len(datasets.folder.find_classes(traindir)[0])
model = torchvision.models.resnet152(pretrained = True)
# remove last fully-connected layer
model = nn.Sequential(*list(model.children())[:-1])
In [4]:
model.eval()
features = []
targets = []
for image, target in train_loader:
image, target = Variable(image, volatile=True), Variable(target, volatile=True)
if is_cuda : image, target = image.cuda(), target.cuda()
feature = model(image).data
features.append(feature)
targets.append(target.data.squeeze())
In [5]:
features = torch.cat(features, 0).squeeze()
targets = torch.cat(targets, 0)
torch.save(features, 'flower_feature.pth')
torch.save(targets, 'flower_label.pth')
In [6]:
# load feature datasets
features = torch.load('flower_feature.pth')
targets = torch.load('flower_label.pth')
batch_size = 500
features_datasest = torch.utils.data.TensorDataset(features, targets)
feature_loader = torch.utils.data.DataLoader(
features_datasest,
batch_size=batch_size,
shuffle=True)
In [7]:
# remove last fully-connected layer
fcmodel = nn.Linear(2048, cls_num)
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(fcmodel.parameters(), lr=1e-4, weight_decay=1e-4)
if is_cuda : model.cuda(), loss_fn.cuda()
In [8]:
# trainning
fcmodel.train()
train_loss = []
train_accu = []
i = 0
for epoch in range(1000):
for feature, target in feature_loader:
feature, target = Variable(feature), Variable(target.squeeze()) # 입력image Target 설정
if is_cuda : feature, target = feature.cuda(), target.cuda()
output = fcmodel(feature) # model 생성
loss = loss_fn(output, target) #loss 생성
optimizer.zero_grad() # zero_grad
loss.backward() # calc backward grad
optimizer.step() # update parameter
pred = output.data.max(1)[1]
accuracy = pred.eq(target.data).sum()/batch_size
train_loss.append(loss.data[0])
train_accu.append(accuracy)
if i % 300 == 0:
print(i, loss.data[0])
i += 1
In [9]:
plt.plot(train_accu)
Out[9]:
In [10]:
plt.plot(train_loss)
Out[10]:
In [11]:
checkpoint_filename = 'flowerfeature_resnet152.ckpt'
## save a parameter
torch.save(fcmodel.state_dict(), checkpoint_filename)
이제 학습된 마지막단 fully connected layter를 기존의 모델에 연결하여, prediction을 수행하여 봅니다. batch size를 더 크게 할 수 있어서 그러진 8장의 예제보다 좀 더 정확한 93%정도 수준의 정확도를 보여줍니다.
In [12]:
import torch
import torchvision
import torch.nn as nn
from torchvision import datasets, transforms
from torch.autograd import Variable
traindir = '/tmp/flower_photos'
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
cls_num = len(datasets.folder.find_classes(traindir)[0])
test_loader = torch.utils.data.DataLoader(
datasets.ImageFolder(traindir,
transforms.Compose([
transforms.RandomSizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
normalize,])),
shuffle=True)
model = torchvision.models.resnet152(pretrained = True)
# make new fully connected layer
fcmodel = nn.Linear(2048, cls_num)
# load saved parameter into fc layer
checkpoint_filename = 'flowerfeature_resnet152.ckpt'
checkpoint = torch.load(checkpoint_filename)
fcmodel.load_state_dict(checkpoint)
#connect fc layer to resnet152
model.fc = fcmodel
model.eval()
correct = 0
from itertools import islice
for image, target in islice(test_loader, 100):
if is_cuda : image, target = image.cuda(), target.cuda()
image, target = Variable(image, volatile=True), Variable(target)
output = model(image)
prediction = output.data.max(1)[1]
correct += prediction.eq(target.data).sum()
#print('\nTest set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))
print('\nTest set: Accuracy: {:.2f}%'.format(100. * correct / 100))
In [ ]: