Lec 10-2: Mnist CNN
Deep_Learning study Lec10-2
Boostcourse의 ‘파이토치로 시작하는 딥러닝 기초’를 통한 공부와 정리 Post
Goal of Study
- MNIST 데이터를 CNN으로 적용해본다.
Keyword
- 딥러닝 학습 단계
- CNN
1. 강의 요약
MNIST
MNIST 학습에 CNN을 적용 해보자.
다음과 같은 구조를 거쳐 학습할 것이다.
합성곱(nn.Cov2d) + 활성화 함수(nn.ReLU)를 하나의 합성곱 층으로 보고, 맥스풀링(nn.MaxPoold2d)은 풀링 층으로 별도라고 하자.
CrossEntropyLoss:
LogSoftmax와 NLLLoss(Negative Log Likelihood Loss)의 기능이 하나의 class에 합쳐져 있는 것이다.
즉, Log 처리와 softmax 처리, NLLLoss연산을 한번에 하므로 NLLLoss와 LogSoftmax를 같이 사용하는 것보다 수식이 간소화되어 더 안정적으로 역전파가 이루어진다.참고 포스팅(외부)
MNIST CNN
import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
import matplotlib.pyplot as plt
import random
USE_CUDA = torch.cuda.is_available() # GPU를 사용가능하면 True, 아니라면 False를 리턴
device = torch.device("cuda" if USE_CUDA else "cpu") # GPU 사용 가능하면 사용하고 아니면 CPU 사용
print("다음 기기로 학습합니다:", device)
# for reproducibility
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
torch.cuda.manual_seed_all(777)
다음 기기로 학습합니다: cpu
#parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
#MNIST dataset
mnist_train = dsets.MNIST(root='E:\DeepLearningStudy',
train=True,
transform=transforms.ToTensor(),
download=True)
mnist_test = dsets.MNIST(root='E:\DeepLearningStudy',
train=False,
transform=transforms.ToTensor(),
download=True)
# dataset loader
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
batch_size=batch_size,
shuffle=True,
drop_last=True)
Dataloader class는 batch기반의 딥러닝모델 학습을 위해서 mini batch를 만들어주는 역할을 한다.
dataloader를 통해 dataset의 전체 데이터가 batch size로 slice된다.
Layer
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 1번 레이어 : 합성곱층(Convolutional layer)
self.layer1 = nn.Sequential(
nn.Conv2d(1, 32, kernel_size = 3, stride = 1, padding = 1),
nn.ReLU(),
nn.MaxPool2d(2)
)
# 2번 레이어 : 합성곱층(Convolutional layer)
self.layer2 = nn.Sequential(
nn.Conv2d(32, 64, kernel_size = 3, stride = 1, padding = 1),
nn.ReLU(),
nn.MaxPool2d(2)
)
# 3번 레이어 : 전결합층(Fully-Connected layer)
self.fc = nn.Linear(7*7*64, 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)
out = self.fc(out)
return out
3번 레이어에서는 구현체들을 연결(fully_connected)하여 모델을 완성시킨다.
self.fc = nn.Linear(7*7*64, 10, bias = True)
에서
7 * 7인 64채널의 텐서가 된 이유는 다음과 같다.
첫번째층 에서
ImgIn shape=(?, 28, 28, 1)
Conv -> (?, 28, 28, 32)
Pool -> (?, 14, 14, 32)
두번째층 에서
ImgIn shape=(?, 14, 14, 32)
Conv ->(?, 14, 14, 64)
Pool ->(?, 7, 7, 64)
출력 채널은 지정해준대로, 처음에 1에서 32채널로 출력, 32채널에서 64채널로 출력해주었고(지정), ?는 Batch Size이다.
(이전 포스팅과 nn.Conv2d Document에서 입력의 형태, 출력의 형태 parameter에 대한 부분을 다뤘었다.)
++) Output의 shape를 찍어보면, 실제로는 아래와 같이 나온다.
Conv2D과정에서는 padding을 넣어주어서 input size의 값이 변하지 않고 유지된다.
하지만 이를,
MAX Pooling = 2에 따라 2 by 2 내에서 가장 큰 값이 출력되는 과정을 거쳐
28 by 28에서 14 by 14, 7 by 7인 그리고 이것이 64채널로 구성된다.
이제 이를 가지고 .view()를 사용하여 텐서를 펼치는 작업을 한다.
out = out.view(out.size(0), -1)
의 의미는 첫번째 차원은 그대로 두고 나머지는 펼치는 작업이라 생각하면 된다.
배치 차원을 제외하고 모두 하나의 차원으로 통합되었고,
이를 nn.Linear
를 통해 Incoming data를 선형화해준다. 이를 통해 fully-connected 층을 통과시켰다고 말할 수 있다.
self.fc = nn.Linear(7*7*64, 10, bias = True)
이를 7764에서 MNIST data의 분류 output인 10으로 출력해준다.
두번째 parameter는 output_volume_size(output_channel)이다.
즉, conv1 layer를 거쳐 몇장의 필터를 만들어 내고 싶은가? 이다.
Model
model = CNN().to(device)
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)
)
# define cost/loss & optimizer
criterion = nn.CrossEntropyLoss().to(device) # Softmax is internally computed.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
#training
total_batch = len(data_loader)
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
# image is already size of (28x28), no reshape
# label is not one-hot encoded
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!')
C:\Users\LeeJaeWon\anaconda3\envs\DeepLearningStudy\lib\site-packages\torch\nn\functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at ..\c10/core/TensorImpl.h:1156.)
return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)[Epoch: 1] cost = 0.225650638
[Epoch: 2] cost = 0.0630516708
[Epoch: 3] cost = 0.0462231413
[Epoch: 4] cost = 0.0374182053
[Epoch: 5] cost = 0.0312010683
[Epoch: 6] cost = 0.0261333473
[Epoch: 7] cost = 0.0217183381
[Epoch: 8] cost = 0.0183297545
[Epoch: 9] cost = 0.0160741284
[Epoch: 10] cost = 0.0130791487
[Epoch: 11] cost = 0.00996965356
[Epoch: 12] cost = 0.00974050257
[Epoch: 13] cost = 0.00823498424
[Epoch: 14] cost = 0.00648333086
[Epoch: 15] cost = 0.00675452035
Learning Finished!
# Test model and check accuracy
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)
correct_prediction = torch.argmax(prediction, 1) == Y_test
accuracy = correct_prediction.float().mean()
print('Accuracy:', accuracy.item())
C:\Users\LeeJaeWon\anaconda3\envs\DeepLearningStudy\lib\site-packages\torchvision\datasets\mnist.py:67: UserWarning: test_data has been renamed data
warnings.warn(“test_data has been renamed data”)
C:\Users\LeeJaeWon\anaconda3\envs\DeepLearningStudy\lib\site-packages\torchvision\datasets\mnist.py:57: UserWarning: test_labels has been renamed targets
warnings.warn(“test_labels has been renamed targets”)
Accuracy: 0.9865999817848206
For more Deep
import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
import matplotlib.pyplot as plt
import random
USE_CUDA = torch.cuda.is_available() # GPU를 사용가능하면 True, 아니라면 False를 리턴
device = torch.device("cuda" if USE_CUDA else "cpu") # GPU 사용 가능하면 사용하고 아니면 CPU 사용
print("다음 기기로 학습합니다:", device)
# for reproducibility
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
torch.cuda.manual_seed_all(777)
다음 기기로 학습합니다: cpu
#parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
#MNIST dataset
mnist_train = dsets.MNIST(root='E:\DeepLearningStudy',
train=True,
transform=transforms.ToTensor(),
download=True)
mnist_test = dsets.MNIST(root='E:\DeepLearningStudy',
train=False,
transform=transforms.ToTensor(),
download=True)
# dataset loader
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
batch_size=batch_size,
shuffle=True,
drop_last=True)
# CNN Model
class CNN(torch.nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.keep_prob = 0.5
# L1 ImgIn shape=(?, 28, 28, 1)
# Conv -> (?, 28, 28, 32)
# Pool -> (?, 14, 14, 32)
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 ImgIn shape=(?, 14, 14, 32)
# Conv ->(?, 14, 14, 64)
# Pool ->(?, 7, 7, 64)
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=(?, 7, 7, 64)
# Conv ->(?, 7, 7, 128)
# Pool ->(?, 4, 4, 128)
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 4x4x128 inputs -> 625 outputs
self.fc1 = torch.nn.Linear(4 * 4 * 128, 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 -> 10 outputs
self.fc2 = torch.nn.Linear(625, 10, 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
stride – the stride of the window. Default value is
kernel_size
model = CNN().to(device)
# define cost/loss & optimizer
criterion = nn.CrossEntropyLoss().to(device) # Softmax is internally computed.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
#training
total_batch = len(data_loader)
model.train()
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
# image is already size of (28x28), no reshape
# label is not one-hot encoded
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!')
[Epoch: 1] cost = 0.196751326
[Epoch: 2] cost = 0.0529913679
[Epoch: 3] cost = 0.0360812806
[Epoch: 4] cost = 0.0293815508
[Epoch: 5] cost = 0.0227077473
[Epoch: 6] cost = 0.0191459022
[Epoch: 7] cost = 0.017342383
[Epoch: 8] cost = 0.0143559193
[Epoch: 9] cost = 0.0132799093
[Epoch: 10] cost = 0.0117306057
[Epoch: 11] cost = 0.0092954142
[Epoch: 12] cost = 0.00994911045
[Epoch: 13] cost = 0.00803884584
[Epoch: 14] cost = 0.008628821
[Epoch: 15] cost = 0.00692343339
Learning Finished!
# Test model and check accuracy
with torch.no_grad():
model.eval() # set the model to evaluation mode (dropout=False)
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)
correct_prediction = torch.argmax(prediction, 1) == Y_test
accuracy = correct_prediction.float().mean()
print('Accuracy:', accuracy.item())
Accuracy: 0.9912999868392944
📣
본 포스팅의 학습 환경 : Anaconda
, CPU
, Pytorch
, Jupyter Notebook
포스팅에서 오류나 궁금한 점은 Comments를 작성해주시면, 많은 도움이 됩니다.💡
Leave a comment