郝泽宇作者

超全总结:神经网络加速之量化模型 | 附带代码

量化模型(Quantized Model)是一种模型加速(Model Acceleration)方法的总称,包括二值化网络(Binary Network)、三值化网络(Ternary Network),深度压缩(Deep Compression)等。鉴于网上关于量化模型的不多,而且比较零散,本文将结合 TensorLayer 来讲解各类量化模型,并讨论一下我们过去遇到的各种坑。文章最后会介绍一些关于人工智能芯片的技术。 

TensorLayer 是一个基于 TensorFlow 的高级开发工具,提供大量数据处理和建模 API,具备灵活性高、运行速度快等优点。今年 3 月,TensorLayer 提供了一套搭建量化网络的试验版本 API,不过目前这套 API 依然用矩阵乘法而不是加减或 bitcount 运算来加速(我们等会会提到)。

因此,这套 API 并不能加速,关于产品部署,目前可以用 TensorLayer 训练模型,然后用自定义的 C/C++ 实现的二值化计算(TensorLayer 有可能会提供一套额外的专门运行二值化网络的框架,并支持可以从 TensorLayer 那读取模型)。

注意,作为试验版本,这套 API 有可能会被修改。更多关于模型加速的技术,可关注:https://github.com/tensorlayer/tensorlayer/issues/416 

Keywords:模型压缩(Model Compression),模型加速(Model Acceleration),二值化网络(Binary Network),量化模型(Quantized Model)

随着神经网络深度增加,网络节点变得越来越多,规模随之变得非常大,这是对移动硬件设备非常不友好的,所以想要在有限资源的硬件设备上布置性能良好的网络,就需要对网络模型进行压缩和加速,其中量化模型由于在硬件上移植会非常方便,在理论上来讲,是非常有发展潜力的。

比较有名气的量化模型有 Deepcompression,Binary-Net,Tenary-Net,Dorefa-Net,下面对这几种量化模型进行介绍。

DeepCompression

SongHan 这篇文章可以说是神经网络压缩领域开山之作,怎么说呢这篇文章很早就注意到了,也复现了,做了很多实验。也一直想用到硬件参数压缩以及模型加速当中,在这个过程中遇到了很多问题,现在提出来跟大家一起探讨。

算法整体框架如图:

DeepCompression 主要分为三个主要的部分:剪枝,量化,哈夫曼编码,下面分别探讨这几种方法并且分析他们在硬件前向配置的加速潜力。

剪枝(purning):其实这个思路的核心非常简单,就是当网络收敛到一定程度的时候,作者认为阈值小于一定权重权重对网络作用很小,那么这些权重就被无情的抛弃了。注意,是抛弃,彻底抛弃,在复现的时候这个地方是一个大坑,被剪掉的权重不会再接收任何梯度。

然后下面的套路简单了,就是很简单的将网络 reload,然后重新训练至收敛。重复这个过程,直到网络参数变成一个高度稀疏的矩阵。这个过程最难受的就是调参了,由于小的参数会不断被剪枝,为了持续增大压缩率,阈值必须不断增大,那么剩下的就看你的调参大法 6 不 6 了。

当初为了解决这个问题还专门设计了一个基于准确率损失和压缩率上升的公式,用于压缩。算是效果还可以,自己调参真的很难受。

最后参数会变成一个稀疏的矩阵,作者自己提出了一种编码方式:

当压缩率低于一定的值时,编码解码开销其实是非常大的,甚至到一定范围,编码后的存储量甚至大于不压缩。

第二个就是量化了,将接近的值变成一个数。大概的思路如下:

需要注意的是,量化其实是一种权值共享的策略。量化后的权值张量是一个高度稀疏的有很多共享权值的矩阵,对非零参数,我们还可以进行定点压缩,以获得更高的压缩率。 

论文的最后一步是使用哈夫曼编码进行权值的压缩,其实如果将权值使用哈夫曼编码进行编码,解码的代价其实是非常大的,尤其是时间代价。还需要注意的是,DeepCompression 中对于输出没有压缩。所以这种方案对于硬件加速的主要作用体现在遇到 0 即可 zero skip,即使用判断语句替代乘法器。

Binary-Net

  • Quantized Neural Networks: Training Neural Networks with Low Precision Weights and Activations

  • Binarized Neural Networks: Training Deep Neural Networks with Weights and Activations Constrained to +1 or -1

  • XNOR-Net: ImageNet Classification Using Binary Convolutional Neural Networks

