# mypy: 允许未类型化装饰器
# mypy: 允许未类型化定义
来自 collections.abc
导入
迭代器
来自
打字
导入
可选
导入
火炬
导入 torch.ao.nn.intrinsic
作为 nni
导入 torch.ao.nn.intrinsic.qat
作为 nniqat
导入 torch.nn
作为
然后
来自 torch.nn.utils.fusion
导入 fuse_linear_bn_weights
来自 torch.nn.utils.parametrize
导入 type_before_parametrizations
来自
.工具
导入 _hide_packed_params_repr, _quantize_weight,
加权量化模块
__all__ = [LinearPackedParams,
"线性"]
类
线性打包参数(
火炬.nn.
模块):
_version = 3
定义
初始化(
自身,
数据类型=
火炬.qint8):
超级().
初始化()
自身.dtype = dtype
如果
自身.dtype ==
火炬.qint8:
wq = 火炬.
_空线性量化(
[1, 1]
比例=1.0,
零点=0,
数据类型=
火炬.qint8
)
elif 自身.dtype ==
火炬.float16:
wq = 火炬.
零([1, 1
]
数据类型=
火炬.float)
自身.
设置权重偏差(wq,
无) # type: ignore[possibly-undefined]
@torch.算子.
导出
定义
设置权重偏差(
自身,
重量:
火炬.
张量,
偏置:
可选[
火炬.
张量]
) -> 无:
如果
自身.dtype ==
火炬.qint8:
自身._packed_params =
火炬.
操作.
量化.
线性预打包(
重量,
偏置)
elif 自身.dtype ==
火炬.float16:
自身._packed_params =
火炬.
操作.
量化.
线性预打包 fp16(
重量,
偏置)
否则:
抛出异常
运行时错误(
"在动态量化线性中不支持数据类型!")
@torch.算子.
导出
定义
权重偏置(
自身):
如果
自身.dtype ==
火炬.qint8:
返回
火炬.
操作.
量化.
线性解包(
自身._packed_params)
elif 自身.dtype ==
火炬.float16:
返回
火炬.
操作.
量化.
线性解包_fp16(
自身._packed_params)
否则:
抛出异常
运行时错误(
"在动态量化线性中不支持数据类型!")
定义
前向(
自身, x):
返回 x
# 版本 1
# self
# |--- 权重 : 张量
# 偏置 : 张量
#
# 版本 2
# self
# |--- 重量 : 张量
# |--- 偏置 : 张量
torch.dtype
#
# 版本 3
# self
# |--- _packed_params : (Tensor, Tensor) 表示 (权重, 偏置)
# LinearPackedParams 的
torch.dtype
定义
保存到状态字典(
自身,
目的地,
前缀,
保留变量):
超级().
保存到状态字典(
目的地,
前缀,
保留变量)
目的地[
前缀 + "dtype"] =
自身.dtype
目的地[
前缀 + "_packed_params"] =
自身.
权重偏置()
定义
从状态字典加载(
自身,
state_dict,
前缀,
本地元数据,
严格的,
缺少键,
预期之外的键,
错误信息,
):
版本 =
本地元数据.
获取(
版本,
无)
如果
版本
是 None
或
版本 < 2:
自身.dtype =
火炬.qint8
否则:
自身.dtype = state_dict[
前缀 + "dtype"]
state_dict.弹出(
前缀 + "dtype")
如果
版本
是 None
或
版本 < 3:
自身.
设置权重偏差(
state_dict[前缀 +
权重
] state_dict[
前缀 +
偏置]
)
state_dict.弹出(
前缀 +
权重)
state_dict.弹出(
前缀 +
偏置)
如果
版本 == 3:
重量,
偏差 = state_dict[
前缀 + "_packed_params"]
state_dict.弹出(
前缀 + "_packed_params")
自身.
设置权重偏差(
重量,
偏置)
超级().
从状态字典加载(
state_dict,
前缀,
本地元数据,
错误,
缺少键,
预期之外的键,
错误信息,
)
定义 __repr__(
自身):
返回
自身.
权重偏置().__repr__()
[文档]
类
线性(
加权量化模块):
r""
一个量化线性模块,输入和输出都是量化张量。
我们采用与 `torch.nn.Linear` 相同的接口,请参阅文档。
https://pytorch.org/docs/stable/nn.html#torch.nn.Linear 查看文档。
与 :class:`~torch.nn.Linear` 相似,属性将在模块创建时随机初始化,稍后将被覆盖
权重(Tensor):模块的非可学习量化权重
属性:
weight (Tensor):该模块的非可学习量化权重
形状 :math:`(\text{out\_features}, \text{in\_features})`.
偏置(Tensor):该模块的非可学习偏置,形状为 :math:`(\text{out\_features})`.
如果 :attr:`bias` 为 ``True``,则值初始化为零。
scale:输出量化张量的 `scale` 参数,类型:double
`zero_point` 参数用于输出量化张量,类型:长整型
示例:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_QENGINE)
>>> m = nn.quantized.Linear(20, 30)
>>> input = torch.randn(128, 20)
>>> # xdoctest: +SKIP
>>> input = torch.quantize_per_tensor(input, 1.0, 0, torch.quint8)
>>> output = m(input)
>>> 打印(output.size())
torch.Size([128, 30])
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
_version = 3
浮点模块 = (nn.
线性, nn.
模块.
线性.
非动态量化的线性)
定义
初始化(
自身,
输入特征,
输出特征, bias_=True,
数据类型=
火炬.qint8):
超级().
初始化()
我们在这里不与缓冲区或属性等纠缠
为了保持模块简单,*一切*都只是 Python 属性
序列化逻辑在下面的序列化和反序列化模块中显式处理
模块中进行
自身.
输入特征 =
输入特征
自身.
输出特征 =
输出特征
偏差 = None
如果
偏差:
偏差 =
火炬.
零(
输出特征,
数据类型=
火炬.float)
如果 dtype ==
火炬.qint8:
权重 =
火炬.
_空线性量化(
[输出特征,
输入特征
]
比例=1,
零点=0,
数据类型=
火炬.qint8
)
elif dtype == 火炬.float16:
权重 =
火炬.
零([
输出特征,
输入特征
]
数据类型=
火炬.float)
否则:
抛出异常
运行时错误(
"指定的量化线性数据类型不受支持!")
自身._packed_params =
线性打包参数(
数据类型)
自身._packed_params.
设置权重偏差(
权重,
偏置)
自身.
缩放 = 1.0
自身.
零点 = 0
定义
_获取名称(
自身):
返回
"量化线性"
定义
额外表示(
自身):
返回 (
fin_features={
自身.
输入特征}, out_features={
自身.
输出特征}
,缩放={
自身.
比例}
,"
fzero_point={
自身.
零点}
, 协议方案={
自身.
重量().
q 方案()}"
)
定义 __repr__(
自身):
返回 _hide_packed_params_repr(
自身,
线性打包参数)
定义
前向(
自身, x:
火炬.
张量) ->
火炬.
张量:
返回
火炬.
操作.
量化.
线性(
x, 自身._packed_params._packed_params,
自身.
比例,
自身.
零点
)
# ===== 序列化方法 =====
# 在这里需要特别注意,我们必须将权重解包到它们
# 序列化 QTensor 的常规形式。打包的权重不应存在于
# 创建它们的进程之外,而应从 QTensor 权重派生。
#
#
# 版本 1
# self
# |--- 缩放 : float
# |--- 零点 : int
# |--- 重量 : Tensor
# |--- 偏置 : Tensor
#
# 版本 2
# self
# |--- 缩放 : float
# |--- 零点 : int
# |--- _packed_params : 模块
# |--- 重量 : 张量
# |--- 偏置 : 张量
#
# 版本 3
# self
# |--- 缩放比例 : 浮点数
# |--- 零点 : 整数
# |--- _packed_params : 模块
表示线性打包参数 C++结构体的权重和偏置的 Tensor
与序列化方法相对应,我们必须将序列化的 QTensor 权重打包成打包格式,以便由 FBGEMM 操作使用。
#
定义
保存到状态字典(
自身,
目的地,
前缀,
保留变量):
超级().
保存到状态字典(
目的地,
前缀,
保留变量)
目的地[
前缀 +
"缩放"] =
火炬.
张量(
自身.
比例)
目的地[
前缀 +
零点] =
火炬.
张量(
自身.
零点)
# ===== 反序列化方法 =====
对应于序列化方法,我们必须将序列化的 QTensor 权重打包成打包格式,以便由 FBGEMM 操作使用。
将序列化的 QTensor 权重打包成打包格式,以便由 FBGEMM 操作使用。
定义
从状态字典加载(
自身,
state_dict,
前缀,
本地元数据,
严格的,
缺少键,
预期之外的键,
错误信息,
):
自身.
缩放 = float(state_dict[
前缀 +
"缩放"])
state_dict.弹出(
前缀 +
"缩放")
自身.
零点 = int(state_dict[
前缀 +
零点])
state_dict.弹出(
前缀 +
零点)
版本 =
本地元数据.
获取(
版本,
无)
如果
版本
是 None
或
版本 == 1:
我们将参数移动到了一个 LinearPackedParameters 子模块中
权重 = state_dict.
弹出(
前缀 +
权重)
偏差 = state_dict.
弹出(
前缀 +
偏置)
state_dict.更新(
{
前缀 + "_packed_params.weight":
重量,
前缀 + "_packed_params.bias":
偏置,
}
)
超级().
从状态字典加载(
state_dict,
前缀,
本地元数据,
错误,
缺少键,
预期之外的键,
错误信息,
)
函数而非属性以确保 JIT 序列化不会
将此注册为属性
定义
权重偏置(
自身):
返回
自身._packed_params.
权重偏置()
定义
重量(
自身):
返回
自身.
权重偏置()[0]
定义
偏置(
自身):
返回
自身.
权重偏置()[1]
定义
设置权重偏差(
自身, w:
火炬.
张量, b:
可选[
火炬.
张量]) ->
无:
自身._packed_params.
设置权重偏差(w, b)
[文档] @classmethod
定义
从浮点数(
类, mod,
使用预计算的假量化=
错误):
r从观察到的浮点模块创建量化模块
参数:
mod (模块):一个浮点模块,可以是 torch.ao.quantization
工具或由用户提供的
use_precomputed_fake_quant (布尔值): 如果为 True,模块将重用预计算伪量化的最小/最大值。
从预计算的伪量化模块中获取值。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
如果
有属性(mod,
"权重伪量化"):
如果
参数化前的类型(mod) == nniqat.
线性 Bn1d:
mod.重量, mod.
偏差 =
合并线性 BN 权重(
mod.重量,
mod.偏置,
mod.孟加拉语.
运行平均值,
mod.孟加拉语.
运行变量,
mod.孟加拉语.eps,
mod.孟加拉语.
重量,
mod.孟加拉语.
偏置,
)
权重后处理 = mod.weight_fake_quant
activation_post_process = mod.activation_post_process
否则:
# 此函数不参与 JIT,因此可以忽略
# 赋值中的类型不匹配问题。同时,mypy 也存在问题
# 不实现可迭代对象,因此也忽略这些。
如果 not isinstance(
类._FLOAT_MODULE,
迭代器):
类.
浮点模块 = [
类._FLOAT_MODULE]
支持的模块 =
“,”.
加入(
[浮点模块.__name__
为
浮点模块
在
类._FLOAT_MODULE]
)
错误信息 = f
nnq。{
类.__name__}
.from_float 只适用于{
支持的模块}
,但得到:{
类型(mod)}"
断言 (
参数化前的类型(mod)
在
类.
浮点模块
), 错误信息.
格式()
断言
有属性(
mod, qconfig
), 输入浮点模块必须定义 qconfig
activation_post_process = mod.activation_post_process
如果
参数化前的类型(mod) == nni.
线性 ReLU:
修饰 = mod[0]
权重后处理 = (
mod.qconfig.重量()
如果 not
有属性(mod,
"权重伪量化")
否则 mod.weight_fake_quant
)
如果 not
使用预计算的假量化:
观察者可能尚未被调用
观察者可能在之前的阶段通过 PTQ 算法(例如 AdaRound)被调用
权重后处理(mod.
重量)
dtype = 权重后处理.dtype
act_scale, act_zp = 激活后处理.
计算 q 参数()
断言 dtype ==
火炬.qint8,
权重观察者必须具有 torch.qint8 数据类型
权重 = _quantize_weight(mod.
重量.float(),
权重后处理)
q 线性 =
类(mod.
输入特征, mod.
输出特征,
数据类型=
数据类型)
q 线性.
设置权重偏差(
权重, mod.
偏置)
q 线性.
缩放 = float(act_scale)
q 线性.
零点 = int(
活动零偏置)
返回 qlinear
[文档] @类方法
def from_reference(cls, ref_qlinear, output_scale, output_zero_point):
r"""从参考量化模块创建一个(fbgemm/qnnpack)量化模块
Args:
ref_qlinear (模块): 一个引用的量化线性模块,可以是 torch.ao.quantization
工具生成的,或者由用户提供的
output_scale (浮点数): 输出张量的缩放比例
输出零点(int):输出张量的零点
"""
qlinear = cls(ref_qlinear.in_features, ref_qlinear.out_features)
qweight = ref_qlinear.get_quantized_weight()
qlinear.set_weight_bias(qweight, ref_qlinear.bias)
qlinear.scale = float(output_scale)
qlinear.zero_point = int(output_zero_point)
return qlinear