합성곱 신경망(Convolutional Neural Network, CNN)
합성곱 : 곱한자료를 더하여 한 개의 값으로 만듦
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
import numpy as np
# 데이터셋 다운로드
(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
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170500096/170498071 [==============================] - 587s 3us/step 170508288/170498071 [==============================] - 587s 3us/step
train_labels
array([[6], [9], [9], ..., [9], [1], [1]], dtype=uint8)
np.shape(train_images), np.shape(train_labels), np.shape(test_images), np.shape(test_labels)
((50000, 32, 32, 3), (50000, 1), (10000, 32, 32, 3), (10000, 1))
훈련과 테스트 데이터의 수 및 32x32 사이즈와 컬러이미지가 동일함을 반드시 확인해야함.
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()
# conv2d는 반드시 input_shape의 개수가 3이어야 함. | r,g,b 별로 다른 필터를 생성하기 때문
# 흑백이미지 일때는 32,32,1 이라고 적어야 함.
# 필터 처리하는 부분
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) # 필터가 3*3사이즈이며, rgb필터 3개가 있음 | ((3*3*3)+1) * 32 = 896의 파라미터
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'))
Maxpooling2D
-
pool_size = (2,2) : 2*2 커널(필터) 크기
-
strides = None : 2칸 건너가기(겹치게 하지 않음) strides가 1이면 1칸씩 겹침
-
padding= ‘valid’ : 감싸지 않음
즉, 사이즈를 줄이는 합성곱이다. 하드웨어 자원이 좋은 최근은 굳이 사이즈를 줄이면서 갈 필요가 없어서 잘 사용하지 않는다.
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 30, 30, 32) 896 max_pooling2d (MaxPooling2D (None, 15, 15, 32) 0 ) conv2d_1 (Conv2D) (None, 13, 13, 64) 18496 max_pooling2d_1 (MaxPooling (None, 6, 6, 64) 0 2D) conv2d_2 (Conv2D) (None, 4, 4, 64) 36928 ================================================================= Total params: 56,320 Trainable params: 56,320 Non-trainable params: 0 _________________________________________________________________
conv2D 레이어의 파라미터 수 계산
첫 번째 Conv2D 레이어:
-
입력 채널 수: 3 (input_shape=(32, 32, 3)에서 마지막 차원) x변수가 r,g,b라는 의미 -
커널 수: 32
-
커널 크기: (3, 3)
-
활성화 함수: relu
-
파라미터 개수 계산:
-
커널당 파라미터 개수: (입력 채널 수 * 커널 크기)+1 = (3 * 3 * 3 )+1 = 28
-
전체 파라미터 개수: 커널당 파라미터 개수 * 커널 수 = 28 * 32 = 896
-
두 번째 Conv2D 레이어:
-
입력 채널 수: 이전 레이어의 커널 수인 32
-
커널 수: 64
-
커널 크기: (3, 3)
-
활성화 함수: relu
-
파라미터 개수 계산:
-
커널당 파라미터 개수: (입력 채널 수 * 커널 크기)+1 = (32 * 3*3) + 1 = 289
-
전체 파라미터 개수: 커널당 파라미터 개수 * 커널 수 = 289 * 64 = 18496
-
세 번째 Conv2D 레이어:
-
입력 채널 수: 이전 레이어의 커널 수인 64
-
커널 수: 64
-
커널 크기: (3, 3)
-
활성화 함수: relu
-
파라미터 개수 계산:
-
커널당 파라미터 개수: (입력 채널 수 * 커널 크기)+1 = (64 * 3*3) + 1 = 577
-
전체 파라미터 개수: 커널당 파라미터 개수 * 커널 수 = 577 * 64 = 36928
-
# 1차원 신경망에서 공부했던 dense 부분
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 30, 30, 32) 896 max_pooling2d (MaxPooling2D (None, 15, 15, 32) 0 ) conv2d_1 (Conv2D) (None, 13, 13, 64) 18496 max_pooling2d_1 (MaxPooling (None, 6, 6, 64) 0 2D) conv2d_2 (Conv2D) (None, 4, 4, 64) 36928 flatten (Flatten) (None, 1024) 0 dense (Dense) (None, 64) 65600 dense_1 (Dense) (None, 10) 650 ================================================================= Total params: 122,570 Trainable params: 122,570 Non-trainable params: 0 _________________________________________________________________
컨볼루션 레이어의 출력텐서 높이, 출력너비 크기
$O = (\frac{I-K+2P}{S}) +1$
-
$O$ : 출력 이미지의 크기
-
$I$ : 입력 이미지의 크기
-
$K$ : conv레이어에서 사용하는 커널의 크기(곱한 값이 가로 세로 각각)
-
$N$ : 커널 수
-
$S$ : 컨볼루션 연산의 스트라이드
-
$P$ : 패딩 사이즈
-
첫번째 레이어 : ((32 - 3 +2*0)/1) +1 = 30
-
두번째 레이어 : maxpoolign2d 는 절반(반내림)으로 이미지 사이즈를 줄인다.(pool_size를 지정하지 않는다면) = 15
-
세번째 레이어 : ((15 - 3 +2*0)/1) +1 = 13
-
네번째 레이어 : 6
-
다섯번째 레이어 : ((6 -3 + 2*0)/1) +1 = 4
-
여섯번째 레이어 : flatten은 1차원 배열로 높이,넓이,채널수를 곱한 값이다. = 1024
fit, compile
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy']) # model에서 원핫인코딩을 처리해주는 sparcecategoricalcorssentropy
history = model.fit(train_images, train_labels, epochs=10,
validation_data=(test_images, test_labels))
Epoch 1/10
c:\devtools\Miniconda3\envs\gpu\lib\site-packages\tensorflow\python\util\dispatch.py:1082: UserWarning: "`sparse_categorical_crossentropy` received `from_logits=True`, but the `output` argument was produced by a sigmoid or softmax activation and thus does not represent logits. Was this intended?" return dispatch_target(*args, **kwargs)
1563/1563 [==============================] - 12s 4ms/step - loss: 1.5446 - accuracy: 0.4375 - val_loss: 1.2451 - val_accuracy: 0.5507 Epoch 2/10 1563/1563 [==============================] - 6s 4ms/step - loss: 1.1639 - accuracy: 0.5877 - val_loss: 1.0682 - val_accuracy: 0.6223 Epoch 3/10 1563/1563 [==============================] - 5s 3ms/step - loss: 1.0157 - accuracy: 0.6440 - val_loss: 1.0435 - val_accuracy: 0.6350 Epoch 4/10 1563/1563 [==============================] - 5s 3ms/step - loss: 0.9280 - accuracy: 0.6757 - val_loss: 1.0041 - val_accuracy: 0.6590 Epoch 5/10 1563/1563 [==============================] - 5s 3ms/step - loss: 0.8512 - accuracy: 0.7038 - val_loss: 0.9263 - val_accuracy: 0.6783 Epoch 6/10 1563/1563 [==============================] - 5s 3ms/step - loss: 0.7950 - accuracy: 0.7207 - val_loss: 0.9054 - val_accuracy: 0.6895 Epoch 7/10 1563/1563 [==============================] - 5s 3ms/step - loss: 0.7459 - accuracy: 0.7402 - val_loss: 0.8709 - val_accuracy: 0.7016 Epoch 8/10 1563/1563 [==============================] - 5s 3ms/step - loss: 0.6981 - accuracy: 0.7560 - val_loss: 0.9180 - val_accuracy: 0.6853 Epoch 9/10 1563/1563 [==============================] - 6s 4ms/step - loss: 0.6576 - accuracy: 0.7702 - val_loss: 0.8590 - val_accuracy: 0.7122 Epoch 10/10 1563/1563 [==============================] - 6s 4ms/step - loss: 0.6209 - accuracy: 0.7809 - val_loss: 0.8630 - val_accuracy: 0.7119
# 모델 검증
plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
313/313 - 0s - loss: 0.8630 - accuracy: 0.7119 - 495ms/epoch - 2ms/step
2 에포크 이후로 과적합 됌
print(test_acc)
0.711899995803833
댓글남기기