머신러닝

CNN 필터링 스트라이딩 풀링 코드 연습

coding art 2021. 7. 9. 21:19
728x90

TensorFlow를 사용하여 CNNMNIST 수기 숫자 인식 문제를 다루어 보기 위한 준비 단계로서 아래 그림에서처럼 흑백 명암 픽셀로 구성된 단순 수치 이미지를 대상으로 CNN 코드 작성 연습을 해 보도록 한다. 이 코드 작성 연습은 TensorFlow 가 설치되어 있는 아나콘다의 쥬피터 또는 구글 Colab을 사용하도록 하자. Colab 사용 시에는 별도로 파이선 라이브러리들을 설치할 필요가 없다.

 

다음의 간단한 연습 코드는 명암 변화가 있는 3X3 격자형 이미지를 준비하자. TensorFlow의 그라프를 생성할 필요가 없으므로 직접 session 명령을 사용하기로 한다. 명암 변화가 있는 격자형 이미지를 numpy 배열 형태로 입력 후 shape 값을 출력해 보자.

다음 코드를 참조하면서, 2X2 convolutional filter의 웨이트 값을 모두 1.0으로 상수 값을 부여하자. shape을 출력해 보면 (2, 2, 1, 1)이 출력되는데 파라메타들의 정의가 어떻게 되는지 판단해 보자. 추측 컨데 2X2, 필터 수 1, 사용 컬러 수 1개 아닌가 한다.

 

TensorFlow가 지원하는 tf.conv2d() 명령을 사용하여 convolution fitering 작업을 실행한다. 이 명령 실행에 필요한 데이터는 이미지 데이터 image, 필터의 weight, 필터의 스트라이드 정보, padding 정보로 구성된다. 3X3 이미지에 2X2 필터인 경우 스트라이딩해 보면 경계선에서 딱 맞아 떨어지므로 별도로 padding을 해 줄 필요가 없다. padding은 이미지 외곽을 따라서 각 격자에 0.0을 채워 넣은 후 스트라이드 작업을 하게 되면 원래 convolutional filtering 처리 전의 이미지 크기와 처리 후 이미지 크기가 같아지게 된다. 지금은 스트라이드 작업 처리 후 원래의 얻고자 하므로 tf.conv2d() 명령의 파라메터를 ’VALID‘ 로 설정한다. 반대로 3X3 이미지에서 3X3 이미지를 얻으려면 tf.conv2d() 명령의 파라메터를‘SAME“ 으로 처리하면 된다.

 

전체를 스트라이드하여 필터링 작업이 완료되면 매트릭스 값이 3, 4, 6, 7 로 얻어지며 위에서처럼 4개의 셀에 명암으로 표현이 가능하다. 이 문제는 원래 이미지가 1, 2, 3,..., 8, 9 로서 특별한 기학학적 정보를 포함하지 않으므로 필터링 된 결과에 특별한 의미를 부여할 필요는 없다. 그 다음은 동일한 필터를 사용하되 padding 조건을 ‘SAME’으로 두고 처리하면 다음과 같이 원래 크기의 이미지가 얻어진다.

아울러 필터수를 3으로 늘려 보기로 한다. 필터가 3개라고 해서 필터별로 특별한 특성이 있는 것은 아니고 단지 숫자 크기만 1.0 대신 10.0  1.0으로 바꾸어 보는 것이다.

특히 마이너스 값의 필터를 사용한 결과를 보면 가장 밝았던 부분이 가장 어두운 부분으로 가장 어두웠던 부분이 가장 밝게 바뀌었음을 알 수 있다.

그 다음 Pooling 과정을 알아보자. Pooling 이란 말 그대로 대표를 뽑는 작업이며 주로 최대값을 가지는 픽셀을 선택한다. 물론 이미지가 추출한 특성을 손상하지 않아야 한다.

Pooling 작업을 해보기로 한다. 다음 페이지의 그림에서처럼 전체 이미지가 2X2 로 주어졌을 때 ‘VAILD“ 조건하에서 2X2 매트릭스로 스트라이딩 시키게 되면 1회 스트라이딩 후 계산 결과 최대값 4를 주고 그대로 끝난다.

반면에 ‘SAME’ 조건을 적용하게 되면 다음 그림에서처럼 가장자리 한 줄을 보충하여 0을 입력한 상태의 3X3 매트릭스가 되므로 총 4회의 스트라이드를 적용할 수 있어 결과 2X2 매트릭스가 얻어진다.

그밖에 ReLU를 적용하는 문제도 있으나 ReLU 적용에 의해 픽셀의 최소값이 0 이상이 되면 이미지가 좀 밝아지는 효과가 있을 정도지만 기하학적 특징(feature) 추출과는 큰 상관이 없다. 단지 이어지는 Fully connected layers 와 연관하여 잘 수렴하는 결과를 줄 수 있도록 도움을 줄 수 있을 것이다.

 

다음 편에는 MNIST에서 임의의 숫자 하나를 택하여 필터링 및 풀링 작업을 한 결과를 코드와 함께 살펴보도록 하자. 28X28 이미지를 다루는 MNIST 예제를 통해서 이 절에서 연습했던 코드들이 어떻게 활용되어 무려 99%의 인식률을 달성하는지 살펴보기로 한다.

 

첨부된 코드를 다운 받아 파라메터를 바꿔가면서 연습해 보자.

 

#exercise

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

sess = tf.InteractiveSession()
image = np.array([[[[1],[2],[3]],
[[4],[5],[6]],
[[7],[8],[9]]]], dtype=np.float32)
print(image.shape)
plt.imshow(image.reshape(3,3), cmap='Greys')

print("image:\n", image)

print("image.shape", image.shape)
weight = tf.constant([[[[1.]],[[1.]]],
[[[1.]],[[1.]]]])
print("weight.shape", weight.shape)
conv2d = tf.nn.conv2d(image, weight, strides=[1, 1, 1, 1], padding='VALID')
conv2d_img = conv2d.eval()
print("conv2d_img.shape", conv2d_img.shape)
conv2d_img = np.swapaxes(conv2d_img, 0, 3)
for i, one_img in enumerate(conv2d_img):
print(one_img.reshape(2,2))
plt.subplot(1,2,i+1), plt.imshow(one_img.reshape(2,2), cmap='gray')