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()