CNN으로 mnist 분류하기
1. 모델 이해하기
1. 첫번째 표기 방법
합성곱 + 활성화 함수를 하나의 합성곱 층으로 보고, 맥스 풀링은 풀링 층으로 별도로 명명
2. 두번째 표기 방법
합성곱 + 활성화 함수 + 맥스 풀링을 하나의 합성곱 층으로 봄.
두번째 표기법을 사용하기로 함.
# 1번 레이어 : 합성곱층(Convolutional layer)
합성곱(in_channel = 1, out_channel = 32, kernel_size=3, stride=1, padding=1) + 활성화 함수 ReLU
맥스풀링(kernel_size=2, stride=2))
# 2번 레이어 : 합성곱층(Convolutional layer)
합성곱(in_channel = 32, out_channel = 64, kernel_size=3, stride=1, padding=1) + 활성화 함수 ReLU
맥스풀링(kernel_size=2, stride=2))
# 3번 레이어 : 전결합층(Fully-Connected layer)
특성맵을 펼친다. # batch_size × 7 × 7 × 64 → batch_size × 3136
전결합층(뉴런 10개) + 활성화 함수 Softmax
2. 모델 구현하기
1. 필요한 도구 임포트와 입력의 정의
import torch
import torch.nn as nn
임의의 텐서를 만듦
# 배치 크기 * 채널 * 높이 * 너비의 크기의 텐서를 선언
inputs = torch.Tensor(1, 1, 28, 28)
2. 합성곱층과 풀링 선언하기
첫번째 합성곱 층 : 1채널 짜리를 입력 받아서 32 채널을 뽑아냄
conv1 = nn.Conv2d(1, 32, 3, padding=1)
두번째 합성곱 층 : 64 채널을 뽑아내는데 커널 사이즈는 3이고 패딩은 1
conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
맥스 풀링 : 정수 하나를 인자로 넣으면 커널 사이즈와 스트라이드가 둘다 해당값으로 지정됨.
pool = n.MaxPool2d(2)
3. 구현체를 연결하여 모델 만들기
입력을 첫번째 합성곱 층을 통과 시킴
out = conv1(inputs)
print(out.shape)
torch.Size([1, 32, 28, 28])
맥스 폴링 통과
out = pool(out)
print(out.shape)
torch.Size([1, 32, 14, 14])
두번째 합성곱 층 통과
out = conv2(out)
print(out.shape)
torch.Size([1, 64, 14, 14])
맥스 폴링 통과
out = pool(out)
print(out.shape)
torch.Size([1, 64, 7, 7])
배치 차원을 그대로 두고 나머지를 펼침
out = out.view(out.size(0), -1)
print(out.shape)
torch.Size([1, 3136])
전결합층(Fully-Connteced layer) 통과. 출력층으로 10개의 뉴련을 배치하여 10개의 차원의 텐서로 변환
fc = nn.Linear(3136, 10)
out = fc(out)
print(out.shape)
torch.Size([1, 10])
3. CNN으로 MNIST 분류하기
필요한 도구 임포트
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
device = 'cuda' if torch.cuda.is_available() else 'cpu'
torch.manual_seed(777)
if device == 'cuda':
torch.cuda.manual_seed_all(777)
학습에 사용할 파라미터 설정
learning_rate = 0.001
training_epochs = 15
batch_size = 100
데이터로더를 사용하여 데이터를 다루기 위해서 데이터셋을 정의
mnist_train = dsets.MNIST(root='MNIST_data/', # 다운로드 경로 지정
train=True, # True를 지정하면 훈련 데이터로 다운로드
transform=transforms.ToTensor(), # 텐서로 변환
download=True)
mnist_test = dsets.MNIST(root='MNIST_data/', # 다운로드 경로 지정
train=False, # False를 지정하면 테스트 데이터로 다운로드
transform=transforms.ToTensor(), # 텐서로 변환
download=True)
데이터로더를 사용하여 배치 크기를 정해줌.
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
batch_size=batch_size,
suffle=True,
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):
out = self.layer1(x)
out = self.layer2(out)
out = out.view(out.size(0), -1)
out = self.fc(out)
return out
모델 정의
model = CNN().to(device)
비용 함수와 옵티마이저 정의
criterion = torch.nn.CrossEntropyLoss().to(device) # 소프트 맥스 포함
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
학습 진행
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))
테스트 진행
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())
댓글