강의자료 · 인공지능응용

Image Classification (MNIST)

Imports

import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
from torch.utils.data import DataLoader

import random
import matplotlib.pyplot as plt

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

# for reproducibility
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)
cuda

1 MNIST dataset

# MNIST dataset
mnist_train = dsets.MNIST(root='MNIST_data/',
                          train=True,
                          transform=transforms.ToTensor(),
                          download=True)

mnist_test = dsets.MNIST(root='MNIST_data/',
                         train=False,
                         transform=transforms.ToTensor(),
                         download=True)
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
Failed to download (trying next):
HTTP Error 403: Forbidden

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to MNIST_data/MNIST/raw/train-images-idx3-ubyte.gz
100%|██████████| 9912422/9912422 [00:00<00:00, 17901167.12it/s]
Extracting MNIST_data/MNIST/raw/train-images-idx3-ubyte.gz to MNIST_data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
Failed to download (trying next):
HTTP Error 403: Forbidden

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to MNIST_data/MNIST/raw/train-labels-idx1-ubyte.gz
100%|██████████| 28881/28881 [00:00<00:00, 515824.43it/s]
Extracting MNIST_data/MNIST/raw/train-labels-idx1-ubyte.gz to MNIST_data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
Failed to download (trying next):
HTTP Error 403: Forbidden

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to MNIST_data/MNIST/raw/t10k-images-idx3-ubyte.gz
100%|██████████| 1648877/1648877 [00:00<00:00, 1925518.73it/s]
Extracting MNIST_data/MNIST/raw/t10k-images-idx3-ubyte.gz to MNIST_data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
Failed to download (trying next):
HTTP Error 403: Forbidden

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to MNIST_data/MNIST/raw/t10k-labels-idx1-ubyte.gz
100%|██████████| 4542/4542 [00:00<00:00, 3221804.29it/s]
Extracting MNIST_data/MNIST/raw/t10k-labels-idx1-ubyte.gz to MNIST_data/MNIST/raw

# dataset loader
batch_size = 100
data_loader = DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

2 CNN model

class CNN(torch.nn.Module):

    def __init__(self):
        super(CNN, self).__init__()
        # L1 Input shape=(?, 1, 28, 28)
        #    Conv     -> (?, 32, 28, 28)
        #    Pool     -> (?, 32, 14, 14)
        self.layer1 = torch.nn.Sequential(
            torch.nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2))
        # L2 Input shape=(?, 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 Linear 64x7x7 inputs -> 10 outputs
        self.fc = torch.nn.Linear(64*7*7, 10, bias=True)
        torch.nn.init.xavier_uniform_(self.fc.weight)

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.view(out.size(0), -1)   # Flatten them for FC
        out = self.fc(out)
        return out

3 학습하기

# parameters
learning_rate = 0.001
training_epochs = 15

# contruct model
model = CNN().to(device)

# define cost/loss & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)    # Softmax
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# train
total_batch = len(data_loader)
print('Learning started. It takes sometime.')
for epoch in range(training_epochs):
    avg_cost = 0

    for X, Y in data_loader:
        X = X.to(device)
        Y = Y.to(device)

        optimizer.zero_grad()
        hypothesis = model(X)
        cost = criterion(hypothesis, Y)
        cost.backward()
        optimizer.step()

        avg_cost += cost / total_batch

    print('[Epoch: {:>4}] cost = {:>.9}'.format(epoch + 1, avg_cost))

print('Learning Finished!')
Learning started. It takes sometime.
[Epoch:    1] cost = 0.225600749
[Epoch:    2] cost = 0.0629422814
[Epoch:    3] cost = 0.0462685339
[Epoch:    4] cost = 0.0374453217
[Epoch:    5] cost = 0.0312564597
[Epoch:    6] cost = 0.0261451434
[Epoch:    7] cost = 0.0218881592
[Epoch:    8] cost = 0.0182996988
[Epoch:    9] cost = 0.0160796437
[Epoch:   10] cost = 0.0133214388
[Epoch:   11] cost = 0.0101956706
[Epoch:   12] cost = 0.00985957589
[Epoch:   13] cost = 0.00824302062
[Epoch:   14] cost = 0.00647699879
[Epoch:   15] cost = 0.00701776193
Learning Finished!
# Test model and check accuracy
with torch.no_grad():
    X_test = mnist_test.data.view(len(mnist_test), 1, 28, 28).float().to(device)
    Y_test = mnist_test.targets.to(device)

    prediction = model(X_test)
    correct_prediction = torch.argmax(prediction, 1) == Y_test
    accuracy = correct_prediction.float().mean()
    print('Accuracy:', accuracy.item())
Accuracy: 0.9848999977111816
# Random sample test
with torch.no_grad():
  r = random.randint(0, len(mnist_test) - 1)
  img_sample = mnist_test.data[r].view(1, 1, 28, 28).float().to(device)
  label_sample = mnist_test.targets[r].to(device)

  print('Label: ', label_sample.item())
  sample_prediction = model(img_sample)
  print('Prediction: ', torch.argmax(sample_prediction, axis=1).item())

  plt.imshow(mnist_test.data[r].view(28, 28), cmap='Greys', interpolation='nearest')
  plt.show()
Label:  9
Prediction:  9
<Figure size 640x480 with 1 Axes>
실행 결과

3 Assignment

다음 미완성 코드를 활용해 새로운 data를 학습해보자

import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
from torch.utils.data import DataLoader

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

from google.colab import drive
drive.mount('/content/drive')

# for reproducibility
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)

# Model
##### 지난 assignment에서 작성한 모델을 활용한다
##### 바뀐 image input에 맞게 변형한다
##### 바뀐 image의 size는 64x128이며, 흑백이 아닌 RGB 3개의 채널임에 유의한다

# parameters
##### 적당히 수정한다
learning_rate =
training_epochs =

# contruct model
model = CNN().to(device)

# define cost/loss & optimizer
criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# train
##### 직접 dataset을 만들어 학습할 때 자주 사용되는 함수이니 기능을 숙지한다
##### pytorch 공식 홈페이지에서 관련 함수의 정보를 직접 찾아보는 것을 추천한다
trans = transforms.Compose([transforms.ToTensor()])
train_data = dsets.ImageFolder(root='/content/drive/MyDrive/Colab Notebooks/courses/AI_Appl/train_data', transform=trans)
data_loader = DataLoader(dataset = train_data, batch_size = 8, shuffle = True)

total_batch = len(data_loader)

##### 학습이 이루어지는 loop
##### 지난 source code를 그대로 사용해도 되지만, 연습삼아 직접 작성해보자

# test
##### 직접 dataset을 만들어 학습할 때 자주 사용되는 함수이니 기능을 숙지한다
##### pytorch 공식 홈페이지에서 관련 함수의 정보를 직접 찾아보는 것을 추천한다
trans=transforms.Compose([transforms.Resize((64,128)),transforms.ToTensor()])
test_data = dsets.ImageFolder(root='/content/drive/MyDrive/Colab Notebooks/courses/AI_Appl/test_data', transform=trans)
test_set = DataLoader(dataset = test_data, batch_size = len(test_data))

with torch.no_grad():
##### 결과 test가 이루어지는 loop
##### 지난 source code를 그대로 사용해도 되지만, 연습삼아 직접 작성해보자
cuda
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
Learning started. It takes sometime.
[Epoch:    1] cost = 0.158599436
[Epoch:    2] cost = 0.00020430611
[Epoch:    3] cost = 2.68744279e-05
[Epoch:    4] cost = 5.39911434e-06
[Epoch:    5] cost = 1.20812297e-06
Learning Finished!
Accuracy: 1.0