Python numpy实现卷积操作
● 原理见链接
● 没有考虑batchsize和偏差项
● 反向传播有待补充
import numpy as np
class Conv2D:
# Not considering of batch size and bias
# Referenced this blog https://github.com/GYee/CV_interviews_Q-A/blob/master/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/03_%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E5%8D%B7%E7%A7%AF%E6%93%8D%E4%BD%9C.md
def __init__(self, input_channel,
output_channel,
kernel_size,
stride=1,
padding=True):
self.input_channel = input_channel
self.output_channel = output_channel
self.kernel_size = kernel_size
self.stride = stride
self.padding = padding
self.weight = np.random.rand(self.input_channel * kernel_size * kernel_size, self.output_channel)
def forward(self, feature_map):
# input feature_map size c * h * w
# circle_h = (ori_h + 2 * padding - kernel_size) / 2 + 1
# circle_w = (ori_w + 2 * padding - kernel_size) / 2 + 1
# output size self.output_channel * circle_h * circle_w
(ori_c, ori_h, ori_w) = feature_map.shape
# padding
if self.padding:
feature_map = np.pad(feature_map, ((0, 0), (self.kernel_size//2, self.kernel_size//2), (self.kernel_size//2, self.kernel_size//2)), 'constant')
(c, h, w) = feature_map.shape
circle_h = (h - self.kernel_size) // self.stride + 1
circle_w = (w - self.kernel_size) // self.stride + 1
else:
circle_h = (ori_h - self.kernel_size) // self.stride + 1
circle_w = (ori_w - self.kernel_size) // self.stride + 1
# feature to matrix
mat_feature_map = np.zeros([circle_h * circle_w, ori_c * self.kernel_size * self.kernel_size], np.float32)
output = np.zeros([self.output_channel, circle_h, circle_w], np.float32)
row = 0
for i in range(circle_h):
for j in range(circle_w):
roi = feature_map[:, i * self.stride:(i * self.stride + self.kernel_size), j * self.stride:(j * self.stride + self.kernel_size)]
mat_feature_map[row] = roi.flatten()
row += 1
mat_out = np.dot(mat_feature_map, self.weight)
for i in range(self.output_channel):
roi = mat_out[:, i]
output[i] = np.reshape(roi, (circle_h, circle_w))
return output
def backword(self, dx, lr):
# How to calculate dx to be added
assert dx.shape == self.weight.shape
self.weight -= dx * lr
if __name__ == '__main__':
x = np.random.rand(2, 8, 8)
conv = Conv2D(2, 3, 3, stride=2, padding=False)
y = conv.forward(x)