CNN 개념
⚠️ 해당 내용은 멋쟁이사자처럼 AI School 오늘코드 박조은 강사의 자료를 토대로 정리한 내용입니다.
12/05 : CNN 개념
CNN(합성곱 신경망)
💡주 핵심 내용 : 합성곱 층 만들기
아래 6줄의 코드에서 Conv2D와 MaxPooling2D 층을 쌓는 일반적인 패턴으로 합성곱 층을 정의한다.
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
CNN은 배치(batch) 크기를 제외하고 (이미지 높이, 이미지 너비, 컬러 채널) 크기의 텐서(tensor)를 입력으로 받는다. MNIST 데이터는 (흑백 이미지이기 때문에) 컬러 채널(channel)이 하나지만 컬러 이미지는 (R,G,B) 세 개의 채널을 가진다. 이 예에서는 MNIST 이미지 포맷인 (28, 28, 1) 크기의 입력을 처리하는 CNN을 정의한다. 이 값을 첫 번째 층의 input_shape
매개변수로 전달하게 된다.
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 3, 3, 64) 36928
=================================================================
Total params: 55,744
Trainable params: 55,744
Non-trainable params: 0
_________________________________________________________________
위에서 Conv2D와 MaxPooling2D 층의 출력은 (높이, 너비, 채널) 크기의 3D 텐서이다. 높이와 너비 차원은 네트워크가 깊어질수록 감소하는 경향을 가진다(Shape가 줄어들고 있다). Conv2D 층에서 출력 채널의 수는 첫 번째 매개변수에 의해 결정된다(예를 들면, 32 또는 64). 일반적으로 높이와 너비가 줄어듦에 따라 (계산 비용 측면에서) Conv2D 층의 출력 채널을 늘릴 수 있다.
❗ 합성곱 신경망(Convolutional Neural Network, CNN) 의 핵심 키워드!
Conv, Pooling(Max), CNN + DNN
Tensorflow import
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
MNIST 데이터셋 다운로드하고 준비하기
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()
# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0
데이터 확인하기
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog', 'horse', 'ship', 'truck']
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i])
# The CIFAR labels happen to be arrays,
# which is why you need the extra index
plt.xlabel(class_names[train_labels[i][0]])
plt.show()
합성곱 층 만들기
model = models.Sequential()
model.add(layers.Conv2D(filters = 32, kernel_size = (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D(pool_size = (2, 2)))
model.add(layers.Conv2D(filters = 64, kernel_size = (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(pool_size = (2, 2)))
model.add(layers.Conv2D(filters = 64, kernel_size = (3, 3), activation='relu'))
맨 위에 작성한 코드와 파라미터가 조금 다를 수 있다. 이는 파라미터의 입력을 생략해도 되지만, 처음에 어떤 파라미터를 지정하는지를 파악하기 위해서 작성을 해놓았다.
CNN의 작동 방법
🤔 합성곱 신경망의 별명은 피처 자동 추출기이다. 그러면 어떻게 피처를 자동으로 추출하는가?
필터(filters)를 랜덤하게 여러 장 만들고 각 필터의 사이즈는 kernel_size로 정하게 된다. 필터를 이미지에 통과시켜서 합성곱 연산을 하여 결과가 나오면 그 결과로 특징을 추출한다. 필터를 랜덤하게 만들다 보면 1자 모양도 있을 수 있고 / 모양도 있을 수 있고 O, ㅁ 등 여러 패턴을 랜덤하게 만들 수 있다. 그리고 그 패턴을 통과시켜서 그 패턴이 얼마나 있는지 확인해 볼 수 있게 된다. 이런 패턴을 여러 장 만든다 => filters => 각 필터의 사이즈 kernel_size라 부른다.
🤔 패딩의 기능?
이미지가 줄어드는 것을 방지하기 위해 사용하기도 하지만 가장자리 모서리 부분의 특징을 좀 더 학습할 수 있다.
Padding을 1로 Kernel Size를 3x3 으로 사용하면 입력과 출력값이 같아지게 된다.
해당 CNN의 필터는 10개(Red, Green, Blue에서 초기에 10개의 슬롯으로 나눠짐)이다.
그리고 해당 Convloution에서는 Kernel size가 3*3임을 확인할 수 있다. Kernel Size를 확인하는 법은가운데의 Kernel 계산 블럭을 확인하거나 (64, 64) => (62, 62) 된걸로도 유추 가능가 가능하다(64 - 62 + 1 + padding). Convolution layer를 통과한 결과 10개의 피처를 ‘Feature map(피처맵)’이라고 부른다.
🤔 Feature map을 만드는 이유?
Convolution filter크기만큼의 피처맵을 생성하기 때문에 입력 데이터의 지역 특성을 학습한다. 또한, Convolution filter의 가중치를 공유하기 때문에 학습된 특징이 나타나면 위치에 상관없이 인식한다. (학습된 특징에 대한 패턴을 매칭하는 것)
전체적인 맵의 층의 shape를 보면 3개로 되어있는 모습을 확인할 수 있다. 이는 3차원 데이터가 아닌, (height, width, filters)를 나타내는 것이다.
위 그림 처럼 활성화 함수(activation function)를 통과한 것을 ‘Activation map(액티베이션맵)’이라고 부른다.
Pooling
합성곱층에서 받은 최종 출력 데이터(Activation Map)의 크기를 줄이거나 특정 데이터를 강조한다. 데이터의 사이즈를 줄여주며 노이즈를 상쇄시키고, 미세한 부분에서 일관적인 특징을 제공한다. 이미지 크기를 줄여 계산을 효율적으로 하고 데이터를 압축하는 효과가 있고 이미지를 추상화해주기 때문에 과도한 학습을 방지하며 오버피팅을 방지해 주기도 한다. 대체적으로 컬러이미지에서는 MaxPooling 을 가장 많이 사용하는 편이며, 흑백이미지에서는 MinPooling을 사용하기도 한다. MaxPooling 은 가장 큰 값을 반환, AveragePooling 은 평균 값 반환, MinPooling 은 최솟값 반환한다.
종합 및 정리
- Convolution 연산을 하면 필터(filters, kernel_size에 해당하는 filters 개수만큼)를 통과시켜서 filters 개수만큼 피처맵(Feature map)을 생성한다. CNN의 별명은 ‘피처자동추출기’ 이다. 비정형 이미지를 입력했을 때 이미지를 전처리 하지 않고 그대로 넣어주게 되면 알아서 피처맵을 생성하게 된다. 피처맵은 피처가 어떤 특징을 갖고 있는지를 나타낸다. 선이 있는지, ), O, 1 등 다양한 모양을 랜덤하게 생성해서 통과 시키면 해당 특징이 있는지를 학습하게 하는게 Convolution 연산이다.
- 피처맵 Output에 Activation Function(활성화함수)을 통과시켜서 액티베이션맵을 생성한다. relu 등을 사용하게 되면 출력값에 활성화 함수를 적용한 액티베이션맵을 반환한다.
- Pooling 에는 Max, Average, Min 등 여러 방법이 있는데, 보통 MaxPooling 을 주로 사용한다. 흑백이미지에서는 MinPooling을 사용한다. MaxPooling 은 가장 큰 값을 반환, AveragePooling 은 평균 값 반환, MinPooling 은 최솟값 반환한다. Pooling은 이미지 크기를 줄여 계산을 효율적으로 하고 데이터를 압축하는 효과가 있기 때문에 오버피팅을 방지해줄 수 있다. 이미지를 추상화 해주기 때문에 너무 자세히 학습하지 않도록해서 오버피팅이 방지되게 된다.
- CNN 층을 얼마나 깊게 쌓는지에 대한 논문들이 존재한다. VGG16, VGG19 등은 층을 16개, 19개 만큼 깊게 만든 것을 의미한다. 30~50층까지 쌓기도 하고 100층 정도 쌓기도 하며, 층의 수를 모델의 이름에 붙이기도 한다. 이게 가능한 이유는 과거에 비해 GPU등의 연산을 더 많이 지원하기 때문에 연산이 빨라진 덕분이다.
- TF API 는 다음의 방법으로 사용한다.
model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
- Padding, Stride 등을 사용해서 입력과 출력사이즈를 조정한다든지, Stride는 필터의 이동 보폭을 조정할 수 있다.
🤔 모델에 패딩을 적용해주는 파라미터 코드는 padding="same"
이다. 그러면 padding 해주면 어떤 효과가 있을까?
이미지가 줄어드는 것을 방지하며, 가장자리 데이터를 더 학습하며 가로 세로 길이를 늘리거나 유지시켜준다.
🤔 DNN을 이미지 데이터에 사용했을 때 어떤 단점이 있을까?
flatten()
으로 1차원 벡터 형태로 주입을 해야 하기 때문에 인접 공간에 대한 정보를 잃어버리게 된다.- 1차원 형태로 주입을 해주게 되면 입력값이 커서 계산이 오래 걸린다.
- Conv과 Pooling 연산을 하게 되면 데이터의 공간적인 특징을 학습하여 어떤 패턴이 있는지를 알게 되며, Pooling을 통해 데이터를 압축하면 데이터의 용량이 줄어들며, 추상화를 하기 때문에 오버피팅을 방지해준다.