通常我们在构建神经网络模型中使用的精度都是 32 位单精度浮点数,在网络模型规模较大的时候,需要的内存资源就会非常巨大,而浮点数是由一位符号位,八位指数位和尾数位三个部分构成的。完成浮点加减运算的操作过程大体分为四步: 

1. 0 操作数的检查,即若至少有一个参与运算的数为零直接可得到结果;

2. 比较阶码大小并完成对阶; 

3. 尾数进行加或减运算; 

4. 结果规格化并进行舍入处理。 

带来的问题是网络在运行过程中不仅需要大量的内存还需要大量的计算资源,那么 quantization 的优越性就体现出来了,在 2016 年发表在 NIPS 的文章 Binarized Neural Networks: Training Deep Neural Networks with Weights and Activations Constrained to +1 or -1 中,提出了利用降低权重和输出的精度的方法来加速模型,因为这样会大幅的降低网络的内存大小和访问次数,并用 bit-wise operator 代替 arithmetic operator。

下面具体介绍一下这种方法的原理,在训练 BNN 时,将权重和输出置为 1 或 -1,下面是两种二值化的方法: 

第一种直接将大于等于零的参数置为 1,小于 0 的置为 -1;

第二种将绝对值大于 1 的参数置为 1,将绝对值小于 1 的参数根据距离 ±1 的远近按概率随机置为 ±1。

公式中是一个 clip 函数:

第二种二值化方式看起来更为合理,但是由于引入了按概率分布的随机一比特数,所以硬件实现会消耗很多时间,我们通常使用第一种量化方法来对权重和输出进行量化。

虽然 BNN 的参数和各层的输出是二值化的,但梯度不得不用较高精度的实数而不是二值进行存储。因为梯度很小,所以使用无法使用低精度来正确表达梯度,同时梯度是有高斯白噪声的,累加梯度才能抵消噪声。 

另一方面,二值化相当于给权重和输出值添加了噪声,而这样的噪声具有正则化作用,可以防止模型过拟合。所以,二值化也可以被看做是 Dropout 的一种变形,Dropout 是将输出按概率置 0,从而造成一定的稀疏性,而二值化将权重也进行了稀疏,所以更加能够防止过拟合。 

由于 sign 函数的导数在非零处都是 0,所以,在梯度回传时使用 tanh 来代替 sign 进行求导。假设 loss function 是 C,input 是 r,对 r 做二值化有:

C 对 q 的的导数使用 gq 表示,那么 q 对 r 的导数就变成了:

这样就可以进行梯度回传,给出一种包含 bn 的二值化网络的梯度算法:

BN 最大的作用就是加速学习,减少权重尺度影响,带来一定量的正则化,可以提高网络性能,但是,BN 涉及很多矩阵运算(matrix multiplication),会降低运算速度,因此,提出了一种 shift-based Batch Normalization。 

使用 SBN 来替换传统的 BN,SBN 最大的优势就是几乎不需要进行矩阵运算,而且还不会对性能带来损失。基于 SBN,又提出 Shift based AdaMax:

网络除了输入以外,全部都是二值化的,所以需要对第一层进行处理:

作者还对二值化网络扩展到 n-bit quantized:

二值化的论文对 mnist、cifar-10、SVHN 进行了测试,最后得到的 test error 如下:

完了作者为了挑战高难度,又用了 alexnet 和 googlenet 在 imagenet 上做了测试,看出来结果也是一般,所以较复杂的网络较大的数据集采用 bnn 看来影响还是蛮大的。

作者不服气又提出了一些小技巧,比如什么放宽 tanh 的边界啊,用 2-bit 的 activitions,也提升了一些准确率,作者也在 rnn 做 language task 上进行了二值化,结果也贴出来,分析了那么多模型,应该可以说在牺牲那么多运算和储存资源的情况下准确率差强人意。

x = tf.placeholder(tf.float32, shape=[batch_size, 28, 28, 1])
net = tl.layers.InputLayer(x, name='input')
net = tl.layers.BinaryConv2d(net, 32, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn1')
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool1')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn1')

net = tl.layers.SignLayer(net)
net = tl.layers.BinaryConv2d(net, 64, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn2')
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool2')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn2')

net = tl.layers.FlattenLayer(net)

net = tl.layers.SignLayer(net)
net = tl.layers.BinaryDenseLayer(net, 256, b_init=None, name='dense')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn3')

