합성곱 신경망은 이미지 인식 분야에서 주로 쓰인다. 완전연결 계층은 평탄화하여 데이터 형상이 무시되는데 CNN은 이를 보완해준다. 지역적인 부분에 대해서 특징을 추출한다는 것이 CNN의 장점이다.
CNN을 활용한 네트워크
- CNN 계층은 Conv - Relu - Pooling의 흐름으로 연결된다.
- 출력에 가까운 층에서는 Affine-Relu 구성을 사용한다.
합성곱 계층
합성곱 계층은 합성곱 연산, 패딩, 스트라이드로 구성된다.
합성곱 연산
필터를 일정 간격으로 이동해가며 입력 데이터에 적용한다.
패딩
입력 데이터 주변을 특정값으로 채우는 기법이다.
스트라이드
필터를 적용하는 위치의 간격을 스트라이드라고 한다.
출력 크기
필터, 패딩, 스트라이드에 따라 출력 shape가 달라지게 된다.
입력 크기를 (H, W), 필터 크기를 (FH, FW), 출력크기를 (OH, OW), 패딩을 P, 스트라이드를 S라 했다.
1개의 필터를 사용하면 출력크기가 다음과 같다.
3차원 이상에서 여러 필터를 사용하면 출력크기가 다음과 같다.
풀링계층
풀링은 세로, 가로 방향의 공간을 줄이는 연산이다.
보통 윈도우의 크기를 스트라이드로 설정한다.
ex)2*2의 윈도우라면 스트라이드도 2
풀링계층의 특징
- 학습해야 할 매개변수가 없다.
- 채널수가 변하지 않는다.
- 입력의 변화에 영향을 적게 받는다.
합성곱/풀링 계층 구현하기
합성곱 계층
합성곱 연산을 구현하려면 for문을 겹겹히 써야한다. 이 대신 im2col이라는 입력데이터를 가중치 계산하기 좋게 전개하는 함수를 사용한다.
#im2col(input_data, filter_h, filter_w, stride=1, pad=0)
from common.util import im2col
x1 = np.random.rand(1, 3, 7, 7)
col1 = im2col(x1, 5, 5, stride=1, pad=0)
print(col1.shape)
# 1번 인자는 인풋데이터의 batch_size*OH*OW이고, 2번 인자는 필터의 원소수, 즉 인풋데이터의 channel * FW * FH
#(9, 75)
이후 필터도 세로로 전개하여 계산하고, 최종 출력데이터를 원래 출력 모양대로 reshape한다.
class Convolution:
def __init__(self, W, b, stride=1, pad=0):
self.W = W
self.b = b
self.stride = stride
self.pad = pad
def forward(self, x):
FN, C, FH, FW = self.W.shape
N, C, H, W = x.shape
out_h = int(1+(H+2*self.pad-FH)/self.stride)
out_w = int(1+(W+2*self.pad-FW)/self.stride)
# 전개
col = im2col(x, FH, FW, self.stride, self.pad)
col_W = self.W.reshape(FN, -1).T
# 계산
out = np.dot(col, col_W) + self.b
# reshape
out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)
return out
풀링계층
class Pooling:
def __init__(self, pool_h, pool_w, stride=1, pad=0):
self.pool_h = pool_h
self.pool_w = pool_w
self.stride = stride
self.pad = pad
def forward(self, x):
N, C, H, W = x.shape
out_h = int(1+(H-self.pool_h)/self.stride)
out_w = int(1+(W-self.pool_w)/self.stride)
# 전개
col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
col = col.reshape(-1, self.pool_h*self.pool_w)
# 최댓값
out = np.max(col, axis=1)
# reshape
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
return out
CNN 구현하기
네트워크 구성
계층은 conv-pool-fc-fc로 구성
- conv : filter (30_1_5*5), stride:1, padding:0
- pooling : filter(2,2), stride:2
- fc1 : w(30_12_12, 100)
- fc2 : w(100, 10)
네트워크 코드
class SimpleConvNet:
def __init__(self, input_dim=(1, 28, 28), conv_param={'filter_num':30, 'filter_size':5, 'pad':0, 'stride':1}, \\
hidden_size=100, output_size=10, weight_init_std=0.01):
filter_num = conv_param['filter_num']
filter_size = conv_param['filter_size']
filter_pad = conv_param['pad']
filter_stride = conv_param['stride']
input_size = input_dim[1]
conv_output_size = ((input_size - filter_size + 2*filter_pad) / filter_stride) +1 # 24
pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2)) # 30*12*12
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
self.params['b1'] = np.zeros(filter_num)
self.params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
self.params['b2'] = np.zeros(hidden_size)
self.params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b3'] = np.zeros(output_size)
self.layers = OrderedDict()
self.layers['Conv1'] = Convolution(self.params['W1'], self.params['b1'], conv_param['stride'], conv_param['pad'])
self.layers['Relu1'] = Relu()
self.layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
self.layers['Affine1'] = Affine(self.params['W2'], self.params['b2'])
self.layers['Relu2'] = Relu()
self.layers['Affine2'] = Affine(self.params['W3'], self.params['b3'])
self.last_layer = SoftmaxWithLoss()
def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)
return x
def loss(self, x, t):
y = self.predict(x)
return self.last_layer.forward(y, t)
def gradient(self, x, t):
# 순전파
self.loss(x, t)
# 역전파
dout = 1
dout = self.last_layer.backward(dout)
layers = list(self.layers.values())
layers.reverse()
for layer in layers:
dout = layer.backward(dout)
# 결과 저장
grads = {}
grads['W1'] = self.layers['Conv1'].dW
grads['b1'] = self.layers['Conv1'].db
grads['W2'] = self.layers['Affine1'].dW
grads['b2'] = self.layers['Affine1'].db
grads['W3'] = self.layers['Affine2'].dW
grads['b3'] = self.layers['Affine2'].db
return grads
def accuracy(self, x, t, batch_size=100):
if t.ndim != 1 : t = np.argmax(t, axis=1)
acc = 0.0
for i in range(int(x.shape[0] / batch_size)):
tx = x[i*batch_size:(i+1)*batch_size]
tt = t[i*batch_size:(i+1)*batch_size]
y = self.predict(tx)
y = np.argmax(y, axis=1)
acc += np.sum(y == tt)
return acc / x.shape[0]
훈련코드
최종 훈련결과 test accuracy가 96%가 나왔다.
import sys, os
sys.path.append('./deep-learning-from-scratch-master')
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
#from simple_convnet import SimpleConvNet
from common.trainer import Trainer
from common.layers import *
from collections import OrderedDict
# 데이터 읽기
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
# 시간이 오래 걸릴 경우 데이터를 줄인다.
x_train, t_train = x_train[:5000], t_train[:5000]
x_test, t_test = x_test[:1000], t_test[:1000]
max_epochs = 20
network = SimpleConvNet(input_dim=(1,28,28),
conv_param = {'filter_num': 30, 'filter_size': 5, 'pad': 0, 'stride': 1},
hidden_size=100, output_size=10, weight_init_std=0.01)
trainer = Trainer(network, x_train, t_train, x_test, t_test,
epochs=max_epochs, mini_batch_size=100,
optimizer='Adam', optimizer_param={'lr': 0.001},
evaluate_sample_num_per_epoch=1000)
trainer.train()
그래프그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
plt.plot(x, trainer.train_acc_list, marker='o', label='train', markevery=2)
plt.plot(x, trainer.test_acc_list, marker='s', label='test', markevery=2)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
CNN 시각화하기
CNN에서는 앞쪽의 층에서는 에지나 블롭 등의 저수준 정보가 추출되고, 깊은 뒤쪽의 층에서는 텍스처, 사물 등의 복잡하고, 추상화된 정보가 추출된다.
'책리뷰' 카테고리의 다른 글
(시작하세요! 텐서플로 2.0 프로그래밍) 3장. 텐서플로 2.0 시작하기 (0) | 2022.07.12 |
---|---|
(밑바닥부터 시작하는 딥러닝) 8장. 딥러닝 (0) | 2022.07.12 |
(밑바닥부터 시작하는 딥러닝) 6장. 학습 관련 기술들 (0) | 2022.06.23 |
(밑바닥부터 시작하는 딥러닝) 5장. 오차역전파법 (0) | 2022.06.23 |
(밑바닥부터 시작하는 딥러닝) 4장. 신경망 학습 (0) | 2022.06.23 |