본문 바로가기
논문 리뷰/Classification

[CNN모델 이해하기] CNN 모델 설계하기 & CNN 모델 인사이트

by inhovation97 2021. 9. 1.

이번 포스팅은 CNN 모델을 설계하면서, 중요한 점을 짚고 무엇이 어떻게 왜 쓰이는지 정리하려고합니다.

 

미리 학습된 모델을 쓰지 않고, 그냥 CNN모델을 설계하면서 성능차이를 봅시다.

캐글 컴피티션에 공유돼있는 노트북의 CNN 모델을 수정해가면서 개념을 되짚고, 성능을 높여보겠습니다.

이 과정에서 과적합을 방지하고 gradient vanishing을 유의하며 모델링합니다.

 

제 글을 끝까지 보시고 제가 공유한 노트북으로 모델 부분만 한 번 수정해보세요!

배운 것으로써는 당연한 결과지만 직접해보고 눈으로 보는 것 만큼 좋은 학습은 없죠 ㅎ

< CNN모델을 설계하면서 깊이 이해해보자! >

1. 캐글 컴피티션에 공유된 아주 basic한 CNN 모델을 살펴보기
2. 리뷰한 CNN 모델의 문제점을 찾고 수정해보기
3. 찾은 문제점으로 수정한 모델의 결과비교
4. 최종 결과 비교
5. 얻은 인사이트

중간 중간에 어떤 개념들이 모르시다면 제가 포스팅했던 cs231n의 내용을 참고 하시면 됩니다!

밑에서 관련 내용의 링크를 달아드립니다.

이 프로젝트는 서울 ICT이노베이션 시각 인공지능 심화과정에서 강사님 하에 진행했었습니다.

 

 

<1. 캐글 컴피티션에 공유된 basic한 CNN 모델 리뷰>

 

 

https://www.kaggle.com/uzairrj/beg-tut-intel-image-classification-93-76-accur

 

[BEG][TUT]Intel Image Classification[93.76% Accur]

Explore and run machine learning code with Kaggle Notebooks | Using data from Intel Image Classification

www.kaggle.com

먼저 캐글에 어떤 분이 공유하신 CNN 모델입니다.

이 사람의 제목으로는 93.7%의 accuracy를 달성했다고 하는군요.

 

코드를 보면 컴피티션은 이렇게 6가지의 이미지를 classification하는 단순한 대회임을 알 수 있습니다.

6가지의 경관을 분류하는 대회인 거죠.

 

전처리 부분은 생략하고, 바로 모델 부분으로 가봅시다.

이번 포스팅의 핵심은 CNN모델의 이해가 바탕이기 때문에 data augmentation, finetuning은 제외하고,  CNN모델을 직접 설계하여 성능을 올려볼 것입니다.

데이터적으로 저는 원래 필자의 7:3 train/validation 세트 비율에서 좀 더 많은 학습 데이터 확보를 위해 8:2로 바꾼 것 밖에 없습니다.

 

 

먼저 flatten하기 전까지의 Conv layer부터 봅시다. 

 

Conv layer는 전부 3x3을 쓰고 있습니다. 

activation function은 relu를 씁니다.

maxpooling은 5x5로 2번 들어갑니다.

conv layer의 채널 개수는 그냥 어떤 순서없이 줄여가는 방식으로 넣어준 것 같습니다.

최종 conv layer에서 50개의 channel을 뽑고 5x5 maxpooling을 진행합니다.

그렇게해서 최종 output feature map이 4x4가 되어 (4x4x50) H,W,C가 됩니다.

 

이제 fc layer를 봅시다.

flatten해줍니다.

relu로 만든 dense layer를 3번 거칩니다. 이번에도 출력 뉴런의 개수는 어떤 의미는 없이 그냥 줄이는 목적으로 설정한 것 같습니다.

0.5 dropout을 한번 깔아준 뒤, 6개 값을 출력하는 softmax로 모델이 구성됩니다.

 

여기까지가 저 분이 공유한 모델의 구성입니다. 성능을 한 번 봅시다.

 

validation셋 best accuracy가 0.8 언저리입니다.

제목에는 93.7%라고 써놓고 ㅋㅋㅋ trainset의 accuracy로 제목을 달았던 거군요...

(그럼 나도 99% 만들 수 있음)

 

---------------------------------------------------------------------------------------------------------------------여기까지 보셨으면, 본인이 직접 한 번 설계하여 성능을 향상시켜 본 뒤 저의 코드와 비교해보시기를 추천드립니다!

제가 공유한 캐글 노트북 링크로 들어가서 로그인 뒤에 저 코드를 본인의 캐글 노트북으로 가져올 수 있습니다.

keras, tf 공홈에 가서 layer를 짜는 문법만 보고 모델만 수정하면 따라할 수 있습니다.https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D

 

 

<2. 리뷰한 CNN 모델의 문제점을 찾고 수정해보기>

 

 

아마 다들 느끼셨는지는 모르겠지만, 저 글의 필자는 그냥 대충 모델을 만든 것 같은 느낌입니다. 

베이직 모델을 제공하신 거죠.

