介绍
在caffe(开源深度学习框架)中,做 卷积运算 时,不是 像下图那样,设计一个滑动的卷积核,进行运算。
为了 在GPU中可以最大限度的加速,做法如下:
是将 图片矩阵 转成 n行1列的矩阵,将 卷积核 扩展成 m行n列的矩阵,
让两个矩阵 做矩阵乘法 运算:
m行n列的矩阵 x n行1列的矩阵 = m行1列的矩阵
然后根据 卷积结果尺寸计算公式,算出卷积结果尺寸为i行j列,
将m行1列的矩阵转成i行j列,这就是最后卷积结果
新图像矩阵
新卷积核矩阵
新卷积核矩阵的 大小
假设卷积核大小是3x3,值如下:
为了让卷积核能够与上图 16行1列的新图像矩阵,进行 矩阵乘法 运算,必须将卷积核扩展成16列,即:新卷积核矩阵为 m行16列(行数暂未知),计算式子如下:
m行16列矩阵 x 16行1列矩阵 = m行1列
结果是 m行1列(行数暂未知),将m行1列转成i行j列后就是 卷积结果,所以m的值,一定等于卷积结果的元素数量。
上文给出卷积结果大小的计算公式:(N1-N2+2P)/S+1
这里为了易于理解,不填充,步长为1,所以卷积结果的大小为:(3-2+2*0)/1+1=2,即:卷积结果大小为:(2,2),共有4个元素
所以 m值为4,也就是 新卷积核大小是:4行16列
新卷积核矩阵的元素
第1次 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图:
所以新卷积核矩阵的 第1行值:
1 2 3 0 4 5 6 0 7 8 9 0 0 0 0 0
第2次 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图:
所以新卷积核矩阵的 第2行值:
0 1 2 3 0 4 5 6 0 7 8 9 0 0 0 0
第3次 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图:
所以新卷积核矩阵的 第3行值:
0 0 0 0 1 2 3 0 4 5 6 0 7 8 9 0
第4次 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图:
所以新卷积核矩阵的 第4行值:
0 0 0 0 0 1 2 3 0 4 5 6 0 7 8 9
新卷积核矩阵如下:
总结成公式为:
矩阵乘法运算
结果大小为:4行1列,在转成 2行2列,就是卷积结果
代码
按照上面理论实现的 卷积代码,经测试,图片尺寸稍微大些的,占用内存就会极大,假设图像尺寸是500 x 500的,卷积核尺寸是3 x 3,那么新卷积核矩阵的列就是:500 x 500=250000,行数是:(500-3+2*0)/1+1=498,那么新卷积核矩阵是:498行250000列,使用这种方式占用内存很大
# 卷积运算,
def run_conv2(data,kernel,step=1):
"""
data:要计算的图像数据
kernel:卷积核值
step:步长
"""
data_w=data.shape[1]
data_h=data.shape[0]
# 卷积核大小
kernel_w=kernel.shape[1]
kernel_h=kernel.shape[0]
# 结果大小
result_w=(data_w-kernel_w)//step+1
result_h=(data_h-kernel_h)//step+1
result_count=result_w*result_h
new_data=data.reshape(-1,1)
new_data_rows=new_data.shape[0]
new_kernel=np.zeros((result_count,new_data_rows))
zero_num=0
for row_index in range(result_count):
if row_index%result_w==0:
zero_num=(row_index//result_w)*data_w
else:
zero_num+=1
for kernel_row_index in range(kernel_w):
start_index=zero_num+kernel_row_index*data_w
new_kernel[row_index,start_index:start_index+kernel_w]=kernel[kernel_row_index]
return np.matmul(new_kernel,new_data).reshape(result_h,result_w)







