컨볼루션 신경망_컴퓨터비전과 딥러닝

김민주·2025년 2월 3일

이 글은 "컴퓨터비전과 딥러닝" 책을 보고 작성되었습니다.

컨볼루션 신경망의 원리는 1980년 네오코그니트론이라는 이론으로 발표
1998년에는 수표 인식하는 실용 시스템 제작에 활용한 사례 발표
2012년 ILSVRC 대회의 자연 영상 인식에서 AlexNet이 우승을 하며 주목받게 됨
이를 계기로 컨볼루션 신경망이 중심인 딥러닝 시대로 대전환

1. 발상과 전개

발상

다층 퍼셉트론은 화소의 연결성을 쓸 수 없음
개별 화소를 보고 분류해야 함

원으로 표시 한 것들이 수용장
첫 번째 층은 대비 특징 추출, 두 번째 층은 에지 특징 추출

각 층에는 특징 맵이 여러 장 배치
특징을 계층적으로 추출하다가 recognition layer이라고 표시된 마지막 층에서 분류 수행

컨볼루션 신경망의 층은 갈수록 깊어짐

초기에는 분류 문제에 집중하다가 2014년에 물체 검출을 위한 RCNN 등장
속도와 정확도를 개선한 fast RCNN, faster RCNN, mask RCNN이 등장

2. 컨볼루션 신경망의 구조

2.1 컨볼루션층과 풀링층

컬러 영상은 3차원 구조의 텐서라 필터를 3차원으로 확장

컨볼루션층

컨볼루션층은 입력 특징 맵(feature map)에 컨볼루션을 적용해서 얻은 특정 맵 출력
입력 특징 맵은 k개 채널로 구성, 깊이가 k인 mxn맵. mxnxk 모양의 3차원 텐서
필터의 깊이는 k, 크기는 hxh(3 또는 5) 필터는 하나의 이진값을 추가로 가짐

(kh2+1)(k h_2 + 1) 개의 가중치
컨볼루션층은 보통 ReLU, ReLU의 변종을 활성함수로 사용

필터 하나가 특징 맵 하나를 생성. 출력 특징 맵은 필터의 개수에 해당하는 (k)( k' ) 깊이의 (m×n)( m' \times n' ) 맵, 즉 (m×n×k)( m'\times n'\times k')

컨볼루션 층을 만들 때 추가적으로 패딩과 스트라이드를 설정해줘야 함
맵의 경계에 필터를 대면 일부 화소가 밖으로 나가서 적용할 수 없음
경계를 제외한다면 맵의 크기는 점점 작아지기 때문에 padding이나 stride를 적용해야 함

0 패딩(Zero Padding): 경계 바깥을 0으로 채운다.
복사 패딩(Copy Padding): 경계의 값을 복사해서 바깥을 채운다.

채널 0:0×1+0×(1)+0×0+0×1+2×(1)+2×0+0×(1)+0×1+0×0채널 1:0×0+0×0+0×0+0×(1)+1×1+0×1+0×1+1×0+2×(1)채널 2:0×(1)+0×1+0×(1)+0×1+0×1+0×1+2×0+2×(1)출력:(채널 결과)+1=4\begin{aligned} &\text{채널 0}: \quad 0 \times 1 + 0 \times (-1) + 0 \times 0 + 0 \times 1 + 2 \times (-1) + 2 \times 0 + 0 \times (-1) + 0 \times 1 + 0 \times 0 \\[5pt] &\text{채널 1}: \quad 0 \times 0 + 0 \times 0 + 0 \times 0 + 0 \times (-1) + 1 \times 1 + 0 \times 1 + 0 \times 1 + 1 \times 0 + 2 \times (-1) \\[5pt] &\text{채널 2}: \quad 0 \times (-1) + 0 \times 1 + 0 \times (-1) + 0 \times 1 + 0 \times 1 + 0 \times 1 + 2 \times 0 + 2 \times (-1) \\[10pt] &\text{출력}: \quad \sum \text{(채널 결과)} + 1 = -4 \end{aligned}

컨볼루션 층에서는 k'개의 h×h×kh \times h \times k 필터가 있어서 가중치는 k(kh2+1)k'(kh_2 + 1)
바이어스 노드 때문에 1 더함

풀링층

컨볼루션층 뒤에 풀링층이 따름

보폭을 2로 설정하면 1개 화소를 건너 필터를 적용하므로 feature map은 반으로 줄어듦

2.2 빌딩블록을 쌓아 만드는 컨볼루션 신경망

블록쌓기

특징 맵의 크기 m×nm \times n은 컨볼루션층과 풀링층의 보폭에 따라 바뀜
깊이 kk인 컨볼루션 층에서는 필터 개수에 따라 바뀌지만, 풀링층에서는 그대로 유지

Flatten연산을 통해 1차원 구조로 변환하여 완전연결층에 입력

LeNet-5 사례

C-P-C-P-C-FC-FC 구조로 되어 있음
가중치는 컨볼루션 층과 완전연결층에만 있음

유연한 구조

컨볼루션층과 풀링층, 완전연결층을 쌓아 만드는 특징으로
데이터에 따라 풀어야하는 문제에 따라 다양한 모양으로 조립할 수 있음

플링층은 모두 제거하고 컨볼루션층만 쌓아서 비슷한 정확도를 낸 연구 결과가 있음
이 신경망은 풀링층 없애는 대신 보폭을 늘림

3. 컨볼루션 신경망의 학습

역전파 알고리즘 사용

