Zhangzhe's Blog

The projection of my life.

0%

URL

https://mlc.ai/zh/chapter_tensor_program/index.html

元张量函数

1.png

  • 元张量函数 表示机器学习模型计算中的单个单元计算。
    • 一个机器学习编译过程可以有选择地转换元张量函数的实现。

张量程序

2.png

  • 张量程序 是一个表示元张量函数的有效抽象。
    • 关键成分包括: 多维数组,循环嵌套,计算语句。
    • 程序变换可以被用于加速张量程序的执行。
    • 张量程序中额外的结构能够为程序变换提供更多的信息。

TensorIR: 张量程序抽象案例研究

  • TensorIR 是标准机器学习编译框架 Apache TVM 中使用的张量程序抽象。

目标

  • 使用 TensorIR 张量程序抽象 ReLU(A @ B) 张量函数。
  • 数学表示:
    • Yi,j=kAi,k×Bk,jY_{i,j}=\sum_k A_{i,k}\times B_{k,j}
    • Ci,j=ReLU(Yi,j)=max(Yi,j,0)C_{i,j}=ReLU(Y_{i,j})=max(Y_{i,j}, 0)

不同实现方法

使用 Numpy 实现

1
2
3
4
5
dtype = "float32"
a_np = np.random.rand(128, 128).astype(dtype)
b_np = np.random.rand(128, 128).astype(dtype)
# a @ b is equivalent to np.matmul(a, b)
c_mm_relu = np.maximum(a_np @ b_np, 0)

使用 Low Level Numpy 实现

Low Level Numpy 是指只使用 Numpy 的数据结构而不调用 Numpy 的 API

1
2
3
4
5
6
7
8
9
10
11
12
# Use low level numpy to implement matmal ReLU
def lnumpy_mm_relu(A: np.ndarray, B: np.ndarray, C: np.ndarray):
Y = np.empty((128, 128), dtype="float32")
for i in range(128):
for j in range(128):
for k in range(128):
if k == 0:
Y[i, j] = 0
Y[i, j] = Y[i, j] + A[i, k] * B[k, j]
for i in range(128):
for j in range(128):
C[i, j] = max(Y[i, j], 0)

使用 TensorIR 实现

TensorIRTVMScript 中的一种 Python 方言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import tvm
from tvm.ir.module import IRModule
from tvm.script import tir as T
@tvm.script.ir_module
class MyModule:
@T.prim_func
def mm_relu(A: T.Buffer[(128, 128), "float32"],
B: T.Buffer[(128, 128), "float32"],
C: T.Buffer[(128, 128), "float32"]):
T.func_attr({"global_symbol": "mm_relu", "tir.noalias": True})
Y = T.alloc_buffer((128, 128), dtype="float32")
for i, j, k in T.grid(128, 128, 128):
with T.block("Y"):
vi = T.axis.spatial(128, i)
vj = T.axis.spatial(128, j)
vk = T.axis.reduce(128, k)
with T.init():
Y[vi, vj] = T.float32(0)
Y[vi, vj] = Y[vi, vj] + A[vi, vk] * B[vk, vj]
for i, j in T.grid(128, 128):
with T.block("C"):
vi = T.axis.spatial(128, i)
vj = T.axis.spatial(128, j)
C[vi, vj] = T.max(Y[vi, vj], T.float32(0))

TensorIR 代码与 Low Level Numpy 代码对比

函数参数

1
2
3
4
5
6
7
8
# TensorIR
def mm_relu(A: T.Buffer[(128, 128), "float32"],
B: T.Buffer[(128, 128), "float32"],
C: T.Buffer[(128, 128), "float32"]):
...
# numpy
def lnumpy_mm_relu(A: np.ndarray, B: np.ndarray, C: np.ndarray):
...

buffer

1
2
3
4
# TensorIR
Y = T.alloc_buffer((128, 128), dtype="float32")
# numpy
Y = np.empty((128, 128), dtype="float32")

循环

1
2
3
4
5
6
# TensorIR
for i, j, k in T.grid(128, 128, 128):
# numpy
for i in range(128):
for j in range(128):
for k in range(128):

计算块

1
2
3
4
5
6
7
8
9
10
11
12
13
# TensorIR
with T.block("Y"):
vi = T.axis.spatial(128, i)
vj = T.axis.spatial(128, j)
vk = T.axis.reduce(128, k)
with T.init():
Y[vi, vj] = T.float32(0)
Y[vi, vj] = Y[vi, vj] + A[vi, vk] * B[vk, vj]
# coressponding numpy code
vi, vj, vk = i, j, k
if vk == 0:
Y[vi, vj] = 0
Y[vi, vj] = Y[vi, vj] + A[vi, vk] * B[vk, vj]

