카테고리 없음

[Pytorch] 5. 파이토치로 합성곱 신경망(CNN) 구축하기

AI 꿈나무 2020. 12. 9. 16:51
반응형

 이전 포스팅에서 torch.nn 모듈을 사용해서 기본적인 신경망을 구축해보았습니다.

 이번에는 파이토치를 사용하여 합성곱 신경망(CNN)을 구축하는 방법을 알아보겠습니다.

 

CNN 으로 넘어가기

 이제 3개의 합성곱 계층(convolutional layers)을 지닌 신경망을 구축해보겠습니다.

 이전 섹션에서 어떤 함수도 모델의 형식에 대해 가정하지 않기 때문에, 수정 없이 CNN을 훈련하기 위해 이전 코드를 사용할 수 있습니다.

 

 합성곱 계층으로서 Pytorch의 사전 정의된 Conv2d 클래스를 사용할 것입니다.

 각 합성곱 뒤에 ReLU가 있습니다.

 마지막에는 평균 풀링(average pooling)을 수행합니다.

 (view 는 numpy의 reshape 의 pytorch 버전입니다.)

 

class Mnist_CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1)
        self.conv2 = nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1)
        self.conv3 = nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1)
        
    def forward(self, xb):
        xb = xb.view(-1, 1, 28, 28)
        xb = F.relu(self.conv1(xb))
        xb = F.relu(self.conv2(xb))
        xb = F.relu(self.conv3(xb))
        xb = F.avg_pool2d(xb, 4)
        return xb.view(-1, xb.size(1))

lr = 0.1

 

 Momentum 은 이전 갱신도 고려하고 일반적으로 빠른 훈련으로 이어지는 확률적 경사 하강법(SGD, stochastic gradient descent)의 변형입니다.

model = Mnist_CNN()
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

fit(epochs, model, loss_func, opt, train_dl, valud_dl)

 

Out :

0 0.3963693150997162
1 0.2549770093679428

 

nn.Sequential 를 이용하여 코드를 간단히 하기

 torch.nn 에는 코드를 간단히하기 위해 사용할 수 있는 또 다른 편리한 클래스(Sequential)이 있습니다.

 Sequential 객체는 이것 안에 포함된 각 모듈을 순차적으로 실행합니다.

 이것은 신경망을 작성하는 데 더 간단한 방법입니다.

 

 이를 활용하려면 주어진 함수에서 사용자 정의 계층(custom layer)을 쉽게 정의할 수 있습니다.

 예를 들어 PyTorch는 view 계층이 없으므로 이것을 우리의 신경망 용으로 만들어야 합니다.

 Lambda Sequential 로 신경망을 정의했을 때 사용할 수 있는 계층을 생성합니다.

 

class Lambda(nn.Module):
    def __init__(self, func):
        super().__init__()
        self.func = func
        
    def forward(self, x):
        return self.func(x)
        
    def preprocess(x):
        return x.view(-1, 1, 28, 28)

 

 Sequential 로 생성된 모델은 간단합니다.

