- Convolution의 기초 명령어 Conv2D 예시입니다.
- 딥러닝의 일부로서가 아닌 명령어 자체 기능을 봅니다.
- 무엇을 받아서 무엇으로 바꾸는지 살펴봅니다.
1. 2D Convolution
- convolution, 또는 합성곱 연산은 CNN(Convolution Neural Network)이라는 이름으로 접하신 분이 많을테지만 image processing을 비롯한 signal processing에서 사용되어 온 연산 기법입니다.
- 다음 두 가지 특징이 있습니다.
- 인접 데이터끼리 연산 (localization)
- 동일 연산을 전체 데이터에 적용 (weight sharing)
2. Keras의 Conv2D
2.1. 기본 문법
- 공식 홈페이지에 따르면 입출력은 다음과 같습니다.
- 입력 형식 : 4차원 이상의 텐서.
data_format='channel_first'
일 때: batch_shape + (channels, rows, cols),data_format='channel_last'
일 때: batch_shape + (rows, cols, channels), - 출력 형식 : 4차원 이상의 텐서.
data_format='channel_first'
일 때: batch_shape + (filters, rows, cols),data_format='channel_last'
일 때: batch_shape + (rows, cols, filters),
- 입력 형식 : 4차원 이상의 텐서.
- 텐서를 받아 텐서를 출력합니다.
- 입력의 channel 자리가 출력의 filter 자리로 바뀝니다.
- 또한, rows와 columns는 padding, strides 등에 따라 달라질 수 있습니다.
- 텐서를 입력으로 받기 때문에 일반 이미지는 텐서로 변환하여 넣어야 합니다.
2.2. 이미지 입력
- 텐서플로와 케라스의 버전을 확인합니다.
1
2
3
4
5
6
7
8
9
10%matplotlib inline
import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import matplotlib.pyplot as plt
print(tf.__version__)
print(tf.keras.__version__)- 실행결과: tensorflow v2.3.1, tf.keras v2.4.0 입니다.
1
2'2.3.1'
'2.4.0'
- 실행결과: tensorflow v2.3.1, tf.keras v2.4.0 입니다.
- 예제 이미지를 읽어옵니다.
1
2
3
4img = plt.imread("./1-conv2d_1.jpg")
print(type(img))
print(img.shape)
plt.imshow(img)- 실행결과 : numpy array 형식, 1080 x 1080 3 channel(RGB) 이미지입니다.
1
2<class 'numpy.ndarray'>
(1080, 1080, 3)
- 실행결과 : numpy array 형식, 1080 x 1080 3 channel(RGB) 이미지입니다.
2.3. Conv2D 적용 (1) 1 filter
이미지를 텐서로 변환합니다.
1
2
3
4img_tf = tf.convert_to_tensor([img], dtype="float32")
print(type(img_tf))
print(img_tf.shape)
print(img_tf.dtype)- 실행결과 : numpy array가 EagerTensor로 변환되었습니다.
3차원을 4차원으로 만들어주기 위해 []를 씌웠습니다.
1
2
3<class 'tensorflow.python.framework.ops.EagerTensor'>
(1, 1080, 1080, 3)
<dtype: 'float32'>
- 실행결과 : numpy array가 EagerTensor로 변환되었습니다.
Convolution을 수행합니다.
1
2
3
4conv_1 = layers.Conv2D(1, 3, padding="same")(img_tf)
print(type(conv_1))
print(conv_1.shape)
print(conv_1.dtype)- 실행결과 : 1 channel EagerTensor가 출력되었습니다.
1
2
3<class 'tensorflow.python.framework.ops.EagerTensor'>
(1, 1080, 1080, 1)
<dtype: 'float32'>
- 실행결과 : 1 channel EagerTensor가 출력되었습니다.
matplotlib에서 출력하기 위해 다시 numpy로 변환합니다.
연산 범위가 0~1을 넘어갈 수 있으므로 normalize 처리를 합니다.
1
2conv_1_np = conv_1.numpy()
plt.imshow((conv_1_np[0]-conv_1_np[0].min())/(conv_1_np[0].max()-conv_1_np[0].min()), cmap="gist_gray")- 실행결과 : convolution이 적용되어 그림 모양이 바뀌었습니다.
- 실행결과 : convolution이 적용되어 그림 모양이 바뀌었습니다.
그림이 어떻게 바뀔지는 예측할 수 없습니다.
kernel_initializer
기본값이glorot_uniform
으로, 랜덤이기 때문입니다.
2.3. Conv2D 적용 (2) 1 filter x 8회
- 랜덤한 커널의 영향을 확인해 보겠습니다.
- Conv2D를 반복해서 실행하며 결과가 바뀌는지 확인합니다.
1
2
3
4
5
6
7
8
9
10fig, axes = plt.subplots(ncols=4, nrows=2, figsize=(13, 6))
axs = axes.ravel()
for i, ax in enumerate(axs):
conv_1 = layers.Conv2D(1, 3, padding="same")(img_tf)
conv_1_np = conv_1.numpy()
ax.imshow(conv_1_np[0], cmap="gist_gray")
ax.set_title(f"try {i}")
fig.tight_layout()- 실행결과 : 실행할때마다 다른 그림이 나옵니다.
- 실행결과 : 실행할때마다 다른 그림이 나옵니다.
2.3. Conv2D 적용 (3) 16 filter
- 필터의 수를 지정하면 반복된 결과물이 channel로 쌓입니다.
1
2
3
4conv_16 = layers.Conv2D(16, 3, padding="same")(img_tf)
print(type(conv_16))
print(conv_16.shape)
print(conv_16.dtype)- 실행결과 : 16 channel이 출력됩니다.
1
2
3<class 'tensorflow.python.framework.ops.EagerTensor'>
(1, 1080, 1080, 16)
<dtype: 'float32'>
- 실행결과 : 16 channel이 출력됩니다.
- 각각의 채널을 출력합니다.
1
2
3
4
5
6
7
8
9
10
11conv_16_np = conv_16.numpy()
conv_16_norm = (conv_16_np[0]-conv_16_np.min())/(conv_16_np.max()-conv_16_np.min())
fig, axes = plt.subplots(ncols=4, nrows=4, figsize=(13, 13))
axs = axes.ravel()
for i, ax in enumerate(axs):
ax.imshow(conv_16_norm[:,:,i], cmap="gist_gray")
ax.set_title(f"Channel {i}")
fig.tight_layout()- 실행결과 : 랜덤 커널 적용 결과 16개가 나왔습니다.
- 실행결과 : 랜덤 커널 적용 결과 16개가 나왔습니다.
- CNN 학습은 커널의 가중치를 목적에 맞도록 조정하는 과정입니다.