模型优化与tensorflow

模型优化与tensorflow

 

 

模型优化方法介绍

 

神经网络的要求:小、准、快

小:要求网络权重存储空间小

准:准确率高

快:计算量小

目前有四种方法达到这种要求;裁剪,蒸馏,模型结构搜索,量化。

 

剪裁原理介绍

该策略参考paper: Pruning Filters for Efficient ConvNets

 

该策略通过减少卷积层中卷积核的数量,来减小模型大小和降低模型计算复杂度。

2.1 剪裁卷积核

2.2 Uniform剪裁卷积网络

2.3 基于敏感度剪裁卷积网络

 

 

 

蒸馏原理介绍

 

一般情况下,模型参数量越多,结构越复杂,其性能越好,但参数也越允余,运算量和资源消耗也越大;模型蒸馏是将复杂网络中的有用信息将复杂网络中的有用信息提取出来提取出来,迁移到一个更小的网络中去,在我们的工具包中,支持两种蒸馏的方法。

第一种是传统的蒸馏方法(参考论文:Distilling the Knowledge in a Neural Network)

使用复杂的网络作为teacher模型去监督训练一个参数量和运算量更少的student模型。teacher模型可以是一个或者多个提前训练好的高性能模型。student模型的训练有两个目标:一个是原始的目标函数,为student模型输出的类别概率和label的交叉熵,记为hard-target;另一个是student模型输出的类别概率和teacher模型输出的类别概率的交叉熵,记为soft target,这两个loss加权后得到最终的训练loss,共同监督studuent模型的训练。 第二种是基于FSP的蒸馏方法(参考论文:A Gift from Knowledge Distillation: Fast Optimization, Network Minimization and Transfer Learning) 相比传统的蒸馏方法直接用小模型去拟合大模型的输出,该方法用小模型去拟合大模型不同层特征之间的转换关系,其用一个FSP矩阵(特征的内积)来表示不同层特征之间的关系,大模型和小模型不同层之间分别获得多个FSP矩阵,然后使用L2 loss让小模型的对应层FSP矩阵和大模型对应层的FSP矩阵尽量一致,具体如下图所示。这种方法的优势,通俗的解释是,比如将蒸馏类比成teacher(大模型)教student(小模型)解决一个问题,传统的蒸馏是直接告诉小模型问题的答案,让小模型学习,而学习FSP矩阵是让小模型学习解决问题的中间过程和方法,因此其学到的信息更多。

 

由于小模型和大模型之间通过L2 loss进行监督,必须保证两个FSP矩阵的维度必须相同,而FSP矩阵的维度为M*N,其中M、N分别为输入和输出特征的channel数,因此大模型和小模型的FSP矩阵需要一一对应。

轻量级模型结构搜索原理介绍

深度学习模型在很多任务上都取得了不错的效果,网络结构的好坏对最终模型的效果有非常重要的影响。手工设计网络需要非常丰富的经验和众多尝试,并且众多的超参数和网络结构参数会产生爆炸性的组合,常规的random search几乎不可行,因此最近几年自动模型搜索技术(Neural Architecture Search)成为研究热点。区别于传统NAS,我们专注在搜索精度高并且速度快的模型结构,我们将该功能统称为Light-NAS.

 

 

 

 

 

 

 

量化原理介绍

https://github.com/Xilinx/ml-suite/blob/master/notebooks/integer_quantization.ipynb

https://zhuanlan.zhihu.com/p/132561405?utm_source=wechat_session&utm_medium=social&utm_oi=1125014943078109184

 

https://github.com/Ewenwan/MVision/blob/master/CNN/Deep_Compression/quantization/Ristretto/readme.md

 

 

本文介绍了几种网络压缩的方法,压缩特征图和参数。

方法包括:

    定点法(Fixed Point Approximation)、

    动态定点法(Dynamic Fixed Point Approximation)、

    迷你浮点法(Minifloat Approximation)和

    乘法变移位法(Turning Multiplications Into Bit Shifts),

所压缩的网络包括LeNet、CIFAR-10、AlexNet和CaffeNet等。

