im2col函数是进行卷积运算所常用的一个函数,它的作用是将进行卷积运算的一组图片二维化,而后再与卷积核进行矩阵相乘,代替了卷积运算原来相乘再相加的运算形式,可以大大减少运算所需时间。接下来介绍im2col函数的实现原理以及其不同形式。
先上代码
def im2col(input_img, FH, FW, stride=1, pad=0):
"""
:param input_img: 输入的数据
:param FH: 卷积核高度
:param FW: 卷积核宽度
:param stride: 卷积核移动步长
:param pad: 填充
:return: 图片二维返回值,高度为:(一组图片数目)*(输出图片宽度)*(输出图片高度),宽度为:(通道)*(滤波器高度)*(滤波器宽度)
"""
N, C, H, W = input_img.shape
out_h = 1 + int((H + 2 * pad - FH) / stride)
out_w = 1 + int((W + 2 * pad - FW) / stride)
img = np.pad(input_img, [(0, 0), (0, 0), (pad, pad), (pad, pad)], 'constant') # 在行始填充pad个0,行末填充pad个0,列始,列末同理
out_img = np.zeros((N, C, FH, FW, out_h, out_w))
for y in range(FH):
y_max = y + out_h * stride
for x in range(FW):
x_max = x + out_w * stride
out_img[:, :, y, x, :, :] = img[:, :, y:y_max:stride,
x:x_max:stride]
out_img = np.transpose(out_img,
(0, 4, 5, 1, 2, 3)) # 换轴函数,读取维度顺序为N,OH,OW,C,FH,FW,逻辑为将N张图片读取为OH,OW二维,内容为C个通道FH,FW的原始图片
out_img = out_img.reshape(N * out_h * out_w, -1) # 将图片reshape为高度为N*out_h*out_w,宽度为C*FW*FH的二维数据
return out_img
原理:我们先建立了初始输出数组,它的shape按顺序表为
图片数目
图片维度
滤波器高度
滤波器宽度
输出图片的高度(也表示了纵轴上滤波器个数)
输出图片的宽度(也表示了横轴上滤波器个数)
利用for循环,我们向输出数组中每张图片每个维度纵轴横轴所确定的滤波器中对应位置,即**(y,x)**赋上了原图的相应值,也就是说我们获取了第N张图片第C个通道上第(out_h,out_w)个滤波器的(y,x)的值。
目前坐标读取顺序为(N,C,FH,FW,out_h,out_w),而需要得到的坐标顺序应该为(N,out_h,out_w,C,FH,FW),以通过reshape(默认顺序为从右到左展开)函数二维化,因此我们还需使用transhpose函数改变坐标读取顺序,最后再reshape一下就完成了。
变体:可以看到我们在for循环当中是写入(y,x)位置所有滤波器的信息,其实也可以写入(out_h,out_w)个滤波器所有位置信息,只是这样会使循环次数变多,但这种方法可以使我们更好的了解im2col这一方法的本质就是写入坐标再改变读取顺序,变体代码如下:
def im2col(input_img, FH, FW, stride=1, pad=0):
"""
将多维图片转化为二维
:param input_data: 输入的数据
:param filter_h: 卷积核高度
:param filter_w: 卷积核宽度
:param stride: 卷积核移动补偿
:param pad: 填充
:return: 二维数组
"""
N, C, H, W = input_img.shape
out_h = 1 + int((H + 2 * pad - FH) / stride)
out_w = 1 + int((W + 2 * pad - FW) / stride)
img = np.pad(input_img, [(0, 0), (0, 0), (pad, pad), (pad, pad)], 'constant') # 在行始填充pad个0,行末填充pad个0,列始,列末同理
out_img = np.zeros((N, C, FH, FW, out_h, out_w))
for y in range(out_h):
y_left=y*stride
for x in range(out_w):
x_left=x*stride
out_img[:, :, :, :, y, x] = img[:, :, y_left:y_left+FH,
x_left:x_left+FW] # 对应(x,y)的fillter维度:包含数据为维度顺序为N,C,y方向滤波器覆盖范围,x方向滤波器覆盖范围
out_img = np.transpose(out_img,
(0, 4, 5, 1, 2, 3)) # 换轴函数,读取维度顺序为N,OH,OW,C,FH,FW,逻辑为将N张图片读取为OH,OW二维,内容为C个通道FH,FW的原始图片
out_img = out_img.reshape(N * out_h * out_w, -1) # 将图片reshape为高度为N*out_h*out_w,宽度为C*FW*FH的二维数据
return out_img