net = tl.layers.SignLayer(net)
net = tl.layers.BinaryDenseLayer(net, 10, b_init=None, name='bout')
net = tl.layers.BatchNormLayer(net, is_train=is_train, name='bno')

上面是给 MNIST 设计的一个 BinaryNet。 

作者最后又分析了一下时间复杂度和功率效率,毕竟 bnn 的主要任务就是压缩和加速,说了时间复杂度可以降低 60%,原理是说可以卷积核复用。

举个例子,因为一个 3 x 3 的卷积核做了二值以后,只有 2 的 9 次方个独一的卷积核,相比于没有二值化的卷积核,在文章中的 cifar-10 网络中独一的卷积核数量只有 42% 那么多。

内存资源减少了 31/32(原本每个参数 32bit,压缩后每个参数 1bit),运算资源,硬件层面上看 32bits 损耗 200 个位,1bit 只损耗一个位(bit-wise operation)。

最后在 gpu 上还可以进行 SWAR(single instruction,multiple data within register)的处理,对 xnor 进行优化,SWAR 的基本思想是将 32 个二进制变量组连接成 32 位寄存器,从而在按位操作(例如 XNOR)上获得 32 倍的加速。 

使用 SWAR,可以仅用 3 条指令评估 32 个连接:

就可以用 1(加和)+4(popcount,四个 8 位)+1(xnor)个 time cycle 来进行运算,原来的,则是 32 个 time cycle,提高了 32/6 倍的速度。

Xnor-Net 在 BNN 的基础上引入了比例因子,让二值化之后的参数和原始的参数的 L2 范数最小,提高了模型的精度。

对卷积操作的比例因子进行简化,降低了其运算复杂度。

由于在一般网络下,一层卷积的 kernel 规格是固定的,kernel 和 input 在进行卷积的时候,input 会有重叠的地方,所以在进行量化因子的运算时,先对 input 全部在 channel 维求平均,得到的矩阵 A,再和一个 w x h 的卷积核 k 进行卷积得到比例因子矩阵 K,其中:

在 imagenet 上结果也比 bnn 要好很多。

Ternary-Net

  • Ternary Weight Networks paper 

权值三值化的核心: 

首先,认为多权值相对比于二值化具有更好的网络泛化能力。其次,认为权值的分布接近于一个正态分布和一个均匀分布的组合。最后,使用一个 scale 参数去最小化三值化前的权值和三值化之后的权值的 L2 距离。 

基本原理阐述如下: 

参数三值化的方式如下:

其实就是简单的选取一个阈值(Δ),大于这个阈值的权值变成 1,小于-阈值的权值变成 -1,其他变成 0。当然这个阈值其实是根据权值的分布的先验知识算出来的。本文最核心的部分其实就是阈值和 scale 参数 alpha 的推导过程

参数三值化之后,作者使用了一个 scale 参数去让三值化之后的参数更接近于三值化之前的参数。具体的描述如下:

利用此公式推导出 alpha 的值如下:

由此推得阈值的计算公式如下:

由于这个式子需要迭代才能得到解,会造成训练速度过慢的问题,所以如果可以提前预测权值的分布,就可以通过权值分布大大减少阈值计算的计算量。文中推导了正态分布和平均分布两种情况,并按照权值分布是正态分布和平均分布组合的先验知识提出了计算阈值的经验公式。

三值化论文的最终结果如下:

反正就是抓住 BNN 一顿 diss 呗,谁让人家准确率高呢。

当然,这种方法有进化版本,我们完全可以将权值组合变成(-2,-1,0,1,2)的组合,以期获得更高的准确率。正好我之前也推过相关的公式,现在贴出来供大家参考,这个时候权值的离散化公式变成了:

Scale 参数的计算公式变成了:

此时阈值的计算公式变成了:

需要声明的是,这个算法我只在一个非常不知名的 matlab 的一个纯 cpu 版本慢到爆炸反正就是难以忍受那种框架上面实际实现过,取得了比三值化更高的准确率,但是!对于这个算法在 tensorflow 上面的实现我真是一筹莫展,因为 tensorflow 某些机制……算法的具体实现方式如下:

net = tl.layers.InputLayer(x, name='input')
net = tl.layers.TernaryConv2d(net, 32, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn1')
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool1')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn1')
net = tl.layers.TernaryConv2d(net, 64, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn2')
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool2')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn2')

