参考课程:https://novel.ict.ac.cn/aics/
卷积层
import numpy as np
import time # 导入时间模块
class ConvolutionalLayer(object):
def __init__(self, kernel_size, channel_in, channel_out, padding, stride):
# 卷积层的初始化
self.kernel_size = kernel_size # 卷积核大小
self.channel_in = channel_in # 输入通道数
self.channel_out = channel_out # 输出通道数
self.padding = padding # 填充大小
self.stride = stride # 步长
print('\tConvolutional layer with kernel size %d, input channel %d, output channel %d.' % (self.kernel_size, self.channel_in, self.channel_out))
def init_param(self, std=0.01): # 参数初始化
self.weight = np.random.normal(loc=0.0, scale=std, size=(self.channel_in, self.kernel_size, self.kernel_size, self.channel_out)) # 初始化权重
self.bias = np.zeros([self.channel_out]) # 初始化偏置
def forward(self, input): # 前向传播的计算
start_time = time.time()
self.input = input # [N, C, H, W]
# 计算填充后的输入高度和宽度
height = self.input.shape[2] + self.padding * 2
width = self.input.shape[3] + self.padding * 2
self.input_pad = np.zeros([self.input.shape[0], self.input.shape[1], height, width]) # 创建填充后的输入
# 填充输入
self.input_pad[:, :, self.padding:height-self.padding, self.padding:width-self.padding] = self.input
height_out = (height - self.kernel_size) / self.stride + 1 # 计算输出特征图的高度
width_out = (width - self.kernel_size) / self.stride + 1 # 计算输出特征图的宽度
self.output = np.zeros([self.input.shape[0], self.channel_out, height_out, width_out]) # 初始化输出特征图
# 执行卷积操作
for idxn in range(self.input.shape[0]): # 遍历输入的样本
for idxc in range(self.channel_out): # 遍历输出通道数
for idxh in range(height_out): # 遍历输出特征图的高度
for idxw in range(width_out): # 遍历输出特征图的宽度
# 计算当前位置的卷积
hs = idxh * self.stride
ws = idxw * self.stride
self.output[idxn, idxc, idxh, idxw] = np.sum(self.weight[:, :, :, idxc] * \
self.input_pad[idxn, :, hs:hs+self.kernel_size, ws:ws+self.kernel_size]) + \
self.bias[idxc] # 计算卷积加偏置项
return self.output # 返回输出特征图
def load_param(self, weight, bias): # 参数加载
assert self.weight.shape == weight.shape
assert self.bias.shape == bias.shape
self.weight = weight
self.bias = bias