본문 바로가기

프로그래머/Pytorch

[Pytorch] MNIST 간단한 CNN 구현 및 정리

MNIST 간단한 CNN 구현 및 정리

모두의 딥러닝 시즌2 - Pytorch를 참고 했습니다.
모두의 딥러닝 시즌2 깃헙


import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
  1. pytorch import
device = 'cuda' if torch.cuda.is_available() else 'cpu'

torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(123)
  1. device 설정(GPU or CPU)
learning_rate = 0.001
training_epochs = 15
batch_size = 100
  1. parameter 설정(learning rate, training epochs, batch size)
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)
  1. mnist import
    transforms.ToTensor() -> pytorch에서 다룰 수 있는 tensor의 형태로 불러온다
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                         batch_size=batch_size,
                                         shuffle=True,
                                         drop_last=True)
  • DataLoader로 mnist_train 데이터를 미니배치 단위로 처리할 수 있고,
  • shuffle함으로서 학습의 효율성을 향상
  • drop_last=True -> 데이터를 배치 사이즈로 나누었을 때, 나머지를 버림
class CNN(torch.nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        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)
        )
        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)
        )
        self.fc = torch.nn.Linear(7*7*64, 10, bias=True)
        torch.nn.init.xavier_uniform_(self.fc.weight)

    def forward(self, x):
#         print(x.size())
        out = self.layer1(x)
#         print(out.size())
        out = self.layer2(out)
#         print(out.size())
        out = out.view(out.size(0), -1)
#         print(out.size())
        out = self.fc(out)
#         print(out.size())
        return out
  • CNN 모델에서의 처리 과정은 다음과 같다. [batch_size, number_of_kernels, w, h]
  • shape를 print 함으로서 확인할 수 있다.
    [100, 28, 28, 1] -> layer1 -> [100, 14,14,32] -> layer2 -> [100, 7, 7, 64] -> view(펼치기) -> [100, 3136] -> fc -> [100, 10]

model

CNN(
(layer1): Sequential(
(0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(layer2): Sequential(
(0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(fc): Linear(in_features=3136, out_features=10, bias=True)
)

풀어서 표현하면 위와 같다

model = CNN().to(device)

CNN 모델을 device에 넣어줌

criterion = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
  • cost/loss 설정(크로스엔트로피)

    cross-entropy loss : 신경망의 출력이 0~1 사이로 나오는 경우 loss 함수로 사용할 수 있다.
  • optimizer 설정(adam optimizer)
total_batch = len(data_loader)
# total_batch

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))

[Epoch: 1] cost = 0.231875896
[Epoch: 2] cost = 0.0620613769
[Epoch: 3] cost = 0.0451710336
[Epoch: 4] cost = 0.0371446609
[Epoch: 5] cost = 0.0305327885
[Epoch: 6] cost = 0.0256100874
[Epoch: 7] cost = 0.021398209
[Epoch: 8] cost = 0.0179504156
[Epoch: 9] cost = 0.0161231514
[Epoch: 10] cost = 0.013235067
[Epoch: 11] cost = 0.0123889502
[Epoch: 12] cost = 0.0102491155
[Epoch: 13] cost = 0.00809138734
[Epoch: 14] cost = 0.0077691027
[Epoch: 15] cost = 0.00681020087

{ } 안의 :>4는 4자리 오른쪽 정렬, :>.9는 소숫점 9자리 오른쪽정렬 이라는 뜻이다.

print(len(mnist_train))
print(batch_size)
print(total_batch)
print(len(mnist_test))

60000
100
600
10000

  • 6만개의 training data와 1만개의 test data
  • batch size 100으로 600개의 batch를 만들어 training
with torch.no_grad():
    X_test = mnist_test.test_data.view(len(mnist_test), 1, 28, 28).float().to(device)
    Y_test = mnist_test.test_labels.to(device)

    prediction = model(X_test)
    print(prediction.size())
    correct_prediction = torch.argmax(prediction, 1) == Y_test
    accuracy = correct_prediction.float().mean()
    print('Accuracy: ', accuracy.item())

torch.Size([10000, 10])
Accuracy: 0.9882999658584595

  • test 시에는 gradient가 필요 없으믈 torch.no_grad()로 감싸줌
  • batch 없이 1만개의 데이터 한번에 test
  • 마찬가지로 to(device)
  • prediction size [10000, 10]에 대해 argmax (axis = 1)
  • 모든 test 결과에 대해 평균 .mean(), 값만 빼옴 .item()

torch.Size([10000, 10])
Accuracy: 0.9882999658584595