net = tl.layers.FlattenLayer(net)
net = tl.layers.TernaryDenseLayer(net, 256, b_init=None, name='dense')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn3')
net = tl.layers.TernaryDenseLayer(net, 10, b_init=None, name='bout')
net = tl.layers.BatchNormLayer(net, is_train=is_train, name='bno')
return net

上面是 TensorLayer 提供的三值化的 MNIST 测试代码。

权值三值化并没有完全消除乘法器,在实际前向运算的时候,它需要给每一个输出乘以一个 scale 参数,然后这个时候的权值是(-1,0,1),以此来减少了乘法器的数目,至于为什么减少跟 BNN 是一样的道理。

DoReFa-Net

  • DoReFa-Net: Training Low Bitwidth Convolutional Neural Networks with Low Bitwidth Gradients 

Face++ 团队在 16 年 6 月提出的 Dorefa-Net 和上面两种量化方法思路也是比较接近,但 DoReLa-Net 对比例因子的设计更为简单,这里并没有针对卷积层输出的每一个过滤映射计算比例因子,而是对卷积层的整体输出计算一个均值常量作为比例因子。这样的做法可以简化反向运算,因为在他们反向计算时也要实现量化。 

文章首先概述如何利用 DoReFa-Net 中的比特卷积内核,然后详细说明量化权值,激活和梯度以低比特数的方法。 

和之前 BNN 的点积方法一样,DoReFa 也采用了这种简化的点积方式。

对于定点数 x 和 y,可以得到下面的公式:

同样为了规避 0 梯度的问题,采用了直通估计(STE):

对于权重二值化的梯度回传,采用下面的方法,即二值化乘比例因子,回传时直接跳过二值化。

比特数 k 大于 1 的梯度回传,需要先对参数 clip 到 [0,1] 之间:

由于二值化输出会降准确率,所以采用 k-bit 量化(k>1),这里的 r 也要经过 clip。

DoReFa 的梯度量化方法比较复杂,因为梯度是无界的,并且可能具有比隐层输出更大的值范围。我们可以通过使可微分非线性函数传递值来将隐层输出范围映射到 [0,1]。 但是,这种构造不适用于渐变。 文章设计了以下用于梯度 k 位量化的函数,这里 dr 是 r 对损失函数 C 的偏导。

为了补偿量化梯度带来的潜在偏差,在 clip 后的结果增加了一个高斯噪声

梯度的量化仅在回程中完成,因此文章在每个卷积层的输出上应用以下 STE:

最终得到了 DoReFa-net 的算法,这里对第一层和最后一层不做量化,因为输入层就图像任务来说通常是 8-bit 的数据,做低比特量化会对精度造成很大的影响,输出层一般是一些 one-hot 向量,所以一般对输出层也保持原样,除非做特殊的声明。

DoReFa-net 为了进一步节省资源将 3,4,6 步放在一起做,将 11,12 步融合在一起,节省了中间步骤的全精度数储存消耗的资源。

DoReFa-Net 分别对 SVHN 和 ImageNet 进行了实验,准确率如下:

net = tl.layers.InputLayer(x, name='input')
net = tl.layers.DorefaConv2d(net, 1, 3, 32, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn1')  #pylint: disable=bare-except
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool1')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn1')
net = tl.layers.DorefaConv2d(net, 1, 3, 64, (5, 5), (1, 1), padding='SAME', b_init=None, name='bcnn2')  #pylint: disable=bare-except
net = tl.layers.MaxPool2d(net, (2, 2), (2, 2), padding='SAME', name='pool2')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn2')

net = tl.layers.FlattenLayer(net)
net = tl.layers.DorefaDenseLayer(net, 1, 3, 256, b_init=None, name='dense')
net = tl.layers.BatchNormLayer(net, act=tl.act.htanh, is_train=is_train, name='bn3')
net = tl.layers.DenseLayer(net, 10, b_init=None, name='bout')
net = tl.layers.BatchNormLayer(net, is_train=is_train, name='bno')

上面是 TensorLayer 提供的 DoReFa-Net 的 MNIST测试代码,需要注意的是不同于DoReFa-Net,我们的实现默认梯度为 32bits 来尽量获得更高的训练准确率,而且在实际的硬件前向配置中其实是不需要梯度信息的。

压缩算法局限性