块(Block)TensorIR 中的基本计算单位。

  • 值得注意的是,对于一组固定的 vi 和 vj,计算块在 Y 的空间位置 (Y[vi, vj]) 处生成一个点值,该点值独立于 Y 中的其他位置(具有不同的vi, vj 值的位置)。我们可以称 vi、vj 为 空间轴,因为它们直接对应于块写入的缓冲区空间区域的开始。 涉及归约的轴(vk)被命名为 归约轴
  • 空间轴上的每个点都独立于其他点。
1
2
3
4
5
6
vi = T.axis.spatial(128, i)
vj = T.axis.spatial(128, j)
vk = T.axis.reduce(128, k)
# 使用语法糖可等价写成如下形式
# SSR means the properties of each axes are "spatial", "spatial", "reduce"
vi, vj, vk = T.axis.remap("SSR", [i, j, k])

函数属性

1
T.func_attr({"global_symbol": "mm_relu", "tir.noalias": True})

其中:

  • global_symbol 对应函数名。
  • tir.noalias 是一个属性,表示所有的缓冲存储器不重叠。

装饰器

  • @tvm.script.ir_module 表示被装饰的类是一个 IRModule。
  • @T.prim_func 表示被装饰的函数是一个张量函数。

URL

https://mlc.ai/zh/chapter_introduction/index.html

什么是机器学习编译

  • 机器学习编译 (machine learning compilation, MLC) 是指,将机器学习算法从开发阶段,通过变换和优化算法,使其变成部署状态。
    1.png

机器学习的痛点之一是:训练框架繁多/部署终端种类繁多,开发与部署存在 gap 。

  • 开发形式 是指我们在开发机器学习模型时使用的形式。典型的开发形式包括用 PyTorch、TensorFlow 或 JAX 等通用框架编写的模型描述,以及与之相关的权重。
  • 部署形式 是指执行机器学习应用程序所需的形式。它通常涉及机器学习模型的每个步骤的支撑代码、管理资源(例如内存)的控制器,以及与应用程序开发环境的接口(例如用于 android 应用程序的 java API)。
  • 机器学习编译的目标
    • 集成与最小化依赖
    • 利用硬件加速
    • 通用优化

机器学习编译的关键要素

  • 张量
  • 张量函数
  • 抽象:做什么
  • 实现:怎么做
    2.png

绿色节点表示张量,白色节点表示张量函数
3.png
机器学习编译过程中的张量函数变换过程
4.png
抽象和实现

总结

  • 机器学习编译的目标
    • 集成与最小化依赖
    • 利用硬件加速
    • 通用优化
  • 为什么学习机器学习编译
    • 构建机器学习部署解决方案
    • 深入了解现有机器学习框架
    • 为新兴硬件建立软件栈
  • 机器学习编译的关键要素
    • 张量和张量函数
    • 抽象和实现是值得思考的工具

需求弹性

  • 弹性:衡量需求量或供给量对其某种决定因素的变动的反应程度的指标。
  • 需求价格弹性(Price elasticity of demand):衡量一种物品需求量对其价格变动反应程度的指标,用需求量变动百分比除以价格变动百分比来计算。

需求价格弹性的决定因素

  • 相似替代品的可获得性
  • 必需品和奢侈品:必需品往往缺乏弹性,奢侈品往往富有弹性。
  • 市场的定义:任何一个市场的需求弹性都取决于我们如何划定市场的边界,狭窄定义的市场比宽泛定义的市场的弹性更大,例如:香草冰淇淋的弹性很大,但冰淇淋的弹性较小。
  • 时间范围:物品的需求往往在长期内更富有弹性。

需求价格弹性的计算

Price elasticity of demand=Demand change PercentagePrice change percentage   ,(change percentage>=0)Price\ elasticity\ of\ demand=\frac{Demand\ change\ Percentage}{Price\ change\ percentage}\ \ \ ,(change\ percentage >= 0)
假设某种物品存在如下两个需求价格统计点:

  • A:价格 4 / 需求量 120
  • B:价格 6 / 需求量 80
    则需求价格弹性计算可知:
  • A>B Price elasticity of demand=(12080)/120(64)/4=23A -> B\ Price\ elasticity\ of\ demand = \frac{(120 - 80)/120}{(6 - 4)/4}=\frac{2}{3}
  • B>A Price elasticity of demand=(12080)/80(64)/6=1.5B -> A\ Price\ elasticity\ of\ demand = \frac{(120 - 80)/80}{(6 - 4)/6}=1.5
    可以看出 A -> B 的需求价格弹性和 B -> A 的需求价格弹性不一致,因此提出中点法。

