본문 바로가기
AI/DeepLearning_WIL

[DL/WIL] 2 합성곱 신경망(Convolution Neural Network, CNN)

by SolaKim 2024. 11. 19.

필터와 커널

Convolution Neural Network 에서는 Fully Connected Neural Network 와는 다르게 뉴런을 Filter 라고 부른다.
뉴런 = 필터 = 커널 모두 같은 말이라고 생각해도 된다.

Keras 에서 Filter 는 뉴런 개수를, Kernel 은 입력에 곱해지는 가중치를 의미한다.

 

합성곱 신경망에서 실제 계산은 밀집층과 동일하게 단순히 입력과 가중치를 곱하는 것이지만 2차원 형태를 유지하는 점이 다르다. 

또 입력보다 훨씬 작은 크기의 커널을 사용하고 입력 위를 (왼쪽에서 오른쪽으로, 위에서 아래로) 이동하면서 2차원 특성 맵을 만든다. 이렇게 2차원 구조를 그대로 사용하기 때문에 합성곱 신경망이 이미지 처리 분야에서 뛰어난 성능을 발휘한다.

 

케라스로 구현한 합성곱 층

from tensorflow import keras

keras.layers.Conv2D(10, kernel_size=(3, 3), activation='relu')

첫번째 매개변수는 필터 개수, 두번째는 커널의 크기. 이는 반드시 사용자가 지정해야되는 매개변수이다.
보통 커널 크기는 (3, 3)이나 (5, 5)가 권장된다.

 

패딩(Padding)과 스트라이드(Stride)

• Padding 이란 (출력의 크기를 입력의 크기와 동일하게 만들기 위해서) 마치 더 큰 입력에 합성곱을 하는 척을 하여 입력 배열의 주위를 가상의 원소로 채우는 것이다.
• 실제 입력값이 아니기 때문에 패딩은 0으로 채운다. 
• 즉 (4, 4) 크기의 입력에 0을 1개 패딩하면 (6, 6) 크기의 입력이 된다.
• 패딩의 역할은 순전히 커널이 도장(필터)를 찍을 횟수를 늘려주는 것 밖에는 없다. 실제 값은 0으로 채워져 있기 때문에 계산에 영향을 미치지는 않는다
• 입력과 특성 맵의 크기를 동일하게 만들기 위해서 입력 주위에 0으로 패딩 하는 것을 Same Padding 이라고 한다. 합성곱 신경망에서는 세임 패딩이 많이 사용된다. 즉, 입력과 특성 맵의 크기를 동일하게 만드는 경우가 많다.
• 패딩 없이 순수한 입력 배열에서만 합성곱을 하여 특성 맵을 만드는 경우를 Valid Padding 이라고 한다. 밸리드 패딩은 특성 맵의 크기가 줄어들 수 밖에 없다. 

합성곱에서는 패딩을 왜 즐겨 사용할까?
만약 패딩이 없다면 모서리에 있는 중요한 정보가 특성 맵으로 잘 전달되지 않을 가능성이 높다. 적절한 패딩은 이처럼 이미지 주변에 있는 정보를 잃어버리지 않도록 도와준다. 

• Stride 란 합성곱 연산의 이동 크기이다.
• 튜플로 이동 칸수를 지정할 수 있지만, 기본 값인 1 이외에는 잘 사용하지 않는다. 

 

풀링(Pooling)

• 풀링은 합성곱 층에서 만든 특성 맵의 가로세로 크기를 줄이는 역할을 수행한다.
• 예를 들어 (2, 2, 3)크기의 특성 맵에 풀링을 적용하면 마지막 차원인 개수를 그대로 유지하고 너비와 높이만 줄어들어 (1, 1, 3)이 된다. 

위의 그림에서는 (2, 2) 크기로 풀링을 한다. 하지만 풀링에는 가중치가 없다. 도장을 찍은 영역에서 가장 큰값을 고르거나(Max pooling), 평균값을 계산한다(Average pooling). 

