欢迎关注我的公众号 [极智视界],回复001获取Google编程规范

O_o>_<   o_OO_o~_~o_O

  大家好,我是极智视界,本文剖析一下ACIQ 对称量化算法实现,以 Tengine 的实现为例。

  这是量化实现的第三篇,前面还有一、二,有兴趣的同学可以查阅

  (1) 《【模型推理】量化实现分享一:详解 min-max 对称量化算法实现》;

   (2)《【模型推理】量化实现分享二:详解 KL 对称量化算法实现》;

   ACIQ 和前面的量化策略类似,也是会截取一个阈值 T,然后将 [-T, T] 映射到量化值域,不同的是寻找 T 的过程,本文不止讲原理,也结合 tengine 讲讲量化策略的实现。下面开始。

1、ACIQ 量化策略原理

   ACIQ 量化策略在论文《Post training 4-bit quantization of convolutional networks for rapid-deployment》中被提出,先贴一下效果:

  上图比对统一采用 8-bit 权值量化、4-bit 激活值量化,在量化效率上 ACIQ 比 KL 量化过程快 4000 倍(unbelievable~),在量化精度上,可以看到除了 resnet-101,其他测试的网络量化效果均好于 KL 量化,可以说是效率和效果一个也不落。

   在文章的一开始,作者就写道 Unlike traditional approaches that focus on the quantization at the network level, in this work we propose to minimize the quantization effect at the tensor level. 可以看出 ACIQ 是从 Tensor 级别出发的量化策略,整个推导逻辑主要是:

  (1) first, derive a generic expression for any given distribution for the expected MSE as a function of clipping value;

  (2) then use this expression to develop a specifific expression for each distribution;

  (3) finally, establish the optimal clipping values by solving the equations for which the derivative with respect to the clipping value are set to zero;

  通常在量化的时候需要做裁剪,以应对原始数据的长尾问题,假设 α 为截断值,截断可以表示为:

  ACIQ 需要一个较强先验假设:Tensor (feature map) 服从拉普拉斯分布或高斯分布,然后采用最优化思想求解量化过程截断值对应的最小量化损失,整个量化过程是将服从原始分布的值映射到 2^M量化离散值域,M 为量化比特数,意思是将上面的 [-α, α] 的值域等分给 2^M,如下图:

  假设原始分布的概率密度函数为 f(x),截断值 α 以及量化函数 Q(x),则量化前后的 L2 Loss 可以这么计算:

  以上算式很明显可以分为三个部分:

   (1) [负无穷, -α];

   (2) [-α, α];

  (3) [α, 正无穷];

  对于高斯分布N(0, σ^2) 或者 拉普拉斯分布 Laplace(0, b)) 这种 0 轴对称分布来说,(1) 和 (3) 是等价的,含义是 |x| 到 |α| 之间的均方误差 (mean-square-error)。在做 [-α, α] 等分映射到 2^M 后,每个量化值会取每段中间的值 q1、q2、q3 ... q2^M,第 (2) 项就是中间截断的累计误差。现在整个量化过程转化为求一个使 E[(X - Q(X))^2] 最小的截断值 α (深度学习到最后都是数学问题啊~~),然后再结合先验分布,做一些公式的等价变换~变换~之后,得到最终的整体量化损失优化目标函数:

   数学上,要求目标函数的最小值 ==> 求偏导,令其为 0。

   对于拉普拉斯分布来说,求偏导后的表达式为:

   对于高斯分布来说,求偏导后的表达式为:

  最后不管对于拉普拉斯分布还是高斯分布来说,M 是你想量化的比特位,还有像 β (拉普拉斯分布参数)、σ (高斯分布参数) 这些都是已知值,自然可以求出我们想要的截断值 α 了,对于对称量化来说有了截断值就 ok 了。

2、ACIQ 量化策略实现

   下面来看 ACIQ 在 tengine 中的实现。

   量化实现主要代码:

case ALGORITHM_ACIQ:{
   if (quant_tool.scale_file.empty()){
       quant_tool.scale_file = "table_aciq.scale";
       quant_tool.activation_quant_tool();
  }
   save_graph_i8_perchannel(quant_tool.model_file.c_str(), quant_tool.scale_file.c_str(), quant_tool.output_file, quant_tool.inplace, false);
   /* Evaluate quantitative losses */
   if (quant_tool.evaluate){
       fprintf(stderr, "[Quant Tools Info]: Step Evaluate, evaluate quantitative losses\n");
       quant_tool.assess_quant_loss(0);
  }
   break;
}