中点法:一个计算变动百分比和需求价格弹性更好的方法
Price elasticity of demand=(Q2Q1)/[(Q2+Q1)/2](P2P1)/[(P2+P1)/2]Price\ elasticity\ of\ demand = \frac{(Q_2-Q_1)/[(Q_2+Q_1)/2]}{(P_2-P_1)/[(P_2+P_1)/2]}

  • A -> B 的中点 C:价格 5 / 需求量 100
  • 因此 AB and BA Price elasticity of demand=(12080)/100(64)/5=1A \rightarrow B\ and\ B \rightarrow A\ Price\ elasticity\ of\ demand = \frac{(120-80)/100}{(6-4)/5} = 1

各种需求价格曲线

1.png

总收益

  • 总收益:一种物品的买者支付从而卖者得到的量,用该物品的价格乘以销售量来计算。
    1.png

可以由上图中阴影部分表示

  • 当需求富有弹性(价格弹性大于 1 )时,价格和总收益反方向变动;价格上升,总收益减少。
  • 当需求缺乏弹性(价格弹性小于 1 )时,价格和总收益同方向变动;价格上升,总收益增加。
  • 如果需求是单位弹性的(价格弹性等于 1 )时,价格变动,总收益保持不变。

其他需求弹性

  • 需求收入弹性:衡量一种物品需求量对消费者收入变化反应程度的指标;用需求量变动百分比除以收入变动百分比来计算。
  • 需求交叉价格弹性:衡量一种物品需求量对另一种物品价格变动的反应程度的指标;用第一种物品的需求量变动百分比除以第二种物品的价格变动百分比来计算。

供给弹性

市场与竞争

  • 市场:由某种物品或服务的买者与卖者组成的一个群体。
  • 竞争市场:由许多买者与卖者,以至于每个人对市场价格的影响微乎其微的市场。

需求

  • 需求量:买者愿意并且能够购买的一种商品的数量。
  • 需求定理:认为在其他条件不变时,一种物品的价格上升,对该物品的需求量减少的观点。
  • 需求表:表示一种物品的价格和需求量之间关系的表格(离散)。
  • 需求曲线:表示一种物品的价格和需求量之间关系的曲线(连续)。
    市场需求是个人需求之和,一个市场的需求量是所有买者在每一价格水平下需求量的总和。
    6.png
  • 需求增加:使每一种价格水平下的需求量都增加的任何变动,都会使 需求曲线向右移动,我们称之为需求增加。
  • 需求减少:使每一种价格水平下的需求量都减少的任何变动,都会使 需求曲线向左移动,我们称之为需求减少。

影响需求的因素

  • 价格
  • 收入
    • 正常物品:在其他条件相同时,收入增加引起需求量增加 的物品。
    • 低档物品:在其他条件相同时,收入增加引起需求量减少 的物品。
  • 相关物品的价格
    • 替代品:一种物品需求量 上升 引起另一种物品需求量 上升 的两种物品。
    • 互补品:一种物品需求量 上升 引起另一种物品需求量 下降 的两种物品。
  • 爱好
  • 预期
  • 买者的数量

其中,除了 “价格” 因素是将需求沿着需求曲线移动之外,其余的因素都会使得需求曲线移动。

供给

  • 供给量:卖者愿意并且能够出售的一种商品的数量。
  • 供给定理:认为在其他条件不变时,一种物品的价格上升,对该物品的供给量增加的观点。
  • 供给表:表示一种物品的价格和供给量之间关系的表格(离散)。
  • 供给曲线:表示一种物品的价格和供给量之间关系的曲线(连续)。
    市场供给是个人供给之和,一个市场的供给量是所有卖者在每一价格水平下供给量的总和。
    5.png
  • 供给增加:使每一种价格水平下的供给量都增加的任何变动,都会使 需求曲线向右移动,我们称之为供给增加。
  • 供给减少:使每一种价格水平下的供给量都减少的任何变动,都会使 供给曲线向左移动,我们称之为供给减少。

影响供给的因素

  • 价格
  • 投入品价格
  • 技术
  • 预期
  • 卖者的数量

其中,除了 “价格” 因素是将需求沿着供给曲线移动之外,其余的因素都会使得供给曲线移动。

供给与需求的组合

4.png

  • 均衡:市场价格达到使供给量与需求量相等的水平时的状态。
  • 均衡价格:使供给与需求达到均衡状态的价格。
  • 均衡数量:均衡价格下的供给量与需求量。
    1.png
  • 过剩:供给量大于需求量的状态。
  • 短缺:需求量大于供给量的状态。
  • 供求定理:认为任何一种物品的价格都会自发调整,使该物品的供给与需求达到平衡的观点。

分析均衡变动的三个步骤

  1. 确定该事件是使供给曲线移动还是需求曲线移动(或者使两者都移动)
  2. 确定曲线的移动方向
  3. 用供求图说明这种移动如何改变均衡价格和均衡数量
    2.png
  • 需求供给变化笛卡尔积表
    2.png

