量化配置#
QConfig
通过设置配置变量来配置量化行为。
备注
QConfig
对象在 C++ 中由节点系统(node system)支持,并且可以与 Python 和 C++ 之间交换参数。
不要直接构造,而是使用 qconfig()
。
一旦实例被构造,由 C++ 节点支持的字段就是不可变的。有关字段的信息请参见 tvm.relay.quantize.QConfig._node_defaults
。
小技巧
tvm.ir.make_node()
通过其类型键和字段创建新的 IR 节点。如果创建的节点是 AttrsNode 的实例,则创建函数还将运行绑定检查和 Attrs 支持的默认值设置。
比如:
x = tvm.ir.make_node("IntImm", dtype="int32", value=10)
assert isinstance(x, tvm.tir.IntImm)
assert x.value == 10
%cd ..
import testing
/media/pc/data/lxw/ai/tvm-book/doc/read/relay
from tvm import relay
relay.quantize.QConfig._node_defaults
{'nbit_input': 8,
'nbit_weight': 8,
'nbit_activation': 32,
'dtype_input': 'int8',
'dtype_weight': 'int8',
'dtype_activation': 'int32',
'calibrate_mode': 'global_scale',
'global_scale': 8.0,
'weight_scale': 'power2',
'skip_dense_layer': True,
'skip_conv_layers': [0],
'do_simulation': False,
'round_for_shift': True,
'debug_enabled_ops': None,
'rounding': 'UPWARD',
'calibrate_chunk_by': -1,
'partition_conversions': 'disabled'}
备注
/*! \brief Attribute for simulated quantize operator */
struct SimulatedQuantizeAttrs : public tvm::AttrsNode<SimulatedQuantizeAttrs> {
int kind;
bool sign;
std::string rounding;
TVM_DECLARE_ATTRS(SimulatedQuantizeAttrs, "relay.attrs.SimulatedQuantizeAttrs") {
TVM_ATTR_FIELD(kind).describe("kind of field, hint for nbit/dtype configuration.");
TVM_ATTR_FIELD(sign).set_default(true).describe("whether to use signed data type.");
TVM_ATTR_FIELD(rounding).set_default("round").describe(
"rounding mode. Can be 'floor', 'ceil', 'round'");
}
};
SimulatedQuantizeAttrs
结构体用于表示模拟量化算子的属性。该结构体继承自 tvm::AttrsNode
类,并使用 TVM_DECLARE_ATTRS
宏来声明属性。
在结构体中,定义了三个成员变量:
kind
:表示字段的类型和配置提示,用于指导量化算子的 nbit/dtype 设置。sign
:表示是否使用带符号的数据类型,默认为true
。rounding
:表示舍入模式,可以是floor
(向下取整)、ceil
(向上取整)或round
(四舍五入),默认为round
。
通过 TVM_ATTR_FIELD
宏来指定每个成员变量的名称和描述信息。
这个结构体可以用于定义模拟量化算子所需的属性,例如在模型编译期间传递给量化层的配置参数。
用于存储量化配置选项的类:
class QConfigNode : public Object {
public:
int nbit_input = 8; // 输入张量的位宽,默认为8位。
int nbit_weight = 8; // 权重张量的位宽,默认为8位。
int nbit_activation = 32; // 激活函数输出张量的位宽,默认为32位。
DataType dtype_input = DataType::Int(8); // 输入张量的数据类型,默认为整数类型(8位)。
DataType dtype_weight = DataType::Int(8); // 权重张量的数据类型,默认为整数类型(8位)。
DataType dtype_activation = DataType::Int(32); // 激活函数输出张量的数据类型,默认为整数类型(32位)。
std::string calibrate_mode = "global_scale"; // 校准模式
double global_scale = 8.0; // 全局缩放因子
std::string weight_scale = "power2"; // 权重缩放模式
bool skip_dense_layer = true; // 是否跳过 dense 层
Array<Expr> skip_conv_layers = Array<Expr>(ObjectPtr<Object>(nullptr)); // 要跳过的卷积层的列表,默认为空。
bool do_simulation = false; // 是否进行模拟计算
bool round_for_shift = true; // 是否为移位操作进行舍入
Array<Expr> debug_enabled_ops = Array<Expr>(ObjectPtr<Object>(nullptr)); // 要启用调试的算子列表,默认为空。
std::string rounding = "UPWARD"; // 舍入模式
int calibrate_chunk_by = -1; // 按块进行校准的块大小
std::string partition_conversions = "disabled"; // 分区转换模式
// 用于访问和处理属性的成员函数
void VisitAttrs(AttrVisitor* v) {
...
}
static constexpr const char* _type_key = "relay.quantize.QConfig"; // 标识该类的类型
TVM_DECLARE_FINAL_OBJECT_INFO(QConfigNode, Object); // 声明该类为 final 类
};
QConfig
类和 QConfigContext
结构体,用于管理构建配置的上下文。
QConfig
类是容器类,它继承自 ObjectRef
类。它具有以下成员函数:
默认构造函数和带有
ObjectPtr<Object>
参数的构造函数。重载了箭头运算符
->
,以支持获取QConfigNode
对象。EnterQConfigScope
静态函数,用于将新的BuildConfig
上下文压入线程本地栈中。ExitQConfigScope
静态函数,用于从线程本地上下文栈中弹出BuildConfig
上下文,恢复之前的配置作为当前上下文。Current
静态函数,用于从线程本地存储中获取当前的BuildConfig
上下文,如果没有进入BuildConfig
范围,则返回默认配置。使用
ContainerType
别名指定QConfigNode
为容器类型。
QConfigContext
结构体是 RAII(资源获取即初始化)容器,用于提供受控的 BuildConfig
上下文。它在构造时将配置压入上下文栈中,并在析构时弹出上下文。
Python 端 tvm.relay.quantize.qconfig
参数解读:
nbit_dict: QAnnotateKind
: 每种注释字段的位数。calibrate_mode: str
: 校准模式:‘global_scale’ 或者 ‘kl_divergence’。global_scale
: 使用 global scale。kl_divergence
: 在数据集中通过 KL 散度查找 scale。
global_scale: float
: 校准的全局 scale。weight_scale: str
: 计算权重的 scale 的方法(用QAnnotateKind.WEIGHT
注解)。power2
: 找到张量绝对值的最大值,然后将其向上取到 \(2\) 的幂次方。max
: 找到张量绝对值的最大值。
skip_dense_layer: bool = True
: 是否跳过所有的nn.dense
层类型。skip_conv_layers: list[int]
: 指定要跳过的层。提供索引列表,指示哪些卷积层保持不变。从 \(0\) 开始。do_simulation: bool
: 是否仅使用浮点运算进行模拟。round_for_shift: bool
: 是否在移位时添加舍入偏差。debug_enabled_ops: list[str]|None = None
: 部分量化指定的算子进行调试。默认值为None
,这意味着将尝试调用所有算子的注解重写函数。rounding: str
: 定点乘法的舍入方向。“UPWARD” 或者 “TONEAREST”。partition_conversions: str = 'disabled'
: 可选值:'disabled'
、'enabled'
或者'fully_integral'
。如果设置为'enabled'
或'fully_integral'
,则将量化的结果划分到模块容器,其中包含前缀函数(由输入转换为量化数据空间组成),中间函数(由核心量化网络组成),后缀函数(由输出反量化组成)以及主函数(依次调用前缀、中间和后缀函数)。如果设置为'fully_integral'
且结果中存在未量化的算子,则会引发异常。默认值为'disabled'
。