注:Ristretto原指一种特浓咖啡(Caffe),本文的Ristretto沿用了Caffe的框架。

 

 

 

    r""" Simulate the quantize and dequantize operations in training time.

    The output of this module is given by

    x_out = (clamp(round(x/scale + zero_point), quant_min, quant_max)-zero_point)*scale

    * :attr:`scale` defines the scale factor used for quantization.

    * :attr:`zero_point` specifies the quantized value to which 0 in floating point maps to

    * :attr:`quant_min` specifies the minimum allowable quantized value.

    * :attr:`quant_max` specifies the maximum allowable quantized value.

    * :attr:`fake_quant_enable` controls the application of fake quantization on tensors, note that

      statistics can still be updated.

    * :attr:`observer_enable` controls statistics collection on tensors

    * :attr:`dtype` specifies the quantized dtype that is being emulated with fake-quantization,

                    allowable values are torch.qint8 and torch.quint8. The values of quant_min and

                    quant_max should be chosen to be consistent with the dtype

    Args:

        observer (module): Module for observing statistics on input tensors and calculating scale

                           and zero-point.

        quant_min (int): The minimum allowable quantized value.

        quant_max (int): The maximum allowable quantized value.

        observer_kwargs (optional): Arguments for the observer module

    Attributes:

        observer (Module): User provided module that collects statistics on the input tensor and

                           provides a method to calculate scale and zero-point.

 

什么是模型量化?为什么要进行模型量化?

模型量化是由模型、量化两个词组成。我们要准确理解模型量化,要看这两个词分别是什么意思。

在计算机视觉、深度学习的语境下,模型特指卷积神经网络,用于提取图像/视频视觉特征。

量化是指将信号的连续取值近似为有限多个离散值的过程。可理解成一种信息压缩的方法。在计算机系统上考虑这个概念,一般用“低比特”来表示。也有人称量化为“定点化”,但是严格来讲所表示的范围是缩小的。定点化特指scale为2的幂次的线性量化,是一种更加实用的量化方法。

 

模型量化还有一个潜在的好处是降低运行时内存占用,这个特性无论是在移动端还是云端都是具有现实意义的。如果降低内存占用,可以得到如下好处:

1、降低访存量,存在提升速度的可能 。

2、在同样硬件环境下,同时处理更多视频或者视频路数 。

3、训练更大的模型。

 

近年来,定点量化使用更少的比特数(如8-bit、3-bit、2-bit等)表示神经网络的权重和激活已被验证是有效的。定点量化的优点包括低内存带宽、低功耗、低计算资源占用以及低模型存储需求等

低精度定点数操作的硬件面积大小及能耗比高精度浮点数要少几个数量级。 使用定点量化可带来4倍的模型压缩、4倍的内存带宽提升,以及更高效的cache利用(很多硬件设备,内存访问是主要能耗)。除此之外,计算速度也会更快(通常具有2x-3x的性能提升)。由表2可知,在很多场景下,定点量化操作对精度并不会造成损失。另外,定点量化对神经网络于嵌入式设备上的推断来说是极其重要的。

本节描述了通用的量化方案,即,值的比特表示(以下用q表示量化值)与实数解释(以下用r表示实值)之间的对应关系。本文的量化方案是在推理过程中使用纯整数算法,在训练过程中使用浮点算法实现的,两种实现方式保持高度对应。为了实现这一目标,本文首先对量化方案做数学上的严格定义,然后分别采用该方案进行整数算术推理和浮点数训练。

 

本文的量化方案的基本要求是,仅对量化值使用整数运算就可以实现所有算术操作(避免使用需要查找表的实现,因为与SIMD硬件上的纯算术相比,表的性能往往较差)。这等效于要求量化方案是整数q到实数r的仿射(affine mapping),即,对整数S和Z,具有形式:

 

r = S(q − Z) (1)

 

公式(1)即为量化方案,常数S和Z是量化参数。本文的量化方案针对每个特征阵列和每个权重阵列中的所有值使用一组量化参数;单独的阵列使用单独的量化参数。

 

对于8位量化,q量化为8位整数。通常将偏置矢量阵列量化为32位整数,请参见第2.4节。

 

常数S(用于“缩放(scale)”)是任意正实数,通常在软件中以浮点数表示,这与实值r类似。 2.2节描述了避免在推理工作量中表示此类浮点数的方法。

 

常数Z(用于“零点”)与量化值q具有相同的类型,实际上Z是与实数值0对应的量化值q。这是为了让实值r = 0用量化值精确表示。因为神经网络算子通常需要对边界周围的数组进行零填充,这些零也需要量化。

 

生产一个量化模型的有以下几种方法,借鉴了ICCV2019上一篇data-free量化论文的定义。

L1:直接将一个浮点参数直接转化成量化数,一般会带来很大的精度损失,但使用上非常简单。

L2:基于数据校准的方案,很多芯片都会提供这样的功能,比如tensorRT,高通,寒武纪等。它需要转模型的时候提供一些真实的计算数据。

L3:基于训练finetune的方案,有很多论文都是使用这种方法,它的好处是可以带来更大的精度提升,缺点是需要修改训练代码,实施周期比较长。

上图描述了一种实用的pipeline流程,一般会优先使用不进行finetune的offline方法,也就是离线方案。当离线方案精度损失过于严重,我们才会进行基于finetune的方法,来做进一步的抢救。

 

量化方式

学术界主要将量化分为两大类:Post Training Quantization和Quantization Aware Training。

Post Training Quantization(离线量化)是指使用KL散度、滑动平均等方法确定量化参数且不需要重新训练的定点量化方法。

Quantization Aware Training(伪量化,在线量化)是在训练过程中对量化进行建模以确定量化参数,它与Post Training Quantization模式相比可以提供更高的预测精度。

最近又出来了一种叫做 int8 训练模型,以前都是 float训练或FP16 训练。

 

量化细节

 

 

 

 

  1. 伪量化与量化的区别

 

 

 

图1 量化过程                 图2 伪量化前向过程

 

由图1、图2可以看出量化的流程是quantize->mul(int)->dequantize,而伪量化的流程是quantize->dequantize->mul(float)。伪量化对原先的float先quantize到int,再dequantize到float,这个步骤用于模拟量化过程中round操作所带来的误差,用这个存在误差的值再去进行前向运算。图3可以比较直观的表示引起误差的原因,从左到右数第4个黑点表示一个浮点数,quantize后映射到253,dequantize后取到了第5个黑点,这就引起了误差。

 

量化训练时(伪量化)怎么进行反向传播

如图4所示,经过quantize和dequantize后得到的是有误差的浮点数,所以训练还是针对浮点,反向传播过程中的所有输入和输出均为浮点型数据。梯度更新时,计算出的梯度将被加到原始权重上而非量化后或反量化后的权重上。

图4 伪量化反向传播流程和权重更新示意图

  1. 对称量化与非对称量化

3.对称量化与非对称量化

 

非对称量化将浮点数范围内的最小/最大值映射为整数范围内的最小/最大值。这是通过使用零点(也称为量化偏差,或偏移)来实现的。需要注意的是bias的需要是整型,因为在深度学习的模型中,有太多的0-padding存在了,若是bias非整型,那么在量化过程中会有大量的数值0的精度收到损失。

 

 

图5 非对称量化示意图

对称量化在最大或最小值间选择最大的绝对值作为量化范围,不设置零点,量化的浮点范围关于原点对称。

 

 

图6 对称量化示意图

对称量化的范围选择有full range和restricted range两种,论文上说restricted range精度会更低一些。PyTorch(v1.3)和ONNX用的是full range,TensorFlow、 NVIDIA TensorRT 和Intel DNNL (aka MKL-DNN)用的是restricted range。

 

 

图7 对称量化范围比较

这两种模式的选择主要是做简单性和量化范围利用率之间的trade off。当使用非对称量化时,量化范围被充分利用,浮点数的min、max直接映射到量化范围的min、max;当使用对称量化时,如果浮点数分布偏向零点一侧,会造成量化范围利用率降低(如ReLU,相当于有效位减少了1bit)。另一方面来看,非对称量化要引入零点增加复杂度。

 

目前一般做法;weight 对称,量化零点为0 ,减少计算量

  1. 逐层量化和逐通道量化

某些层的权重参数不同通道之间的数据方差很大,利用常见的per-layer量化策略(即整个层的参数作为一个tensor进行量化),则会使得值较小的通道直接全部被置为0,导致精度的下降,per-channel的方法可以解决这个问题,但是在硬件实现上因为要针对每一个通道都有自己独立的缩放系数和偏移值考虑,会导致很多额外的开销,所以目前TensorRT和Tensorflow等都采用的是per-layer。

 

  1. add和concat怎么量化?

量化的add相比float计算开销更expensive,需要将一组input基于另一组input先rescale,公式为 [公式] 。

 

concat支持和add一样的rescale方法来实现,但uint8的rescale是一个有损的操作,tensorflow采用重新统计concat op的input、output,采用input、output统一min、max的方式可以实现无损,代码如下:

  1. 量化范围的选取

量化分为weight和activation的量化。

 

weight量化范围通过每次forward时,对weight的绝对值取最大值得到。

 

activation量化范围用EMA算法平滑,可以避免一些极端激活值情况带来的参数分布影响,公式如下 :[公式]

 

https://www.zhihu.com/equation?tex=moving_max+%3D+moving_max+%2A+momenta+%2B+max%28abs%28activation%29%29+%2A+%281-+momenta%29

[公式] 为每个batch的激活值, [公式] 为接近1的值,可取0.9。

 

、学习量化范围

 

权重量化与激活量化的量化范围不同:

 

对于权重,基本思想是设置a:= minw,b:= maxw。方案中对设置进行了一些微调,将权重量化为int8值,落在[−127,127]范围内,不会出现−128这样的值,这会带来很多其它的优化可能(更多详细信息,请参阅附录B)。

对于激活,范围取决于网络的输入。为了估计范围,收集了在训练过程中落在[a; b]范围的数据,然后通过平滑参数接近1的指数移动平均值(EMA),对在数千个训练步骤中观察到的数据范围进行平滑处理。鉴于输入特征数据范围快速变化时,EMA更新数据范围有明显延迟,我们发现在训练开始时(例如,在训练刚开始的5万到200万步)完全禁用输入激活量化非常有用。这使网络进入更稳定的状态,这时的输入激活量化范围不会排除大量值。

在这两种情况下,都微调边界[a; b],以便量化后将值0.0精确地表示为整数z(a,b,n)。结果,学习得到的量化参数映射到(1)式中的缩放标度S和零点Z:

 

6. Scale factor approximation (post-training only) ,

# Adjust A

# A was an integer accumulator, you could assume the width to be 32b; INT32x^{^{2}}  \frac{}{}

# We need to dequantize it back to floating point (Divide by the scaling factors of the inputs)

# We need to quantize it to INT8 for use in the next layer's multiplier (Multiply by scaling factor for next layer)

# This creates an adjustment factor

A["adjustment"] = A["sf"]/(W0["sf"]*X["sf"])

 

# The challenge posed now is to do this manipulation in the integer domain

# There are several options to acheive this, but here we will simply do an integer multiply,

# followed by a right shift

# These shift and scale parameters are found heuristically offline before the computation is performed,

# just like the scale factors

from util import findShiftScale

shift,scale = findShiftScale(A["adjustment"])

A["int8"] = scale*A["int"] # Integer will be multiplied

A["int8"] = np.power(2,shift)*A["int8"] # Shift out the unnecessary bits

 

Scale factor approximation (post-training only): This can be enabled optionally, to simulate an execution pipeline with no floating-point operations. Instead of multiplying with a floating-point scale factor, we multiply with an integer and then do a bit-wise shift: Q≈A/2nQ≈A/2n, where QQ denotes the FP32 scale factor, AA denotes the integer multiplier and nn denotes the number of bits by which we shift after multiplication. The number of bits assigned to AA is usually a parameter of the HW, and in Distiller it is configured by the user. Let us denote that with mm. Given QQ and mm, we determine AA and nn as follows:

 

 

 

 

7 层合并Batch Normalization折叠

https://zhuanlan.zhihu.com/p/133703941

对于使用批处理归一化的模型(请参见[17]),存在额外的复杂性:训练图将Batch Normalization作为单独的操作块,而推理图将Batch Normalization参数“折叠”为卷积层或完全连接层的权重和偏见,以提高效率。为了准确地模拟量化效果,需要模拟这种折叠,并在按Batch Normalization参数缩放权重后对权重进行量化。通过以下方式可以做到这一点:

 

 

其中,γ是Batch Normalization的缩放参数,EMA(σ2B)是是整个批次中卷积结果方差的移动平均估计值,ε是为了数值稳定目的的小常数。

 

折叠后,Batch Normalization的卷积层简化为图1.1a中所示的简单卷积层,折叠后的权重为wfold,偏置也被折叠。附录中有经过Batch Normalization的卷积层训练图(图C.5),相应的推理图(图C.6),经过Batch Normalization折叠后的训练图(图C.7),以及经过折叠和量化后的训练图(图C.8)。

 

 

8.量化其他技巧

https://nervanasystems.github.io/distiller/algo_quantization.html#quantization-algorithms

DoReFa

PACT

WRPN

int8的量化训练

https://zhuanlan.zhihu.com/p/128018221

post_training_float16_quant

 

Tensorflow模型优化方法

https://www.tensorflow.org/model_optimization/guide

https://www.tensorflow.org/lite/performance/model_optimization?hl=zh-cn

 

 

TensorFlow模型优化工具包

最大限度地降低了优化机器学习推理的复杂性。

在部署机器学习模型时,由于延迟,内存利用率以及在许多情况下的功耗,推理效率是一个关键问题。特别是在诸如移动和物联网(IoT)的边缘设备上,资源进一步受到限制,并且模型尺寸和计算效率成为主要关注点。

 

优化你的模型

模型压缩旨在创建更小的模型,并且通常更快、更高效节能。因此它们能被部署到移动设备上。

剪枝

  1. 降低云和边缘设备(例如移动设备和 IoT 设备)的延迟时间和推断成本。
  2. 将模型部署到边缘设备,这些设备在处理、内存、耗电量、网络连接和模型存储空间方面存在限制。
  3. 在现有硬件或新的专用加速器上执行模型并进行优化。

 

对模型训练的计算需求随着在不同体系结构上训练的模型的数量而增长,而推理的计算需求与用户数量成比例地增长。

用例

除其他事项外,模型优化很有用,如:

减少云和边缘设备(例如移动,物联网)推理的延迟和成本。

在边缘设备上部署模型,限制计算处理,内存和/或功耗。

减少模型大小以进行在线模型更新。

在只能进行定点操作的硬件或为定点操作优化的硬件上运行模型。

为专用硬件加速器优化模型。

优化技术

模型优化的领域可能涉及各种技术:

 

通过剪枝和结构化剪枝减少模型参数个数。

通过量化(quantization)降低表示精度。

通过减少参数或更快执行速度,将原始模型拓扑更新为更高效的拓扑。例如,张量分解方法和蒸馏。

我们的工具包支持训练后量化和修剪。量化

量化

模型是具有较低精度的模型,例如使用8位整数而不是32位浮点数。某些硬件的要求使用较低的精度。

稀疏性和剪枝

稀疏模型是那些在操作(operator)(即神经网络层)之间的连接被剪枝的模型,它的实现是将零引入参数张量。

https://github.com/guan-yuan/awesome-AutoML-and-Lightweight-Models

https://paddlepaddle.github.io/PaddleSlim/algo/algo.html

https://www.tensorflow.org/model_optimization

https://www.tensorflow.org/lite/performance/quantization_spec

https://www.tensorflow.org/model_optimization/guide/get_started

 

 

 

 

 

 

  1. Tensorflow Lite post-training quantization 量化使权重和激活值的 Post training 更简单。
  2. Quantization-aware training 可以以最小精度下降来训练网络;这仅适用于卷积神经网络的一个子集
  3. .https://nervanasystems.github.io/distiller/algo_quantization.html

 

Tensorflow 伪量化,在线量化

 

https://github.com/tensorflow/tensorflow/blob/v1.15.2/tensorflow/contrib/quantize/README.md 

 

https://github.com/tensorflow/tensorflow/blob/v1.15.2/tensorflow/lite/g3doc/performance/model_optimization.md s

 

 

 

 

 

 

 

 

 

 

参考干货:

 

  1. mxnet
  2. ncnn
  3. pocketflow
  4. distiller
  5. pytorch qnnpack
  6. openvivo neck
  7. tensorrt
  8. tensorflow- Model optimization
  9. Paddle-Lite
  10. Vitis
  11. Ml-suit
  12. PaddlePaddle
  13. .https://github.com/Xilinx/ml-suite/blob/master/notebooks/integer_quantization.ipynb https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/docs/user_guides/model_quantization.md

 

 

参考链接:

 

https://mlir.llvm.org/

 

https://nervanasystems.github.io/distiller/algo_pruning.html

 

 

https://nervanasystems.github.io/distiller/knowledge_distillation.html

 

 

https://github.com/Ewenwan/MVision/blob/master/CNN/Deep_Compression/quantization/Weighted-Entropy-based-Quantization/readme.md

 

 

 

上一篇:python – 安装Tensorflow并提供量化支持


下一篇:Sampling and quantization 翻译