본문 바로가기

BLOG/머신러닝

[머신러닝] CNN(합성곱 신경망) 모델 만들기 (텐서플로 / 코드)

이번 글에서 텐서플로(tensorflow)를 이용하여 합성곱 층(CNN)을 만들어보도록 하겠습니다. 모델에 사용할 데이터는 텐서플로에서 제공하는 MNIST 데이터셋을 사용하도록 하겠습니다.

 

 

1. 텐서플로 import & 데이터셋 준비

먼저, tensorflow 라이브러리를 import 해준 뒤, 학습을 위한 데이터를 다운로드합니다. 

 

import tensorflow as tf
from tensorflow.keras import datasets, layers, models
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()

 

이미지 데이터는 아래 코드처럼 28 x 28 형태의 shape으로 바꾸고, 픽셀 값을 0~1 사이로 정규화를 하도록 하겠습니다.

 

train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))
train_images, test_images = train_images / 255.0, test_images / 255.0

 

2. CNN 층 만들기

 

데이터가 준비되었다면, 합성곱 층을 만들어볼텐데요, 3 x 3 필터를 갖는 3개의 CNN 층과 그 사이에  2 x 2 max pooling을 하는 층을 만들어보도록 하겠습니다. 각 CNN 층의 활성화 함수는 'relu'로 설정하겠습니다.

 

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'))

 

이와 같이 입력하면 합성곱 층이 만들어지는데요, 여기서 input_shape 값에 이미지의 픽셀 크기에 맞게 입력을 잘해주셔야 합니다.

 

한편, 모델의 구조를 출력해보면 다음과 같습니다.

 

model.summary()

#output :
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
_________________________________________________________________

 

Ouput shape 부분을 보면, 3x3 filter, 2x2 max pooling에 따라 출력되는 높이, 너비의 크기가 감소하는 것을 살펴볼 수 있습니다. 

 

 

한편, 이 구조가 끝이 아닌데요, 마지막에 Flatten 층과 Dense 층을 추가해야 합니다. Flatten 층에서는 3D 형태의 텐서를 1D 형태의 텐서로 펼치는 작업을 수행하고, Dense 층에서는 데이터를 분류하는 작업을 수행합니다. 따라서, 다음과 같이 코드를 추가로 작성해주면 됩니다.

 

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

 

위 코드를 보면 Flatten() 으로 Flatten 층을 만들어주었고, 마지막 CNN 층의 채널 수인 64를 똑같이 Dense층의 output 채널 값으로 입력해주었습니다. 이때 활성화 함수는 'relu' 함수를 사용했습니다. 마지막 층에는 10개의 클래스로 분류하기 위해 출력할 채널 값을 10으로 설정해주었고, 다중분류를 위한 'softmax' 함수를 활성화함수로 사용하였습니다.

 

 

최종 모델 구조는 다음과 같습니다.

 

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     
_________________________________________________________________
flatten (Flatten)            (None, 576)               0         
_________________________________________________________________
dense (Dense)                (None, 64)                36928     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                650       
=================================================================
Total params: 93,322
Trainable params: 93,322
Non-trainable params: 0
_________________________________________________________________

 

 

3. 학습하기

CNN 합성곱 모델이 잘 만들어졌는지 확인하기 위해 1번에서 준비한 데이터로 학습을 시켜보도록 하겠습니다. 

 

#모델 학습
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(train_images, train_labels, epochs=5)

#정확도 측정
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
print("테스트 데이터에 대한 정확도:" test_acc)


#output :
테스트 데이터에 대한 정확도: 0.9874

 

학습 결과, 테스트 데이터에 대한 정확도는 0.9874로, 적절한 모델로 학습시켰음을 확인할 수 있습니다.