Pytorch
에는 CNN
을 개발 하기 위한 API
들이 있습니다. 다채널로 구현 되어 있는 CNN 신경망을 위한 Layers, Max pooling, Avg pooling 등, 이번 시간에는 여러 가지 CNN
을 위한 API
를 알아 보겠습니다. 또한, MNIST
데이터 또한 학습 해 보겠습니다.
Convolution
연산을 위한 레이어들은 다음과 같습니다.
위 3가지 API
들은 내부 원리는 다 같습니다. 이번에는 자주 사용하는 Conv2d
를 중점으로 설명 하도록 하겠습니다.
일단 Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
의 파라미터는 다음과 같습니다.
in_channels
: 입력 채널 수을 뜻합니다. 흑백 이미지일 경우 1, RGB 값을 가진 이미지일 경우 3 을 가진 경우가 많습니다.out_channels
: 출력 채널 수을 뜻합니다.kernel_size
: 커널 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다.stride
: stride 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다. 기본 값은 1입니다.padding
: padding 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다. 기본 값은 0입니다.padding_mode
: padding mode를 설정할 수 있습니다. 기본 값은 'zeros' 입니다. 아직 zero padding만 지원 합니다.dilation
: 커널 사이 간격 사이즈를 조절 합니다. 해당 링크를 확인 하세요.groups
: 입력 층의 그룹 수을 설정하여 입력의 채널 수를 그룹 수에 맞게 분류 합니다. 그 다음, 출력의 채널 수를 그룹 수에 맞게 분리하여, 입력 그룹과 출력 그룹의 짝을 지은 다음 해당 그룹 안에서만 연산이 이루어지게 합니다.bias
: bias 값을 설정 할 지, 말지를 결정합니다. 기본 값은 True
입니다.Input Tensor의 모양과 Output Tensor의 모양은 다음과 같습니다.
in_channels
에 넣은 값과 일치하여야 함.out_channels
에 넣은 값과 일치 함.import torch
import torch.nn as nn
import torch.nn.functional as F
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=3, kernel_size=5, stride=1)
self.conv2 = nn.Conv2d(in_channels=3, out_channels=10, kernel_size=5, stride=1)
self.fc1 = nn.Linear(10 * 12 * 12, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
print("연산 전", x.size())
x = F.relu(self.conv1(x))
print("conv1 연산 후", x.size())
x = F.relu(self.conv2(x))
print("conv2 연산 후",x.size())
x = x.view(-1, 10 * 12 * 12)
print("차원 감소 후", x.size())
x = F.relu(self.fc1(x))
print("fc1 연산 후", x.size())
x = self.fc2(x)
print("fc2 연산 후", x.size())
return x
cnn = CNN()
output = cnn(torch.randn(10, 1, 20, 20)) # Input Size: (10, 1, 20, 20)
연산 전 torch.Size([10, 1, 20, 20])
conv1 연산 후 torch.Size([10, 3, 16, 16])
conv2 연산 후 torch.Size([10, 10, 12, 12])
차원 감소 후 torch.Size([10, 1440])
fc1 연산 후 torch.Size([10, 50])
fc2 연산 후 torch.Size([10, 10])
Pooling
연산을 위한 레이어 들은 다음과 같습니다.
위 6가지 API
들은 차원 수, Pooling
연산의 방법을 제외하곤 다 같습니다. 대표적인 MaxPool2d
를 설명 해 보겠습니다.
일단 MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
의 파라미터는 다음과 같습니다.
kernel_size
: 커널 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다.stride
: stride 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다. 기본 값은 1입니다.padding
: zero padding을 실시 할 사이즈를 뜻합니다. int
혹은 tuple
이 올 수 있습니다. 기본 값은 0입니다.dilation
: 커널 사이 간격 사이즈를 조절 합니다. 해당 링크를 확인 하세요.return_indices
: True
일 경우 최대 인덱스 를 반환합니다.ceil_mode
: True
일 경우, Output Size에 대하여 바닥 함수대신, 천장 함수를 사용합니다.Input Tensor의 모양과 Output Tensor의 모양은 다음과 같습니다.
import torch
import torch.nn as nn
import torch.nn.functional as F
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.max_pool1 = nn.MaxPool2d(kernel_size=2)
self.max_pool2 = nn.MaxPool2d(kernel_size=2)
self.fc1 = nn.Linear(10 * 5 * 5, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
print("연산 전", x.size())
x = F.relu(self.max_pool1(x))
print("max_pool1 연산 후", x.size())
x = F.relu(self.max_pool2(x))
print("max_pool2 연산 후",x.size())
x = x.view(-1, 10 * 5 * 5)
print("차원 감소 후", x.size())
x = F.relu(self.fc1(x))
print("fc1 연산 후", x.size())
x = self.fc2(x)
print("fc2 연산 후", x.size())
return x
cnn = CNN()
output = cnn(torch.randn(10, 1, 20, 20))
연산 전 torch.Size([10, 1, 20, 20])
max_pool1 연산 후 torch.Size([10, 1, 10, 10])
max_pool2 연산 후 torch.Size([10, 1, 5, 5])
차원 감소 후 torch.Size([1, 250])
fc1 연산 후 torch.Size([1, 50])
fc2 연산 후 torch.Size([1, 10])
일단 MNIST
모델을 불러오기 위해서는 torchvision
의 설치가 선행 되어야 합니다.
pip install torchvision
torchvision
을 설치한 후, 필요한 라이브러리를 import
합니다.import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
MNIST
데이터를 가져오기 위해, datasets
를 사용 하고, 이를 Tensor
객체로 가공 하기 위해, transforms
를 사용합니다. Compose
함수를 이용해, Tensor
로 가공 후, 정규화 또한 진행합니다. MNIST
데이터를 배치 학습 시키기 위해, DataLoader
를 사용 합니다.train_data = datasets.MNIST('./data/', train=True, download=True, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])) # 학습 데이터
train_loader = torch.utils.data.DataLoader(dataset=train_data, batch_size=50, shuffle=True)
test_data = datasets.MNIST('./data/', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])) # 테스트 데이터
test_loader = torch.utils.data.DataLoader(dataset=test_data, batch_size=50, shuffle=True)
CNN
클래스를 선언해 줍니다.class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=20, kernel_size=5, stride=1)
self.conv2 = nn.Conv2d(in_channels=20, out_channels=50, kernel_size=5, stride=1)
self.fc1 = nn.Linear(4 * 4 * 50, 500)
self.fc2 = nn.Linear(500, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, kernel_size=2, stride=2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, kernel_size=2, stride=2)
x = x.view(-1, 4 * 4 * 50) # [batch_size, 50, 4, 4]
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
CNN
객체와, optimizer
, loss function
객체를 선언 해 줍니다.cnn = CNN()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(cnn.parameters(), lr=0.01)
data
의 사이즈는 (50, 1, 28, 28)이고, target
사이즈는 (50) 입니다.cnn.train() # 학습을 위함
for epoch in range(10):
for index, (data, target) in enumerate(train_loader):
optimizer.zero_grad() # 기울기 초기화
output = cnn(data)
loss = criterion(output, target)
loss.backward() # 역전파
optimizer.step()
if index % 100 == 0:
print("loss of {} epoch, {} index : {}".format(epoch, index, loss.item()))
cnn.eval() # test case 학습 방지를 위함
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
output = cnn(data)
test_loss += criterion(output, target).item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
결과 : Test set: Average loss: 297.5230, Accuracy: 9761/10000 (98%)
다음 시간에는 자연어 처리에서 많이 사용하는 RNN
의 API
들을 알아보는 시간을 가져 보겠습니다.