Quantization

Table of Contents

1. Quantization

1.1. Overview

quantization 要解决的问题是: 如何用尽可能多的用简单的整数运算代替浮点数计算.

例如要计算 0.1*0.2, 可以转换为如下的形式: (1*2)*0.01

  • 把 0.1 (a) 映射为 1 (Q_a) 的过程称为 quantization, 用 Q 表示.
  • 把 2 (Q_z) 乘 0.01 得到 0.02 (z) 的过程称为 dequantization, 用 DQ 表示.

量化后的 ai 推理过程大约如下图所示:

           layer_{n-1}
         +---------------------+                     layer_{n}
---Q(o)--+--------------+      |                 +---------------------+
         |              +--O---+--DQ(O)----Q(o)--+--------------+      |
         +   w---Q(w)---+      |                 |              +--O---+--DQ(O)--
         +---------------------+                 +   w---Q(w)---+      |
                                                 +---------------------+

其中两个 layer 之间的 `DQ–Q` 是一个常量, 可以提前转换成近似的整数操作 (例如 cmsis 的 output_shift 和 tflite 的 real_multiplier)

quantization 时会限制 Q_a 的范围, 例如 int8 量化会限制 Q_a 只能用 int8 表示 ([-128, 127))

quantization 的核心问题是如何把浮点数`线性`映射为某一范围内的整数, 即求解 \(Q=scale*q+bias\), 其中 q 是浮点数, Q 是它对应的量化后的结果, scale 和 bias 是要求解的值, 即量化参数. 这种量化实际类似于信号处理中的均匀量化 (uniform quantization)

最简单的方法是:

把 (q_min,Q_min) 和 (q_max, Q_max) 两个代入, 即可解出 scale 和 bias, bias 也叫做 zero_point.

但有时我们不希望有 zero_point, 因为它会使量化后的计算比较复杂, 例如计算 a*b:

  • 量化后有 zero_point 时要计算的式子为 \(\frac{(Q_a-Z_a)*(Q_b-Z_b)}{S_a*S_b}\)
  • 没有 zero_point 时要计算的式子为 \(\frac{Q_a*Q_b}{Sa*Sb}\)

因此有些框架 (例如 cmsis, tvm) 会要求 zero_point 必须为 0. zero_point 为 0 的量化称为对称量化, 反之称为非对称量化.

采用对称量化时, 我们不再选择 (q_min,Q_min) 和 (q_max, Q_max) 来求解线性映射, 而是选择 (0,0) 和 (abs(q)_max, Q_max), 即要求线性映射过零点, 另一个点则选择绝对值最大的点

scale 正常为浮点数, 但有些框架例如 CMSIS 会要求 scale 的值必须是 \(2^{n}\) 的形式, 这样可以避免浮点数乘法, 同时可以用移位代替整数乘法. tflite 会使用浮点数 scale, 但是可以用 rounding_doubling_high_mul 转换为整数乘法.

还有一些框架例如 TVM 会采用更复杂的量化方式, 因为选择 (q_min, Q_min), (q_max, Q_max) 来计算线性映射并不是唯一的方法, 理论上最佳的量化方式可以最小化量化误差, 即 minimize_divergency(x, DQ(Q(x)))

计算量化参数 scale 和 bias 时需要确定浮点数的范围, 对于模型的参数 (weight, bias), 范围是确定的, 可以直接计算. 对于 activation (每一层的输入输出), 范围取决于模型的输入, 因此在量化时需要给模型提供一些校准数据以统计实际推理时 activation 的范围, 当校准数据与实际数据有较大偏差时, 量化误差会很大.

由于量化会引入误差, 导致推理时性能下降, 因此存在一种技术称为 Quantization Aware Training ,其核心思想是把 forward (x) 修改为 forward (DQ(Q(x))), 即在训练时就能看到量化误差, 其中的 DQ(Q(x)) 称为 fake quantization

除此已外, 还存在一些其它的量化方法, 例如:

  • fp16, 由于 gpu 支持 float16, 所以在 gpu 上运行的模型可以使用 float16 来`量化`
  • bf16, 使用 float16 时, 如果碰到 gpu 不支持的算子, fallback 到 cpu 会涉及 float16 与 float32 的转换开销. bf16 可以减小这种开销, 一方面, 支持 bf16 的 AI 加速器 (例如 google cloud tpu) 可以减小 fallback 时转换的开销, 另一方面, 部署到不支持 bf16 的 cpu 上也可以通过较小的转换开销支持尺寸更小的模型

Author: [email protected]
Date: 2020-08-12 Wed 00:00
Last updated: 2024-02-01 Thu 14:04

知识共享许可协议