• 풀링에서는 겹치지 않고 이동한다. 풀링의 크기가 (2,  2) 이면 가로세로 두 칸씩 이동한다(stride 가 2). (3, 3) 풀링이면 가로세로 세 칸씩 이동한다.(stride 가 3)

keras.layers.MaxPooling2D(2)

• MaxPooling2D의 첫 번째 매개변수로 풀링의 크기를 지정한다. 대부분 풀링의 크기는 2이다. 즉, 가로세로 크기를 절반으로 줄인다

• 많은 경우 평균 풀링보다 최대 풀링을 많이 사용한다. 평균 풀링은 특성 맵에 있는 중요한 정보를 (평균하여) 희석시킬 수 있기 때문이다.

 

합성곱 신경망의 전체 구조

• 합성곱 층은 활성화 함수로 렐루 함수를 많이 사용한다.
• 밀집층에서 Flatten 클래스를 사용하여 3차원 배열을 1차원으로 펼친다. 이 배열은 12개의 원소를 가진 1차원 배열이고 출력층의 입력이 된다.
출력층에는 3개의 뉴런을 두었다. 즉, 3개의 클래스를 분류하는 다중 분류 문제이다. 

• 컬러 이미지의 경우(너비, 높이, 깊이)로 3차원의 입력층이기 때문에 필터의 커널 크기도 3차원이 된다. => 커널 배열의 깊이는 항상 입력의 깊이와 같아야하기 때문

• 여기서 중요한 것은 입력이나 필터의 차원이 몇 개인지 상관없이 항상 출력은 하나의 값이다. 즉, 특성 맵에 있는 한 원소가 채워진다

 

합성곱 층 - 풀링 층 다음에 다시 합성곱 층이 올때는 다음 그림과 같다.

예를 들어 첫 번째 합성곱 층의 필터 개수가 5개라고 가정하여 첫번째 풀링 층을 통과한 특성 맵의 크기가 (4, 4, 5)라고 해보자.
두번째 합성곱 층에서 필터의 너비와 높이가 각각 3이라면 이 필터의 커널 크기는 (3, 3, 5)가 된다. 왜냐하면 입력의 깊이와 필터의 깊이는 같아야 하기 때문이다. 위의 그림처럼 (3 x 3 x 5 = 45 개의 가중치를 곱하고 절편을 더한) 이 합성곱의 결과는 1개의 출력을 만든다. 

두번째 합성곱 층의 필터 개수가 10개라면 만들어진 특성 맵의 크기는 (2, 2, 10)이 될 것이다. 이렇게 합성곱 신경망은 너비와 높이는 점점 줄어들고 깊이는 점점 깊어지는 것이 특징이다. 그리고 마지막에 출력층 전에 특성맵을 모두 펼쳐서 밀집층의 입력으로 사용한다.

💡 합성곱 신경망에서 필터는 이미지에 있는 어떤 특징을 찾는다고 생각할 수 있다. 처음에는 간단한 기본적인 특징(직선, 곡선 등)을 찾고 층이 깊어질수록 다양하고 구체적인 특징을 감지할 수 있도록 필터의 개수를 늘린다. 또 어떤 특징이 이미지의 어느 위치에 놓이더라도 쉽게 감지할 수 있도록 너비와 높이 차원을 점점 줄여간다.

이렇게 합성곱 층과 풀링 층은 거의 항상 함께 사용된다. 합성곱 층에서 입력의 크기를 유지하며 각 필터가 추출한 특성 맵을 출력하면 풀링 층에서 특성 맵의 가로세로를 줄인다.

 

Keras 이용해서 합성곱 신경망 만들기

model = keras.Sequential()
model.add(keras.layers.Conv2D(32, kernel_size=3, activation = 'relu', padding = 'same', input_shape=(28,28,1)))

모델의 add() 메서드를 사용해 층을 하나씩 추가할 수 있다. 
이 합성곱 층은 32개의 필터를 사용한다. 커널의 크기는 (3,3)이고 렐루 활성화 함수와 세임 패딩을 사용한다.
완전 연결 신경망에서처럼 케라스 신경망 모델의 첫 번째 층에서 입력의 차원을 지정해 주어야 한다. 