目前的压缩算法是存在一些局限性的,最主要的问题还是准确率,论文中为了数据好看往往是选择传统的神经网络结构比如 AlexNet,VGG 作为测试对象,而这种网络一般是比较冗余的。

如果想把参数压缩方案和其他一些方案结合,比如说下面讲到的一些 SqueezeNet,MobileNets,ShuffleNet 结合起来,会对准确率造成比较大的影响。原因可以归为参数压缩算法其实是一个找次优解的问题,当网络冗余度越小,解越不好找。所以,目前的高精度压缩算法只适合于传统的有很多冗余的网络

更多加速方法

理论上来讲,量化模型是通往高速神经网络最佳的方法,不过由于种种问题,如实现难度大、准确性不稳定,使用门槛非常大,所以除了量化模型外,目前有很多更加常用的模型加速方法: 

  • A Survey of Model Compression and Acceleration for Deep Neural Networks (end of 2017) 

这是 2017 年底的一篇 survey。

有基于 Pruning 的:

  • Channel Pruning for Accelerating Very Deep Neural Network

也有基于改变卷积方式的,这是目前最常用的方法:

  • SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size 

  • MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications 

  • ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices 

传送门:纵览轻量化卷积神经网络:SqueezeNet、MobileNet、ShuffleNet、Xception

值得注意的是,当 TensorLayer 和 Keras 使用完全相同的 MobileNet 时,TensorLayer 的速度是后者的 3 倍(Titan XP 上测试),大家可以试试。

关于AI芯片

关于硬件实现,这里要推荐一篇非常好的survey:

http://www.rle.mit.edu/eems/wp-content/uploads/2017/11/2017_pieee_dnn.pdf

大家看完这篇文章会对目前最先进的神经网络硬件加速架构有所了解。

由于目前基于 PC 平台的神经网络加速一定程度上不能满足需要,开发基于硬件例如 FPGA 的硬件加速平台显得很有必要。其实硬件加速神经网络前向运算的最主要的任务就是完成卷积优化,减少卷积运算的资源和能源消耗非常核心

卷积优化的主要思路

内存换取时间:如果深度学习中每一层的卷积都是针对同一张图片,那么所有的卷积核可以一起对这张图片进行卷积运算,然后再分别存储到不同的位置,这就可以增加内存的使用率,一次加载图片,产生多次的数据,而不需要多次访问图片,这就是用内存来换时间。

乘法优化:以下图为例,上面是两张图片,右边是卷积核。我们可以把卷积核心展开成一条行,然后多个卷积核就可以排列成多行,再把图像也用类似的方法展开,就可以把一个卷积问题转换成乘法问题。这样就是一行乘以一列,就是一个结果了。这样虽然多做了一些展开的操作,但是对于计算来讲,速度会提升很多。

GPU优化:

1. 了解 IO 访问的情况以及 IO 的性能; 

2. 多线程的并行计算特性; 

3. IO 和并行计算间的计算时间重叠。

对于 NVIDIA 的 GPU 来讲,内存访问是有一些特性的,连续合并访问可以很好地利用硬件的带宽。你可以看到,NVIDIA 最新架构的 GPU,其核心数目可能并没有明显增加,架构似乎也没有太大变化,但在几个计算流处理器中间增加缓存,就提高了很大的性能,为 IO 访问这块儿带来了很大优化。 

Strassen 算法

分析 CNN 的线性代数特性,增加加法减少乘法,这样降低了卷积运算的计算的复杂度,但是这种方法不适合在硬件里面使用,这里就不做详细的介绍了。 

卷积中的数据重用

在软件中的卷积运算,其实我们是在不断的读取数据,进行数据计算。也就是说卷积操作中数据的存取其实是一个很大的浪费,卷积操作中数据的重用如下图所示:

那么想办法减少数据的重用,减少数据的存取成为解决卷积计算问题的一个很重要的方面。

目前这样的方法有很多种,最主要的方法包括以下几种: 

权重固定:最小化权重读取的消耗,最大化卷积和卷积核权重的重复使用; 

输出固定:最小化部分和 R/W 能量消耗,最大化本地积累; 

NLR (No Local Reuse):使用大型全局缓冲区共享存储,减少 DRAM 访问能耗; 

RS:在内部的寄存器中最大化重用和累加,针对整体能源效率进行优化,而不是只针对某种数据类型。 