一个现代经济寓言

3.png

  • 根据 “人们面临权衡取舍” 原理可知,生产者生产存在生产可能性边界,上图蓝色的直线表示生产可能性边界。
  • Frank 每 8 小时可生产 8 oz 肉或者 32 oz 土豆。
  • Ruby 每 8 小时可生产 24 oz 肉或者 48 oz 土豆。
  • 没有贸易时,Frank 按照点 A 进行生产,每天可收货 4 oz 肉和 16 oz 土豆,Ruby 按照点 B 进行生产,每天可收货 12 oz 肉和 24 oz 土豆。


    2.png
  • 当存在贸易时,Frank 只生产土豆,每天可获得 32 oz 土豆;Ruby 每天生产 18 oz 肉和 12 oz 土豆。
  • Frank 使用 15 oz 土豆换取 Ruby 5 oz 肉,则 Frank 每天可收货 5 oz 肉和 17 oz 土豆;Ruby 每天可收货 13 oz 肉和 27 oz 土豆。
  • “贸易可以使每个人情况变得更好”,Frank 和 Ruby 通过贸易都变得更好。

比较优势:专业化的动力

  • 贸易使每个人都变得更好的原因:专业化
  • 专业化的动力:比较优势
  • 绝对优势和比较优势:
    • 绝对优势 :一个生产者比另一个生产者更少的投入生产某种商品的能力。Ruby 在生产土豆和肉的方面相较于 Frank 都有绝对优势。
    • 比较优势:一个生产者以低于另一个生产者的 机会成本 生产某种物品的能力。由下表可知,Ruby 在生产肉方面相较于 Frank 有比较优势,Frank 在生产土豆方面相较于 Ruby 有相对优势。

    机会成本:为了得到某种东西所必须放弃的东西。
    1.png
    贸易可以使参与贸易的每个人都获益,因为它使人们可以专门从事他们具有比较优势的活动。
    对于在贸易中获益的双方而言,贸易的价格一般在两种机会成本之间。

  • 由此根据上表可知:Ruby 和 Frank 肉的贸易应该在 2 ~ 4 oz 土豆之间。

作为科学家的经济学家

  • 科学方法:观察、理论和进一步观察
  • 假设的作用:假设可以使复杂的世界简单化,从而使解释这个世界变得更为容易。
  • 经济模型:经济学家使用经济模型来解释经济行为。
    2-1.png

循环流量图模型: 上图阐述了企业和家庭相互交易的经济行为,绿色箭头表示货币流向,红色箭头表示商品和服务流向。
2-2.png

  • 生产可能性边界:表示在可能的生产要素与生产技术既定时,一个经济所能生产的产品数量的各种组合的图形。
  • 上图 生产边界模型 中的任何一点都表示电脑和汽车的产量组合。阴影部分是可以达到的生产效率。
  • F、A、B、E 都是以可以达到的最高效率生产产量。
  • D 是低效率的生产方式。由于某种原因(例如:大规模失业),该经济的产量小于他可以获得的资源中所能得到的最大产量。
  • C 是无法达到的生产效率。
    2-3.png
    上图表示由于某种原因(例如:电脑生产技术的升级),导致生产可能性边界向上移动。
    最终导致的结果是:电脑和汽车的产量都可以提高。
  • 微观经济学:研究家庭和企业如何做出决策,以及它们如何在市场上相互交易的学科。
  • 宏观经济学:研究整体经济现象,包括通货膨胀、失业和经济增长的学科。

作为政策顾问的经济学家

  • 实证表述:试图描述世界是什么样子的观点。
  • 规范表述:试图描述世界应该是什么样子的观点。
    例如:

“最低工资法引起了失业” 是一句实证表述。
“政府应该提高最低工资” 是一句规范表述。

  • 凯恩斯的观点:经济学家和政治哲学家的思想,无论正确与否,实际上都要比一般所想象的更有力量。事实上,这个世界就是由他们统治的。那些自认为能够免受经济学家思想影响的实干家往往只是某些已故经济学家的俘虏。那些当权狂人信奉的其实也不过是若干年前某些末流学者的狂妄思想。

经济学家意见分歧的原因

有两个基本原因:

  • 实证分析角度:经济学家可能对世界如何运行的不同实证理论哪一种正确有着不同的看法。
  • 规范分析角度:经济学家可能有不同的价值观,因此对政策应该努力实现的目标有不同的规范观点。
    具体来说有三种可能的原因:
  • 科学判断不同
  • 价值观不同
  • 感觉与现实

基本概念

  • 稀缺性:社会资源是有限的。
  • 经济学:研究社会如何管理自己的稀缺资源。

