# mypy: 允许未类型化定义
导入
复制
导入
检查
导入 itertools
导入
警告
导入
火炬
导入 torch.ao.nn.quantized
是 nnq
导入 torch.nn
是
神经网络
from torch.ao.nn.intrinsic 导入 _FusedModule
from torch.ao.quantization.observer 导入
激活后处理
from torch.ao.quantization.qconfig 导入 (
激活无记忆性,
添加模块到 qconfig_obs_ctr,
默认动态 Q 配置,
float16 动态 Q 配置,
float_qparams_weight_only_qconfig,
float_qparams_weight_only_qconfig_4bit,
)
from torch.ao.quantization.quantization_mappings 导入 (
_get_special_act_post_process,
_has_special_act_post_process,
获取默认动态量化模块映射,
获取默认 QAT 模块映射,
获取默认 Qconfig 传播列表,
获取默认静态量化模块映射,
获取默认静态量化引用模块映射,
未设置观察者,
)
from torch.ao.quantization.stubs 导入 DeQuantStub, QuantWrapper
from torch.nn.utils.parametrize 导入 type_before_parametrizations
from .工具
导入
获取查询参数字典,
忽略参数化,没有子项
全部 = [
"获取默认自定义配置字典",
"传播量化配置_",
"添加量化和反量化",
"准备",
"量化",
"动态量化",
"准备量化加速训练(QAT)",
"量化 QAT",
"转换",
"swap_module",
]
# TODO 一旦不再需要向后兼容,请删除此注释以避免严重错误
是否是激活后处理 =
激活后处理
默认自定义配置字典 = {
float_to_observed_custom_module_class: {
神经网络.
长短期记忆网络:
神经网络.
可量化的.
长短期记忆网络,
神经网络.
多头注意力:
神经网络.
可量化的.
多头注意力,
},
"观测到量化自定义模块类": {
神经网络.
可量化的.
长短期记忆网络:
神经网络.
量化的.
长短期记忆网络,
神经网络.
可量化的.
多头注意力:
神经网络.
量化的.
多头注意力,
},
}
def 获取默认自定义配置字典():
r定义默认自定义配置字典。
返回
默认自定义配置字典
def 传播 qconfig 辅助函数(
模块,
qconfig 字典,
qconfig 父类=
无,
前缀=
输入文本翻译为简体中文为:"",
准备自定义配置字典=
无,
):
r这是一个用于 `propagate_qconfig_` 的辅助函数
参数:
模块:输入模块
qconfig_dict:将子模块名称映射到量化的字典
配置
qconfig_parent:父模块的量化配置,我们将回退到
此配置当未指定当前配置时
模块
当前模块对应的前缀,用作键
qconfig_dict
prepare_custom_config_dict: 自定义模块处理的字典
查看文档了解 :func:`~torch.ao.quantization.prepare_fx`
返回:
None, 模块就地修改并附加了 qconfig
"文档"
模块_qconfig =
qconfig 字典.
获取(
参数化前的类型(
模块),
qconfig 父
)
模块_qconfig =
qconfig 字典.
获取(
前缀,
模块_qconfig)
模块_qconfig = getattr(
模块,
qconfig,
模块_qconfig)
火把.
嗳.
量化.qconfig._assert_valid_qconfig(
模块_qconfig,
模块)
带设备检查的 qconfig =
添加模块到 qconfig_obs_ctr(
模块_qconfig,
模块)
模块.qconfig =
带设备检查的 qconfig
for 名称,
儿童
在
模块.
命名子项():
模块前缀 =
前缀 + "." +
名称
如果
前缀
否则
名称
# 如果子模块不可追踪,则不将 qconfig 传播到子模块
如果
准备自定义配置字典
是
无
或者
不 (
名称
在
准备自定义配置字典.
获取(
"不可追踪的模块名称",
[]
或者
类型(
儿童)
在
准备自定义配置字典.
获取(
"不可追踪的模块类",
[]
):
_传播_qconfig 助手(
儿童,
qconfig 字典,
带设备检查的 qconfig,
模块前缀
)
[文档]def 传播_qconfig_(模块, qconfig_dict=None, prepare_custom_config_dict=None):
传播 qconfig 通过模块层次结构并分配 `qconfig`
属性在每个叶子模块上
参数:
模块:输入模块
qconfig_dict:将子模块的名称或类型映射到量化配置的字典
量化配置,qconfig 适用于给定模块的所有子模块,除非为子模块指定了 qconfig(当子模块已经具有 qconfig 属性时)
除非为子模块指定了 qconfig(当子模块已经具有 qconfig 属性时)
除非为子模块指定了 qconfig(当子模块已经具有 qconfig 属性时)
prepare_custom_config_dict: 自定义模块处理的字典
see docs for :func:`~torch.ao.quantization.prepare_fx`: 查看文档了解 :func:`~torch.ao.quantization.prepare_fx`
Return:
None, module is modified inplace with qconfig attached
"""
如果 qconfig_dict 为 None:
qconfig_dict = {}
如果 prepare_custom_config_dict 为 None:
prepare_custom_config_dict = {}
_propagate_qconfig_helper(
模块,qconfig_dict,prepare_custom_config_dict=prepare_custom_config_dict
)
def _observer_forward_hook(我,
输入,
输出):
r前向钩子,调用观察者在输出上
返回
我.
激活后处理(
输出)
def _observer_forward_pre_hook(我,
输入):
r前置预钩子,调用观察者处理输出
返回
我.
激活后处理(
输入[0])
def _注册激活后处理钩子(
模块, pre_hook=
错误):
断言
有属性(
模块,
"激活后处理"
), "期望模块已附加激活后处理属性"
如果 pre_hook:
模块.
注册前向钩子(_observer_forward_pre_hook,
预先添加=
是)
否则:
模块.
注册前向钩子(_observer_forward_hook,
预先添加=
是)
def _add_observer_(
模块,
qconfig_propagation_list=无,
非叶模块列表=
无,
设备=
无,
自定义模块类映射=
无,
):
r添加模块叶子的观察者。
此函数将观察者模块插入到所有叶子子模块中。
具有有效的 qconfig 属性。
参数:
模块:输入模块,具有所有要量化的叶子模块的 qconfig 属性。
qconfig_propagation_list:一个将添加观察者的可量化模块列表。
如果它们是叶子节点。
设备:父设备(如果有)
非叶模块列表:我们想要添加观察者的非叶模块列表
返回:
无,模块就地修改,添加了观察者模块和前向钩子
"文档"
如果 qconfig_propagation_list
是
无:
qconfig 传播列表 =
获取默认 qconfig 传播列表()
如果
自定义模块类映射
是
无:
自定义模块类映射 = {}
添加观察者时请尊重设备亲和性
如果
设备
是
无:
设备 = _get_unique_devices_(
模块)
断言 (
长度(
设备)
≤ 1
), f"_add_observer_" 只适用于 cpu 或单设备 CUDA 模块,但得到了设备{
设备}"
设备 =
下一(
迭代(
设备))
如果
长度(
设备) > 0
否则
无
def 获取激活后处理(qconfig,
设备,
特殊行为后处理=
无):
激活 = (
qconfig.激活()
如果
特殊行为后处理
是
无
否则
特殊行为后处理()
)
如果
设备
是
不
无:
激活.
到(
设备)
返回
激活
def 需要观察(m):
返回
有属性(m, "qconfig")
并且 m.qconfig
是
不
无
def 插入激活后处理(m,
特殊激活后处理=
无):
添加激活后处理模块并注册
模块调用的前或后钩子
"文档"
对于 DeQuantStub 不插入 observer/fake_quantize
如果
需要观察(m)
并且
不 isinstance(m, DeQuantStub):
模块交换后观察者和钩子将消失
m.添加模块(
激活后处理,
获取激活后处理(
m.qconfig, 设备,
特殊激活后处理
),
)
将观察者注册为钩子列表中的第一个条目
所有前置转发钩子都将被保留,并在转换前执行观察者之后
_注册激活后处理钩子(
m, pre_hook=_激活是无状态的(m.qconfig)
)
for 名称,
儿童
在
模块.
命名子项():
# TODO 在代码库稳定后删除 Dropout 特殊处理
如果
参数化前的类型(
儿童)
在 [
神经网络.Dropout
]:
continue
elif 派生类(
参数化前的类型(
儿童), (
氮气.FloatFunctional,
氮气.
函数性)
):
如果
需要观察(
儿童):
断言
有属性(
儿童,
"激活后处理"
), f"功能类"{
参数化前的类型(
儿童)}
没有预定义的 `activation_post_process`
儿童.activation_post_process =
获取激活后处理(
儿童.qconfig,
设备
)
elif isinstance(儿童, _FusedModule):
现在直接将 activation_post_process 添加到 nn.Sequential/_FusedModule
如果
需要观察(
儿童):
插入 activation_post_process(
儿童)
elif (
非叶模块列表
是
不
无
并且
参数化前的类型(
儿童)
在
非叶模块列表
):
如果
需要观察(
儿童):
插入激活后处理(
儿童)
elif _具有特殊活动后处理(
儿童):
特殊动作后处理 =
_获取特殊动作后处理(
儿童)
插入激活后处理(
儿童,
特殊动作后处理)
elif (
需要观察(
儿童)
并且
参数化前的类型(
儿童)
在
自定义模块类映射
):
被观察类 =
自定义模块类映射[
参数化前的类型(
儿童)
]
观测子 =
观测类别.
从浮点数(
儿童)
setattr(模块,
名称,
观察到的子项)
# TODO: 这些是无法观察到的模块
# 一旦更多,我们应该将它们移动到单独的列表中
如果
不
派生类(
观察到的类,
元组(
无观察者设置())):
插入激活后处理(
被观察子)
否则:
_添加观察者_(
儿童,
qconfig 传播列表,
非叶模块列表,
设备,
自定义模块类映射,
)
仅插入叶节点的观察者,注意,此观察者是用于
模块输出,对于 QuantStub 的输入将观察它们
如果 (
忽略参数化,没有子项(
模块)
并且
不 isinstance(
模块,
火把.
神经网络.
顺序的)
并且
参数化前的类型(
模块)
在
qconfig 传播列表
):
插入激活后处理(
模块)
# 这是 AdaRound eager 模式的特殊情况
# AdaRound 包含需要从 API 传播到转换的 weight_fake_quant
# 叶子节点检查具有多个子节点的天真假设是块
# 为 AdaRound 添加一个异常情况
如果 (
有属性(
模块,
"权重伪量化")
并且
不 isinstance(
模块,
火把.
神经网络.
顺序的)
并且
参数化前的类型(
模块)
在
qconfig 传播列表
):
插入激活后处理(
模块)
def _获取唯一设备_(
模块):
返回 {p.
设备 for p
在
模块.
参数()
如果 p.
设备.
类型 !=
元数据} | {
p.设备 for p
在
模块.
缓冲区()
如果 p.
设备.
类型 !=
元数据
}
[文档]def add_quant_dequant(module):
将叶子子模块包裹在 QuantWrapper 中,如果它有一个有效的 qconfig
请注意,此函数将就地修改模块的子项
可以返回一个新的模块,该模块将输入模块包装起来。
Args:
模块:具有 qconfig 属性的输入模块,适用于所有需要量化的叶子模块
我们想要量化的
Return:
无论是原地修改的模块及其子模块被`QuantWrapper`包装,还是基于 qconfig 的新`QuantWrapper`模块,或者是将输入模块包装起来的模块,后一种情况仅发生在输入模块是叶子模块且我们想要对其进行量化时。
`QuantWrapper`基于 qconfig 或创建一个新的`QuantWrapper`模块,该模块将输入模块包装起来,
当输入模块是叶子模块且我们想要对其进行量化时,才会发生这种情况。
当输入模块是叶子模块且我们想要对其进行量化时,才会发生这种情况。
"""
if (
检查模块是否有无子模块,忽略参数化
并且模块具有 "qconfig" 属性
和模块.qconfig
):
返回 QuantWrapper(module)
对于 name, child in module.named_children():
module._modules[name] = add_quant_dequant(child)
return module
[文档]def prepare(
模型,
内置=
错误,
allow_list=无,
观察者非叶模块列表=
无,
准备自定义配置字典=
无,
):
r准备模型进行量化校准或量化感知训练的副本。
量化配置应预先分配
在 `.qconfig` 属性中指向各个子模块。
模型将附加观察器或伪量化模块,并将 qconfig 传播。
将传播。
参数:
`model`: 要就地修改的输入模型。
`inplace`: 在原地执行模型转换,原始模块将被修改
`allow_list`: 可量化的模块列表
`observer_non_leaf_module_list`: 我们想要添加观察者的非叶模块列表
`prepare_custom_config_dict`: prepare 函数的自定义配置字典
.. 代码块 :: python
准备自定义配置字典示例
prepare_custom_config_dict = {
用户将手动定义相应的观察
# 模块类具有一个 from_float 类方法,该方法可以将浮点数转换为
自定义浮点模块到观察自定义模块
"float_to_observed_custom_module_class": {
自定义模块: 观察自定义模块
}
}
"文档"
火把._C._log_api_usage_once(
"量化 API.量化.准备")
如果
准备自定义配置字典
是
无:
准备自定义配置字典 =
获取默认自定义配置字典()
自定义模块类映射 =
准备自定义配置字典.
获取(
float_to_observed_custom_module_class, {}
)
如果
不
内置:
模型 =
复制.
深拷贝(
模型)
# TODO: 删除 allow_list
qconfig_propagation_list = 允许列表
如果
允许列表
是
无:
qconfig 传播列表 =
获取默认 qconfig 传播列表()
propagate_qconfig_(模型, qconfig_dict=
无)
# 疯狂检查常见 API 误用
如果
不
任何(
有属性(m, "qconfig")
并且 m.qconfig for m
在
模型.
模块()):
警告.
警告(
"没有任何子模块应用了 qconfig。请确保通过`qconfig_dict`传递正确的配置或"
"直接在子模块上分配`.qconfig`属性"
"在子模块上直接分配`.qconfig`属性"
)
_add_observer_(
模型,
qconfig 传播列表,
观察者非叶子模块列表,
自定义模块类映射=
自定义模块类映射,
)
返回
模型
def _移除激活后处理(
模块):
# TODO: 可能我们应该将 activation_post_process 改为 _activation_post_process
# 以防止它被用户使用
如果
有属性(
模块,
"激活后处理")
并且 _is_activation_post_process(
模块.
激活后处理
):
delattr(模块,
"激活后处理")
移除 activation_post_process 预处理和后处理钩子
def 移除钩子(pre_hook=
错误):
钩子映射 =
模块._forward_pre_hooks
如果
预钩子
否则
模块.
前向钩子
观察者钩子 = (
_observer_forward_pre_hook 如果
预钩子
否则 _observer_forward_hook
)
处理要删除的 ID =
设置()
for 处理 ID,
钩子函数
在
钩子映射.
项目():
如果
hook 函数
是
观察者钩子:
处理要删除的 ID.
添加(
处理 ID)
for handle_id 在 handle_ids_to_remove:
hook_map.流行(handle_id)
删除钩子(pre_hook=
是)
删除钩子(pre_hook=
错误)
# TODO: 更名为一个更通用的名称
def _移除_qconfig(
模块):
r清理模块中遗留的 qconfig,以便新的 qconfig 可以
传播。
参数:
模块:需要清理的模块
"文档"
for 儿童
在
模块.
儿童():
_remove_qconfig(儿童)
如果
有属性(
模块,
qconfig):
删除
模块.qconfig
_remove_activation_post_process(模块)
[文档]def quantize(model, run_fn, run_args, mapping=None, inplace=False):
r"""使用训练后静态量化对输入浮点模型进行量化。"""
首先它会为校准准备模型,然后调用
`run_fn` 函数来运行校准步骤,之后我们将
将模型转换为量化模型。
参数:
模型:输入浮点模型
run_fn:用于校准准备好的模型的校准函数
run_args:`run_fn`的位置参数
inplace:就地执行模型转换,原始模块被修改
映射:原始模块类型与量化对应物之间的对应关系
返回:
量化模型。
```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)
```
torch._C._log_api_usage_once("量化_api.量化.量化")
if mapping is None:
mapping = get_default_static_quant_module_mappings()
if not inplace:
model = 深度复制(model)
model.eval()
prepare(model, inplace=True)
run_fn(model, *run_args)
convert(model, mapping, inplace=True)
return model
[文档]def quantize_dynamic(
模型, qconfig_spec=
无,
数据类型=
火把.qint8,
映射=
无,
内置=
假
):
r将浮点模型转换为动态(即仅权重)量化模型。
将指定的模块替换为仅权重量化的动态版本,并输出量化模型。
对于最简单的使用,请提供`dtype`参数,可以是 float16 或 qint8。默认情况下,对于权重大小较大的层(即线性层和 RNN 变体)将执行仅权重量化。
默认情况下,仅权重量化将应用于权重大小较大的层,即线性层和 RNN 变体。
使用 `qconfig` 和类似 `quantize()` 的 `mapping` 可以实现细粒度控制。
如果提供了 `qconfig`,则忽略 `dtype` 参数。
参数:
输入模型
qconfig_spec: 或者:
- 一个将子模块的名称或类型映射到量化配置的字典
qconfig 应用于给定模块的所有子模块
模块除非指定了子模块的 qconfig(当子模块已经具有 qconfig 属性时)
字典中的条目需要是 QConfig 实例。
- 应用动态量化的类型集和/或子模块名称
- 应用动态量化的类型集和/或子模块名称
在这种情况下,使用 `dtype` 参数来指定位宽
就地:在原地执行模型转换,原始模块被修改
映射:将子模块的类型映射到相应动态量化版本的类型
与需要替换的子模块相关
"文档"
火把._C._log_api_usage_once(
quantization_api.quantize.quantize_dynamic)
如果 qconfig_spec
是
无:
如果 dtype ==
火把.qint8:
qconfig_spec = {
神经网络.
线性: default_dynamic_qconfig,
神经网络.
长短期记忆网络:
默认动态 Q 配置,
神经网络.GRU:
默认动态 Q 配置,
神经网络.LSTMCell:
默认动态量化配置,
神经网络.
RNN 单元:
默认动态量化配置,
神经网络.
GRU 单元:
默认动态 Q 配置,
}
elif dtype == 火把.float16:
Q 配置规范 = {
神经网络.
线性:
float16 动态 Q 配置,
神经网络.
长短期记忆网络:
float16 动态 Q 配置,
神经网络.GRU: float16_dynamic_qconfig,
神经网络.LSTMCell: float16_dynamic_qconfig,
神经网络.
RNN 单元: float16_dynamic_qconfig,
神经网络.
GRU 单元: float16_dynamic_qconfig,
}
elif dtype == 火把.quint8:
qconfig 规范 = {
神经网络.EmbeddingBag:
仅权重_qconfig 的浮点_qparams,
神经网络.
嵌入:
仅权重_qconfig 的浮点_qparams,
}
elif dtype == 火把.quint4x2:
qconfig 规范 = {
神经网络.EmbeddingBag:
仅权重浮点_qparams_4 位 qconfig,
}
否则:
raise ValueError(
f不知道如何使用默认设置进行量化{
数据类型}
请提供完整的 qconfig
)
elif isinstance(qconfig 规范,
设置):
如果 dtype
是
火把.qint8:
默认_qconfig = default_dynamic_qconfig
elif dtype 是
火把.float16:
默认_qconfig =
float16 动态 qconfig
elif dtype 是
火把.quint8:
默认_qconfig = float_qparams_weight_only_qconfig
elif dtype 是
火把.quint4x2:
默认_qconfig =
仅权重浮点 Q 参数_4 位 Q 配置
否则:
raise 运行时错误(
"指定的量化动态数据类型未知:",
字符串(
数据类型)
)
qconfig 规范 =
字典(zip(
qconfig 规范, itertools.
重复(
默认 Q 配置)))
如果
映射
是
无:
映射 =
获取默认动态量化模块映射()
如果
不
内置:
模型 =
复制.
深拷贝(
模型)
模型.
评估()
propagate_qconfig_(模型, qconfig_spec)
转换(
模型,
映射,
内置=
是)
返回
模型
[文档]def prepare_qat(model, mapping=None, inplace=False):
r"""
准备模型的副本以进行量化校准或
量化感知训练,并将其转换为量化版本。
应预先将量化配置分配给各个子模块的 `.qconfig` 属性。
到 `.qconfig` 属性中的各个子模块。
Args:
模型:要就地修改的输入模型
mapping:将浮点模块映射到要替换的量化模块的字典
。
inplace: 在原地执行模型转换,原始模块
被修改
"""
torch._C._log_api_usage_once("量化_api.quantize.prepare_qat")
断言 model.training,"prepare_qat 仅在模型训练模式下工作"
如果 mapping 为 None:
mapping = get_default_qat_module_mappings()
如果 not inplace:
model = 深度复制(model)
propagate_qconfig_(model, qconfig_dict=None)
convert(model, mapping=mapping, inplace=True, remove_qconfig=False)
prepare(model, observer_non_leaf_module_list=set(mapping.values()), inplace=True)
返回模型
[文档]def quantize_qat(model, run_fn, run_args, inplace=False):
r"""进行量化感知训练并输出量化模型
Args:
model: 输入模型
run_fn:评估准备好的模型的函数,可以是
函数仅运行准备好的模型或训练
循环
run_args: `run_fn`的位置参数
返回:
量化模型。
"""
torch._C._log_api_usage_once("量化_api.量化.量化_qat")
如果不是原地修改:
模型 = copy.deepcopy(模型)
模型.train()
prepare_qat(模型, inplace=True)
run_fn(model, *run_args)
convert(model, inplace=True)
return model
[文档]def
转换(
模块,
映射=
无,
内置=
错误,
删除_qconfig=
是,
是引用=
错误,
将自定义配置字典转换=
无,
使用预计算的假量化=
错误,
):
r将输入模块中的子模块转换为不同的模块,根据 `mapping`
通过在目标模块类上调用 `from_float` 方法。并移除 qconfig 在
如果 remove_qconfig 设置为 True 则结束。
参数:
`模块`: 准备并校准的模块
`映射`: 一个从源模块类型映射到目标模块类型的字典
类型,可以被覆盖以允许交换用户定义的
模块
`inplace`: 在原地执行模型转换,原始模块将被修改
被修改
`convert_custom_config_dict`: 转换函数的自定义配置字典
`use_precomputed_fake_quant`: 一个标志,用于启用预计算的假量化
.. 代码块 :: python
转换自定义配置字典示例
convert_custom_config_dict = {
用户将手动定义相应的量化模块类
该类具有一个 from_observed 类方法,用于转换
观测的自定义模块转换为量化自定义模块
"observed_to_quantized_custom_module_class": {
ObservedCustomModule: QuantizedCustomModule
}
}
"文档"
火把._C._log_api_usage_once("quantization_api.quantize.convert")
如果
不
内置:
模块 =
复制.
深拷贝(
模块)
转换(
模块,
映射,
内置=
是,
是参考=
是参考,
转换自定义配置字典=
转换自定义配置字典,
使用预计算的假量化=
使用预计算的假量化,
)
如果
移除 qconfig:
移除_qconfig(
模块)
返回
模块
def 转换(
模块,
映射=
无,
内置=
错误,
参考项=
错误,
转换自定义配置字典=
无,
使用预计算的假量化=
错误,
):
r将输入模块中的子模块根据 `mapping` 转换为不同的模块
通过在目标模块类上调用 `from_float` 方法
参数:
模块:输入模块
映射:一个从源模块类型映射到目标模块类型的字典
模块类型,可以被重写以允许替换用户定义的
模块
就地:在原地执行模型转换
是突变的
is_reference:启用量化参考模块的标志
使用预计算伪量化标志
"文档"
如果
映射
是
无:
映射 = (
获取默认静态量化引用模块映射()
如果
是否为引用
否则
获取默认静态量化模块映射()
)
如果
转换自定义配置字典
是
无:
转换自定义配置字典 =
获取默认自定义配置字典()
自定义模块类映射 =
转换自定义配置字典.
获取(
"观测到量化自定义模块类", {}
)
如果
不
内置:
模块 =
复制.
深拷贝(
模块)
重新分配 = {}
for 名称,
修饰
在
模块.
命名子项():
# 两个融合模块和观测自定义模块都被
# 当作一个单元进行交换
如果 (
不 isinstance(
模块,
混合模块)
并且
参数化前的类型(
模块)
不
在
自定义模块类映射
):
转换(
模块,
映射,
是,
#就地
是否为引用,
转换自定义配置字典,
使用预计算的假量化=
使用预计算的假量化,
)
重新分配[
名称] =
模块交换(
模块,
映射,
自定义模块类映射,
使用预计算的假量化
)
for 键,
值
在
重新分配.
项目():
模块.
模块[
键] =
值
返回
模块
[文档]def
交换模块(
模块,
映射,
自定义模块类映射,
使用预计算假量化=
假
):
r交换具有量化对应模块的模块
观察者附加。
参数:
模块:输入模块
映射:从 nn 模块到 nnq 模块的字典
返回:
`mod` 对应的量化模块
"文档"
new_mod = 修饰
如果
有属性(
模块,
qconfig)
并且
模块.qconfig
是
不
无:
交换 =
假
如果
参数化前的类型(
模块)
在
自定义模块类映射:
新模块 =
自定义模块类映射[
参数化前的类型(
模块)
].来自观察(
模块)
交换的 =
真实
elif 参数化前的类型(
模块)
在
映射:
qmod = 映射[
参数化前的类型(
模块)]
如果
有属性(qmod, "_IS_REFERENCE")
并且 qmod.
参考项:
断言
模块.qconfig
是
不
无
权重后处理 =
模块.qconfig.
重量()
权重后处理(
模块.
重量)
权重查询参数 =
获取查询参数字典(
权重后处理)
新模块 = qmod.
从浮点数(
模块,
权重参数)
否则:
sig = 检查.
签名(qmod.
从浮点数)
如果
使用预计算的假量化
在
签名.
参数:
新模块 = qmod.
从浮点数(
模块,
使用预计算的假量化=
使用预计算的假量化
)
否则:
新模块 = qmod.
从浮点数(
模块)
交换的 =
真实
如果
交换:
# 保留模块的预前向钩子。它们将在量化输入上被调用
for pre_hook_fn 在
模块.
_前向预处理钩子.
值():
新模块.
注册前向钩子(
预钩子函数)
保留模块的转发钩子,除了_observer_forward_hook
转换后,它们将使用量化输出工作
for 钩子函数
在
模块.
_前向钩子.
值():
如果
钩子函数
是
不 _observer_forward_hook:
新模块.
注册前向钩子(
钩子函数)
# 尊重设备亲和性以交换模块
设备 =
_获取唯一设备_(
模块)
断言
长度(
设备)
≤ 1
或者 (
长度(
设备) == 2
并且
火把.
设备(
元数据)
在
设备
), f"swap_module 仅支持与 CPU 或单设备 CUDA 模块一起使用,但得到了设备"{
设备}"
设备 =
下一(
迭代(
设备))
如果
长度(
设备) > 0
否则
无
如果
设备:
新模块.
到(
设备)
返回
新模块
def _get_observer_dict(模块,
目标字典,
前缀=
输入文本翻译为简体中文为:""):
r"遍历模块并将所有观察者保存到字典中。"
这主要用于量化精度调试
参数:
模块:我们要保存所有观察者的顶级模块
前缀:当前模块的前缀
target_dict:保存所有观察者的字典
"文档"
def 获取前缀(
前缀):
返回
前缀
如果
前缀 ==
请提供需要翻译的文本
否则
前缀 + "."
如果
有属性(
模块,
"激活后处理"):
目标字典[
获取前缀(
前缀) +
"激活后处理"
] = 模块.
激活后处理
for 名称,
儿童
在
模块.
命名子项():
模块前缀 =
获取前缀(
前缀) +
名称
如果
前缀
否则
名称
获取观察者字典(
儿童,
目标字典,
模块前缀)