본문 바로가기
컴퓨터비전/CNN

[딥러닝] CNN(Convolutional Neural Network)의 이해

by PIAI 2022. 3. 11.

CNN(Convolutional Neural Network)의 필요성

 

기존 DNN의 경우에는 기본적으로 2차원이나 3차원 데이터를 Flatten으로 1차원 형태로 변형시켜 사용한다. 28 x 28의 흑백 이미지는 768개의 1차원 형태로 입력을 받는다. 하지만 요즘 이미지는 500 x 500 이 그냥 넘는다. 이것을 1차원으로 나열했을 시에 250000개의 입력 데이터가 주어지고, 여기에 따른 가중치를 계산하면 시간이 매우 많이 소요된다.

그리고 이미지가 중앙이나 왼쪽 오른쪽에 고정돼서 나오는 것이 아니라 여러방향으로 주어진다. 만약 강아지를 분류하는 모델에서 사람과 강아지가 같이 나온 사진이 있으면 강아지를 찾지 못하고 사람을 강아지로 인식할 수도 있다는 이야기이다. 그래서 나온 것이 CNN이다.

 

CNN의 구조

 

https://www.mdpi.com/applsci/applsci-09-04209/article_deploy/html/images/applsci-09-04209-g001.png
일반적인 CNN 구조

 

CNN은 Feature extraction + Classification으로 나뉜다. Classification은 일반 DNN(Deep Neural Network)의 구조이다. 그럼 이제 Feature extraction을 알아보면, 이미지를 계속 추상화시켜 Classification에 맞는 최적의 Feature를 찾는것이다. 

위의 사진 이미지를 여러 가지 필터로 처음 추상화시킨 것이다. 형태를 알아보기 힘들어졌다. 

위의 사진을 보면 한번더 추상화시킨 것이다. 좀 더 알아보기 힘들어졌다. 이처럼 여러 가지의 필터로 계속해서 추상화 해 나아가면서 최적의 Feature 추출을 위한 최적의 Weight값을 계산하는 것이다. 최종으로 최적의 Feature 추출을 위한 필터의 가중치 값을 계산하는것이다.

 

https://halfundecided.medium.com/%EB%94%A5%EB%9F%AC%EB%8B%9D-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-cnn-convolutional-neural-networks-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-836869f88375

쉽게 설명하면 위의 2개의 새의 사진이 있다. 새를 분류하는 가장 중요한 척도를 새의 부리라고 가정하면, 새의 부리를 찾기 위한 최적의 Weight값을 학습해 나아가는 것이라고 보면 된다. 새의 부리를 보다 쉽게 찾기 위해 새의 부리의 추출을 위해 여러 가지 필터의 최적의 Weight값을 학습해 나아가는 것이다.

 

필터의 적용

왼쪽 상단 3x3의 필터만 적용한 결과이다. 필터와 이미지의 곱의 합으로 5x5의 이미지에서 3x3의 결과로 추상화되었다.

아래 그림은 모든 곳에 필터를 적용한 결과이다. 

http://deeplearning.stanford.edu/wiki/images/6/6c/Convolution_schematic.gif

 

 

Stride

  • stride는 입력 데이터(원본 image 또는 입력 feature map)에 Filter를 적용할 때 Sliding Window가 이동하는 간격을 의미한다. 
  • 기본은 1이지만, 2를 적용하여 feature map의 크기를 대략 절반으로 줄인다.
  • stride를 크게 할수록 당연히 원본 이미지가 작아져 공간적인 feature 특성을 손실할 가능성이 높아지지만, 이것이 반드시 feature들의 손실을 의미하지는 않는다. 오히려 불필요한 특성을 제거하는 효과를 가져올 수 있을뿐더러 Convolution 연산 속도를 향상한다.

Padding

 

위의 이미지를 보면 5x5 이미지에 3x3 필터를 적용했을 때 3x3의 Feature Map이 나온다. 

 

