前言
在卷积网络中,卷积运算的运算量是巨大的,如果使用Naive的for循环来完成卷积运算,真的是很Naive。而另一方面,无论是CPU还是GPU都对矩阵运算有着很好的支持和优化,那么,将卷积运算转化为矩阵运算就能很好的提升性能。
Im2Col - Image To Column
Im2Col将输入"图片"中卷积核扫过的区域转化为列向量输出。经过Im2Col函数处理后,卷积运算就可以转化为卷积核与这些列向量之间的点乘运算。

Im2Col运算过程[1]
Im2Col的算法实现
以单通道,步长为1为例,实现代码如下:
x_pad = np.pad(x, pad, 'constant')
i0 = np.repeat(np.arange(out_height), out_width).reshape(-1,1)
i1 = np.tile(np.arange(filter_height), filter_width)
i = i0 + i1
j0 = np.tile(np.arange(out_width), out_height).reshape(-1,1)
j1 = np.repeat(np.arange(filter_width),filter_height)
j = j0 + j1
cols = x_pad[i, j]
可以通过观察卷积核运动过程中横纵坐标的变化规律
i - 横坐标 <i = i0 + i1>
0 1 2 0 1 2 0 1 2 | < i1
0 1 2 0 1 2 0 1 2 - 第一行卷积扫过的横坐标
0 1 2 0 1 2 0 1 2 |
-------------------
1 2 3 1 2 3 1 2 3 |
1 2 3 1 2 3 1 2 3 - 第二行卷积扫过的横坐标
1 2 3 1 2 3 1 2 3 |
-------------------
2 3 4 2 3 4 2 3 4 |
2 3 4 2 3 4 2 3 4 - 第三行卷积扫过的横坐标
2 3 4 2 3 4 2 3 4 |
^
i0
j - 纵坐标 <j = j0 + j1>
0 0 0 1 1 1 2 2 2 | < j1
1 1 1 2 2 2 3 3 3 - 第一行卷积扫过的纵坐标
2 2 2 3 3 3 4 4 4 |
-------------------
0 0 0 1 1 1 2 2 2 |
1 1 1 2 2 2 3 3 3 - 第二行卷积扫过的纵坐标
2 2 2 3 3 3 4 4 4 |
-------------------
0 0 0 1 1 1 2 2 2 |
1 1 1 2 2 2 3 3 3 - 第三行卷积扫过的纵坐标
2 2 2 3 3 3 4 4 4 |
^
j0
对于步长大于1以及多通道的情况可以在此基础上进一步扩展。
后记
一开始也是尝试了用几层for循环实现卷积运算,效率低的令人发指,使用Im2Col之后,卷积运算速度提升巨大,果然是真香。
参考文献
[1]https://blog.csdn.net/u013498583/article/details/79414225