卷积运算-矩阵方式 作者:马育民 • 2020-03-06 10:18 • 阅读:10424 # 介绍 在caffe([开源深度学习框架](http://caffe.berkeleyvision.org/ "开源深度学习框架"))中,做 **卷积运算** 时,**不是** 像下图那样,设计一个滑动的卷积核,进行运算。 [![](https://www.malaoshi.top/upload/0/0/1EF52IpmOtMl.gif)](https://www.malaoshi.top/upload/0/0/1EF52IpmOtMl.gif) 为了 **在GPU中可以最大限度的加速**,做法如下: 是将 **图片矩阵** 转成 `n行1列的矩阵`,将 **卷积核** 扩展成 `m行n列的矩阵`, 让两个矩阵 做**矩阵乘法** 运算: ``` m行n列的矩阵 x n行1列的矩阵 = m行1列的矩阵 ``` 然后根据 卷积结果尺寸计算公式,算出卷积结果尺寸为`i行j列`, 将`m行1列的矩阵`转成`i行j列`,这就是最后卷积结果 # 新图像矩阵 假设有一个图片的numpy矩阵,大小是4x4,如下: [![](https://www.malaoshi.top/upload/0/0/1EF56R3WXsxU.png)](https://www.malaoshi.top/upload/0/0/1EF56R3WXsxU.png) 将该矩阵转成 n行1列,即16行1列的矩阵 [![](https://www.malaoshi.top/upload/0/0/1EF56RA9CXel.png)](https://www.malaoshi.top/upload/0/0/1EF56RA9CXel.png) # 新卷积核矩阵 ### 新卷积核矩阵的 大小 假设卷积核大小是3x3,值如下: [![](https://www.malaoshi.top/upload/0/0/1EF56RJ033N3.png)](https://www.malaoshi.top/upload/0/0/1EF56RJ033N3.png) 为了让卷积核能够与上图 `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次** 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图: [![](https://www.malaoshi.top/upload/0/0/1EF56fUpQ952.png)](https://www.malaoshi.top/upload/0/0/1EF56fUpQ952.png) 所以新卷积核矩阵的 **第1行值**: ``` 1 2 3 0 4 5 6 0 7 8 9 0 0 0 0 0 ``` **第2次** 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图: [![](https://www.malaoshi.top/upload/0/0/1EF56fXCOMb9.png)](https://www.malaoshi.top/upload/0/0/1EF56fXCOMb9.png) 所以新卷积核矩阵的 **第2行值**: ``` 0 1 2 3 0 4 5 6 0 7 8 9 0 0 0 0 ``` **第3次** 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图: [![](https://www.malaoshi.top/upload/0/0/1EF56fXiDSiD.png)](https://www.malaoshi.top/upload/0/0/1EF56fXiDSiD.png) 所以新卷积核矩阵的 **第3行值**: ``` 0 0 0 0 1 2 3 0 4 5 6 0 7 8 9 0 ``` **第4次** 卷积运算(上面矩阵是卷积核,下面矩阵是图像),如下图: [![](https://www.malaoshi.top/upload/0/0/1EF56fZvRxLI.png)](https://www.malaoshi.top/upload/0/0/1EF56fZvRxLI.png) 所以新卷积核矩阵的 **第4行值**: ``` 0 0 0 0 0 1 2 3 0 4 5 6 0 7 8 9 ``` **新卷积核矩阵如下:** [![](https://www.malaoshi.top/upload/0/0/1EF56S5qnrJL.png)](https://www.malaoshi.top/upload/0/0/1EF56S5qnrJL.png) **总结成公式为:** [![](https://www.malaoshi.top/upload/0/0/1EF56SQrWK56.png)](https://www.malaoshi.top/upload/0/0/1EF56SQrWK56.png) ### 矩阵乘法运算 [![](https://www.malaoshi.top/upload/0/0/1EF56eGcUO3t.png)](https://www.malaoshi.top/upload/0/0/1EF56eGcUO3t.png) [![](https://www.malaoshi.top/upload/0/0/1EF56SDbETOZ.png)](https://www.malaoshi.top/upload/0/0/1EF56SDbETOZ.png) 结果大小为: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) ``` 原文出处:http://malaoshi.top/show_1EF56ffEDLaN.html