output 채널도 원래는 보통 2의 n제곱으로 만들어 컴퓨터의 연산을 고려해서 짜죠.

 

이제 저 모델을 한 번 고쳐봅시다!

 

일단 모델을 어떻게 짜야 성능이 잘 나올지 생각해봅시다.

일단 모델의 깊이와 성능은 '어느 정도' 양의 상관관계가 있습니다.

이건 vggnet, resnet 논문에서도 연구한 결과입니다.

( 관련 포스팅 : CNN 대표적인 모델 )

( 관련 포스팅 : vggnet 논문 리뷰)

 

저는 최대한 모델의 깊이를 늘릴 것입니다.

그렇다고 무자비하게 막 쌓아버리면 또 성능이 안 나올겁니다. 

그렇게 잘 나왔다면 resnet도 resnet 10000짜리가 있겠죠?

과적합의 위험 때문입니다. 

또? gradient vanishing 때문입니다. 

그래서 최대한으로 과적합과 gradient vanishing을 견제(?)하면서, 많은 층을 쌓을 겁니다.

전체적인 숲으로는 과적합이 되지 않도록, 기울기가 소실되지 않도록, 모델을 깊게 효율적으로 짜야한다는 겁니다. 

즉, 이 분이 짜신 모델보다 적은 수의 파라미터로 더 깊은 모델을 만들면 됩니다.

그러면 최소 이 모델보다는 좀 더 효율적인 모델일 겁니다! 

성능은 최소 그 이상이여야겠죠?

 

Conv layer를 먼저 봅시다.

 

3x3 filter를 쓰는 건 좋아 보입니다. 적은 수의 파라미터로 layer를 많이 깔 수 있기 때문입니다.

padding도 깔아줍시다. 최종 feature map 사이즈를 고려하면서 layer를 좀 더 깊게 쌓을 수 있을 것 같습니다.

'relu' 함수는 Conv layer 에서 가장 많이 쓰이는 activation function입니다. 바꿀 필요는 없어보입니다.

output channel은 위에서 설명한 대로 2의 n제곱으로 뽑아줍시다.

 

층을 많이 쌓으려면, gradient vanishing 문제를 해결해야합니다. 

저는 2가지 방법이 떠올랐습니다.

 

1. weight initailization

2. batch normalization

위 모델에는 이 2가지가 없습니다. 

저는 이 두 방법을 고려해서 gradient vanishing 문제를 견제(?) 할 겁니다.

 

maxpooling을 봅시다.

maxpooling도 3x3으로 할 겁니다. 이건 그냥 순전히 제 감인데... 3x3 filter로 특징을 추출한 feature map을3x3 사이즈로 max값을 추출하는게 낫지 않을까? 하는... 5x5는 뭔가 놓치는 특징이 있을 것 같은...

그리고 그냥 최종 모델의 사이즈를 봣을 때 3x3이 적당한 크기인 것 같습니다.

5x5쓰면 feature map사이즈가 확 줄어들어 layer를 깊게 쌓지 못할 겁니다.

그리고 넣어주는 시기는 Conv layer를 3개 지날 때마다 넣어줍니다.  

최종 feature map사이즈를 고려한 것도 있고, vggnet의 영감입니다. 

 

Conv layer는 layer를 깊게 쌓기위해 최종 feature map size가 5x5가 될 때까지 down sampling을 해줄겁니다.

 

fc layer를 봅시다.

아시는 내용일 수 있지만 vggnet에는 flatten 후에, fc layer가 3개나 들어갑니다.

이게 엄청난 파라미터 개수를 차지합니다.

저는 resnet에서부터 쓰인 좀 더 효율적인 Global Average Pooling으로 feature map들을 벡터화시킨 뒤, fc layer를 2개를 넣을 건데 2개를 넣는 이유는 중간에 dropout을 껴서 regularization 가해주기 위함입니다.

이렇게 fc layer에서는 과적합을 견제하는 것을 초점으로 설계할겁니다.

( 관련 포스팅 : CNN 대표적인 모델 )

 

이제 초보에게 가장 난감한 batch size와 learning rate를 봅시다. 

여기서 batch size는 설정 안햇으니 케라스에서 디폴트로 32가 들어갈겁니다. 

batch size : 16 & learning rate : 0.0001    or    batch size : 256& learning rate : 0.0005

 