2.1 激活值量化

   激活值量化入口:

quant_tool.activation_quant_tool();

   首先就是求 min、max 值,这个过程和前面写过的量化策略是一样的逻辑,就不多说了,接着进 ACIQ 策略:

for (int i = 0; i < ir_graph->tensor_num; i++){
   struct tensor* t = ir_graph->tensor_list[i];
   if (t->tensor_type == TENSOR_TYPE_VAR || t->tensor_type == TENSOR_TYPE_INPUT){
       float absmax = 0.f;
       float act_scale = 1.f;
       int act_zero_point = 0;
       int emlement_num = t->elem_num;

       absmax = std::max(std::abs(max_activation[i]), std::abs(min_activation[i]));
       float threshold = compute_aciq_gaussian_clip(absmax, emlement_num, 8);
       act_scale = threshold / 127.f;

       /* the scale of softmax is always scale = 1 / 127.f */
       for (int j = 0; j < ir_graph->node_num; j++){
           struct node* noden = ir_graph->node_list[j];
           struct tensor* tensor_tmp = get_ir_graph_tensor(ir_graph, noden->output_tensors[0]);

           if (!(tensor_tmp->tensor_type == TENSOR_TYPE_INPUT || tensor_tmp->tensor_type == TENSOR_TYPE_VAR))
               continue;

           std::string tmp_op_name = get_op_name_from_type(noden->op.type);
           std::string cur_name = t->name;
           std::string tmp_name = tensor_tmp->name;

           if ((cur_name == tmp_name) && tmp_op_name == "Softmax"){
               act_scale = 1 / 127.f;
               break;}
      }
       fprintf(fp_aciq, "%s %f %d\n", ir_graph->tensor_list[i]->name, act_scale, act_zero_point);}
}

   关键是这个函数,tengine 里默认先验服从高斯分布, int8 量化:

float threshold = compute_aciq_gaussian_clip(absmax, emlement_num, 8);

   来看一下它的实现:

static float compute_aciq_gaussian_clip(float absmax, int N, int num_bits)
{
   const float alpha_gaussian[8] = {0, 1.71063519, 2.15159277, 2.55913646, 2.93620062, 3.28691474, 3.6151146, 3.92403714};   // 当8-bit量化时,α=3.92403714

   const double gaussian_const = (0.5 * 0.35) * (1 + sqrt(3.14159265358979323846 * log(4)));

   double std = (absmax * 2 * gaussian_const) / sqrt(2 * log(N));  

   return (float)(alpha_gaussian[num_bits - 1] * std);
}

   这样就得到了截断值,然后就可以求 scale 了:

act_scale = threshold / 127.f;

   这样就完成了激活值的量化。

2.2 权值&偏置量化

   权值&偏置的量化过程和前面介绍过的 MIN-MAX 和 KL 量化的逻辑一样,这里不再赘述。

   最后实践一下,可以发现 ACIQ 的量化过程十分的快,比 KL 量化快 4000 倍不是瞎说的,主要是源于先验的高斯分布 alpha_gaussian、gaussian_const、std 这些值不需要进行搜索。

  以上分享了 ACIQ 的量化原理和实现,希望我的分享能对你的学习有一点帮助。

【公众号传送】

【模型推理】量化实现分享三:详解 ACIQ 对称量化算法实现