그 다음 풀링 층을 추가한다. 

model.add(keras.layers.MaxPooling2D(2))

(2,2) 풀링을 적용했기 때문에 너비와 높이가 절반으로 줄어든다. 합성곱 층에서 32개의 필터를 사용했기 때문에 이 특성 맵의 깊이는 32가 된다. 따라서 Maxpooling 을 통과한 특성 맵의 크기는 (14, 14, 32)가 된다.

두 번째 합성곱-풀링 층

model.add(keras.layers.Conv2D(64, kernel_size=3, activation='relu', padding='same'))
model.add(keras.layers.MaxPooling2D(2))

세임 패딩을 이용하여 입력의 가로 세로 크기는 줄이지 않았지만 풀링 층에서 크기를 절반으로 줄인다. 즉, 특성 맵의 크기는 (7, 7, 64)가 된다.

이제 이 3차원 특성 맵을 일렬로 펼칠 차례이다. 이렇게 하는 이유는 마지막에 10개의 뉴런을 가진 (밀집) 출력층에서 확률을 계산하기 때문이다. 여기에서는 특성 맵을 일렬로 펼쳐서 바로 출력층에 전달하지 않고 중간에 하나의 밀집 은닉층을 하나 더 둘 수 있다. 즉, Flatten 클래스 다음에 Dense 은닉층, 마지막으로 Dense 출력층의 순서대로 구성한다. 

model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation='relu')
model.add(keras.layers.Dropout(0.4))
model.add(keras.layers.Dense(10, activation='softmax'))

드롭아웃 층이 은닉층의 과대적합을 막아 성능을 조금 더 개선해줄 것이다. 위의 코드는 클래스 10개를 분류하는 다중 분류 문제이기 때문에 마지막 층의 활성화 함수는 소프트맥스를 사용한다.

자, 이제 모델 파라미터의 개수를 계산해보자.

첫 번째 합성곱 층은 32개의 필터를 가지고 있고 크기가 (3, 3), 깊이가 1이다. 또 필터마다 하나의 절편이 있다.
따라서 총 3 x 3 x 1 x 32 + 32 = 320개의 파라미터가 있다.

두 번째 합성곱 층은 64개의 필터를 사용하고 크기가 (3, 3), 깊이가 32이다. 또 필터마다 하나의 절편이 있다.
따라서 총 3 x 3 x 32 x 64 + 64 = 18,496개의 파라미터가 있다. 

Flatten 클래스에서 (7, 7 ,64) 크기의 특성 맵을 1차원 배열로 펼치면 (3136, ) 크기의 배열이 된다. 이를 100개의 뉴런과 완전히 연결해야 하므로 은닉층의 모델 파라미터 개수는 3,136 x 100 + 100 = 313,700개 이다. 마찬가지 방식으로 계산하면 마지막 출력층의 모델 파라미터 개수는 1,010개 이다. 

다음과 같은 코드를 사용해서 층의 구성을 그림으로 표현할 수 있다.

keras.utils.plot_model(model, show_shapes=True)

 

모델 컴파일과 훈련

model.compile(optimize='adam', loss='sparse_categorical_crossentropy', metrics='accuracy')

checkpoint_cb = keras.callbacks.ModelCheckpoint('best-cnn-model.h5', save_best_only=True)

early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)

history = model.fit(train_scaled, train_target, epochs=20, validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb, early_stopping_cb])

 

ModelCheckpoint는 학습 중 특정 조건을 만족할 때 가중치(weights) 또는 전체 모델을 저장하는 역할을 한다.

EarlyStopping 은 모델이 더 이상 개선된지 않는다고 판단되면, 학습을 조기 종료하는 역할을 한다. 

'AI > DeepLearning_WIL' 카테고리의 다른 글

[DL/WIL] 3 텍스트 데이터를 위한 인공 신경망  (0) 2024.11.23