Flowers retraining example

이미 학습된 잘 알려진 모델을 이용하여 꽃의 종류를 예측하는 예제입니다.

기존의 Minst 예제와는 거의 차이점이 없습니다. 단지 2가지만 다를 뿐입니다.

  1. 숫자이미지 대신에 꽃이미지이름으로 분류되어 있는 folder를 dataset으로 이용한다.
  2. 이미 잘 짜여진 Neural model과 사전학습된(pretrained) parameter를 사용한다.
  3. classificaion 숫자를 조정한 새로운 Network로 재구성한다.

pytorch의 imageFolder라는 dataset클래스를 사용하였습니다.

traindir = './flower_photos'
batch_size = 8 
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)

Microsoft에서 발표한 resnet152를 사용합니다.

model = torchvision.models.resnet152(pretrained=True)

새로운 Network로 재구성합니다.

### don't update model parameters
for param in model.parameters() :
    param.requires_grad = False
#modify last fully connected layter
model.fc = nn.Linear(model.fc.in_features, cls_num)

일단, 밑의 명령어를 수행시켜서, 실행디렉토리 밑에 꽃 이미지 압축파일을 풀어 놓습니다.


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

1. 입력DataLoader 설정

  • train 데이터로 loader를 지정 (dataset은 imagefolder, batch 사이즈 32, shuffle를 실행)
  • test 데이터로 loader를 지정 (dataset은 imagefoder, batch 사이즈 32,shuffle를 실행)

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 = 256 
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,
    num_workers=4)

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,])),
    batch_size=batch_size,
    shuffle=True,
    num_workers=1)

2. 사전 설정

  • model

여기서 약간 특별한 처리를 해주어야 합니다.

  1. resnet152는 pretrained된 것은 분류개수가 1000개이라서, flower폴더에 있는 5개로 분류개수를 가지도록 재구성합니다.
  2. 마지막 parameter만를 update할 수 있도록 나머지 layer는 requires_grad를 False로 합니다.
  • loss
  • opimizer

그리고 최적화에는 재구성한 마지막 layer만을 update하도록 설정합니다.


In [4]:
model = torchvision.models.resnet152(pretrained = True)

### don't update model parameters
for param in model.parameters() :
    param.requires_grad = False
#modify last fully connected layter
model.fc = nn.Linear(model.fc.in_features, cls_num)

fc_parameters = [
    {'params': model.fc.parameters()},
]
optimizer = torch.optim.Adam(fc_parameters, lr=1e-4, weight_decay=1e-4)
loss_fn = nn.CrossEntropyLoss() 

if is_cuda : model.cuda(), loss_fn.cuda()

3. Trainning loop

* (입력 생성)
* model 생성
* loss 생성
* zeroGrad
* backpropagation
* optimizer step (update model parameter)

```


In [5]:
# trainning
model.train()
train_loss = []
train_accu = []
i = 0
for epoch in range(35):
    for image, target in train_loader:
        image, target = Variable(image.float()), Variable(target) # 입력image Target 설정 
        if is_cuda :  image, target = image.cuda(), target.cuda() 
        output = model(image) # 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


0 1.698183536529541
300 0.5475694537162781

In [6]:
plt.plot(train_accu)


Out[6]:
[<matplotlib.lines.Line2D at 0x7fc7f702dc88>]

In [7]:
plt.plot(train_loss)


Out[7]:
[<matplotlib.lines.Line2D at 0x7fc7f6f57860>]

4. Predict & Evaluate


In [8]:
model.eval()
correct = 0
for image, target in test_loader:
    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)))


Test set: Accuracy: 88.23%