Skip to content

Latest commit

 

History

History
77 lines (43 loc) · 6.84 KB

File metadata and controls

77 lines (43 loc) · 6.84 KB

separable convolutions in image processing

引言

在计算机图像处理中,有一种经常进行的操作,就是图像滤波,也叫图像卷积(深度学习中的卷积概念也是衍生于它,只不过深度学习中的卷积核是三维的,图像处理中的卷积核是二维的),比如用Canny卷积提取图像中的边缘信息,用Gaussian卷积构造金字塔等等。在深度学习中,深度可分离卷积(Depth-wise Separable Convolution)取代传统卷积,可以起到加速(减少计算量)和减小模型大小(参数数量)的作用;类似地,在图像处理中,往往也可以用两个独立的小的卷积串联,取代一个大的卷积,也可以起到减少计算量和减小参数数量的作用。

**请注意,本文所用的术语“卷积convolution”并不是很恰当,恰当的称呼应该叫“滤波filter”或者“空间相关”,卷积的话卷积核要旋转180度。**但太多情况下并不区分这两者,这里将错就错称之为“卷积”,但这并不影响我们的结论。

欢迎探讨,本文持续维护。

实验平台:

  • 操作系统:Ubuntu 16.04 LTS,Ubuntu 18.04 LTS

  • 编译器:g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609

        gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609

1,二维Gaussian卷积核的可分离性分析

  • 推导过程:

可以从上图推导过程中看出,一个m行乘以n列的高斯卷积可以分解成一个1行乘以n列的行卷积,之后串联一个m行乘以1列的列卷积的形式,输出保持不变。行卷积的卷积核参数(均值和方差)等于原始m行n列卷积核在列方向(Y方向)的均值和方差,列卷积的卷积核参数等于原始m行n列卷积核在行方向(X方向)上的均值和方差。

  • 计算量分析:

原始卷积的mxn的卷积和,卷积一个图像,乘加次数等于图像的像素个数WxH,乘以以单个像素为中心店做卷积时卷积的乘加次数mxn,总次数等于MxHxmxn。

在把原始卷积拆分为行卷积和列卷积后,行卷积的乘加次数等于输入图像的像素点个数WxH,乘以单个行卷积的乘加次数n,列卷积的乘加次数等于上一步行卷积输出图像的像素点个数WxH,乘以单个列卷积的乘加次数m,所以,总的次数是WxHxn+WxHxm。

由此可见,将卷积分离后的计算量比原始计算量等于(m+n)/(mxn),常见的宽高相等,假设为k,则计算量的比可以简化为2/k。**计算复杂度从原来的O(k^2)将为了O(k)。**是一个很大的提速。

  • 参数数量分析:

原始卷积的参数数量为mxn个,卷积拆分后的参数数量为n+m。考虑到高斯核的对称性,这个数还略有冗余。

2,二维Gaussian卷积核的可分离代码实测

代码都放在code/目录下,都是按照高斯函数的定义写的,不过假设了卷积核是11x11的正方形框,x和y方向的方差都一样。

速度实测如下:

取kernalsize=11, sigma=0.8,处理一副490x490的彩色图像,传统高斯滤波耗时498200us,卷积核分离之后滤波,耗时114679us。加速比为4.3443:1,和理论值(k^2)/(2k)=11:2=5.5:1稍微差一点。卷积核的size越大,加速效果越明显

3,理论推广,什么样的核才可分离

上面已经在理论和实测中证明了高斯核的可分离性和加速效果。那么就有个很自然的问题,除了高斯核,还有哪些核也是可分离的,核的可分离性的充分必要条件是什么,弄清楚了这些问题,我们就可以在碰到新核的时候考虑一下它是否可用可分离性加速,或者我们自己设计新的满足可分离性的核。

先说结论,一个卷积核K,如果可以表达成一个水平核h和一个竖直核v相乘的形式,即K=v*transpose(h)那么K就是可以分离的;反之,一个卷积核是可分离的,那么必然可以分解成一个水平核h和一个竖直核v相乘的形式。

证明如下(这里只以K=v*transpose(h)的形式证明充分性,必要性反推即可):

所以,我们按照这个思路,可以发现,除了高斯卷积可以分离,方框卷积、双线性卷积、高斯二阶导数卷积,也是可以分离的。

4,理论再推广,把不能分离的核做近似分离

毕竟,不是每个核K都一定是可以分解成一个水平核和一个竖直核相乘的形式的。不过我们可以把核看成一个mxn的矩阵,对其进行奇异值分解,就可以得到一些水平核和一些竖直核相乘再累加的形式K=sum(sigma_i*u_i*transpose(v_i))。这里面的sqrt(sigma_i)*u_i和sqrt(sigma_i)*v_i就是每一组的水平和竖直的卷积核。组数取得越多,计算的结果越和原始K卷积的结果相近,但是计算量也会增加;组数取得越少,计算的结果越和原始卷积结果相远,但是速度也越快。

这种分离方式加速的多少和原卷积核效果近似的程度,取决于a. 原始核K的size大小,1节已经证明了卷积核分离算法的加速情况,原始核K的size越大,加速比越大;b. 原始核K的奇异值分解得到的奇异值数量和分布,分解得到的奇异值的绝对值如果都集中在头部,那么可以忽略很多不重要的奇异值,那么加速效果好,质量损失小(其实可分离性,是奇异值分解的一个特例,如果奇异值分解后得到的奇异值,除了一个不为0,其他都为0,那就是前面几节讨论到的可分离);c. 加速效果还和具体的实现有关,比如内存的访问,cache等等。

总结

把一个大卷积操作分解为一个水平卷积串联一个竖直卷积的过程叫卷积可分离,卷积可分离是图像处理中一个常见的优化手法,其效果和原始卷积相同,但是计算量是原始卷积计算量的2k/k^2,卷积核越大,计算量下降越明显。

卷积核只是一个矩阵,对这个矩阵做奇异值分解,如果有且仅有一个不为零的奇异值,那么它就是可以分离的;如果还有其它的奇异值,那么它就是可近似分离的,分离的效果取决于奇异值的分布。

最后值得一提的是,这种将一个大卷积分解成多个小卷积的串联来减小计算量和内存消耗的思路,在深度学习的研究中,也有很大的影响。

参考资料