※ 본 게시물에 사용된 내용은 대다수 <실전! 텐서플로2를 활용한 딥러닝 컴퓨터 비전>에서 사용된 자료이며, 일부 자료는 추가 수정한 부분도 존재합니다.
합성곱 신경망(Convolutional Neural Network)의 발견
CNN : 다차원 데이터를 위한 신경망
자세한 개념은 다음 포스팅
본 챕터에서는 CNN의 기초적인 동작부터 간단한 CNN모델까지 구현해보는 실습을 진행한다.
자세한 개념은 상위 포스팅에서 다루니 바로 예제 코드를 리뷰해본다.
이미지 로딩
초반에 텐서플로로 이미지를 로딩하는 방법부터 배워보자. 이때 필요한 라이브러리는 scikit-image내 io모듈을 참고한다.
(opencv를 설치하여, cv2.imread 함수로 이미지를 로딩하는 방법도 많이 사용한다.)
%matplotlib inline
# !pip install scikit-image # 설치할려면 주석 해제
# !pip install matplotlib # 설치할려면 주석 해제
import tensorflow as tf
import matplotlib
from matplotlib import pyplot as plt
from skimage import io # 이미지 로딩을 위함
io모듈의 imread함수로 이미지를 불러오면 다음과 같이 실제 이미지가 로딩되는 것을 볼 수 있다.
image = io.imread("./res/bird_pic_by_benjamin_planche.png")
print("Image shape: {}".format(image.shape))
plt.imshow(image, cmap=plt.cm.gray)
로딩된 이미지의 사양은 680x608사이즈의 흑백 이미지로 이 이미지를 Tensorflow에 적용시키 위해 Tensor형태로 변환해준다. 대다수의 데이터 로딩 방식 상, batch size를 설정하여 (BatchSize, Height, Width, Channel) 형태로 데이터를 로딩하므로, 여기서도 tensor feature의 dimension을 하나 늘려주도록 한다.
image = tf.convert_to_tensor(image, tf.float32, name="input_image")
image = tf.expand_dims(image, axis=0) # we expand our tensor, adding a dimension at position 0
추가로, 이미지의 채널 수(RGB)에 따라 마지막 텐서의 크기를 조절해줘야 하는데, 본 예제는 흑백 이미지 이므로 제일 마지막 channel의 개수를 1로 설정한다.
image = tf.expand_dims(image, axis=-1) # we expand our tensor, adding a dimension at position 0
print("Tensor shape: {}".format(image.shape))
Convolution
컨볼루션의 기본 개념은 앞에서 이미 보고 왔다 가정하도록 한다. Tensorflow 내 이미지 컨볼루션을 적용하는 기본적인 방법으로는 tf.nn.conv2d()를 적용하면 된다. 총 2가지 예제를 통해 몇가지 필터를 적용한 Convolution 과정을 확인해보자.
첫번째 예제는 이미지에 블러 처리를 진행하는 예제로, kernel값으로는 가우시안 블러로 잘 알려진 값을 적용한다.
# 가우시안 필터로 알려진 값을 정의
kernel = tf.constant([[1 / 16, 2 / 16, 1 / 16],
[2 / 16, 4 / 16, 2 / 16],
[1 / 16, 2 / 16, 1 / 16]], tf.float32, name="gaussian_kernel")
#N개의 필터가 쌓여서 형상이 $(k_H, k_W, D, N)$인 텐서가 된다.
kernel = tf.expand_dims(tf.expand_dims(kernel, axis=-1), axis=-1)
이제 tf.nn.Conv2d를 호출하고 필요한 매개변수를 입력한다.
tf.nn.Conv2d()
- input : 형상이 $(B, H, W, D)$인 입력 이미지의 배치. B는 배치 크기
- filter : N개의 필터가 쌓여 형상이 $(k_H, k_W, D, N)$인 텐서가 됨
- stride: 배치로 나눈 입력의 각 차원에 대한 보폭을 나타내는 4개의 정수 리스트. $[1,s_H, s_W, 1]$가 default값
- padding : 배치로 나눈 입력데이터의 각 차원 전후에 붙이는 padding을 나타냄. (4x2)개의 정수 리스트나 사전 정의된 패딩 중 무엇을 사용할지 정의함(VALID or SAME)
- VALID : 이미지에 padding을 더하지 않음.
- SAME : 합성곱 출력이 보폭이 1인 입력과 동일한 높이, 너비를 갖는 p를 계산
- name : 이 연산을 식별하는 이름(분명하고 가독성이 높은 그래프 생성시 유용)
blurred_image = tf.nn.conv2d(image, kernel, strides=[1, 1, 1, 1], padding="SAME")
블러 처리가 완료된 이미지를 확인해보면 다음과 같다. 새의 깃털이나 주변 배경이 약간 흐릿한 걸로 봤을 때 블러처리가 정상적으로 적용된것을 확인할 수 있다.
blurred_res = blurred_image.numpy()
# We "unbatch" our result by selecting the first (and only) image; we also remove the depth dimension:
blurred_res = blurred_res[0, ..., 0]
plt.imshow(blurred_res, cmap=plt.cm.gray)
블러처리 외에 윤곽처리 예제를 통해 더 극명한 결과물을 확인해보자.
앞에서와 동일하게 테두리/윤곽선 추출로 잘 알려진 필터 값을 정의해주고 확인해보자.
kernel = tf.constant([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]], tf.float32, name="edge_kernel")
kernel = tf.expand_dims(tf.expand_dims(kernel, axis=-1), axis=-1)
edge_image = tf.nn.conv2d(image, kernel, strides=[1, 2, 2, 1], padding="SAME")
edge_res = edge_image.numpy()[0, ..., 0]
plt.imshow(edge_res, cmap=plt.cm.gray)
자세히 보면 이미지의 윤곽에 흰색 테두리가 보이는데, 이는 커널필터에 의해 윤곽으로 감지된 zero padding(Padding값을 SAME으로 설정했기 때문에)으로 인해 발생하였다. 실제로 image에 pad를 채우지 않으면(아래 예제)
edge_image = tf.nn.conv2d(image, kernel, strides=[1, 2, 2, 1], padding="VALID")
edge_res = edge_image.numpy()[0, ..., 0]
plt.imshow(edge_res, cmap=plt.cm.gray)
Pooling
kernel을 통해 실제 이미지를 처리하는 convolution과정을 확인해봤으므로, 다음으로 pooling을 예제로 확인해보자.
pooling의 개념은 상단 포스팅에서 확인한다 가정하고 진행하였다.
Tensorflow에서 pooling과정은 tf.nn.avg_pool/tf.nn.max_pool을 통해 실행해볼 수 있다.
# Average Pooling
avg_pooled_image = tf.nn.avg_pool(image, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
avg_res = avg_pooled_image.numpy()[0, ..., 0]
plt.imshow(avg_res, cmap=plt.cm.gray)
# Max Pooling
max_pooled_image = tf.nn.max_pool(image, ksize=[1, 10, 10, 1], strides=[1, 2, 2, 1], padding="SAME")
max_res = max_pooled_image.numpy()[0, ..., 0]
plt.imshow(max_res, cmap=plt.cm.gray)
좌측이 실제 average pooling을 적용한 이미지이다. 원본과 큰 차이가 없다 생각할 수 있지만 실제 이미지의 dimension을 확인해보면 두 pooling image 모두 원본의 절반 크기로 줄어있는 것을 확인할 수 있다. maxpooling은 픽셀에서 가장 높은 값만을 추출하기 때문에 원본과 비교하면 확연한 차이가 있는 것을 확인할 수 있다.
'머신러닝 > Computer Vision' 카테고리의 다른 글
[OpenCV] Histogram, Normalize (0) | 2021.11.09 |
---|---|
Tensor to image / numpy array to image / PIL image save (Save feature as image) (0) | 2021.10.29 |
[Computer Vision 기초] 2. 텐서플로 기초와 모델 훈련 (0) | 2021.07.14 |
[Computer Vision 기초] 1.컴퓨터 비전과 신경망 (0) | 2021.06.28 |
[Computer Vision 기초] 0.Introduction (0) | 2021.06.28 |