[Pytorch] 간단한 CNN으로 MNIST 분류하기

y30n9ju1v·2021년 10월 10일
0

딥러닝

목록 보기
4/4
import torch
import torchvision.datasets as datasets
import torchvision.transforms as transforms

필요한 모듈을 가져옵니다.

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

# 랜덤 시드 고정
torch.manual_seed(777)

# GPU 사용 가능일 경우 랜덤 시드 고정
if device == 'cuda':
    torch.cuda.manual_seed_all(777)

GPU를 사용할 수 있으면 사용합니다.
랜덤 시드를 고정하는 이유는 다음에 다시 돌렸을 경우에도 같은 결과를 얻기 위해서 입니다.

learning_rate = 0.001
training_epochs = 15
batch_size = 100

학습에 관련된 하이퍼 파라미터를 설정합니다.

mnist_train = datasets.MNIST(root='Data/',
                             train=True,
                             transform=transforms.ToTensor(),
                             download=True)

mnist_test = datasets.MNIST(root='Data/',
                            train=False,
                            transform=transforms.ToTensor(),
                            download=True)

root는 다운로드 경로 지정합니다.
train을 True로 설정하면 훈련 데이터로 다운로드합니다.
ToTensor()는 텐서로 만들고 [0 ... 1] 사이의 값으로 변환합니다.

data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size=batch_size,
                                          shuffle=True,
                                          drop_last=True)

drop_last는 전체 데이터 수에서 batch_size로 나눈 나머지가 있을 경우 버리는 것입니다.

class CNN(torch.nn.Module):
    def __init__(self):
        super().__init__()
        # 첫번째층
        # 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))

        # 두번째층
        # 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))

        # 전결합층 7x7x64 inputs -> 10 outputs
        self.fc = torch.nn.Linear(7 * 7 * 64, 10, bias=True)

    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = torch.nn.Flatten()(out)   # 전결합층을 위해서 Flatten
        out = self.fc(out)
        return out

간단한 모델을 구성합니다.

model = CNN().to(device)

CNN 인스턴스를 생성 후 인스턴스의 파라미터들과 버터를 GPU로 옮깁니다.

criterion = torch.nn.CrossEntropyLoss().to(device) 
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

loss함수로는 CrossEntropy, optimization함수로는 Adam을 사용합니다.

total_batch = len(data_loader)
print('총 배치의 수 : {}'.format(total_batch))
총 배치의 수 : 600

minist_train의 수는 60,000개인데 batch_size가 100이므로 총 배치의 수는 600개입니다.

for epoch in range(training_epochs):
    avg_cost = 0

    for X, Y in data_loader: # 미니 배치 단위로 꺼내온다. X는 미니 배치, Y느 ㄴ레이블.
        # 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))
[Epoch:    1] cost = 0.209929511
[Epoch:    2] cost = 0.0615508817
[Epoch:    3] cost = 0.0456047803
[Epoch:    4] cost = 0.0363934599
[Epoch:    5] cost = 0.0300672501
[Epoch:    6] cost = 0.0253494326
[Epoch:    7] cost = 0.0202930104
[Epoch:    8] cost = 0.018379068
[Epoch:    9] cost = 0.0153796058
[Epoch:   10] cost = 0.0118981814
[Epoch:   11] cost = 0.0107681192
[Epoch:   12] cost = 0.00951414276
[Epoch:   13] cost = 0.0088522248
[Epoch:   14] cost = 0.00605905708
[Epoch:   15] cost = 0.00637460686

optimizer.zero_grad()는 이전 epoch의 미분값을 버립니다.
cost.backward()는 back propagation을 수행합니다.
optimizer.step()은 계산된 미분값에 따라 weight를 업데이트 합니다.

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.9881999492645264

학습을 진행하지 않을 것이므로 torch.no_grad()를 수행합니다.
argmax는 입력 텐서에 있는 모든 요소의 최대값의 인덱스를 반환합니다.

참고

0개의 댓글