model = nn.Sequential(
    Lambda(preprocess),
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AvgPool2d(4),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

 

Out :

0 0.34744078179597854
1 0.24735325412750245

 

DataLoader로 감싸기

 CNN은 상당히 간결하지만 MNIST에 대해서만 작동합니다.

  • 입력값은 28*28의 긴 벡터로 가정합니다.
  • 최종적은 CNN 격자 크기는 4*4로 가정합니다. (평균 풀링 커널 크기 때문입니다.)

 

 위 두 가정을 제거하여, 2d 단일 채널 이미지에서 작동하도록 하겠습니다.

 첫번째로, 초기의 Lambda 계층을 제거하고 데이터 전처리를 제너레이터(generator) 로 이동시킬 수 있습니다.

 

def preprocess(x, y):
    return x.view(-1, 1, 28, 28), y
    
class WrappedDataLoader:
    def __init__(self, dl, func):
        self.dl = dl
        self.func = func
        
    def __len(self):
        return len(self.dl)
        
    def __iter__(self):
        batches = iter(self.dl)
        for b in batches:
            yield (self.func(*b))
            
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

 

 다음에 nn.AvgPool2dnn.AdaptiveAvePool2d 로 대체하여 우리가 갖고 있는 입력 tensor가 아니라 우리가 원하는 출력 tensor의 크기를 정의할 수 있습니다.

 결과적으로 우리 모델은 모든 크기의 입력과 함께 작동합니다.

 

model = nn.Sequential(
    nn.Conv2d(1, 16, kervel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU()
    nn.Conv2d(16, 10, kernal_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d(1),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum-0.9)

   

 이제 실행해보겠습니다.

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

                                                                                                                                                        Out :

0 0.3237307893395424
1 0.28560210869312286

   

GPU 사용하기

 만약 운이 좋아서 CUDA 지원 GPU를 사용할 수 있다면 이것을 사용하여 코드 실행 속도를 높일 수 있습니다.

 첫번째로 GPU가 Pytorch에서 작동하는지 확인합니다.

print(torch.cuda.is_available())

 

Out :

True

                                                         

 그리고나서 이것을 위한 디바이스 객체를 생성합니다.

dev = torch.devide(
    'cuda') if torch.cuda.is_abailabel() else torch.device('cpu')

 

 배치를 GPU로 이동시키기 위해 preprocess 를 업데이트 하겠습니다.

def preprocess(x, y):
    return x.view(-1, 1, 28, 28).to(dev), y.to(dev)
    
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

 

 마지막으로 모델을 GPU로 이동시키겠습니다.

model.to(dev)
opt - optim.SGD(model.parameters(), lr=lr, momentum=0.9)

                                                                                                                                                         이제 더 빠르게 실행됩니다.

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

 

Out :

0 0.2804358744978905
1 0.18753825498819351

 

마치면서

 이제 Pytoch를 사용하여 많은 종류의 모델을 훈련시키기 위해 사용되는 데이터 파이프라인과 훈련 루프를 갖고 있습니다.   

 모델을 훈련시키는 것이 얼마나 간단한지 보기 위해 mnist_sample 노트북을 살펴보세요

 

 물론, 데이터 증강(data augmentation), 초매개변수 조정(hyperparameter tuning), 훈련과정 모니터링(monitoring training), 전이 학습(transfer learning) 등과 같이 추가하고 싶은 것이 많습니다.

 이러한 기능들은 이번 튜토리얼에서 나타난 동일한 설계 접근 방식을 사용하여 개발된 fastai 라이브러리에서 사용할 수 있으며, 모델을 더욱 발전시키려는 실무자들을 위해 자연스럽게 다음 단계를 제공합니다.

 

torch.nn

  • Module : 함수 처럼 작동하지만 상태를 포함할 수 있는(신경망의 가중치와 같이) 호출 가능한 오브젝트를 생성합니다. 이것은 포함된 Parameter 가 어떤 것인지 알고 기울기를 0으로 설정하고 가중치를 갱신하기 위해 반복할 수 있습니다.       
  • Parameter : Module 에 역전파 동안 갱신할 필요가 있는 가중치가 있음을 알려주는 tensor 용 wrapper 입니다. requires_grad 속성이 설정된 tensor만 갱신합니다.
  • functional : 활성화 함수, 손실 함수 뿐만 아니라 합성곱 및 선형 계등과 같이 상태를 저장하지(non-stateful) 않는 q버전을 포함하는 모듈(보통 관습에 따라 F 네임스페이스로 임포트됩니다.) 입니다.

torch.optim

 역전파 단계에서 Parameter 의 가중치를 갱신하는 SGD와 같은 optimizer를 포함합니다.

 

Dataset

 TensorDataset 과 같은 Pytorch 에서 제공되어지는 클래스를 포함하는 __len__ __getitem__ 을 지닌 객체의 추상적인 인터페이스 입니다.

 

DataLoader

 모든 Dataset을 받아 데이터의 배치를 반환하는 반복자(iterator)를 생성합니다.

 


공부 목적으로 파이토치 튜토리얼 홈페이지를 번역해보았습니다.

 

What is torch.nn really? — PyTorch Tutorials 1.7.0 documentation

Note Click here to download the full example code What is torch.nn really? by Jeremy Howard, fast.ai. Thanks to Rachel Thomas and Francisco Ingham. We recommend running this tutorial as a notebook, not a script. To download the notebook (.ipynb) file, clic

pytorch.org

반응형