7장 가중치(파라미터) 만들고, 결괏값을 만들어 이 둘을 저장하는 법 - LOPES-HUFS/DeepLearningFromForR GitHub Wiki
아래 코드는 7장의 CNN을 돌려서 가중치와 Conv1
의 결과값, Pool1
의 결과값을 H5로 저장하는 코드입니다.
전체 코드
import numpy as np
import tensorflow as tf
from tensorflow import keras
from keras.utils import np_utils
mnist = keras.datasets.mnist
(x_train, t_train), (x_test, t_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], 1, 28, 28).astype('float64')
x_test = x_test.reshape(x_test.shape[0], 1, 28, 28).astype('float64')
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train.shape
x_train[0:10,:,:,:].shape
x_train_10 = x_train[0:10,:,:,:]
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
pool_output_size = int(filter_num * (conv_output_size/2) * (conv_output_size/2))
params = {}
params['W1'] = weight_init_std * np.random.randn(filter_num, input_dim[0], filter_size, filter_size)
params['b1'] = np.zeros(filter_num)
params['W2'] = weight_init_std * np.random.randn(pool_output_size, hidden_size)
params['b2'] = np.zeros(hidden_size)
params['W3'] = weight_init_std * np.random.randn(hidden_size, output_size)
params['b3'] = np.zeros(output_size)
def conv_output_size(input_size, filter_size, stride=1, pad=0):
return (input_size + 2*pad - filter_size) / stride + 1
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
"""
Parameters
----------
input_data : (データ数, チャンネル, 高さ, 幅)の4次元配列からなる入力データ
filter_h : フィルターの高さ
filter_w : フィルターの幅
stride : ストライド
pad : パディング
Returns
-------
col : 2次元配列
"""
N, C, H, W = input_data.shape
out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1
img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))
for y in range(filter_h):
y_max = y + stride*out_h
for x in range(filter_w):
x_max = x + stride*out_w
col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
return col
def col2im(col, input_shape, filter_h, filter_w, stride=1, pad=0):
"""
Parameters
----------
col :
input_shape : 入力データの形状(例:(10, 1, 28, 28))
filter_h :
filter_w
stride
pad
Returns
-------
"""
N, C, H, W = input_shape
out_h = (H + 2*pad - filter_h)//stride + 1
out_w = (W + 2*pad - filter_w)//stride + 1
col = col.reshape(N, out_h, out_w, C, filter_h, filter_w).transpose(0, 3, 4, 5, 1, 2)
img = np.zeros((N, C, H + 2*pad + stride - 1, W + 2*pad + stride - 1))
for y in range(filter_h):
y_max = y + stride*out_h
for x in range(filter_w):
x_max = x + stride*out_w
img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]
return img[:, :, pad:H + pad, pad:W + pad]
class Convolution:
def __init__(self, W, b, stride=1, pad=0):
self.W = W
self.b = b
self.stride = stride
self.pad = pad
# 中間データ(backward時に使用)
self.x = None
self.col = None
self.col_W = None
# out 값을 저장하기 위해 만듬
self.out = None
# 重み・バイアスパラメータの勾配
self.dW = None
self.db = None
def forward(self, x):
FN, C, FH, FW = self.W.shape
N, C, H, W = x.shape
out_h = 1 + int((H + 2*self.pad - FH) / self.stride)
out_w = 1 + int((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
out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)
# out 값을 저장
self.out = out
self.x = x
self.col = col
self.col_W = col_W
return out
def backward(self, dout):
FN, C, FH, FW = self.W.shape
dout = dout.transpose(0,2,3,1).reshape(-1, FN)
self.db = np.sum(dout, axis=0)
self.dW = np.dot(self.col.T, dout)
self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)
dcol = np.dot(dout, self.col_W.T)
dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)
return dx
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
self.x = None
self.arg_max = None
# out 값을 저장
self.out = None
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)
arg_max = np.argmax(col, axis=1)
out = np.max(col, axis=1)
out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)
# out 값을 저장하기 위해 만듬
self.out = out
self.x = x
self.arg_max = arg_max
return out
def backward(self, dout):
dout = dout.transpose(0, 2, 3, 1)
pool_size = self.pool_h * self.pool_w
dmax = np.zeros((dout.size, pool_size))
dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
dmax = dmax.reshape(dout.shape + (pool_size,))
dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)
return dx
class Relu:
def __init__(self):
self.mask = None
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
def backward(self, dout):
dout[self.mask] = 0
dx = dout
return dx
from collections import OrderedDict
layers = OrderedDict()
layers['Conv1'] = Convolution(params['W1'], params['b1'], conv_param['stride'], conv_param['pad'])
layers['Relu1'] = Relu()
layers['Pool1'] = Pooling(pool_h=2, pool_w=2, stride=2)
for layer in layers.values():
x = layer.forward(x_train_10)
layers['Conv1'].out.shape
layers['Pool1'].out.shape
import h5py
hf = h5py.File('simple_convnet_7.h5', 'w')
hf.create_dataset('W1',data=params['W1'], dtype=np.dtype('float64'))
hf.create_dataset('W2',data=params['W2'], dtype=np.dtype('float64'))
hf.create_dataset('W3',data=params['W3'], dtype=np.dtype('float64'))
hf.create_dataset('b1',data=params['b1'], dtype=np.dtype('float64'))
hf.create_dataset('b2',data=params['b2'], dtype=np.dtype('float64'))
hf.create_dataset('b3',data=params['b3'], dtype=np.dtype('float64'))
hf.create_dataset('Conv1',data=layers['Conv1'].out, dtype=np.dtype('float64'))
hf.create_dataset('Pool1',data=layers['Pool1'].out, dtype=np.dtype('float64'))
hf.close()