精华内容
下载资源
问答
  • 神经网络量化
    2022-08-03 10:38:44

    Reference:

    神经网络量化简介

    神经网络加速库QNNPACK

            浮点运算不仅耗时, 训练得到的模型消耗的内存也较大. 由于神经网络训练都是在一个dataset上重复epoch, 理论上可以认为模型会被过参数化, 参数具有很多冗余信息, 没必要这么精确. 因此, 将浮点input和参数映射到整数, 能加快运行速度减小内存, 同时不会显著影响模型的性能.

            可以把浮点训练的模型, 对权重加入一个quantize以及dequantize的过程, 训练一个量化所需要的浮点值域min/max, 保证模型性能不显著下降.

            可以调整 min/max 来选择一个值域,使得值域的值更准确地量化,而范围外的值映射到定点的 min/max)。例如,当从原始值范围 [−1,1] 中选定x_f^{min} = -0.9, x_f^{max} = 0.8., [−0.9,0.8] 中的值将更准确地映射到 [0,255] 中,而 [−1,−0.9] 和 [0.8,1] 中的值分别映射为 0 和 255。

    更多相关内容
  • 摘要:传统的卷积神经网络在执行语音分类任务时存在模型存储规模大、浮点数值格式算力需求高的问题,限制了算法在低功耗和高吞吐率场景下的应用。通过对网络参数进行二值化
  • 回顾下神经网络量化的过往

    (本文首发于公众号,没事来逛逛)

    之前写过一系列网络量化相关的文章,它们都出自 Google 在 2018 年发表的一篇论文,目前也是 tflite 和 pytorch 等框架中通用的量化标准。不过,最近有读者在后台问我,说他看到的一些论文和我文章中的方法差别很大,被搞懵了。因此,今天想整理一下网络量化的发展脉络,帮助刚入门的同学更好地理清这里面的来龙去脉。

    为什么要模型量化

    关于模型量化,最直接的想法当然是把所有浮点运算都转变为定点运算,换言之需要把所有数值从 float 等浮点型上转变为 int16、int8 等整型变量,甚至变成 2bit、3bit 等极低比特表达。要知道一个 float32 的数值需要占据 4 个字节,而 int8 最多一个,不仅内存读取上快了几倍,而且定点运算也会比浮点运算更容易实现硬件加速 (2bit 等极端情况甚至用移位来实现,快到飞起)。

    而神经网络里面的数值主要分三种:网络权重、中间的输出特征 (feature map),梯度。如果把权重和特征可以定点化,那推理的时候就可以在 FPGA 等硬件上跑完整个网络,节能又高效,如果梯度也能定点化,那训练的时候也可以提速,总之,量化高效节能环保,好处大大的有。

    稳扎稳打派

    最开始的时候人们并不知道量化会对网络产生什么影响,因此需要一点点尝试。比如过,先对权重 weight 做量化,看看网络还能不能 work。

    典型代表如 MIT 的韩松教授。刚入门模型量化的同学应该都读过他的 Deep Compression 论文,这是集剪枝量化等技术于一身的作品。其中,量化这一步的基本操作如图中所示:

    这是一种非常朴素的思想。假设权重的数值是在区间 [-1.08, 2.12] 之间,那一种最简单的量化方法就是找出 -1, 0, 1, 2 这几个整数作为中心,然后把各个权重四舍五入到这几个数即可。这种四舍五入的操作会导致误差 (这也是量化误差的来源),假设有一个输入是 0.5,对应的浮点权重本来是 2.09,结果被我们量化到 2,在前向传播的时候,就会从 0.5 × 2.09 0.5 \times 2.09 0.5×2.09 变成 0.5 × 2 0.5 \times 2 0.5×2。综合起来,每一层前向传播都会累积大量的误差,这些误差会在 loss 上体现出来,又以梯度的形式传回来,最终,更新到原来的浮点权重上。

    这种量化的思路相信大部分人都能理解。作为量化上开荒时代的作品,它对落地并不友好 (这种聚类找量化中心的形式不方便硬件加速,同时由于没有对中间的 feature 量化,前向传播其实还是要浮点进行),并且在量化训练上也存在一些难点 (万一权重都在 0~1 之间,那量化后的权重就变成 0 或者 1,信息都丢掉了)。

    之后也有一些论文针对它做了一些改进,比如周教授在英特尔做的 Incremental Network Quantization,他们采用的是移位量化,因此会量化到 2 − 1 2^{-1} 21 2 − 2 2^{-2} 22 等一些数值上 (在硬件上可以通过 bitshift 来实现,非常快,不过本质上和量化到 1、2…等意义是一样的)。他们估计是发现之前的方法在量化训练上存在一些问题 (比如直接四舍五入后,在前向传播中信息丢失太多,导致网络的训练优化很困难),因此改进了量化训练方式,采用逐步量化,而不是一口吃成一个胖子,让一部分权重保持全精度来更好地学习量化误差。

    当然,这些改进工作并没有做到真正的全量化,对网络中间的 feature 还是采用浮点的形式保存 (为什么都没有对 feature 做量化,可以猜测是网络优化的难度太大),因此落地价值都不算大。

    极致压缩派

    江湖上其实还有另一伙狂人,追求极致压缩,要用 3 个比特甚至 2 个比特来实现量化。

    第一个吃螃蟹的人中,典型的如 Bengio 大佬。他的研究组提出了 Binarized Neural Networks,仅使用 +1 和 -1 来表达所有数值,并且是做到 weight 和 feature 都量化,因此很适合硬件部署 (如果模型效果不掉的话)。他们的量化方式也很直接,直接根据原数值判断,如果大于 0 就量化到 +1,否则量化量化到 -1。

    他们量化训练的方法已经有后来 tflite 中量化训练的影子了:

    1. 前向传播:逐层对 weight 和 feature 进行二值化,一直到最后一层的输出;
    2. 反向传播:根据网络输出结果,计算 loss,回传梯度。这里需要注意,如果只是对 weight 做量化,梯度是可以正常算的 (因为梯度是对 feature 求导),如果对 feature 也做了量化,考虑到量化本身不可导或者导数为 0,就需要使用 STE(straight-through estimator) 将梯度跳过量化函数;
    3. 参数更新:在浮点 weight 上更新梯度。

    应该说,这套量化策略对落地是很友好的,量化训练本身也 make sense,很容易用现有的深度学习框架实现。不过,在模型效果方面,精度损失有点惨不忍睹,离全精度模型的性能相差甚大,因此不太可能落地。

    后来有很多人看到这里面的潜力,纷纷涌上去一通改造。比如被各大自媒体吹捧的 XNOR-Net、Ternary weight networks、DoReFa-Net 等都对其进行较大改进,一方面对网络优化方面的难点做了些优化,另一方面也对量化策略本身做一些改进 (毕竟只量化到 -1 和 1 的话,整个网络的权重和 feature 都变成二维码了,信息损失很大)。

    工业落地派

    在量化领域,学术界和工业界一直存在较大的隔阂。学术界的人追求理论上的完备,并要求尽可能低的压缩比特 (8bit 是 baseline,没什么难度,不做到 4bit 以下发什么论文),但工业界需要的是能落地的方案,所谓落地,就是硬件上能很快跑起来,同时精度要没什么损失,至于什么 2bit、3bit,要么精度没法看,要么需要特殊的硬件加持,工程师们提不起兴趣。

    因此,以 Google 为代表的企业提出了一套更加通用的量化标准,并且在 tflite 中真正实现落地。这套标准就是我前面文章中介绍的量化算法,对应论文《Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference》。

    这篇文章相比前面介绍的那些,优点在于它考虑到更加现实的落地需求,针对 8bit 这样的量化要求提出了一套更加有效的量化策略,尽可能保证精度,保证落地的效果 (毕竟大家更多的还是需要在 8bit 上把精度做到最高)。

    回顾一下,这篇论文提出的量化策略是把浮点权重和 feature 通过线性映射量化到 [0, 255] 的区间 (对于 8bit 来说)。我们重点对比一下在前向传播时和之前文章的区别 (由于是全量化流程,因此只对比 Bengio 的 BNN 网络)。

    上图就是 BNN 前向传播的基本思路。正如前文介绍的,BNN 其实就是把 input 和 weight 分别量化后,再做卷积或者其他运算,得到的 output 也同样是量化的,这个 output 会继续和后面的量化 weight 进行下一步操作。

    而 Google 的文章相比而言,在 output 的地方多了一些额外的操作:

    上图是 Google 论文里面卷积在量化推理时的流程 (不熟悉的同学请查阅我之前的文章)。可以看到,和 BNN 最主要的差异其实是在 output 的时候会有一个 bitshift 并乘上一个定点小数「fixed multiplier」。为什么要多这一步呢?

    我的理解是这样的,量化其实是把 weight 和 input 从浮点这个 domain 转换到另一个 domain (int8,或者 2bit 等)。在 BNN 网络中,每一层的 output 受 weight 和 input 的影响,也从浮点域被转换到定点域,然后这个 output 作为下一层的 input 继续影响下一层的数值分布 (或者叫概率分布),如此下去,就导致整个网络的输出和原先浮点输出相比差了十万八千里。但是,在参数更新的时候,又是在浮点权重上更新的,对于复杂网络来说,优化上难度极大。

    而 Google 的工程师们在 output 后面接了一个 bitshift + fixed multiplier 的操作,其实是把每一层量化的输出和原先的浮点结果保持在一个可控的线性映射上 (看过我之前的文章的话,你就会明白,这里面每一层量化的输出和原来的浮点输出相比,都可以通过一个 scale 和 zeropoint 进行换算)。由于每一层的量化结果都只是浮点结果的线性映射,因此整个网络的输出结果在概率分布上和原先的浮点运算结果相差不会很大,对网络优化和性能的保持有很大作用。

    除此以外,很多同学对 Google 在量化训练时采用的伪量化 (论文称 simulated training,tflite 里面叫做 fake quantize,如下图所示) 表示不理解。其实这一步也是为了让网络的优化更加简单。细想一下,按照 Google 给出的量化推理步骤,这里面从浮点到定点的转换中,误差主要来自量化函数 (round) 的数值截断以及后面的 bitshift + fixed multiplier,其中,又以截断误差最为严重。因此,我们就在量化训练的前向传播中加上这一步 (即 fake quantize 中 float->int 这一步)。

    那为什么又要反量化回 float 呢?这不是多此一举?我在之前的文章中提到过 Google 论文里的一个公式:
    S 3 ( q 3 i , k − Z 3 ) = ∑ j = 1 N S 1 ( q 1 i , j − Z 1 ) S 2 ( q 2 j , k − Z 2 ) (1) S_3(q_3^{i,k}-Z_3)=\sum_{j=1}^{N}S_1(q_{1}^{i,j}-Z_1)S_2(q_2^{j,k}-Z_2) \tag{1} S3(q3i,kZ3)=j=1NS1(q1i,jZ1)S2(q2j,kZ2)(1)
    这其实是 Google 量化方案的总纲领。这里面的 q 1 q_1 q1 q 2 q_2 q2 q 3 q_3 q3 分别是量化后的 input、weight、output,通过 S S S Z Z Z 可以换算回对应的浮点数。而反量化就是为了保证量化训练的时候,得到的 output 可以对应这里的 S 3 ( q 3 i , k − Z 3 ) S_3(q_3^{i,k}-Z_3) S3(q3i,kZ3)。这和前面说的 bitshift + fixed multiplier 是呼应的。前者保持数值在浮点域 (方便量化训练),后者保持数值在定点域,而彼此之间可以通过 S S S Z Z Z 换算得到。这也是这篇文章区别于 BNN 的地方。

    当然,如果量化到 2bit 或者 3bit 等极端情况,这种量化训练的方法也会存在很大困难,但工业界也不追求这种极端的量化,只要保证 int8 的效果能赶上全精度网络就行。

    这里要多说一句,在大部分量化训练框架中,如果在 python 里面对网络进行量化,那么一般对应的是训练时的伪量化,换句话说,并不是真正意义上的量化。一般需要用 C/C++ 等更底层的语言部署到 DSP/FPGA 等硬件上面运行,才能得到真正的量化效果 (包括速度和精度)。伪量化的精度一般会略微高于真实量化,原因在于伪量化只模拟了截断带来的损失,但其实 bitshift + fixed multiplier 这一步也会有一点损失,加上底层代码在实现上和前端的 python 代码可能会存在一些差异,导致实际部署的时候,量化效果会稍差于伪量化的效果 (在一些底层视觉任务中尤其明显,比如图像修复等)。

    后量化时代

    Google 这一套量化方案成了工业界事实上的量化标准 (毕竟人家在 tflite 中抢先一步落地了,所以很多厂商都选择跟进,早就是优势),后来不少公司,包括学术界的一些改进都是在这套框架下进行的。这里说的后量化时代,指的也是在 Google 这套框架下进行的各种改进研究。

    按照这套量化方案的理论,只要找出网络中每一层 weight 以及 feature (叫 activation 也行) 的 scale 和 zero point,就可以将全精度的模型转换为量化的模型。因此,这套量化方案下的量化算法分两种:后训练量化 (post training quantization,简称 PTQ) 和量化感知训练 (quantization aware training,简称 QAT)。前者就是在不重新训练的前提下,直接找出 scale 和 zero point,操作起来相对方便友好 (最新的一些
    算法也会修改一些网络权重,典型如高通的 DFQ)。而后者需要在网络中加入 fake quantize 节点进行量化训练,操作起来相对繁琐,但效果会更好 (一般来说,QAT 的效果决定了 PTQ 的上界)。

    最后

    这篇文章从早期量化算法的研究谈起,简单梳理了神经网络量化的发展脉络,并引申到目前工业界量化方案中的诸多改进点。扯了这么多,基本是我个人的一些感悟和思考,如有雷同,三生有幸,如不苟同,后台坐等撕逼。

    后面的文章中,我会重点介绍一些比较有效的 PTQ 和 QAT 算法,感兴趣的读者欢迎一键三连等发车。

    欢迎关注我的公众号:大白话AI,立志用大白话讲懂AI。

    展开全文
  • 神经网络量化简介

    千次阅读 2019-11-26 13:48:25
    神经网络量化简介黎明灰烬​阿里巴巴 机器学习工程师128 人赞同了该文章原载于黎明灰烬 博客。采用知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可授权,转载请注明出处。文章是从 Neural Network Quantization ...

    神经网络量化简介

    128 人 赞同了该文章
    原载于 黎明灰烬 博客。采用 知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可授权,转载请注明出处。文章是从 Neural Network Quantization Introduction 转译而来,因此有些翻译感,对原文感兴趣亦可直接查看。
    知乎似乎不支持对公式编号,如果公式和文字的联系对你比较重要,建议参考 原文


    前言

    计划写一系列关于神经网络量化(Neural Network Quantization)的文章已经有一段时间了。这篇神经网络量化简介列出了一些重要的主题。

    近年来快速发展的深度学习(Deep Learning)有很多关于量化方法的研究。然而,大多数作者都急于讨论他们的研究细节,以至于新手很难理解研究的立足点。这在一个快速发展的领域可不是好现象。我最初的计划是用便于理解的方式讨论量化的各个方面,包括理论,算术,研究和工业。正如标题所述,本文是关注背景和理论的介绍。

    该系列假设读者熟悉机器学习(Machine Learning),神经网络和深度学习相关知识。如有缺乏相关背景知识,Andrew Ng 的机器学习课程是一个非常好的开头。 Google 还提供了基于 TensorFlow 的大量资料。如果您对学院派或理论风格的资料更感兴趣,可以尝试 Goodfellow 的深度学习教材和李飞飞的用于视觉识别的卷积神经网络(即 cs231)。

    简介的简介

    本节介绍了引入神经网络量化的原因和简要介绍一些主要的研究方向和工业界的解决方案。

    为什么需要量化

    深度学习已被证明在包括图像分类(Image Classification),目标检测(Object Detection),自然语言处理(Natural Language Processing)等任务上效果很好。大量的应用程序都配备了图像(计算机视觉)相关的深度学习算法,例如 Animoji。而人们使用这些应用程序甚至不知道这种技术的存在。

    图一:模型 MAC和网络预测准确度

    AlexNet 伊始,基于 ImageNet 的深度学习算法(或模型)改进都和模型大小相关。在如上的由 Google 研究人员给出的 图一 中,垂直方向是网络在给定任务上的效果,横向是网络的大小。通过对比图中 AlexNet,GoogleNetVGG 的趋势不难看出,当模型变大时网络的准确度(accuracy)可能更高。 虽然精心设计的 MobileNet 能在保持较小的体积时仍然具有与 GoogleNet 相当的准确度,不同大小的 MobileNet 本身就表明——也许一个好的模型设计可以改进准确度,但同类模型中仍然是更大的网络,更好的效果!

    随着模型预测(predication)越来越准确,网络越来越深,神经网络消耗的内存大小成为问题(图二),尤其是在移动设备上。通常情况下,目前(2019年初)的手机一般配备 4GB 内存来支持多个应用程序的同时运行。而三个模型运行一次通常就要占用1GB内存。

    模型大小不仅是内存容量问题,也是内存带宽问题。模型在每次预测时都会使用模型的权重(weights),图像相关的应用程序通常需要实时处理数据,这意味着至少 30 FPS(Frame per Second,每秒帧数)。因此,如果部署相对较小的 ResNet-50 网络来分类,运行网络模型就需要 3GB/s 的内存带宽。网络运行时,内存,CPU 和电池会都在飞速消耗,我们无法为了让设备变得智能一点点就负担如此昂贵的代价。

    图二:网络的模型大小和 GFLOPS。

    因此,深度学习领域对这些问题投入了大量的研究资源,主要有两个方面:

    • 设计更有效的网络架构,用相对较小的模型尺寸达到可接受准确度,例如 MobileNet 和 SequeezeNet
    • 通过压缩、编码等方式减小网络规模。量化是最广泛采用的压缩方法之一。

    这两个方面有时可以共同使用并取得令人瞩目的成果。例如,TensorFlow 量化的MobileNetV1 仅为 4.8MB,这甚至比大多数 GIF 动图还要小,从而可以轻松地部署在任何移动平台上。

    量化就是将神经网络的浮点算法转换为定点。这可以在移动手机上实现网络的实时运行,对云计算的部署也有帮助。

    学术界的工作

    量化有若干相似的术语。低精度(Low precision)可能是最通用的概念。常规精度一般使用 FP32(32位浮点,单精度)存储模型权重;低精度则表示 FP16(半精度浮点),INT8(8位的定点整数)等等数值格式。不过目前低精度往往指代 INT8。

    混合精度(Mixed precision)在模型中使用 FP32 和 FP16 。 FP16 减少了一半的内存大小,但有些参数或操作符必须采用 FP32 格式才能保持准确度。如果您对该主题感兴趣,请查看 Mixed-Precision Training of Deep Neural Networks

    量化一般指 INT8 。不过,根据存储一个权重元素所需的位数,还可以包括:

    • 二进制神经网络:在运行时具有二进制权重和激活的神经网络,以及在训练时计算参数的梯度。
    • 三元权重网络:权重约束为+1,0和-1的神经网络。
    • XNOR网络:过滤器和卷积层的输入是二进制的。 XNOR 网络主要使用二进制运算来近似卷积。

    其他一些研究更关注如何压缩整个模型而非存储一个元素的位数。 Deep Compression 是该方向最重要的工作之一,作者将剪枝、量化和编码等技术结合起来,在不显著影响准确性的前提下,将存储需求减少 35x(AlexNet)至 49x(VGG-19)。如图三所示,该论文还表明量化卷积层需要 8 位以避免显着的精度损失,而全连接只需要 4 位。

    图三:深度压缩中的权重位和网络准确度

    Cheng Yu 关于模型压缩的调查列出了许多工作,并将它们分类为参数剪枝和共享,低秩分解和稀疏性,传递/紧凑卷积滤波器和知识蒸馏等。

    工业界的工作

    理论是一回事,实践是另一回事。如果一种技术方法难以推广到通用场景,则需要进行大量的额外支持。花哨的研究往往是过于棘手或前提假设过强,以至几乎无法引入工业界的软件栈。

    工业界最终选择了 INT8 量化—— FP32 在推理(inference)期间被 INT8 取代,而训练(training)仍然是 FP32。TensorRTTensorFlowPyTorchMxNet 和许多其他深度学习软件都已启用(或正在启用)量化。

    通常,可以根据 FP32 和 INT8 的转换机制对解决方案进行分类。一些框架简单地引入了 QuantizeDequantize 层,当从卷积或全链接层送入或取出时,它将 FP32 转换为 INT8 或相反。在这种情况下,如图四的上半部分所示,模型本身和输入/输出采用 FP32 格式。深度学习框架加载模型,重写网络以插入QuantizeDequantize 层,并将权重转换为 INT8 格式。

    图四:混合 FP32/INT8 和纯 INT8 推理。红色为 FP32,绿色为 INT8 或量化。

    其他一些框架将网络整体转换为 INT8 格式,因此在推理期间没有格式转换,如图四的下半部分。该方法要求算子(Operator)都支持量化,因为运算符之间的数据流是INT8。对于尚未支持的那些,它可能会回落到 Quantize/Dequantize 方案。下文的讨论都基于这种方式。

    由于 INT8 使用的比特数只有 FP32 的 25% ,在 INT8 和 FP32 之间转换数值的方法非常重要,因为它会显着影响预测精度。

    量化的算术

    量化过程可以分为两部分:将模型从 FP32 转换为 INT8,以及使用 INT8 进行推理。本节说明这两部分背后的算术原理。如果不了解基础算术原理,在考虑量化细节时通常会感到困惑。

    定点和浮点

    从事计算机科学的人很少了解算术运算的执行方式。由于量化桥接了固定点(fixed point)和浮点(floating point),在接触相关研究和解决方案之前,有必要先了解它们的基础知识。

    定点和浮点都是数值的表示(representation),它们区别在于,将整数(integer)部分和小数(fractional)部分分开的,点在哪里。定点保留特定位数整数和小数,而浮点保留特定位数的有效数字(significand)和指数(exponent)。

    图五:定点和浮点的格式和示例。

    图五给出了定点和浮点表示的格式和示例。对于定点,𝐼 表示整数,𝐹 表示 𝐼𝐼𝐼𝐼𝐼.𝐹𝐹𝐹𝐹𝐹 中的分数。对于浮点数,base 分别为二进制、十进制和十六进制格式的 2、10 和 16 。定点和浮点的数值示例在图五中是一一对应的。

    在指令集(Instruction Set Architecture)的内置数据类型中,定点是整数,浮点是二进制格式。一般来说,指令集层面的定点是连续的,因为它是整数,且两个邻近的可表示数字的间隙是 1 。另一方面,浮点代表实数,其数值间隙由指数确定,因而具有非常宽的值域(32 位数值最大整数是 [公式] ,而浮点值域为 [公式] ,值越接近零就越准确。一个观察结果是,在给定指数时,浮点在不同范围内拥有数值数量相同数量,如图六。例如,[1,2) 中浮点值的数量与 [0.5,1)、[2,4]、[4,8] 等相同。

    图六:实数和浮点数。

    浮点运算可以由整数运算组成,在计算机发展的早期,浮点计算都是用软件在定点硬件上模拟的。下面的等式展示了如何将浮点乘法用定点乘法和加法表示。加法的表示方法要复杂得多,这里不做进一步讨论,有需求的可以参考计算机体系结构相关资料。

    [公式] 等式:浮点乘法拆解。

    实际上,在上面有效数字的整数乘法之后,当乘法结果相对于表示范围太大时,通常需要重新缩放,如图七。重新缩放移动将有效数字结果的一部分转移到指数,并以最近舍入方法舍入剩余的有效数字。图七的右半部分是一个例子。由于部分数字被舍弃,浮点乘法会丢失一些信息。

    图七:浮点乘法的有效数字部分。

    量化浮点

    神经网络由浮点运算构成。如定点与浮点所述,FP32 和 INT8 的值域是 [公式][公式] ,而取值数量大约分别为 [公式][公式] 。因此,将网络从 FP32 转换为 INT8 并不像数据类型转换截断那样简单。

    幸运的是,神经网络权重的值分布范围很窄,非常接近零。图八给出了 MobileNetV1 中十层(拥有最多值的层)的权重分布。

    图八:十层 MobileNetV1 的权重分布。

    当值落在 (−1,1) 中,量化浮点使用类似 [公式] 的方法将 FP32 映射到 INT8,其中 [公式] 表示 FP32 权重, [公式] 表示量化的 INT8 权重, [公式] 是映射因子(缩放因子)。有时我们不希望将 FP32 零映射到 INT8 零,即数字信号处理中的均一量化和等式5 。

    大多数情况下量化选用无符号整数,那么 INT8 值域为 [0,255] 。𝑧𝑒𝑟𝑜_𝑝𝑜𝑖𝑛𝑡 在这种情况下更有意义。具体而言,如下面的 等式6-9 所示,量化浮点值可以分为两个步骤:

    1. 通过在权重张量(Tensor)中找到 minmax 值从而确定 [公式][公式]
    2. 将权重张量的每个值从 FP32 转换为 INT8 。

    注意,当浮点运算结果不等于整数时,需要额外的舍入步骤。例如将 FP32 值域 [−1,1] 映射到 INT8 值域 [0,255],有 [公式] ,而 [公式]

    量化过程中存在误差是不可避免的,就像数字信号处理中量化一样。图十显示了数字信号处理的量化和误差

    图十:数字信号处理的量化和误差。

    量化算术

    量化的一个重要议题是用量化算术表示非量化算术,即量化神经网络中的 INT8 计算是描述常规神经网络的 FP32 计算。算术表示的原理和定点和浮点 一节中浮点乘法(等式 2-5)过程非常相似。

    下面的等式10-16 是量化乘法 [公式] 蕴含的原理。等式 15[公式] 表示等式 14中的 [公式] 。对于给定神经网络,输入 𝑥、权重 𝑦 和输出 𝑧 的缩放因子都是已知的, [公式] 可在网络运行前预先计算。因此,除了 [公式][公式] 之间的乘法之外,等式 16 中的运算都是整数。

    [公式] 等式:量化乘法运算。

    对于等式 15可以应用的大多数情况,𝑞𝑢𝑎𝑛𝑡𝑖𝑧𝑒𝑑 和 𝑧𝑒𝑟𝑜_𝑝𝑜𝑖𝑛𝑡 是 INT8,𝑠𝑐𝑎𝑙𝑒 是 FP32。实际上两个 INT8 之间的算术运算会累加到 INT16 或 INT32,因为 INT8 的值域可能无法保存运算结果。例如,对于 [公式][公式] ,有 [公式] 超出 INT8 值范围 [0,255]。

    数据类型转换可能将 [公式] 转换为 INT32 或 INT16,和 [公式] 一道确保计算结果几乎全部落入 INT8 值域 [0,255][0,255] 中。

    等式 17-26是量化加法算法。它与乘法非常相似,这里不做展开介绍。

    [公式] 等式:量化加法算法。

    除了乘法和加法外,还有诸如除法、减法、指数等数值计算,它们都有这些操作都有特定的方法分界为乘法和加法。采用这些方法,量化神经网络可以运行得到和原始网络一样有效的结果。

    量化方法的改进

    本节探讨工业界提出的解决方案的趋向,它们着力于解决将 FP32 转换为 INT8 时碰到的实际问题。

    准确度问题

    量化浮点部分中描述的方法非常简单。在深度学习框架的早期开发中,这种简单的方法能快速跑通 INT8 功能,然而采用这种方法的网络的预测准确度通常会出现明显的下降。

    如前所述,虽然 FP32 权重的值域很窄,在这值域中数值点数量却很大。以上文的缩放为例,[−1,1] 值域中 [公式] (是的,基本上是总得可表示数值的一半)个 FP32 值被映射到 256 个 INT8 值。再联系量化算术部分讨论的两个重要规则:

    • 浮点值越接近零,其值密度越高,对实数的刻画也越准确。
    • 均一量化方法将具有动态值密度的浮点映射成具有恒定值密度的定点。

    采用普通量化方法时,靠近零的浮点值在量化时没有精确地用定点值表示。因此,与原始网络相比,量化网络预测结果的准确性要差得多。对于均匀量化,这个问题是不可避免的。

    等式 4表明值映射的精度受由 [公式][公式] 得到的 [公式] 的显着影响。并且,如图八所示,权重中邻近 [公式][公式] 附近的值通常是可忽略的。那么,或许可以选择映射关系中浮点值的 minmax

    图十:将浮点量化为定点时调整最小值/最大值

    图十展示了可以调整 min/max 来选择一个值域,使得值域的值更准确地量化,而范围外的值映射到定点的 min/max)。例如,当从原始值范围 [−1,1] 中选定 [公式][公式] ,[−0.9,0.8] 中的值将更准确地映射到 [0,255] 中,而 [−1,−0.9] 和 [0.8,1] 中的值分别映射为 0 和 255。

    值域调整方法

    值域调整是另一个机器学习过程,学习的目标是一队能在量化后更准确地运行网络的超参数 min/max。目前已经提出的调整方法可分为训练后量化训练时量化根据调整何时发生,代表分别为 Nvidia CalibrationTensorFlow Quantization-aware Training

    TensorRT、MXNet 等可能在推理环境中部署的框架都配备了校准(Calibration)功能。 图十一的上半部分是校准过程,它与训练过程无关,而是从预训练的模型开始工作。校准通常将 min/max 搜索和量化合并为一个步骤,校准后网络被量化,从而可以直接部署。Nvidia 展示了 TensorRT 校准的架构和相关实验,可参考 GTC2017 的幻灯片相关博客


    图十一:训练后和训练时量化的过程。

    TensorFlow 在支持训练后量化的同时还引入了训练时量化 Quantization-aware Training,其中包括四个步骤:

    1. 用常规方法训练一个 TensorFlow 浮点模型。
    2. tf.contrib.quantize 重写网络以插入Fake-Quant 节点并训练 min/max
    3. 用 TensorFlow Lite 工具量化网络(该工具读取步骤 2 训练的 min/max
    4. 用 TensorFlow Lite 部署量化的网络。

    步骤 2 是所谓的量化感知训练(Quantization-aware Training),其中网络的前向(forward)模拟 INT8 计算,反向(backward)仍然是 FP32 。图十二左半部分是量化网络,它接收 INT8 输入和权重并生成 INT8 输出。图十二右半部分是步骤 2 重写的网络,其中 Fake-Quant 节点(粉色)在训练期间将 FP32 张量量化为 INT8 (严格来讲仍然是经过 Quantize/Dequantize 过程的 FP32)。

    图12:量化感知训练的网络节点示例。

    Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference 揭示了量化感知训练的诸多细节。

    总结

    本文介绍了神经网络量化的背景,探讨了量化的基础算法,并列举了学术界的一些研究和工业界的解决方案。

    您可能会问为什么量化是有效的(具有足够好的预测准确度),尤其是将 FP32 转换为 INT8 时已经丢失了信息?严格来说,目前尚未出现相关的严谨的理论。一个直觉解释是,神经网络被过度参数化,进而包含足够的冗余信息,裁剪这些冗余信息不会导致明显的准确度下降。相关证据是,对于给定的量化方法,FP32 网络和 INT8 网络之间的准确度差距对于大型网络来说较小,因为大型网络过度参数化的程度更高。

    参考

    所有参考文献都列在 Neural Network Quantization Resources 中。

    编辑于 2019-11-21
    神经网络
    深度学习(Deep Learning)
    机器学习
    赞同 128​ 53 条评论
    分享
    收藏
    展开全文
  • 神经网络量化----吐血总结

    千次阅读 多人点赞 2020-11-13 15:11:48
    量化技术是连接学院派和工程派之间的桥梁,效果再好的网络速度不快,那么也不会在工业上普及,因此量化技术还是很有发展潜力的。

     神经网络量化----吐血总结


    目录

     神经网络量化----吐血总结

    1. 前言

    1.1 量化是什么?

    1.2 量化会带来什么?

    2. 量化具体介绍

    2.1 非对称量化

    2.2 对称量化

    2.3 随机量化

    2.4 量化感知训练

    3. 经典量化论文解读

    3.1 Google 8-bit Integer-Arithmetric-Only Inference



    1. 前言

    本文主要借鉴于Google关于量化的白皮书,Quantizing deep convolutional networks for efficient inference: A whitepaper
    并感谢666DZY666大佬的开源项目:https://github.com/666DZY666/model-compression 
    能力有限,若有描述不当的地方,请大佬勿喷,仅为学习使用,若侵权,请告知,立删。

    1.1 量化是什么?

    量化是模型压缩的一种方式。量化就是把高位宽(例如32float)表示的权值或者激活值用较低位宽来近似表示(int8),在数值上的体现就是将连续的值离散化。

    1.2 量化会带来什么?

    量化主要用在边缘计算等硬件限制较大的场景下,即工业应用上(总不能在边缘上都带着GPU吧)。现有很多先进的神经网络(例如resnet,densenet)在分类、识别上都取得了较好的效果,但其普及程度远不及效果稍差但模型小、运算快的mobilenet,而mobilenet就是在权衡速度、识别率下产物。当然了,mobilenet不是量化模型,只是用来举个例子,用于说明量化的潜力。

    以下为量化所带来的一些影响:

    • 优点1:加快运算速度。当把32float转变为int8表示时,在不考虑系统有浮点加速模块时,定点运算要比浮点运算快,感兴趣的可查阅定点数和浮点数运算的区别
    • 优点2:减少存储空间。若将32浮点数转变为8位表示时,存储空间减小到了1/4大小。
    • 缺点1:在用低带宽数值近似表示时,会造成一些精度损失。值得高兴的是,神经网络的参数大多是冗余的(或者说是对噪声的容忍度),所以当在近似变换时对精度的影响不是特别大

    下面用图来说明量化是怎么带来损失的,A为实际的浮点值,量化后近似为B,但其表示的值为C点,缩放因子越大,A和C的距离就越远,误差就越大,所以在量化时引入的近似会带来一些精度上的损失。(后面会具体讲解如何设置最值,来找到合适的缩放因子)
     

    图片1


    2. 量化具体介绍

    2.1 非对称量化

    本文都以量化到8-bit为例
    1)首先,设置浮点数的最大值x_max,最小值x_min

    • 对于权重:权重在训练后大小都是固定的,一般直接求出权重的最大值和最小值。
    • 对于激活值:会随着输入值的改变而改变,所以不能直接求其最值,google使用了滑动均值平均的方法,TensorRT使用KL散度,Easyquant使用cos相似度,后面会具体介绍。

    2)其次,设置要量化的范围x_q_max,x_q_min,在非对称量化下为[0,255]。
    3)之后,计算缩放因子Scale(float32)和平移因子Zero_point(int8):      
                                                               ,  
    4)最后进行量化和解量化:图中的N_levels-1为255,round为四舍五入
             
    然而为什么是在量化时使用先放缩再移位,解量化时先移位再放缩呢?可不可以反过来呢?答案是否定的,主要从效果和运算两个方面考虑:


           在运算上,主要考虑如何使用整形运算代替浮点运算,可以参考google论文(后面会有详细介绍)
          在效果上,主要考虑关键数0,浮点中的0的关键用法主要在于补零padding和激活Relu上,所以为了保证量化效果,需要将浮点0无偏差的使用整形来代替。可以参考这里,详细解释如下:

    两种解量化方法如下:
        (讨论的解量化)
      (本文中的解量化,先移位再放缩,上下文移位的正负号一致性请忽略)
    对于第一种,让real_value为0,得到的zero_point如下,很难保证zero_padding为整形,因为缩放因子为浮点数。
     
    而对于第二种,是不是就很完美了,zero_point很自然的就是整形了。
      

     

    2.2 对称量化

    对称量化可以看作非对称量化的一种特殊形式,怎么特殊呢?无非就是将zero_point设置为了0,在量化时不考虑移位的概念,那么量化的坐标轴就是对齐的了。具体如下:  (量化)
                                 (解量化)
    因此,计算缩放因子时就没有了最小值的概念,全部使用绝对值的最大值。如下:
     (除以127为有符号数,除以255为无符号数)
    对称量化相当于简化了网络部署的运算,那么精度必然要稍微降低一点点。但是既然敢这样简化,必然有相对应的策略的,有兴趣的可以研究8-bit inference with TensorRT的做法,论文点这里视频点这里比较好的博客点这里
    具体如下:
    1)TensorRT认为对于权重没有提升的空间,因此,在对权重量化时,采用了和Google一样的形式,直接求最值。
    2)而对于激活值,相当于做了两遍inference,第一遍,测出激活值的最值,然后根据最值划分直方图。第二次设置阈值量化,然后根据两次的KL散度来找出最佳的阈值。

    2.3 随机量化

    即在量化时加入噪声,可能在量化感知训练时比较有效,以后再研究post-train量化。

    2.4 量化感知训练

    在讲量化感知训练之前,首先说一下训练后量化(post-train quantization),直接拿在浮点域下训练好的神经网络模型进行量化可以不可以呢?当然可以,尤其在大网络下,参数的冗余程度较大,量化的效果还是挺可观的,例如:Easyquant直逼32float全精度的准确率。但是在小网络下,效果并不好,有的很差,例如Google的训练后量化在Mobilenet下识别几乎为随机事件。什么原因呢?主要有两种:
    1)不同channel下的激活值的分布差异较大,导致1.2中我们所讲的带来较大损失。使用channel这个level下的量化会解决这个问题。
    2)异常权重的出现会导致权重的量化出现较大损失,那么为什么不在量化权重的时候加上阈值或者使用KL散度呀,是有的,不知道是不是Easyquant,后续会补充。

    OK!那么有没有一步到位的方法呢,现在引出量化感知训练,如下图,用前向传递来模拟量化所带来的误差,神经网络可以被训练到量化误差较小的位置。
                                       
    计算误差时使用量化后的输出计算,在后向传播时则不考虑量化的部分,听起来有些抽象,下面来看一段代码(pytorch),本人就因为需要研究量化理论才从keras跳到pytorch的,友情建议一下,如果有修改网络的需求的话,尽量不要使用keras了,keras高度API好用些,但不容易对内部进行改写(尝试过把源代码抽出来进行改写,不是很方便)。

    class Round(Function):
    
        @staticmethod
        def forward(self, input):
            output = torch.round(input)
            return output
    
        @staticmethod
        def backward(self, grad_output):
            grad_input = grad_output.clone()
            return grad_input
    class Quantizer(nn.Module):
        def __init__(self, bits, range_tracker):
            super().__init__()
            self.bits = bits
            self.range_tracker = range_tracker
            self.register_buffer('scale', None)      # 量化比例因子
            self.register_buffer('zero_point', None) # 量化零点
    
        def update_params(self):
            raise NotImplementedError
    
        # 量化
        def quantize(self, input):
            output = input * self.scale - self.zero_point
            return output
    
        def round(self, input):
            output = Round.apply(input)
            return output
    
        # 截断
        def clamp(self, input):
            output = torch.clamp(input, self.min_val, self.max_val)
            return output
    
        # 反量化
        def dequantize(self, input):
            output = (input + self.zero_point) / self.scale
            return output
    
        def forward(self, input):
            if self.bits == 32:
                output = input
            elif self.bits == 1:
                print('!Binary quantization is not supported !')
                assert self.bits != 1
            else:
                self.range_tracker(input)
                self.update_params()
                output = self.quantize(input)   # 量化
                output = self.round(output)
                output = self.clamp(output)     # 截断
                output = self.dequantize(output)# 反量化
            return output

    以下有点需要对代码进行说明:

    1)继承nn.module的类中一般需要定义前向传播函数即forward(),其他的quantize(), dequantize(), round(), clamp()等都是为forward服务的。
    2)Tensor的自动求导机制,是根据内部的节点计算而来的,而clamp(), abs(), 2*out等等都是不会影响梯度的,pytorch的register_buffer就类似常量的概念,不会对其进行求导。
    3)对round函数的改写,定义了前向和后向传播函数。虽然在2中讲到这些特殊的运算不会影响梯度大小,但会阻止损失的后向传播,因此需要对round()重新定义。
    4)怎么使用这个函数,定义一个conv2d的类,在forword()中加上conv2d函数,并在之前加上相关的量化函数即可。
    5)需要对代码修改的部分:在forword中需要定义training时更新参数,不然每推断时都会对参数进行更新;在定义module时需要将在forword中return output,不然summary时会报错。
    6)对截断操作的理解:有些人可能会疑惑,为什么截断操作可以让神经网络往量化误差小的方向训练呢,从求导的方式我也很难讲清楚,所以可以试试从概念上理解一下,那就是截断操作可以消除异常值对误差的影响,也就是说网络会弱化生成异常值的网络节点,从而异常值的截断操作没那么重要了。

    关于梯度的测试代码如下:

    import torch
    import torch.nn as nn
    
    inp = torch.ones(1, 1, 4, 4)
    conv = nn.Conv2d(1, 1, 3)
    
    out = torch.abs(conv(inp))  #在前向传播中使用abs函数
    loss = torch.mean(out)
    loss.backward()  #反向传播求导
    print(out.data)
    print(conv.weight.grad.data)  #梯度被正常计算出来了
    
    # out = torch.clamp((conv(inp)), -0.1, 0.1)  #在前向传播中使用clamp函数
    out = torch.round(conv(inp))  
    
    # out = out *2
    # print(out.data)
    loss = torch.mean(out)
    loss.backward()  #再一次反向传播求导
    print(conv.weight.grad.data)  #梯度还是被正常计算出来了

    3 经典论文解读之 Google 8-bit Integer-Arithmetric-Only Inference

    谷歌的这篇论文不是量化的开山之作,但为什么讲它的?真的是有新奇之处的,比如量化部署的计算,BN的处理方式,量化感知训练等,,,

    论文链接:Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference

    3.1 量化方案

    采用非对称的量化方案,文章中有示例卷积是怎么通过8bit进行运算的,如下:

    也就是说只要知道输入的8-bit weight和8-bit activation,那么就能得到输出的8-bit activation,整个计算中,除了M为浮点值外,其他的运算都是整数。而在量化网络下是最好不要涉及到浮点运算的,而文章也有提出他们的想法:

     

    个人的一些想法:

    • 文中所说的M0在[0.5,1)的范围,是经过实验得到的,然后使用32位定点数来表示这个小数,之后通过和定点数相乘再移位的方式来达到浮点计算的效果。
    • 在实际计算时,可以简要这一步骤,不管M是什么,那么既然是浮点数,就可以近似表示为整数加移位的组合,而和浮点数相乘那就是可以先和整数部分相乘,再进行移位。

    经过简化,可得以下公式:

    分析简化前和简化后的复杂度,上述的两个N*N的矩阵相乘,可得N*N个值,为方便叙述,在这里称之为N*N个单位。简化前,每个单位有(2N个减法+1N个乘法),共(2N^3个减法,N^3个乘法);简化后,总共需要求出N次a1的行均值、a2的列均值,因此只需要2N^2次加法,简化了很多吧!简化的优点:减小了复杂度,将乘法运算控制在16-bit以内。要不说google牛逼呢。

    若存在偏置的话,该怎么处理呢?不慌,因为以上的乘加运算在32-bit中进行,故也将偏置映射到32-bit中,设置为s1*s2,zero_point为零。得到以下公式:

    3.2 量化感知训练

    关于训练后量化,这里不做过多阐述,有兴趣的可去阅读原论文。

    1)conv

        Google在网络将要做运算之前,插入伪量化节点,对参数和激活值做离散化处理,如下图:

        量化操作如下:

    • 先截断,将其限制在设定最大值最小值之间,这里可能会有人疑问,其值肯定在最大值和最小值的范围内呀,为什么要限制呢?这里埋藏个问题,后面讲到最大值和最小值的设定你就懂了。
    • 再量化
    • round一下
    • 再反量化    注(公式中的量化和反量化貌似和我第二章讲的相反了,并且Google的量化感知训练和训练后量化也相反了,这里就不清楚为什么了,并没有文档对其解释,我的理解是当使用了量化感知训练时两者的差别不大,又或者说是部署框架的需求。)

    2)BN和conv的融合

        首先复习一下BN的理论知识:

    总体来说就是先统计一个batch中的均值和方差,对输入做归一化操作,之后对其进行缩放和移位。

    好的,那么理论已经具备,实际中神经网络是怎么训练和推荐的呢?如下:

    在推断时BN是和Conv结合在一起的,可达到加快运算速度的效果,具体公式如下:

    为了模拟这种效果,Google采用的方法很独特,加入了将原先的卷积和BN的基础上添加了一个卷积,共两个卷积,其中一个用于获取BN的参数,另一个用于量化后卷积。如下图:

    以上两张图中都有两条通路:右侧用于卷积、BN,然后将参数都量化出来;左侧使用量化后的参数进行卷积。为了便于理解,放上一段代码:
     

    def forward(self, input):
            # 训练态
            if self.training:
                # 先做普通卷积得到A,以取得BN参数
                output = F.conv2d(
                    input=input,
                    weight=self.weight,
                    bias=self.bias,
                    stride=self.stride,
                    padding=self.padding,
                    dilation=self.dilation,
                    groups=self.groups
                )
                # 更新BN统计参数(batch和running)
                dims = [dim for dim in range(4) if dim != 1]
                batch_mean = torch.mean(output, dim=dims)
                batch_var = torch.var(output, dim=dims)
                with torch.no_grad():
                    if self.first_bn == 0:
                        self.first_bn.add_(1)
                        self.running_mean.add_(batch_mean)
                        self.running_var.add_(batch_var)
                    else:
                        self.running_mean.mul_(1 - self.momentum).add_(batch_mean * self.momentum)
                        self.running_var.mul_(1 - self.momentum).add_(batch_var * self.momentum)
                # BN融合
                if self.bias is not None:  
                  bias = reshape_to_bias(self.beta + (self.bias -  batch_mean) * (self.gamma / torch.sqrt(batch_var + self.eps)))
                else:
                  bias = reshape_to_bias(self.beta - batch_mean  * (self.gamma / torch.sqrt(batch_var + self.eps)))# b融batch
                weight = self.weight * reshape_to_weight(self.gamma / torch.sqrt(self.running_var + self.eps))     # w融running
            # 测试态
            else:
                #print(self.running_mean, self.running_var)
                # BN融合
                if self.bias is not None:
                  bias = reshape_to_bias(self.beta + (self.bias - self.running_mean) * (self.gamma / torch.sqrt(self.running_var + self.eps)))
                else:
                  bias = reshape_to_bias(self.beta - self.running_mean * (self.gamma / torch.sqrt(self.running_var + self.eps)))  # b融running
                weight = self.weight * reshape_to_weight(self.gamma / torch.sqrt(self.running_var + self.eps))  # w融running
    
            # 量化A和bn融合后的W
    
            if not self.first_layer:
    
                input = self.activation_quantizer(input)
    
            q_input = input
    
            q_weight = self.weight_quantizer(weight) 
    
            # 量化卷积
    
            if self.training:  # 训练态
    
              output = F.conv2d(
    
                  input=q_input,
    
                  weight=q_weight,
    
                  bias=self.bias,  # 注意,这里不加bias(self.bias为None)
    
                  stride=self.stride,
    
                  padding=self.padding,
    
                  dilation=self.dilation,
    
                  groups=self.groups
    
              )
    
              # (这里将训练态下,卷积中w融合running参数的效果转为融合batch参数的效果)running ——> batch
    
              output *= reshape_to_activation(torch.sqrt(self.running_var + self.eps) / torch.sqrt(batch_var + self.eps))
    
              output += reshape_to_activation(bias)
    
            else:  # 测试态
    
              output = F.conv2d(
    
                  input=q_input,
    
                  weight=q_weight,
                  bias=bias,  # 注意,这里加bias,做完整的conv+bn
                  stride=self.stride,
                  padding=self.padding,
                  dilation=self.dilation,
                  groups=self.groups
    
              )
    
            return output

     

     3)最大值和最小值的获取

    3.3 部署

    1)conv

    对于单个卷积的量化部署基本已在3.1中讲过,另外补充一点,在最后需要做一步round操作,因为量化后的那个式子不是严格的等式,还是有量化误差的。

    2)conv and Relu

    首先一般会想到:先按照3.1中的那样量化计算,之后根据zero_point做Relu激活,然而Google并不是这样使用的。
           根据3.2中的第一张图可知,在conv和relu之间没有做量化处理,为什么可以将Relu和conv结合在一起运算?可以这么理解,假设输出浮点数在[-1,1],使用[0,255]的数值表示;结合后浮点数范围为[0,1],也使用[0,255]表示,虽然两种情况下相同的浮点数使用不同的整形来表示(例如第一种情况浮点数0,那么在整形中使用128来表示;第二种情况的浮点数0使用0来表示),但scale和zero_point也不同,使用3.2中的公式也是可以达到目的的。为了便于理解,这里有两种表述方式:第一种,浮点数的范围不同,仅仅会导致离散化的精度不同,而计算出的大于0的数该是多少,还是多少(会有误差,但误差多少,请看第二种),小于0的数则全都等于0;第二种,可以理解为Relu和conv结合后,相当于将[-1,1]的浮点数使用[-255,255]之间,误差能看懂了吗,相比Relu和conv结合之前,精度是升高的。为什么可以将Relu和conv结合在一起运算?可以这么理解,假设输出浮点数在[-1,1],使用[0,255]的数值表示;结合后浮点数范围为[0,1],也使用[0,255]表示,虽然两种情况下相同的浮点数使用不同的整形来表示(例如第一种情况浮点数0,那么在整形中使用128来表示;第二种情况的浮点数0使用0来表示),但scale和zero_point也不同,使用3.2中的公式也是可以达到目的的。为了便于理解,这里有两种表述方式:第一种,浮点数的范围不同,仅仅会导致离散化的精度不同,而计算出的大于0的数该是多少,还是多少(会有误差,但误差多少,请看第二种),小于0的数则全都等于0;第二种,可以理解为Relu和conv结合后,相当于将[-1,1]的浮点数使用[-255,255]之间,误差能看懂了吗,相比Relu和conv结合之前,精度是升高的。

    之前一直对论文中这句话不理解,In practice, the quantized training process (section3) tends to learn to make use of the whole output uint8 [0, 255] interval so that the activation function no longer does anything, its effect being subsumed in the clamping to [0, 255] implied in the saturating cast to uint8. 经过以上思考终于明白了,果然clamp的使用直接就可以起到Relu的作用了。

    3)average_pooling

    部署时是求整数的平均,可是如果整数的平均不是整数呢?这个时候可以在训练模拟部署时的运算,不是整数,可以四舍五入,所以在训练时可以对pooling之后的输入做量化,这个量化所需的最大值、最小值、scale、zero_point都是上一层输出的值,这个量化的过程就是四舍五入的过程,因此在部署时会和训练时保持一致。(可以自己构建一个module改写pool,里面包含对pool输出的量化

    四、经典论文解读之TensorRT

    请转链接:TensorRT 

    先发表出去,慢慢更新!!!

     

     

    展开全文
  • 基于pytorch的卷积神经网络量化实现

    万次阅读 2021-03-27 17:47:09
    1,神经网络和卷积神经网络模型量化方法,主要包括线性量化和聚类量化两种方法。 2,可指定模型进行定点话,并输出量化后参数统计和finetune,可设置任意bit量化。 3,支持MLP,Lenet,Alexnet,VGG,GoogleNet系列,...
  • 人工智能-卷积神经网络量化研究及FPGA实现.pdf
  • 神经网络量化入门--基本原理

    千次阅读 2020-10-31 11:35:06
    神经网络量化入门系列第一篇:基本原理
  • 神经网络量化方法

    2020-12-22 06:29:41
    神经网络虽然在多个领域取得了非常巨大的成就,但是其本质是大量参数的拟合和泛化,如果想处理更加复杂的任务,在没有过拟合的情况下,增加训练数据和加大网络规模无疑是简单有效的手段。现实情况就是这么做的,但是...
  • 神经网络量化入门--量化感知训练

    千次阅读 2022-03-10 08:58:21
    神经网络量化入门系列第三篇:后量化训练
  • 神经网络量化基础 神经网络量化基础(1)——模型的构建与基础量化函数的实现 文章目录神经网络量化基础前言1. 网络量化模块5. 网络量化模块5. 网络量化模块 前言 本文是在阅读博客时对代码的整理,旨在对量化的...
  • 神经网络量化原理

    千次阅读 2021-05-06 13:57:18
    量化是将数值 x 映射到 y 的过程,其中 x 的定义域是一个大集合(通常是连续的),而 y 的定义域是一个小集合(通常是可数的)。8-bit 低精度推理,是将一个原本 FP32 的浮点张量转化成一个 int8/uint8 张量来处理。先...
  • 一种超低损失的深度神经网络量化压缩方法.pdf
  • 本文是在阅读博客时对代码的整理,旨在对量化的基础过程有更加清晰的认识。 网络模型构建 本文采用pytorch手工构建了一个基础网络模型,数据集采用mnist数据集。这里不在赘述,直接看训练代码 网络结构 首先说明定义...
  • 基于Octave卷积的混合精度神经网络量化方法.pdf
  • 基于动态映射的卷积神经网络量化重训练方法.pdf
  • 面向“边缘”应用的卷积神经网络量化与压缩方法.pdf
  • sigmoid, tanh, 量化推理 简介 在嵌入式设备,ARM的M...神经网络量化 负数补码 sigmoid/tanh量化推理 这里我们以ARM的CMSIS_5中的代码进行原理和代码的解说。 1. 查表法 sigmoid,tanh及类似的非线性激活函数都是.
  • 网络游戏-用于神经网络量化的方法和设备.zip
  • 网络游戏-用于神经网络量化的方法和设备[1].zip
  • 自组织映射神经网络量化机器人强化学习方法研究.pdf
  • 基于权值熵的深度神经网络量化

    千次阅读 2018-01-06 11:12:33
     量化是优化神经网络模型前向计算耗时的最有效的方法之一,以便它们部署到资源受限的移动或嵌入式系统中。在这类方法中,最重要是提供低精度损失量化。在这篇论文中,作者提出了一种基于加权熵概念的量化权值和激活...
  • 深度学习神经网络量化

    万次阅读 2017-08-22 14:24:51
    此外,SGD(Stochastic Gradient Descent)所需要的精度仅为6~8bit,因此合理的量化网络也可保证精度的情况下减小模型的存储体积影响DNN压缩看参考Stanford大学Han Song博士的几篇论文,如下: Learning both ...
  • 神经网络量化入门系列第五篇:Fold BN ReLU代码实现
  • 神经网络模型量化

    2021-08-02 16:16:24
    量化模型(Quantized Model)是一种模型加速(Model Acceleration)方法的总称,包括二值化...在计算机视觉、深度学习的语境下,模型特指卷积神经网络,用于提取图像/视频视觉特征。 量化是指将信号的连续取值近似为有.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,614
精华内容 11,445
关键字:

神经网络量化

友情链接: ssbmxt.zip