一个利用低精度和量化技术实现的神经网络压缩与加速方案。 个人认为,这是低精度量化方面少有的具有一定工程可行性的方案(虽然文中没有给出详细的模型大小速度方面的指标)。
文章链接: 《ShiftCNN: Generalized Low-Precision Architecture for Inference of Convolutional Neural Networks》
模型转换示例代码: https://github.com/gudovskiy/ShiftCNN
相关背景
(1) 低精度数据表达
通常神经网络计算使用float32位。 有些人尝试用16bit或者8bit数据,但由于不再能使用现成的一些BLAS库,导致实际部署效率可能和设想相差较多。 另外,像BinaryNet(-1,+1)、ternary quantization(-1,0,+1)等,虽然可以采用移位操作来代替乘法,但往往导致网络性能下降较多。
(2) 卷积计算方式
除了在频率域计算卷积之外,利用矩阵乘法结合BLAS库是采用最多的卷积计算方法。 此外,也有一些采用查表法计算卷积的,但往往受限于码本导致性能不足。
(3) 最优量化
量化可以看作用离散码本描述样本分布。 优化目标(最大概率准则)和优化方法(L1和L2正则化)通常导致了神经网络参数呈现中心对称的非均匀分布。 因此,一个最佳的量化码本应当是一个非均匀分布的码本。 这也是为什么BinaryNet(-1,+1)、ternary quantization(-1,0,+1)这种策略性能不足的一个重要原因。
量化
ShiftCNN所采用是一种相当巧妙的类似于残差量化的方法。
完整的码本包含 \(N\) 个子码本。 每个码本包含 \(M=2^{B}-1\) 个码字,即每一个码字可以用 \(B\ bit\) 表示。
每个码本定义如下:
\(C_n = {0, \pm2^{-n+1},\pm2^{-n},…,\pm2^{-n-\lfloor M/2 \rfloor + 2}}\)
假设 \(N = 2,B=4\),则码本为
\(C_1 = {0,\pm2^{-1},\pm2^{-2},\pm2^{-3},\pm2^{-4},\pm2^{-5},\pm2^{-6}}\)
\(C_2 ={0,\pm2^{-2},\pm2^{-3},\pm2^{-4},\pm2^{-5},\pm2^{-6}},\pm2^{-7}\)
于是,每一个权重都可以使用 \(NB\ bit\) 的索引通过下式求和计算得到:
\(\hat{w_i}=\sum_{n=1}^{N}C_n[idx_i(n)]\)
整个对参数进行量化的流程如下:
需要注意的是,量化之前需要对参数进行范围归一化,即除以最大值的绝对值,这样保证参数的绝对值都小于1。
该量化方法具有码本小、量化简单、量化误差小的优点。
卷积计算
卷积计算的复杂度主要来自乘法计算。 ShiftCNN采用简单的移位和加法来实现乘法,从而减少计算量。
比如计算 \(y = wx\), 而 \(w\) 通过量化已经被我们表示成了类似于 \(2^{-1}+2^{-2}+2^{-3}\) 这种形式,于是 \(y = x>>1 + x>>2+x>>3\)。
应该注意到,尽管\(N\) 个子码本,每个码本都包含 \(M=2^{B}-1\) 个码字,但其实只有 \(P=M+2(N-1)\) 个不同的码字。
因此,本文的卷积的核心是对输入数据进行预计算,因为移位的情况有限。 假设输入纬度为 \(C\times H\times W\), 则我们可以提前计算所有可能的移位情况,得到 \((P-1)\times C\times H\times W\)。 这里减1是因为忽略码字为0的情况。
整个卷积的计算如下所示:其核心为一个移位单元以及一个累加单元。
其中累加单元如下:(主要是逻辑控制与求和)
实验
ShiftCNN量化后无需再训练。 个人觉得再训练应该会更好一点。
理论复杂度就不说了,没意思。虽然我预估计算量依然比较大。 文章还给出了一部分FPGA上的实验,但我其实最想看的是更多的横向对比,比如在PC或者Android设备上的速度对比之类的。