( batch size : 16 & learning rate 관련 포스팅 https://inhovation97.tistory.com/32)

대략적으로 설명하자면 batch size를 크게 가져가면, 한 번의 step에서 loss의 편차가 더 작아지므로(n의 수가 큼) 좀 더 일반화시킬 수 있고 batch size를 작게 가져가면, step 마다 loss의 편차가 크기 때문에 더 민감하게 모델을 학습시킬 수 있는 것입니다.

 

저 둘의 조합 성능이 비슷비슷 하더군요.

이것도 따로 한번 더 포스팅 하려합니다.

 

여기까지 읽으셨으면, 제 모델을 보기 전에 공유해드린 링크로가서 캐글 노트북으로 설명따라 모델을 한 번 설계해보시길 추천드립니다.

 

 

 

<3. 찾은 문제점으로 수정한 모델의 결과 비교>

 

 

이제 제가 최종적으로 설계한 모델을 봅시다.

Conv layer 먼저 봅시다.

사실 저도 뚝딱 만든 것 같이 포스팅하지만, Conv layer 개수나 fc layer를 2개 쌓은 거나 그런 부분들은 전부 결과를 보면서 비교하며 쌓은 모델입니다. 하루종일 뭐가 더 좋은지 비교하면서 쌓은 거죠.

conv layer를 6개 ~ 12개에서 9개가 좋았고, 드랍 아웃을 포함한 dense layer 2개가 더 좋았고...

이렇게 비교해가면서말이죠.

 

위에서 제가 말한 전략을 제외하고 경험적으로 얻은 것에 대해 제가 수정한 모델을 설명하자면, 

우선 weight init은 케라스에서는 디폴트로 xavier initilization일 겁니다. (아마도...)

저는 he init이 relu를 타깃으로 만든거라 he initilization을 넣어주었습니다.

 

batch norm은 가중치가 잘 flow 되도록 layer마다 깔아주는데, 처음에는 maxpooling 전에 BN을 깔아주지 않았습니다. 용도가 그런 용도가 아니니까요.

BN은 활성화 함수에 값들을 넣기 전에, 입력값들의 범위를 normalize해주어서 Saturate를 어느 정도 control 해주는 용도입니다. 

 

그런데 BN을 max pooling하기 전에 넣어주니 성능이 확연하게 더 좋게 나오더군요.

이건 <5. 인사이트 공유>에서 결과를 또 공유합니다.

 

(weight initilization, batch normalization 관련 포스팅: https://inhovation97.tistory.com/23)

(이 영상의 뒷 부분에 설명이 나옵니다. weight initilization 설명 영상 16분부터 보시면됩니다.)

fc layer를 봅시다.

여기서는 과적합을 방지하는게 포인트입니다.

global AVG pooling의 효과가 생각보다 대단합니다. 파라미터 수도 훨씬 많이 줄어들고 성능도 좋아집니다.

global AVG pooling 이후에 바로 softmax or dense layer + drop out + softmax 둘 중에 고민했습니다. 

파라미터가 더 많아져도 dropout을 낀 후자가 훨씬 더 결과가 좋더군요.

드랍아웃을 설정한 저의 생각을 설명하자면,

최종적으로 얻은 feature map들은 각자가 전부 가중치가 다른 filter들로 나온 이미지의 어떤 부분들에 대한 전문가 입니다. 

그니까 저는 최종적으로 feature map을 128개를 뽑았고, 그걸 avg 풀링으로 128개의 전문가들이 있는 겁니다.

이게 전부 6개의 이미지들을 분류하는 데에 필요하진 않을 겁니다. 약간 덜 떨어진 전문가 피쳐맵도 있을 거예요. 그래서 이걸 dense layer에 200개로 차원을 늘린 뒤에, 0.8 rate의 드랍아웃으로 매우 강한 'regularization'을 준겁니다.

regularization은 모델의 과적합을 방지해주니까요. 

생각은 이렇게 했지만, 적게도 해보긴해봤습니다.

생각대로 많은 뉴런으로 0.8 드랍아웃이 효과가 좋았습니다. 

 

 

 

 

<4. 최종 결과 비교>

 

최종 모델을 비교해보면 conv layer는 6개 -> 9개로 늘렸지만, parameter 개수를 118만개에서 50만개로 절반 이상을 확 줄였습니다!

결과가 비슷하게만 나와도 좀 더 효율적으로 모델을 잘 짯다고 볼 수 있습니다.

 

오른쪽이 제가 수정한 모델의 결과입니다.

최종 best validation accuracy를 비교해보면,

0.8 vs 0.89

제가 설계한 모델이 학습 파라미터도 수도 작고, layer도 더 깊으며, 과적합도 훨씬 뒤에야 발생합니다.

gradient flow문제, 과적합의 문제를 잘 조절하며 성공적으로 모델을 수정한 것 같습니다.

 

 

 

<5. 얻은 인사이트>

 

오른쪽이 max pooling전에 BN을 추가한 모델

 

 

maxpooling전에 BN을 넣어주니 계속 잘 되더군요!

이건 그냥 순서의 차이인것 같습니다.

 

과적합이 12~13 epoch 부근에서 거의 계속 일어났었는데, BN을 maxpooling전에 깔아주니 20정도 까지 과적합을 늦출 수 있었고 loss들도 훨씬 편차가 작아 안정적으로 학습이 이루어집니다. 

 

이 글을 보신 분들은 아마 이제 막 딥러닝을 공부하시는 분일 거라고 생각됩니다. 

제 노트북으로 가서 한 번 개념들을 되새기면서 모델을 수정해보세요! 

큰 도움이 되는 프로젝트일 것 같습니다.

https://www.kaggle.com/inhovation97/beg-tut-intel-image-classification-93-76-accur

 

[BEG][TUT]Intel Image Classification[93.76% Accur]

Explore and run machine learning code with Kaggle Notebooks | Using data from Intel Image Classification

www.kaggle.com

댓글