
【pythonでCNN#6】Convolutional層(逆伝播)
記事の目的
pythonでCNN(畳み込みニューラルネットワーク)を実装していきます。ここにある全てのコードは、コピペで再現することが可能です。
目次
1 逆伝播

2 im2col関数とcol2im関数

# In[1]
import numpy as np
np.random.seed(1)
# In[2]
def im2col(x, fil_size, y_size, stride, pad):
x_b, x_c, x_h, x_w = x.shape
fil_h, fil_w = fil_size, fil_size
y_h, y_w = y_size, y_size
index = -1
x_pad = np.pad(x, [(0, 0), (0, 0), (pad, pad), (pad, pad)], "constant")
x_col = np.zeros((fil_h*fil_w, x_b, x_c, y_h, y_w))
for h in range(fil_h):
h2 = h + y_h*stride
for w in range(fil_w):
index += 1
w2 = w + y_w*stride
x_col[index,:,:,:,:] = x_pad[:,:,h:h2:stride,w:w2:stride]
x_col = x_col.transpose(2,0,1,3,4).reshape(x_c*fil_h*fil_w, x_b*y_h*y_w)
return x_col
# In[3]
def col2im(dx_col, x_shape, fil_size, y_size, stride, pad):
x_b, x_c, x_h, x_w = x_shape
fil_h, fil_w = fil_size, fil_size
y_h, y_w = y_size, y_size
index = -1
dx_col = dx_col.reshape(x_c, fil_h*fil_w, x_b, y_h, y_w).transpose(1,2,0,3,4)
dx = np.zeros((x_b, x_c, x_h+2*pad+stride-1, x_w+2*pad+stride-1))
for h in range(fil_h):
h2 = h + y_h*stride
for w in range(fil_w):
index += 1
w2 = w + y_w*stride
dx[:,:,h:h2:stride,w:w2:stride] += dx_col[index,:,:,:,:]
return dx[:,:,pad:x_h+pad, pad:x_w+pad]
3 Convolutional層

# In[4]
class Conv:
def __init__(self, x_c, y_c, fil_size, stride, pad):
self.x_c, self.y_c = x_c, y_c
self.fil_h, self.fil_w = fil_size, fil_size
self.stride, self.pad = stride, pad
self.w = np.arange(54).reshape(2,3,3,3)
self.b = np.zeros((1,self.y_c))
#self.w = np.random.randn(self.y_c, self.x_c, self.fil_h, self.fil_w)
#self.b = np.random.randn(1, self.y_c)
def forward(self, x):
self.xshape = x.shape
self.x_b, self.x_c, self.x_h, self.x_w = x.shape
self.y_h = (self.x_h - self.fil_h + 2*self.pad) // self.stride + 1
self.y_w = (self.x_w - self.fil_w + 2*self.pad) // self.stride + 1
self.x_col = im2col(x, self.fil_h, self.y_h, self.stride, self.pad)
self.w_col = self.w.reshape(self.y_c, self.x_c*self.fil_h*self.fil_w)
y = np.dot(self.w_col, self.x_col).T + self.b
self.y = y.reshape(self.x_b, self.y_h, self.y_w, self.y_c).transpose(0,3,1,2)
return self.y
def backward(self, dy):
dy = dy.transpose(0,2,3,1).reshape(self.x_b*self.y_h*self.y_w, self.y_c)
dw = np.dot(self.x_col, dy)
self.dw = dw.T.reshape(self.y_c, self.x_c, self.fil_h, self.fil_w)
self.db = np.sum(dy, axis=0)
dx_col = np.dot(dy, self.w_col)
self.dx = col2im(dx_col.T, (self.xshape), self.fil_h, self.y_h, self.stride, self.pad)
return self.dx
# In[5]
x = np.arange(96).reshape(2,3,4,4)
x.shape, x
# In[6]
conv = Conv(3, 2, 3, 1, 0)
# In[7]
y = conv.forward(x)
y.shape, y
# In[8]
conv.backward(np.ones(y.shape))