3.1 컨볼루션 신경망을 위한 역전파 알고리즘

  1. 전방 계산에서 컨볼루션층과 풀링층, 완전연결층을 거쳐 출력 벡터 oo를 출력
  2. 손실 함수를 통해 oo와 참값 벡터 yy의 오류 계산
  3. 역전파 과정에서 오류를 줄이는 방향

학습 대상이 되는 가중치를 빨간색으로 표시

특징 학습과 통째 학습

주어진 데이터 셋에 최적인 필터를 찾아냄
특징 학습을 한다고 표현
이 특징 학습을 다른 관점에서 보면 통째 학습

컨볼루션 신경망이 우수한 이유

  1. 데이터의 원래 구조를 유지. 다층 퍼셉트론은 1차원으로 변환하여 입력하는 반면에 컨볼루션 신경망은 3차원 구조를 그대로 입력
  2. 특징 학습을 통해 최적의 특징을 추출
  3. 신경망의 깊이를 깊게 할 수 있음

4. 컨볼루션 신경망 구현

LeNet-5로 MNIST 인식

import numpy as np
import tensorflow as tf
import tensorflow.keras.datasets as ds

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dropout, Dense
from tensorflow.keras.optimizers import Adam

# 데이터 불러오기 및 전처리
(x_train, y_train), (x_test, y_test) = ds.mnist.load_data()
x_train = x_train.reshape(60000, 28, 28, 1)
x_test = x_test.reshape(10000, 28, 28, 1)

x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0

y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)

# 모델 구성
cnn = Sequential()

cnn.add(Conv2D(6, (5, 5), padding='same', activation='relu', input_shape=(28, 28, 1)))
cnn.add(MaxPooling2D(pool_size=(2, 2), strides=2)) # 풀링층 추가

cnn.add(Conv2D(16, (5, 5), padding='valid', activation='relu')) # 두 번째 풀링층 추가
cnn.add(MaxPooling2D(pool_size=(2, 2), strides=2)) # 최대 풀링 추가

cnn.add(Conv2D(120, (5, 5), padding='valid', activation='relu')) # 세 번째 컨볼루션층 추가

cnn.add(Flatten()) # 1차원 구조로 변환하여 완전연결층에 입력

cnn.add(Dense(units=84, activation='relu'))
cnn.add(Dense(units=10, activation='softmax'))

# 모델 컴파일
cnn.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['accuracy'])

# 모델 학습
cnn.fit(x_train, y_train, batch_size=128, epochs=30, validation_data=(x_test, y_test), verbose=2)

# 모델 평가
res = cnn.evaluate(x_test, y_test, verbose=0)
print("정확률:", res[1] * 100)

컨볼루션 신경망으로 자연 영상 인식하기

import numpy as np
import tensorflow as tf
import tensorflow.keras.datasets as ds

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt

# 데이터 로드 및 전처리
(x_train, y_train), (x_test, y_test) = ds.cifar10.load_data()
x_train = x_train.astype(np.float32) / 255.0
x_test = x_test.astype(np.float32) / 255.0

y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)

# CNN 모델 생성
cnn = Sequential()

cnn.add(Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) # 컨볼루션 층
cnn.add(Conv2D(32, (3, 3), activation='relu')) # 컨볼루션층
cnn.add(MaxPooling2D(pool_size=(2, 2))) # 풀링층
cnn.add(Dropout(0.25)) # 드롭아웃 층

# C-C-P-D 구조

cnn.add(Conv2D(64, (3, 3), activation='relu'))
cnn.add(Conv2D(64, (3, 3), activation='relu'))
cnn.add(MaxPooling2D(pool_size=(2, 2)))
cnn.add(Dropout(0.25))

# C-C-P-D 구조 추가

cnn.add(Flatten()) # 특징 맵 펼침
cnn.add(Dense(units=512, activation='relu'))
cnn.add(Dropout(0.5))
cnn.add(Dense(units=10, activation='softmax'))

#C-C-P-D-C-C-P-D-FC-D-FC 구조 완성

# 모델 컴파일
cnn.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['accuracy'])

# 모델 학습
hist = cnn.fit(x_train, y_train, batch_size=128, epochs=100, validation_data=(x_test, y_test), verbose=2)

# 모델 평가
res = cnn.evaluate(x_test, y_test, verbose=0)
print('정확률 =', res[1] * 100)

# 정확도 시각화
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy graph')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'])
plt.grid()
plt.show()

# 손실값 시각화
plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss graph')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'])
plt.grid()
plt.show()

modles 모듈: Sequential과 Functional API

모델 생성할 때 사용하는 모듈
보통 Sequential 모델이면 충분하지만, 여러 갈래로 나뉠 수 있는 Functional API 모델도 사용 가능

model=SequentialO
model-add(Conv2D(32,3,3), input_shape(32,32,3))
model-add(Conv2D(64,3,3))
model-add(FlattenO)
model-add(Dense(10,activation='softmax')

sequential 클래스로 C-C-FC 구조의 신경망 만듦
이 신경망에서는 텐서 중간에 접근하기 어려움
사실 중간에 접근할 필요가 대부분은 없음

특수한 경우에 사용하는 것이 Functional API

input=Input(shape=(32,32,3))
x1=Conv2D(32,3,3) (input)
x2=Conv2D(64,3,3)(x1)
x3=Flatten((x2)
output=Dense(10,activation='softmax')(x3)
mode l-Model(input,output)

중간 텐서가 변수로 노출됨으로 쉽게 접근할 수 있음

profile
mingdue02

1개의 댓글

comment-user-thumbnail
2025년 2월 3일

👍👍👍

답글 달기