위의 이미지는 padding을 적용했을 때이다. 결과가 원본과 같이 5x5가 나왔다. 필터를 적용하여 Conv 연산 수행 시 출력 Feature Map이 지속적으로 작아지는 것을 막기 위해 적용된다.

Pooling

위의 그림을 보면 Max Pooling은 2x2에서 가장 큰 값을 가져오고, Average는 말 그대로 평균을 내서 가져온다. MaxPooling의 경우보다 더 도드라지는 feature의 값을 가져오고 Average는 Smooth 한 feature의 값을 가져온다. 일반적으로는 Maxpooling이 도드라지는 feature를 가져오기 때문에 Classification에 유리하다. 일반적으로 Pooling 크기와 Stride를 동일하게 부여하여 모든 값이 한 번만 처리될 수 있도록 하고, 보통은 Conv -> Activation 적용 후 적용한다. 위치 변화에 따른 feature 값의 영향도를 줄여서(가장 도드라지는 feature를 추출하기 때문) 오버 피팅 감소 등의 장점을 얻을 수도 있음.

 

코드

 

from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D
from tensorflow.keras.models import Model

input = Input(shape=(28, 28, 1))
x = Conv2D(filters=4, kernel_size=3, strides=1, padding='same', activation='relu')(input)

Convolution의 Input shape는 무조건 3차원으로 주어져야 한다. 위의 같은 경우는 흑백 사진이 입력으로 주어졌을 경우이다. 컬러 같은 경우는 shape=(x, x, 3) RGB로 마지막 차원이 3개가 주어진다. 위 Conv2D는 채널의 수는 4개 3x3 필터 strides는 1, padding은 상하좌우 전부 삽입, activation은 relu로 주어진 결과이다.

x = MaxPooling2D(2)(x)

여기서 더 추상화시키기 위해 MaxPooling2D를 적용한 결과이다. 사이즈는 2x2이다.

 

이제 전체적인 Feature Extraction과 Classification을 코드로 구현해 보겠다.

 

from tensorflow.keras.layers import Dense, Flatten

input = Input(shape=(28, 28, 1))
x = Conv2D(filters=16, kernel_size=3, strides=1, padding='same', activation='relu')(input)
x = Conv2D(filters=32, kernel_size=3, activation='relu')(x)
x = MaxPooling2D(2)(x)

x = Flatten()(x)
x = Dense(50, activation='relu')(x)
output = Dense(10, activation='softmax')(x)
model = Model(inputs=input, outputs=output)
model.summary()

위의 결과에서 Output Shape을 보면 마지막 차원의 숫자가 채널(kernel)의 개수이다. 필터를 적용한 Feature map은 2차원으로 나온다. 그러므로 필터의 shape은 (kenel_size, 이전 채널 개수)이다.

 

Input에서 Conv_1을 적용한 결과

Conv_1의 필터의 개수는 16개 이므로 위와같은 그림이 나온다. 위에서 말한것처럼 마지막 차원의 숫자가 채널의 갯수 이므로 초기 흑백 그림의 shape은 (28, 28, 1)이고 채널의 갯수는 1개이다. 그리고 kernel_size는 3x3이고 이전채널의 갯수는 1이므로 필터의 shape는 (3, 3, 1)이다. 출력 결과의 채널 갯수는 16개 이므로

Param = 필터의 shape x 출력 채널의 개수 + 출력 채널의 개수(절편)

Param = 3 x 3 x 1 x 16 + 16를 해주면 Param의 개수가 160개가 나온다.

 

Conv_1에서 Conv_2를 적용한 결과

Conv_1에서 결과가 (28, 28, 16)이 나왔다. Conv_2의 padding은 default(valid)이고, strides도 default(1), kernel_size=(3x3)이다. filter의 shape은 (3, 3, 16)이고, padding이 없으므로 출력 결과의 shape은 (26, 26, 32)이다. 

Param = 3 x 3 x 16 x 32 + 32 = 4640

 

Conv_2D에서 Pooling을 적용한 결과
Pooling에서 Flatten 적용결과
classification 적용 결과

 

 

댓글