下表是在 45NM CMOS 的基础上对于不同的操作的能耗进行的统计。对 32 位的各种操作的能耗进行统计,可以看到从 DRAM 里面存取数据的能量消耗是最大的。是 32 位整型数据进行加法的能量消耗的 6400 倍。那么,从数据存取角度考虑卷积的优化就显得尤为必要了。

可行性分析

在进行设计之前先对设计的可行性进行分析,分析过程包括卷积运算可实现性分析、卷积运算并行性分析,卷积的计算公式可以表示成下面的形式:

各个参数的意义在表内详细表示:

在 GPU 中加速时,主要通过将数据最大程度的并行运算,增加了 GPU 的使用率从而加快了速度。但是这种方法在硬件实现的时候是不可行的,因为这种方法本质上没有降低能耗,而 DNN 模型的高能耗和大量的数据是其在可穿戴设备上面进行部署所需要面对的困难。 

下面对一个卷积部分和运算进行分析,如下图 : 

对第一组的 PE 整列,输入的是从 Image 的第 0 行到第 R-1 行的 S 列的数据,同样的对于第二列的 PE 阵列输入的是第 2 行到第 R 的 S 列的数据。每一列的 PE 计算得到一个最终的 Psum 的结果,那么如果设置 PE 阵列的列数为 N 的话,每次我们就可以计算得到连续的 N 个部分和的结果。 

不断更新 PE(process element,即处理单元)中 Image 缓冲区的数据,就可以模拟卷积在水平方向上面的滑动,不断更新整个 PE 阵列的数据输入,就可以模拟卷积窗在垂直方向上面的滑动,最终完成整个卷积运算的实现。

对应的卷积运算公式的细节在图中已经给出了,每一组 PE 产生一个部分和的结果的话,那么增加 PE 阵列的组数,就可以一次性产生多个部分和计算结果,这里的组数就是并行度。 

上面的内容简单论证用数据重用的方式实现卷积运算的可行性,至于实现的具体数据流,还有相对用的系统的架构。

压缩算法在实际硬件芯片的应用

其实压缩算法应用硬件芯片非常简单,就是简单的将硬件芯片原来使用的乘法器进行替换,如果是 BNN,参数只有两种情形,那么如果参数为 1 的时候,直接通过,不计算,如果参数为 -1 的时候,翻转最高位即可。 

同理三值化中增加了一个 0 参数,这个可以直接跳过不进行计算。至于参数为(-2,-1,0,1,2)的情形,参数为 2 时就增加了一个移位运算,参数为 -2 的时候增加了一个最高位的翻转。 

如果是 DoReFaNet,权值和输出都固定在一定的种类内部,那么他们的乘积情形也只有一定的种类,这个时候相当于把乘法器变成了一个寻址操作,每次乘法只需要在 LUT(look-up table,查找表)里面寻找到正确的结果读出即可。

PaperWeekly
PaperWeekly

推荐、解读、讨论和报道人工智能前沿论文成果的学术平台。

入门先验知识量化模型深度学习神经网络
82
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

范数技术

范数(norm),是具有“长度”概念的函数。在线性代数、泛函分析及相关的数学领域,是一个函数,其为向量空间内的所有向量赋予非零的正长度或大小。半范数反而可以为非零的向量赋予零长度。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

时间复杂度技术

在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。这是一个代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。例如,如果一个算法对于任何大小为 n (必须比 n0 大)的输入,它至多需要 5n3 + 3n 的时间运行完毕,那么它的渐近时间复杂度是 O(n3)。

剪枝技术

剪枝顾名思义,就是删去一些不重要的节点,来减小计算或搜索的复杂度。剪枝在很多算法中都有很好的应用,如:决策树,神经网络,搜索算法,数据库的设计等。在决策树和神经网络中,剪枝可以有效缓解过拟合问题并减小计算复杂度;在搜索算法中,可以减小搜索范围,提高搜索效率。

收敛技术

在数学,计算机科学和逻辑学中,收敛指的是不同的变换序列在有限的时间内达到一个结论(变换终止),并且得出的结论是独立于达到它的路径(他们是融合的)。 通俗来说,收敛通常是指在训练期间达到的一种状态,即经过一定次数的迭代之后,训练损失和验证损失在每次迭代中的变化都非常小或根本没有变化。也就是说,如果采用当前数据进行额外的训练将无法改进模型,模型即达到收敛状态。在深度学习中,损失值有时会在最终下降之前的多次迭代中保持不变或几乎保持不变,暂时形成收敛的假象。

