관리 메뉴

ComputerVision Jack

PyTorch Lecture 11 : Advanced CNN 본문

DeepLearning/Pytorch_ZeroToAll

PyTorch Lecture 11 : Advanced CNN

JackYoon 2020. 10. 27. 17:14
반응형

Advanced CNN

CNN Model

저번시간 교수님께서 강의해주신 CNN 모델architecture입니다.

하지만 여기서 우리는 의문점이 생깁니다. 이미지에서 Kernel을 통해 feature를 추출할 경우, kernel size를 1 x 1 or 3 x 3, 5 x 5으로 선택해야하기 때문입니다.

교수님은 여기서 Inception Module을 설명해주셨습니다. 

즉, 모든 연산을 다 집어 넣으면서 basic은 1 x 1로 시작하는 방식입니다.

Why 1 x 1 convolution?

1 x 1 convolution을 토대로 3 x 3, 5 x 5, pooling까지 확장해 나아갑니다. 그럼 왜 1 x 1 convolution을 진행할까요?

1 x 1 convolution의 경우 이미지의 손실이 발생하지 않습니다. 하지만 dimensional dot product를 통해 이미지의 depth를 감소시킬 수 있습니다. 

예를 들어 (64 x 56 x 56) 인경우 1 x 1 conv with 1 filters 진행하면 (1 x 56 x 56) 입니다. 즉 64인 depth가 1depth로 감소된 것을 확인할 수 있습니다. 이러한 1 x 1 convolution을 진행하는 이유는 operations 측면에서 시간비용이 감소되기 때문입니다.

Inception Module

그럼 basic을 1 x 1 로 모든 연산을 다 고려하는 Inception Module을 코딩으로 구현해보겠습니다.

[11.toy_inception_mnist.py]

from __future__ import print_function

import argparse

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

from torchvision import datasets, transforms

from torch.autograd import Variable

# 해당 실습에 필요한 라이브러리를 import 합니다.

 

batch_size = 64

# batch size 는 64로 정합니다.

 

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

test_dataset = datasets.MNIST(root='./data/', train=False, transform=transforms.ToTensor())\

# 학습과 테스트에 필요한 mnist 데이터 셋을 다운로드합니다.

 

train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)

# 해당 mnist 데이터셋을 위한 DataLoader를 제작합니다.

 

class InceptionA(nn.Module):

 

    def __init__(selfin_channels):

        super(InceptionA, self).__init__()

        self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1)

 

        self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)

        self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)

 

        self.branch3x3dbl_1 = nn.Conv2d(in_channels, 16, kernel_size=1)

        self.branch3x3dbl_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)

        self.branch3x3dbl_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)

 

        self.branch_pool = nn.Conv2d(in_channels, 24, kernel_size=1)

 

    def forward(selfx):

        branch1x1 = self.branch1x1(x)

 

        branch5x5 = self.branch5x5_1(x)

        branch5x5 = self.branch5x5_2(branch5x5)

 

        branch3x3dbl = self.branch3x3dbl_1(x)

        branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)

        branch3x3dbl = self.branch3x3dbl_3(branch3x3dbl)

 

        branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)

        branch_pool = self.branch_pool(branch_pool)

 

        outputs = [branch1x1, branch5x5, branch3x3dbl, branch_pool]

        return torch.cat(outputs, 1)

# 해당 Inception Module architecture 로 inception class를 구현합니다. 

 레이어와 층을 준비하고, forward 연산을 진행한 후, 리스트로 결과를 담아 concat을 사용하여 넘겨줍니다.

 

class Net(nn.Module):

 

    def __init__(self):

        super(Net, self).__init__()

        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)

        self.conv2 = nn.Conv2d(88, 20, kernel_size=5)

 

        self.incept1 = InceptionA(in_channels=10)

        self.incept2 = InceptionA(in_channels=20)

 

        self.mp = nn.MaxPool2d(2)

        self.fc = nn.Linear(1408, 10)

 

    def forward(selfx):

        in_size = x.size(0)

        x = F.relu(self.mp(self.conv1(x)))

        x = self.incept1(x)

        x = F.relu(self.mp(self.conv2(x)))

        x = self.incept2(x)

        x = x.view(in_size, -1)  # flatten the tensor

        x = self.fc(x)

        return F.log_softmax(x)

# 해당 inception module을 사용하여 network를 구성합니다. 전 시간에 배운 cnn 구성에 inception 처리를 추가했다고 생각하면 됩니다.

 

model = Net()

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

# 해당 모델에 대한 객체를 생성하고, 최적화를 준비합니다.

 

def train(epoch):

    model.train()

    for batch_idx, (data, target) in enumerate(train_loader):

        data, target = Variable(data), Variable(target)

        optimizer.zero_grad()

        output = model(data)

        loss = F.nll_loss(output, target)

        loss.backward()

        optimizer.step()

        if batch_idx % 10 == 0:

            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(

                epoch, batch_idx * len(data), len(train_loader.dataset),

                100. * batch_idx / len(train_loader), loss.item()))

# 학습을 진행합니다. 여기서 깃허브의 코드를 그대로 코렙에 치시면 오류가 발생합니다. 해당 오류는 0차원 텐서의 잘못된 인덱스라고 표기되어있습니다.

error : invalid index of a 0 - dim tensor. Use 'tensor.item() ' in Python or~~

따라서 loss.data[0] 에대한 부분을 loss.item()으로 수정하여 실행하면 됩니다.

 

def test():

    model.eval()

    test_loss = 0

    correct = 0

    for data, target in test_loader:

        data, target = Variable(data, volatile=True), Variable(target)

        output = model(data)

        # sum up batch loss

        test_loss += F.nll_loss(output, target, size_average=False).data

        # get the index of the max log-probability

        pred = output.data.max(1, keepdim=True)[1]

        correct += pred.eq(target.data.view_as(pred)).cpu().sum()

 

    test_loss /= len(test_loader.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(

        test_loss, correct, len(test_loader.dataset),

        100. * correct / len(test_loader.dataset)))

# 해당 학습된 모델에 대해 test를 적용할 함수를 생성합니다.

여기도 data[0] 으로 되어 있는 코드를 data로 수정해야 오류없이 동작합니다.

 

for epoch in range(1, 10):

    train(epoch)

    test()

# 학습을 실행하면 됩니다.

반응형
Comments