상세 컨텐츠

본문 제목

[Dive into Deep Learning / CNN] CNN 구현해보기

심화 스터디/Dive into Deep Learning

by 나는 은쪽이 2022. 11. 21. 01:50

본문

작성자 : 16기 하예은

본 포스팅은 다음 자료들을 참고하여 작성되었습니다.

- https://tutorials.pytorch.kr/beginner/basics/data_tutorial.html

- https://justkode.kr/deep-learning/pytorch-cnn

1) CIFAR Dataset을 활용하여 실제 CNN을 간단하게 학습시키기

CNN 구현에 필요한 라이브러리를 import 해줍니다.

 

먼저, batch size를 8로 지정해줍니다. 보통 batch size는 computational capacity를 고려하여 지정합니다.

그리고 CIFAR Dataset에서 train set과 test set을 불러옵니다.

  • root : 데이터가 저장되는 경로
  • train : True이면 train set, False이면 test set
  • download : root에 데이터가 없는 경우 인터넷에서 다운로드 여부
  • transform=ToTensor() : 데이터를 tensor 형태로 변환

 불러온 데이터를 data loader에 담아서 학습에 필요한 형태로 만들어줍니다.

classes에서 볼 수 있듯이, 비행기부터 트럭까지 10개의 이미지를 분류하는 작업을 해보겠습니다.

 

데이터가 data loader에 담겨져있기 때문에 iter 함수로 데이터셋을 iterate 할 수 있습니다. 반복문을 사용해서 네 개의 이미지를 꺼내면 다음과 같은 이미지가 결과값으로 반환됩니다.

 

 

 

2) Naive Forward Pass

 

 

<입력 사이즈>
- x: (N, C, H, W) - N(이미지 개수), C(Color channel : 3이면 RGB, 1이면 흑백), H(높이), W(너비)

- w: (F, C, HH, WW) - 필터 가중치 : F(필터 개수), C(Color channel), HH(필터 높이), WW(필터 너비)

- b: Biases (F,)
- conv_param: 딕셔너리로 구성된 Convolution 관련 파라미터
- stride: 수직/수평 방향으로 한번에 필터가 움직이는 픽셀 수
- pad: 입력 이미지 주변에 특정 상수 값으로 Padding
 *패딩을 할 때, 원래 입력을 훼손시켜서는 안되며, Padding은 입력 이미지 주변으로 대칭적으로 되어야합니다.
 
<반환값>
- out:  (N, F, H_out, W_out), H_out과 W_out의 사이즈는 다음과 같습니다.
      H_out = 1 + (H + 2 * pad - HH) / stride
      W_out = 1 + (W + 2 * pad - WW) / stride
- cache: (x, w, b, conv_param) Backward 과정에 필요한 값을 담은 cache입니다. (*torch 기준 require_grad로 가져가는 값)

 

위와 같이 (이미지, 필터, bias, 파라미터)를 입력값으로 갖는 con_forward_naive 함수를 정의해줍니다.

 

 이제 데이터를 직접 생성해서 con_foward_naive 함수의 성능을 평가해보겠습니다.

  • np.linspace() : 지정한 구간 내에 균일한 간격으로 숫자를 채우는 함수
  • num : 구간을 몇 개의 간격으로 요소를 만들 것인지
  • np.prod() : array의 element에 대한 곱을 반환하는 함수

x, w, b를 array로 만들어주고 stride와 pad에 대한 값도 지정해줍니다.

만약 forward pass를 잘 구현하였다면 out과 correct_out과의 차이가 매우 작을 것입니다.

 

두 개의 input에 대한 상대적 차이를 반환하는 rel_error 함수를 정의합니다.

 

rel_error 함수로 out과 correct_out과의 차이를 알아본 결과, 매우 작은 값이 출력되었습니다.

이렇게 con_forward_naive 함수로 foward pass를 잘 구현한 것을 확인할 수 있었습니다.

 

 

3) Naive Backward

#gradient output tensor를 initialize해줍니다.

    # db 계산
    # Filter 개수에 대하여 해당 Filter에 걸쳐있는 모든 Tensor들을 합쳐 쌓아주면 됩니다.

    # dW 계산.
    # 입력/필터/높이/너비에 대해 각각 for문을 돌려주고, dw tensor를 어떻게 채울지 고민해볼 수 있습니다. Chain Rule에 의하여 dout*x

    # dx 계산.
    # 마찬가지로 Chain Rule에 의하여 dout*w.

    # dx의 사이즈가 x와 똑같아야 하기에, 원래 사이즈로 조정하기 위하여 padding된 부분을 제거합니다.

  • dx_temp, dw, db : initialize gradient output tensor
  • db 계산 : 필터 개수(F)에 대해서 해당 필터에 걸쳐있는 모든 텐서들을 합쳐서 쌓아줍니다.
  • dw 계산 : 이미지 개수(N), 필터 개수(F), 높이(H_out), 너비(W_out)에 대해 반복문을 사용해 텐서를 채웁니다.
                    Chain Rule에 의해 dw = dout * x로 계산합니다.
  • dx_temp 계산 : dw와 마찬가지로 반복문을 사용해 텐서를 채웁니다.
                             Chain Rule에 의해 dx_temp = dout * w로 계산합니다.
  • dx 계산 : dx의 사이즈가 x와 동일해야하므로 padding 된 부분을 제거하여 원래 사이즈로 조정해줍니다. 

 

 

4) Pytorch 기반 Classifier 학습하기

위와 같이 CNNmodel 클래스를 선언해줍니다.

 

loss function과 optimizer 또한 선언해줍니다. optimizer는 SGD(Stochastic Graident Descent)로, momentum을 0.9로 설정하여 지정해주었습니다.

 

epoch을 설정하여 학습을 진행합니다.

* optimizer.zero_grad()를 사용해 gradient를 0으로 초기화해주어야 합니다.

 

결과를 확인합니다. 50% 정도의 정확도가 나올 것입니다.

Learning_rate, Optimizer, CNN 구조, batch_size, epoch 등을 조정해보는 과정을 통해 성능을 향상시킬 수 있습니다.

 

성능이 좋은 신경망은 다음과 같은 전략을 사용합니다.

  • Batch Normalization(nn.BatchNorm2d) : 해당 batch input의 tensor 값을 정규화합니다.
  • Layer Normalization(nn.LayerNorm2d) : 해당 layer의 tensor값을 input에 대해 정규화합니다.
  • Relu Function(nn.ReLU()) : Activation Function 중 가장 유명하게 쓰이는 비선형 함수입니다.
  • 그 외, AlexNet 과 같은 ImageNet 우승 모델들의 Structure을 참고하면 더 좋은 성능을 내볼 수도 있습니다.

 

관련글 더보기

댓글 영역