损失函数技术

在数学优化,统计学,计量经济学,决策理论,机器学习和计算神经科学等领域,损失函数或成本函数是将一或多个变量的一个事件或值映射为可以直观地表示某种与之相关“成本”的实数的函数。

张量技术

张量是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。其坐标在 维空间内,有 个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。称为该张量的秩或阶(与矩阵的秩和阶均无关系)。 在数学里,张量是一种几何实体,或者说广义上的“数量”。张量概念包括标量、矢量和线性算子。张量可以用坐标系统来表达,记作标量的数组,但它是定义为“不依赖于参照系的选择的”。张量在物理和工程学中很重要。例如在扩散张量成像中,表达器官对于水的在各个方向的微分透性的张量可以用来产生大脑的扫描图。工程上最重要的例子可能就是应力张量和应变张量了,它们都是二阶张量,对于一般线性材料他们之间的关系由一个四阶弹性张量来决定。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

准确率技术

分类模型的正确预测所占的比例。在多类别分类中,准确率的定义为:正确的预测数/样本总数。 在二元分类中,准确率的定义为:(真正例数+真负例数)/样本总数

映射技术

映射指的是具有某种特殊结构的函数,或泛指类函数思想的范畴论中的态射。 逻辑和图论中也有一些不太常规的用法。其数学定义为:两个非空集合A与B间存在着对应关系f,而且对于A中的每一个元素x,B中总有有唯一的一个元素y与它对应,就这种对应为从A到B的映射,记作f:A→B。其中,y称为元素x在映射f下的象,记作:y=f(x)。x称为y关于映射f的原象*。*集合A中所有元素的象的集合称为映射f的值域,记作f(A)。同样的,在机器学习中,映射就是输入与输出之间的对应关系。

先验知识技术

先验(apriori ;也译作 先天)在拉丁文中指“来自先前的东西”,或稍稍引申指“在经验之前”。近代西方传统中,认为先验指无需经验或先于经验获得的知识。先验知识不依赖于经验,比如,数学式子2+2=4;恒真命题“所有的单身汉一定没有结婚”;以及来自纯粹理性的推断“本体论证明”

Alex网络技术

AlexNet是一个卷积神经网络的名字,最初是与CUDA一起使用GPU支持运行的,AlexNet是2012年ImageNet竞赛冠军获得者Alex Krizhevsky设计的。该网络达错误率大大减小了15.3%,比亚军高出10.8个百分点。AlexNet是由SuperVision组设计的,由Alex Krizhevsky, Geoffrey Hinton和Ilya Sutskever组成。

分类问题技术

分类问题是数据挖掘处理的一个重要组成部分,在机器学习领域,分类问题通常被认为属于监督式学习(supervised learning),也就是说,分类问题的目标是根据已知样本的某些特征,判断一个新的样本属于哪种已知的样本类。根据类别的数量还可以进一步将分类问题划分为二元分类(binary classification)和多元分类(multiclass classification)。

规范化技术

规范化:将属性数据按比例缩放,使之落入一个小的特定区间,如-1.0 到1.0 或0.0 到1.0。 通过将属性数据按比例缩放,使之落入一个小的特定区间,如0.0到1.0,对属性规范化。对于距离度量分类算法,如涉及神经网络或诸如最临近分类和聚类的分类算法,规范化特别有用。如果使用神经网络后向传播算法进行分类挖掘,对于训练样本属性输入值规范化将有助于加快学习阶段的速度。对于基于距离的方法,规范化可以帮助防止具有较大初始值域的属性与具有较小初始值域的属相相比,权重过大。有许多数据规范化的方法,包括最小-最大规范化、z-score规范化和按小数定标规范化。

过拟合技术

过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是分类器设计中的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价。

关于stochastic binarization 的有点错误。 对公式理解有问题。并不是当x绝对值大于1 时就取1。公式是hard-sigmoid函数,当x大于0时,取1的概率大,取-1的概率小。当x小于0时,取1的概率小,取-1的概率大。 另外下面的公式也打错了。。。。min()函数里面是(1,(x+1)/2)这两项。漏了一项
另外对sign函数求导也不是转化成对tanh求导吧。f(x)=tanh(x) -> f(x)' = 1-(f(x))^2 。 论文中sign函数的导数含义是当|r|大于1时就舍弃,|r|《=1 时保留原来的值。