【模型推理】量化实现分享三:详解 ACIQ 对称量化算法实现的更多相关文章

  1. 【模型推理】量化实现分享二:详解 KL 对称量化算法实现

      欢迎关注我的公众号 [极智视界],回复001获取Google编程规范   O_o   >_<   o_O   O_o   ~_~   o_O   大家好,我是极智视界,本文剖析一下 K ...

  2. 【模型推理】量化实现分享一:详解 min-max 对称量化算法实现

      欢迎关注我的公众号 [极智视界],回复001获取Google编程规范   O_o   >_<   o_O   O_o   ~_~   o_O   大家好,我是极智视界,本文剖析一下 m ...

  3. 数据挖掘模型中的IV和WOE详解

    IV: 某个特征中 某个小分组的 响应比例与未响应比例之差 乘以 响应比例与未响应比例的比值取对数 数据挖掘模型中的IV和WOE详解 http://blog.csdn.net/kevin7658/ar ...

  4. [转]Vue项目全局配置微信分享思路详解

    这篇文章给大家介绍了vue项目全局配置微信分享思路讲解,使用vue作为框架,使用vux作为ui组件库,具体内容详情大家跟随脚本之家小编一起学习吧 这个项目为移动端项目,主要用于接入公众号服务.项目采用 ...

  5. 转载:数据挖掘模型中的IV和WOE详解

    1.IV的用途 IV的全称是Information Value,中文意思是信息价值,或者信息量. 我们在用逻辑回归.决策树等模型方法构建分类模型时,经常需要对自变量进行筛选.比如我们有200个候选自变 ...

  6. 评分卡模型中的IV和WOE详解

    1.IV的用途   IV的全称是Information Value,中文意思是信息价值,或者信息量. 我们在用逻辑回归.决策树等模型方法构建分类模型时,经常需要对自变量进行筛选.比如我们有200个候选 ...

  7. 模型 - 视图 - 控制器(MVC)详解

    模型视图控制器(MVC)一个相当实用且十分流行的设计模式.作为一位称职码农,你不可能没听说过吧. 不幸的是它难以让人理解. 在本文中,我将给出我认为是MVC的最简单的解释,以及为什么你应该使用它. 什 ...

  8. j2ee model1模型完成分页逻辑的实现 详解!

    在显示用户全部信息的页面,在显示全部数据的时候,长长的滚动条,像是没有边界的天空一样, 让用户查看数据很不方便. 于是, 我们要把这些数据分页显示, 就像office的word一样,每页显示一定数量的 ...

  9. 微信JSSDK分享功能详解

    本文以微信分享到朋友圈,分享给微信好友为例为参考,进行调用测试,想添加其他的功能,自行查看开发人员文档即可 工欲善其事,必先利其器,好好利用下边的帮助工具,都是腾讯给开发人员的工具 1.微信开发者说明 ...

随机推荐

  1. X-MagicBox-820的luatOS之路连载系列6

    继上次用Qt实现了显示地图和MQTT通信之后(X-MagicBox-820的luatOS之路连载系列5),说是要研究下地图的开放接口,也看了标记点和线的方法(地图上自定义标记点和轨迹线的实现).这次就 ...

  2. hadoop运行jar包报错

    执行命令:[root@hadoop102 mapreduce]# hadoop jar mapreduce2_maven.jar Filter 错误信息:Exception in thread &qu ...

  3. LeetCode二维数组中的查找

    LeetCode 二维数组中的查找 题目描述 在一个 n*m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增.请完成一个搞笑的函数,输入这样的一个二维数组和一个整数,判断数 ...

  4. Flink(三)【核心编程】

    目录 一.Environment 二.Source 从集合读取数据 从文件读取数据 从kakfa读取数据(常用) 自定义数据源 三.Transform map Rich版本函数 flatMap key ...

  5. Angular 中 [ngClass]、[ngStyle] 的使用

    1.ngStyle 基本用法 1 <div [ngStyle]="{'background-color':'green'}"></<div> 判断添加 ...

  6. 面试 Java 后端开发的感受

    上周,密集面试了若干位Java后端候选人,工作经验在3到5年间.我的标准其实不复杂(适用90%小小小公司,BAT等自动忽略): 第一能干活,第二Java基础要好,第三最好熟悉些分布式框架.我相信其它公 ...

  7. 2、Redis的安装

    一.Windows下Redis安装 下载地址 Redis中文网站 Github地址 1.将下载下来的文件解压到目录 2.双击redis-server.exe运行   出现如下界面证明运行成功 3.双击 ...

  8. Nginx状态码和日志

    目录 一.Nginx状态返回码 二.Nginx日志统计 一.Nginx状态返回码 http返回状态码(Status-Code), 以3位数字组成 200 成功 301 永久重定向(redirect) ...

  9. Sentry 开发者贡献指南 - 前端(ReactJS生态)

    内容整理自官方开发文档 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Map ...

  10. 录入任务信息(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 日历设置好了,就该录入任务了.当然在录入任务之前还要对任务进行一下面分解,就是一个项目,要分几个大步完成,每个大步又分几个 ...