```
# Preprocessing
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# loading dataset
digits_data = datasets.load_digits()
input_data = digits_data.data
correct = digits_data.target
n_data = len(correct)
# standardize input_data
ave_input = np.average(input_data)
std_input = np.std(input_data)
input_data = (input_data - ave_input) / std_input
# conv. correct_data to one-hot
correct_data = np.zeros((n_data, 10))
for i in range(n_data):
correct_data[i, correct[i]] = 1.0
# train's and test's
index = np.arange(n_data)
index_train = index[index%3 != 0] # 3(k-1)+1,2
index_test = index[index%3 == 0] # 3k
input_train = input_data[index_train, :]
correct_train = correct_data[index_train, :]
input_test = input_data[index_test, :]
correct_test = correct_data[index_test, :]
n_train = input_train.shape[0] # train's sampe_num
n_test = input_test.shape[0]
# settings values
img_h = 8
img_w = 8
img_ch = 1
wb_width = 0.1
eta =0.01
epoch = 50
batch_size = 8
interval = 10
n_sample = 200
# im2col
def im2col(images, flt_h, flt_w, out_h, out_w, stride, pad):
# batch_size, chanel_num, ip_img_h, ip_img_w
n_bt, n_ch, img_h, img_w = images.shape
img_pad = np.pad(images, [(0, 0), (0, 0), (pad, pad), (pad, pad)], "constant")
cols = np.zeros((n_bt, n_ch, flt_h, flt_w, out_h, out_w))
for h in range(flt_h):
h_lim = h + stride*out_h
for w in range(flt_w):
w_lim = w + stride*out_w
cols[:, :, h, w, :, :] = img_pad[:, :, h:h_lim:stride, w:w_lim:stride]
cols = cols.transpose(1, 2, 3, 0, 4, 5).reshape(n_ch*flt_h*flt_w, n_bt*out_h*out_w)
return cols
# col2im
def col2im(cols, img_shape, flt_h, flt_w, out_h, out_w, stride, pad):
n_bt, n_ch, img_h, img_w = img_shape
cols = cols.reshape(n_ch, flt_h, flt_w, n_bt, out_h, out_w, ).transpose(3, 0, 1, 2, 4, 5)
images = np.zeros((n_bt, n_ch, img_h+2*pad+stride-1, img_w+2*pad+stride-1))
for h in range(flt_h):
h_lim = h + stride*out_h
for w in range(flt_w):
w_lim = w + stride*out_w
images[:, :, h:h_lim:stride, w:w_lim:stride] += cols[:, :, h, w, :, :]
return images[:, :, pad:img_h+pad, pad:img_w+pad]
# ConvLayer
# 畳み込み層
class ConvLayer:
# x_ch: 入力チャンネル数、 x_h: 入力画像高さ、 x_w: 入力画像幅
# n_flt: フィルタ数、 flt_h: フィルタ高さ、 flt_w: フィルタ幅
# stride: ストライド幅、 pad: パディング幅
def __init__(self, x_ch, x_h, x_w, n_flt, flt_h, flt_w, stride, pad):
# sum parameter
self.params = (x_ch, x_h, x_w, n_flt, flt_h, flt_w, stride, pad)
# flt & bias 's initial
self.w = wb_width * np.random.randn(n_flt, x_ch, flt_h, flt_w)
self.b = wb_width * np.random.randn(1, n_flt)
# out_img_size
self.y_ch = n_flt # out chanels
self.y_h = (x_h - flt_h + 2*pad) // stride + 1 # out_height
self.y_w = (x_w - flt_w + 2*pad) // stride + 1
# for AdaGrad
self.h_w = np.zeros((n_flt, x_ch, flt_h, flt_w)) + 1e-8
self.h_b = np.zeros((1, n_flt)) + 1e-8
def forward(self, x):
n_bt = x.shape[0]
x_ch, x_h, x_w, n_flt, flt_h, flt_w, stride, pad = self.params
y_ch, y_h, y_w = self.y_ch, self.y_h, self.y_w
# ip_img, filter is converted
self.cols = im2col(x, flt_h, flt_w, y_h, y_w, stride, pad) # conv. (C F_h F_w, B O_h O_w)
self.w_col = self.w.reshape(n_flt, x_ch*flt_h*flt_w) # conv. (M, C F_h F_w)
# output: Mat Product, add bias, posi-fn
u = np.dot(self.w_col, self.cols).T + self.b # conv. (M, B O_h O_w)
self.u = u.reshape(n_bt, y_h, y_w, y_ch).transpose(0, 3, 1, 2) # conv. (B, M, O_h, O_w)
self.y = np.where(self.u <= 0, 0, self.u) # ReLU
def backward(self, grad_y):
n_bt = grad_y.shape[0]
x_ch, x_h, x_w, n_flt, flt_h, flt_w, stride, pad = self.params
y_ch, y_h, y_w = self.y_ch, self.y_h, self.y_w
# delta
delta = grad_y * np.where(self.u <= 0, 0, 1) # times part. ReLU
delta = delta.transpose(0,2,3,1).reshape(n_bt*y_h*y_w, y_ch) # (B O_h O_w, M)
# part. filter, bias
grad_w = np.dot(self.cols, delta)
self.grad_w = grad_w.T.transpose(n_flt, x_ch, flt_h, flt_w)
self.grad_b = np.sum(delta, axis=0)
# part. input
grad_cols = np.dot(delta, self.w_col)
x_shape = (n_bt, x_ch, x_h, x_w)
self.grad_x = col2im(grad_cols.T, x_shape, flt_h, flt_w, y_h, y_w, stride, pad)
def update(self, eta):
self.h_w += self.grad_w * self.grad_w
self.w -= eta / np.sqrt(self.h_w) * self.grad_w
self.h_b += self.grad_b * self.grad_b
self.b -= eta / np.sqrt(self.h_b) * self.grad_b
# poolingLayer
class PoolingLayer:
# x_ch: ip_chanels, x_h: ip_img_h, x_w: ip_img_w
# pool: pooling_size, pad: padding_w
def __init__(self, x_ch, x_h, x_w, pool, pad):
# sum params
self.params = (x_ch, x_h, x_w, pool, pad)
self.y_ch = x_ch # out_chanels
self.y_h = x_h//pool if x_h%pool==0 else x_h//pool+1 # out_h
self.y_w = x_w//pool if x_w%pool==0 else x_w//pool+1 # out_w
def forward(self, x):
n_bt = x.shape[0]
x_ch, x_h, x_w, pool, pad = self.params
y_ch, y_h, y_w = self.y_ch, self.y_h, self.y_w
# conv. ip_img to matrix
cols = im2col(x, pool, pool, y_h, y_w, pool, pad)
cols = cols.T.reshape(n_bt*y_h*y_w*x_ch, pool*pool)
# calc out: maxPooling
y = np.max(cols, axis=1)
self.y = y.reshape(n_bt, y_h, y_w, x_ch).transpose(0,3,1,2)
# maximum's index logging
self.max_index = np.argmax(cols, axis=1)
def backward(self, grad_y):
n_bt =grad_y.shape[0]
x_ch, x_h, x_w, pool, pad = self.params
y_ch, y_h, y_w = self.y_ch, self.y_h, self.y_w
# change axis of output grad
grad_y = grad_y.transpose(0, 2, 3, 1)
# make matrix
grad_cols = np.zeros((pool*pool, grad_y.size))
# insert out_grad to elements of max of each colmn
grad_cols[self.max_index.reshape(-1), np.arange(grad_y.size)] = grad_y.reshape(-1)
grad_cols = grad_cols.reshape(pool, pool, n_bt, y_h, y_w, y_ch)
grad_cols = grad_cols.transpose(5,0,1,2,3,4)
grad_cols = grad_cols.reshape( y_ch*pool*pool, n_bt*y_h*y_w)
# grad input
x_shape = (n_bt, x_ch, x_h, x_w)
self.grad_x = col2im(grad_cols, x_shape, pool, pool, y_h, y_w, pool, pad)
# baseLayer => instantinate mid, out Layer
class BaseLayer:
def __init__(self, n_upper, n):
self.w = wb_width * np.random.randn(n_upper, n)
self.b = wb_width * np.random.randn(n)
self.h_w = np.zeros(( n_upper, n)) + 1e-8
self.h_b = np.zeros(n) + 1e-8
def update(self, eta):
self.h_w += self.grad_w * self.grad_w
self.w -= eta / np.sqrt(self.h_w) * self.grad_w
self.h_b += self.grad_b * self.grad_b
self.b -= eta / np.sqrt(self.h_b) * self.grad_b
# MidLayer -ReLU
class MidLayer(BaseLayer):
def forward(self, x):
self.x = x
self.u = np.dot(x, self.w) + self.b
self.y = np.where(self.u <= 0, 0, self.u) # ReLU
def backward(self, grad_y):
delta = grad_y * np.where(self.u <= 0, 0, 1) # Dif ReLE
self.grad_w = np.dot(self.x.T, delta)
self.grad_b = np.sum(delta, axis=0)
self.grad_x = np.dot(delta, self.w.T)
# OutLayer -ReLU _same before chap.'s one
class OutLayer(BaseLayer):
def forward(self, x):
self.x = x
u = np.dot(x, self.w) + self.b
# softmax
self.y = np.exp(u)/np.sum(np.exp(u), axis=1).reshape(-1, 1)
def backward(self, t):
delta = self.y - t
self.grad_w = np.dot(self.x.T, delta)
self.grad_b = np.sum(delta, axis=0)
self.grad_x = np.dot(delta, self.w.T)
# initialize each layer
cl_1 = ConvLayer(img_ch, img_h, img_w, 10, 3, 3, 1, 1)
pl_1 = PoolingLayer(cl_1.y_ch, cl_1.y_h, cl_1.y_w, 2, 0)
n_fc_in = pl_1.y_ch * pl_1.y_h * pl_1.y_w
ml_1 = MidLayer(n_fc_in, 100)
ol_1 = OutLayer(100, 10)
# forward
def forward_propagation(x):
n_bt =x.shape[0]
images = x.reshape(n_bt, img_ch, img_h, img_w)
cl_1.forward(images)
pl_1.forward(cl_1.y)
fc_input = pl_1.y.reshape(n_bt, -1)
ml_1.forward(fc_input)
ol_1.forward(ml_1.y)
# backward
def backpropagation(t):
n_bt = t.shape[0]
ol_1.backward(t)
ml_1.backward(ol_1.grad_x)
grad_img = ml_1.grad_x.reshape(n_bt, pl_1.y_ch, pl_1.y_h, pl_1.y_w)
pl_1.backward(grad_img)
cl_1.backward(pl_1.grad_x)
# update w, b
def update_wb():
cl_1.update(eta)
ml_1.update(eta)
ol_1.update(eta)
# calc cross-entropy Loss
def get_error(t, batch_size):
return -np.sum(t * np.log(ol_1.y + 1e-7)) / batch_size
# forwarding sample
def forward_sample(inp, correct, n_sample):
index_rand = np.arange(len(correct))
np.random.shuffle(index_rand)
index_rand = index_rand[:n_sample]
x = inp[index_rand, :]
t = correct[index_rand, :]
forward_propagation(x)
return x, t
# logging Loss
train_error_x = []
train_error_y = []
test_error_x = []
test_error_y = []
# logging learn and process
n_batch = n_train // batch_size
for i in range(epoch):
# check Loss
x, t = forward_sample(input_train, correct_train, n_sample)
error_train = get_error(t, n_sample)
x, t = forward_sample(input_test, correct_test, n_sample)
error_test = get_error(t, n_sample)
# logging Loss
train_error_x.append(i)
train_error_y.append(error_train)
test_error_x.append(i)
test_error_y.append(error_test)
# print process
if i%interval == 0:
print("Epoch:" + str(i) + "/" + str(epoch),
"Error_train:" + str(error_train),
"Error_test:" + str(error_test))
# learn
index_rand = np.arange(n_train)
np.random.shuffle(index_rand)
for j in range(n_batch):
mb_index = index_rand[j*batch_size : (j+1)*batch_size]
x = input_train[mb_index, :]
t = correct_train[mb_index, :]
forward_propagation(x)
backpropagation(t)
update_wb()
# print graph of Loss-Log
plt.plot(train_error_x, train_error_y, label="Train")
plt.plot(test_error_x, test_error_y, label="Test")
plt.legend()
plt.xlabel("Epochs")
plt.ylabel("Error")
plt.show()
# calc. corr_ratio
x, t = forward_sample(input_train, correct_train, n_train)
count_train = np.sum(np.argmax(ol_1.y, axis=1) == np.argmax(t, axis=1)
x, t = forward_sample(input_test, correct_test, n_test)
count_test = np.sum(np.argmax(ol_1.y, axis=1) == np.argmax(t, axis=1)
print("Accuracy Train:", + str(count_train/n_train*100) + "%",
"Accuracy Test:", + str(count_test/n_test*100) + "%")
```