十大原理

1. 人们面临权衡取舍

  • 效率:社会能从其稀缺资源中得到最大利益的特性。
  • 平等:经济成员在社会成员中平均分配的特性。
    在某种程度上,效率平等 是互斥的,平等会损害社会效率。

2. 某种东西的成本是为了得到它所放弃的东西

  • 机会成本:为了得到某种东西必须放弃的东西。
    例如:上大学的 机会成本 不只是学费、生活费,还有四年时光。

3. 理性人考虑边际量

  • 理性人:系统而有目的地尽最大努力实现其目标的人。
  • 边际变动:对行动计划的微小增量调整。
    简单理解就是需要更关注变化量而不是价值本身。例如:航空公司一趟航行的总成本均摊到每个座位上是 500 美元,如果起飞前还有十个座位,那么以 100 美元 / 座位的价格卖出也是合理的,原因是:此时增加的飞行成本远低于卖出价格。

4. 人们会对激励做出反应

  • 激励:引起一个人做出行动的某种东西。

5. 贸易可以使每个人的状况都变得更好

6. 市场通常是组织经济活动的一种好方法

  • 市场经济:当许多企业和家庭在物品和服务市场上相互交易时,通过他们的分散决策配置资源的经济。也就是亚当斯密口中的 “看不见的手”。

7. 政府有时可以改善市场结果

  • 产权:个人拥有并控制稀缺资源的能力。
  • 市场失灵:市场本身不能有效配置资源的情况。
  • 外部性:一个人的行为对旁观者的福利产生了影响。例如:环境污染。
  • 市场势力:单个经济活动者(或某个经济活动小群体)对市场价格有显著影响到能力。例如:垄断。
    政府在经济中的作用包括:实施产权制度;在市场失灵时重新配置资源。

8. 一国的生活水平取决于它生产物品和服务的能力

  • 生产率:每单位劳动投入所生产的物品和服务数量。

9. 当政府发行了过多货币时,物价上升

  • 通货膨胀:经济中物价总水平的上升。

10. 社会面临通货膨胀与失业之间的短期权衡取舍

  • 经济周期:就业和生产等经济活动的波动。

分类

  • 人们如何做出决策
    1. 人们面临权衡取舍
    2. 某种东西的成本是为了得到它所放弃的东西
    3. 理性人考虑边际量
    4. 人们会对激励做出反应
  • 人们如何相互影响
    5. 贸易可以使每个人的状况都变得更好
    6. 市场通常是组织经济活动的一种好方法
    7. 政府有时可以改善市场结果
  • 整体经济如何运行
    8. 一国的生活水平取决于它生产物品和服务的能力
    9. 当政府发行了过多货币时,物价上升
    10. 社会面临通货膨胀与失业之间的短期权衡取舍

URL

TL;DR

  • 典型量化算法(如:DoReFaPACTLSQ)对 feature 的量化通常使用无符号量化(负半轴量化到零点):
    • 这种量化算法适用于使用 Relu 激活函数的网络。
    • 但对使用新式激活函数(如:swish, H-swish, Mish, Leaky-ReLU)的网络(如:EfficientNetMixNet)会造成较大的量化误差。
    • LSQ+ 作为一种非对称量化算法可以学习 scaleoffset,去适应需要负数激活函数的网络。
  • 量化网络训练收敛较难,所以 LSQ+ 提出了一种比较高效的 scaleβ\beta 初始化方法:MSE 最小误差初始化方法优于最大最小值。

Algorithm

1. LSQ 算法存在的问题

  • LSQ 公式
    xˉ=clamp(xs,n,p)\bar{x} = \lfloor clamp (\frac{x}{s}, n, p)\rceil
    x^=xˉ×s\hat{x} = \bar{x} \times s
  • LSQ 对例如 Leaky-ReLUSwish 这种存在负半轴的激活函数量化有两种方法:
    • 截断负半轴,即 n=0, p=2b1n=0,\ p=2^b-1,显然降低模型表现能力
    • 正负半轴相同尺度量化,即 n=2b1, p=2b11n=-2^{b-1},\ p=2^{b-1}-1,由于正半轴的信息量远高于负半轴,同尺度量化会增大正半轴的量化误差

2. LSQ+ 的解决方案

  • LSQ+ 的改进主要包含两个方面:
    • LSQ 设置了可学习的参数 scale 的基础上,在 activation 量化上weight 量化没有 offset)增加了另外一个可学习参数 offset
    • 对网络初始化的方法进行了改进

2.1 增加可学习 offset 参数

  • LSQ+ 公式
    xˉ=clamp(xβs,n,p)\bar{x} = \lfloor clamp (\frac{x-\beta}{s}, n, p)\rceil
    x^=xˉ×s+β\hat{x} = \bar{x} \times s + \beta
  • s 的梯度计算:
    x^s\frac{\partial\hat{x}}{\partial{s}} = xˉss+xˉ{xβs+xβs,if n<xβs<pn,if xβs<np,if p<xβs\frac{\partial\bar{x}}{\partial{s}}s + \bar{x} \simeq \begin{cases} -\frac{x-\beta}{s}+\lfloor\frac{x-\beta}{s}\rceil &,if\ n < \frac{x-\beta}{s} < p\\ n&, if\ \frac{x-\beta}{s} < n\\ p&,if\ p<\frac{x-\beta}{s}\end{cases}
  • β\beta 的梯度计算
    x^β=xˉβ+1{0,if n<xβs<p1,otherwise\frac{\partial\hat{x}}{\partial{\beta}}=\frac{\partial\bar{x}}{\partial{\beta}}+1\simeq \begin{cases} 0&,if\ n<\frac{x-\beta}{s} <p\\ 1&,otherwise\end{cases}
  • 加入了 β\beta 参数后,对存在负半轴的激活函数进行非对称量化将几乎没有额外开销
    w^x^=(wˉ×sw)(xˉ×sx+β)=wˉxˉswsx+βswwˉbias\hat{w}\hat{x}=(\bar{w}\times s_w)(\bar{x}\times s_x + \beta)=\bar{w}\bar{x}s_ws_x+\begin{matrix}\underbrace{\beta s_w\bar{w}}\\ bias\end{matrix}

2.2 更合理的 scale 和 β\beta 参数初始化方法

  • 低比特量化神经网络训练的最终性能与参数初始化方法关联性较大,这在深度可分离卷积网络中更为明显(例如: MobileNet系列)
2.2.1 weight 量化的 scale 参数初始化方法
  • LSQ 对于对称量化的 weightscale 初始化公式是:sinit=2<w>ps_{init} = \frac{2<|w|>}{\sqrt{p}}
  • 作者认为这样的 scale 初始化方法会导致初始 scale 太大,所以 LSQ+ 对 weight 对称量化的 scale 初始化方法是:sinit=max(μ3×σ,μ+3×σ)2b1s_{init}=\frac{max(|\mu-3\times\sigma|, |\mu+3\times\sigma|)}{2^{b-1}}
    • 其中,μ, σ\mu,\ \sigma 分别表示本层权重的均值和标准差

由于 weight 是对称量化,所以不需要 β\beta 参数

2.2.2 feature 量化的 scale 和 β\beta 参数初始化方法
  • 一个最理想的量化方式是 x 只被量化,没有被 clamp,因此根据 LSQ+ 的量化公式可知:
    • xminβinitsinitn, xmaxβinitsinitp\frac{x_{min}-\beta_{init}}{s_{init}}\rightarrow n,\ \frac{x_{max}-\beta_{init}}{s_{init}}\rightarrow p
    • 化简后:sinit=xmaxxminpn, βinit=xminn×sinits_{init}=\frac{x_{max}-x_{min}}{p-n},\ \beta_{init} = x_{min} - n \times s_{init}
    • 但是,这种完全不 clamp 的操作容易被离群点干扰,所以 sinit, βinits_{init},\ \beta_{init} 还是使用量化前和反量化后的数据最小 MSE loss 来确定,即:sinit, βinit=argmins,βx^xF2s_{init},\ \beta_{init}=argmin_{s,\beta} ||\hat{x}-x||^2_F

Thought

  • 量化算法中多一个可以被硬件无痛吸收的自由度自然是好事

URL

TL;DR

  • 本文提出一种量化算法 LSQ,旨在通过学习的方式确定每一层量化的 scale
  • LSQ 量化算法比基于统计确定 scale 的量化算法的(例如:DoReFa-Net)效果好

Algorithm

量化和反量化过程

  • 量化过程:vˉ=clip(v/s,QN,Qp)\bar{v} = \lfloor clip(v/s, -Q_N, Q_p) \rceil
  • 反量化过程:v^=vˉ×s\hat{v} = \bar{v} \times s
    其中:
  • vv 表示原始数据(weight / feature)
  • ss 表示量化 scale
  • \lfloor \rceil 表示四舍五入(round)
  • QN, QP-Q_N,\ Q_P 分别表示量化上下界,通常来说:
    • 对于无符号整形量化数据:QN = 0, QP=2b1Q_N\ =\ 0,\ Q_P = 2^{b} - 1
    • 对于有符号整形量化数据:QN = 2b1, QP=2b11Q_N\ =\ 2^{b-1},\ Q_P = 2^{b-1} - 1
  • vˉ\bar{v} 表示量化后的数据
  • v^\hat{v} 表示反量化(×s\times s)后的数据
    lsq1.png

通常反量化会移到后面做,如上图中的 sx, sws_x,\ s_wwˉ @ xˉ\bar{w}\ @\ \bar{x} 之后才会乘上去

对 scale 的梯度定义

v^s={v/s+v/s,if QN<V/s<QPQN,if v/sQNQP,if v/sQP\frac{\partial\hat{v}}{\partial s} = \begin{cases} -v/s+ \lfloor v/s \rceil, & if\ -Q_N < V/s < Q_P\\ -Q_N, & if\ v/s \le -Q_N \\ Q_P, & if\ v/s \ge Q_P\end{cases}

对量化区间外的部分有非常高的梯度,因为 clip 之后原始信息全部丢失。所以需要较大惩罚(梯度)。

  • v^v={1,if QN<v/s<QP0,otherwise\frac{\partial\hat v}{\partial v}=\begin{cases} 1, & if\ -Q_N<v/s<Q_P \\ 0, & otherwise\end{cases}
    lsq2.png

量化前数据和反量化后的数据关系
lsq3.png
量化前数据和 scale 梯度的关系(有效将数据集中在量化点附近,减小量化损失)

  • scale 的初始值 2<v>QP\frac{2<|v|>}{\sqrt{Q_P}},其中 <v><|v|> 表示输入的绝对值均值。

对 scale 的梯度上加的权重

  • 训练中会涉及到 scale 的梯度、weight 的梯度和 feature 的梯度,需要均衡三个梯度,所以需要在weight 的梯度和 feature 的梯度上乘上两个因子进行平衡。
  • R=sLs/wLwR = \frac{\nabla_sL}{s} / \frac{||\nabla_wL||}{||w||},需要 R 尽可能接近 1
  • 经过数学推理和实验,得到两个权重因子 gw, gfg_w,\ g_f 分别表示 weight 梯度权重和 feature 的权重梯度。
  • gw=1NWQPgf=1NFQPg_w = \frac{1}{\sqrt{N_WQ_P}}\\ g_f = \frac{1}{\sqrt{N_FQ_P}},其中 NW,NFN_W,N_F 分别表示 number of weightnumber of feature

一些实验 trick

  • 越低位宽需要越低的 weight_decay 系数
  • cosine learning rate decay 可以涨点
  • 使用 float 模型去蒸馏可以涨点

Through

  • 学出来的 scale 确实比统计出来的 scalemake sense ,毕竟 QAT 给了学习的机会,就多给些可学习的参数是有道理的。

URL

TL;DR

  • GPT (Generative Pre-Training) 是一种基于 transformer decoder 结构的语言预训练模型,和视觉预训练模型不同的是使用没有 label 的文本数据做自监督预训练训练。
  • GPT 训练主要分成两个步骤:
    1. 在无标注数据上做自监督预训练,具体训练目标函数是:根据前 k 个词预测下一个词
    2. 在有监督数据集上做有监督微调,具体微调目标函数是:任务相关预测 + 根据前 k 个词预测下一个词
  • 由于 transformer decoder 中存在 mask,所以不像 Bert 可以根据前后文推理中间缺失的词(完型填空任务),GPT 只能使用根据前文推后文的方法,因此也更适合做文本生成任务
  • 预训练好的模型在下游任务上微调时,只需要对网络输出头做较小的修改即可适配,效果很好。

Algorithm

  • 发展历程: Transformer -> GPT -> Bert -> GPT2 -> GPT3 -> GPT4

example

GPT 模型擅长文本生成,因此以文本生成举例:输入"Hello, world!" 要求生成后续内容。

1. tokenize

2. token embeding

  • 因为 id 串不是神经网络可以处理的格式,所以需要 id 的向量化
  • token embedding 过程本身也是一个查表过程,表格的大小是 vocabulary_size * embedding_sizeGPT-2vocabulary size == 50257embedding size == 768
  • 查表后得到一个 4 * 768token embedding

3. position embeding

  • 给每个 token id 顺序编码一个 position id, 因此 position id[0, 1, 2, 3]
  • 然后将 position id 变成模型可识别的向量,也是一个查表过程,表格本身是可以通过梯度下降学习的,表格的大小是 max_seq_len * embedding_sizemax_seq_len 表示 最大支持的上下文长度GPT-2 中为 1024
  • position embedding 只用在 transformer 第一层之前

4. 生成输入 hidden states

  • token embedding + position embedding = hidden states
  • hidden statesshape = 4 * 768

5. Casual Decoder Layer

  • 这个是 GPT 系列模型的核心,是一种因果注意力机制
  • 因果注意力(Casual)是指每个 hidden state 只能关注之前位置的 hidden state,而不能关注之后的
  • 例如: Hello, world!seq_len == 4,那么注意力矩阵是 4x4,但此矩阵需要是下三角矩阵,即 “,” 只能关注 Hello,而不能关注 world

6. Casual Decoder Layer 输出的 hidden states 再输入下一层 Casual Decoder Layer

  • 输出的 hidden states 和输入的 hidden statesshape 保持一致
  • 再输入下一层 Casual Decoder LayerGPT-212

7. 最后一层输出的 hidden states 的最后一个 hidden state 用于分类

  • 经过重复 12 层的 Casual Decoder Layer,最后输出 hidden states (shape = 4 x 768)
  • 取最后一维 hidden state (shape = 1 x 768) 通过一层或多层 fully connect 映射到 vocabulary size
  • vocabulary size 上取 argmax 得到最大概率的下一个词

8. 合并预测到的词到语句末尾

  • 如果预测的词不是结束符,且语句总长小于 max_seq_len,则将预测得到的词加到原语句末尾
  • 加完之后的长度为 5 的语句继续通过 12Casual Decoder Layer 去预测下一个词
  • 重复直到结束符或 max_seq_len

model architecture

  • token embedding
    gpt2-token-embeddings-wte-2.png
  • postion embedding
    gpt2-positional-encoding.png
  • model architecture
    gpt2-input-embedding-positional-encoding-3.png

Unsupervised pre-training

  • 使用标准语言建模(用前面的词预测下一个词)目标来最大化如下的似然函数:
    目标函数: L1(U)=ilogP(uiuik,...,ui1Θ)L_1(U)=\sum_ilogP(u_i|u_{i-k},...,u_{i-1} | \Theta)
    其中:U 表示 token 的上下文向量,k 为窗口大小, Θ\Theta 为模型参数
  • 模型使用 Transformer decoder 结构,整体计算流程可简写为:
    • h0=UWe+Wph_0=UW_e+W_p
    • hl=transformer_block(hl1),   l[1,n]h_l=transformer\_block(h_{l-1}),\ \ \ \forall l\in[1,n]
    • P(u)=softmax(hnWeT)P(u)=softmax(h_nW_e^T)
      其中: n 表示 transformer 层数,U 表示上下文 tokenWeW_e 表示 tokenembedding 矩阵, WpW_p 表示 position embedding 矩阵

Supervised fine-tuning

  • 有监督 fine-tuning 使用的数据可表示为:
    • 输入 x1,x2,...,xmx_1, x_2, ..., x_m
    • 标签 y
  • 预测 P(yxi,...,xm)=softmax(hlmWy)P(y|x_i,...,x_m)=softmax(h_l^mW_y) 这里使用 最后一层的最后一个 token 对应的输出
  • 因此,有监督目标函数为: L2(C)=(x,y)logP(yx1,...,xm)L_2(C)=\sum_{(x,y)}logP(y|x_1,...,x_m) ,其中 C 表示 fine-tuning 使用的有标签数据集
  • 作者发现在 fine-tuning 阶段,加上无监督损失函数效果会更好,即: L3(C)=L2(C)+λL1(C)L_3(C)=L_2(C)+\lambda * L_1(C)

Task-specific input transformations

  • 本节讨论的是在 fine-tunning 以及 inference 阶段如何构造模型输入
    GPT.png

  • 上图举例了四个常见 NLP 任务:

    • 分类:图中的 StartExtract 分别是两个保留的特殊 token,分别表示输入的开始和输出特征的抽取(linear 层只输入 transformer 最后一层的最后一个 token 的输出,因此在最后填充一个 Extract 特殊标记 token)

    • 蕴含:用于分析 前提(premise) 是否蕴含 假设(hypothesis),本质是一个 蕴含 / 不蕴含 / 不确定 三分类问题,中间的 Delim 是特殊标识 token,表示分割含义

    • 相似:用于分析两个句子是否具有相似关系,由于相似具有对称性,所以需要构造两种顺序的输入,本质是二分类

    • 多选:其中 context 包含上下文文本和问题,需要针对每个答案构建一个 contextanswer 对,最后用 softmax 计算 answer 概率分布

Thought

  • GPT 使用了 Transformer decoder,由于 mask 的存在,无法知道之后的句子,因此选择了比 Bert 更难的标准语言建模(根据前 k 个词预测下一个词)的代理任务,对应的模型无监督预训练效果上限也相应提高。
  • 由于 Bert 使用的 Transformer encoder,因此可以看到句子的上下文,因此 Bert 使用了较为简单的完形填空无监督目标函数。
  • Bert 晚于 GPT,借鉴了很多 GPT 的思想,效果也优于 GPT,但 GPT 开启了语言模型无监督预训练先河,有可能成为 AIGC 的原型机。