• 文档 >
  • 模块代码 >
  • torch >
  • torch.ao.ns._numeric_suite
快捷键

torch.ao.ns._numeric_suite 源代码

# mypy: 允许未类型化定义
from 打字 导入 任何, 可调用, 可选, 联合

导入 火炬
导入 torch.ao.nn.quantized  nnq
导入 torch.ao.nn.quantized.dynamic  nnqd
导入 torch.nn  神经网络
from torch.ao.quantization 导入 准备
from torch.ao.quantization.quantization_mappings 导入 (
    获取默认比较输出模块列表,
)


非叶子模块添加观察者允许列表 = {
    氮气.线性,
    氮气.线性,
    氮气.长短期记忆网络,
    神经网络.长短期记忆网络,
}


def _find_match(
    字符串列表: 联盟[字典[字符串, 任何], 列表[字符串]],
    key_str: 字符串,
    后缀: 字符串,
) -> 可选[字符串]:
    分割字符串 = key_str.分割(“。”)
    如果 分割字符串[-1] == 后缀:
        匹配字符串 = 输入文本翻译为简体中文为:"".连接(key_str.分割(“。”)0:-1])
        for s2  字符串列表:
            模式 1 = 输入文本翻译为简体中文为:"".连接(s2.分割(“。”)0:-1])
            模式 2 = 输入文本翻译为简体中文为:"".连接(s2.分割(“。”)0:-2])
            如果 匹配字符串 == 模式 1:
                返回 s2
            如果 匹配字符串 == 模式 2:
                返回 s2

        用于匹配 "fc.weight" 和 "fc._packed_params._packed_params"
        如果 后缀 == "_packed_params":
            匹配字符串 = 输入文本翻译为简体中文为:"".连接(key_str.分割(“。”)0:-2])
            如果 长度(匹配字符串) == 0:
                返回 
            for s2  字符串列表:
                模式 1 = 输入文本翻译为简体中文为:"".连接(s2.分割(“。”)0:-1])
                模式 2 = 输入文本翻译为简体中文为:"".连接(s2.分割(“。”)0:-2])
                如果 匹配字符串 == 模式 1:
                    返回 s2
                如果 匹配字符串 == 模式 2:
                    返回 s2
        返回 
    否则:
        返回 


[文档]def 比较权重( 浮点字典: 字典[字符串, 任何], 量化字典: 字典[字符串, 任何] ) -> 字典[字符串, 字典[字符串, 火把.张量]] r比较浮点模块与其相应量化模块的权重 模块。返回一个字典,键对应模块名称,每个条目为 一个包含两个键 'float' 和 'quantized' 的字典,包含浮点数和 量化权重。此字典可用于比较和计算量化 浮点模型和量化模型权重错误。 演示用法: wt_compare_dict = compare_weights(浮点模型.state_dict(), qmodel.state_dict()) for key in wt_compare_dict: 对于 wt_compare_dict 中的每个键: print( key, compute_error( wt_compare_dict[key]['float'], wt_compare_dict[key]['quantized'].dequantize() ) ) 参数: float_dict: 浮点模型的状态字典 quantized_dict: 量化模型的状态字典 返回: weight_dict: 与模块名称对应的键的字典,每个条目为 一个包含两个键 'float' 和 'quantized' 的字典,包含浮点数和 量化权重 "文档" 火把._C._log_api_usage_once("quantization_api._numeric_suite.compare_weights") 重量字典: 字典[字符串, 字典] = {} for key 量化字典: 匹配键 = _find_match(浮点字典, , 重量) 如果 匹配键 : 重量字典[] = {} 重量字典[] [浮点数] = 浮点字典[匹配键] 重量字典[] [量化] = 量化字典[] continue 用于匹配 "fc.weight" 和 "fc._packed_params._packed_params" 匹配键 = _find_match(浮点字典, , "_packed_params") 如果 匹配键 : 重量字典[] = {} 重量字典[] [浮点数] = 浮点字典[匹配键] 重量字典[] [量化] = 量化字典[] [0] # 对于 LSTM 分割字符串 = .分割(“。”) 如果 分割字符串[-1] == "参数" 并且 分割字符串[-3] == "所有权重值": = 分割字符串[-2] 模块名称 = “。”.连接(分割字符串[-3]) float_weight_ih_key = 模块名称 + ".weight_ih_l" + float_weight_hh_key = 模块名称 + ".weight_hh_l" + 如果 float_weight_ih_key float_dict 并且 float_weight_hh_key 浮点字典: 重量字典[] = {} 重量字典[] [浮点数] = 浮点字典[浮点权重_ih 键] 重量字典[] [量化] = ( 量化字典[].__getstate__()[0] [4] [0].__getstate__()[0] [0] ) 重量字典[] [浮点数] = 浮点字典[浮点权重 hh 键] 重量字典[] [量化] = ( 量化字典[].__getstate__()[0] [4] [1].__getstate__()[0] [0] ) 返回 重量字典
def _get_logger_dict_helper( 模块: 神经网络.模块, 目标字典: 字典[字符串, 任何], 前缀: 字符串 = 输入文本翻译为简体中文为:"", ) -> : r这是 get_logger_dict 的辅助函数 参数: mod: 我们想要保存所有日志统计信息的模块 prefix: 当前模块的前缀 target_dict: 保存所有日志统计信息的字典 "文档" def 获取前缀(前缀): 返回 前缀 如果 前缀 == 请提供需要翻译的文本 否则 前缀 + "." for 名称, 儿童 模块.命名子项(): 如果 isinstance(儿童, 记录器): 目标字典[获取前缀(前缀) + 统计] = 儿童.统计 断开 for 名称, 儿童 模块.命名子项(): 模块前缀 = 获取前缀(前缀) + 名称 如果 前缀 否则 名称 _get_logger_dict_helper(儿童, 目标字典, 模块前缀)
[文档]def get_logger_dict(mod: nn.Module, prefix: str = "") -> dict[str, dict]: 遍历模块并将所有日志统计信息保存到目标字典中。 这主要用于量化精度调试。 支持的日志记录器类型: ShadowLogger:用于记录量化模块及其匹配的浮点阴影模块的输出, OutputLogger:用于记录模块的输出 Args: mod:我们要保存所有日志统计信息的模块 前缀:当前模块的前缀 返回: 目标字典:用于保存所有日志统计信息的字典 """ torch._C._log_api_usage_once("量化_api._numeric_suite.get_logger_dict") target_dict: dict[str, dict] = {} _get_logger_dict_helper(mod, target_dict, prefix) return target_dict
[文档]class Logger(nn.Module): r"""日志统计的基础类""" def __init__(self): super().__init__() self.stats = {} # 仅当操作使用静态量化时才插入观察者, # 这通过 activation_observer.dtype == quint8 来识别。这在将 Logger 作为观察者附加到 FX 模式时是必需的 # 当将 Logger 作为观察者附加到 FX 模式时是必需的 self.dtype = torch.quint8
[文档] def forward(self, x): # fmt: off """ 空白文档块以使 autodoc 高兴
# fmt: on
[文档]类 ShadowLogger(日志记录器): 用于 Shadow 模块的类,用于记录原始输出 阴影模块。 """ def __init__(self): super().__init__() self.stats["float"] = [] self.stats["quantized"] = []
[文档] def forward(self, x, y): # 类型:忽略[覆盖] # fmt: off ```python # 输入文本 input_text = '"""' # 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API) def translate_to_simplified_chinese(text): # 假设的翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` ``` # 空文档块以使自动文档功能满意 # fmt: 开启格式化 如果 len(x) > 1: x = x[0] 如果 len(y) > 1: y = y[0] self.stats["quantized"].append(x.detach()) self.stats["float"].append(y.detach())
[文档]class OutputLogger(Logger): 类用于记录模块的输出 def __init__(self): super().__init__() self.stats["tensor_val"] = []
[文档] def forward(self, x): # fmt: off """ """ # 空文档块以使 autodoc 高兴 # fmt: 开启格式化 self.stats["tensor_val"].append(x) 返回 x
def 转换为列表
(t: 任何) -> 任何: 返回 [转换为列表(x) for x t] 如果 类型(t) 元组 否则 t def _反量化张量列表(t: 任何) -> 任何: 返回 ( [_反量化张量列表(x) for x t] 如果 类型(t) 列表 否则 t.反量化() 如果 t.是否量化 否则 t )
[文档] 影子(神经网络.模块): r阴影模块将其浮点模块附加到其匹配的量化模块 作为阴影。然后它使用 Logger 模块处理两者的输出 模块 参数: q_module:从 float_module 量化的模块,我们想要进行阴影 float_module:用于遮蔽 q_module 的浮点模块 logger_cls:用于处理 q_module 输出结果的日志器类型 float_module。可以使用 ShadowLogger 或自定义日志器。 "文档" def __init__(, q_module, 浮点模块, 日志类): 超级().__init__() .原模块 = Q 模块 .阴影模块 = 浮动模块 .反量化 = 氮气.反量化化() .记录器 = 日志类()
[文档] def forward(self, *x) -> torch.Tensor: # fmt: off """ """ # 空文档块以使自动文档功能满意 # fmt: 开启格式化 xl = 将元组转换为列表(x) 输出 = self.orig_module(*xl) xl_float = _dequantize_tensor_list(xl) shadow_output = self.shadow_module(*xl_float) self.logger(output, shadow_output) return output
[文档] def add(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: # fmt: off ```python # 输入文本 input_text = '"""' # 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API) def translate_to_simplified_chinese(text): # 假设的翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` ``` # 空文档块以使自动文档功能满意 # fmt: 开启格式化 output = self.orig_module.add(x, y) x = x.dequantize() y = y.dequantize() shadow_output = self.shadow_module.add(x, y) self.logger(输出, 阴影输出) 返回输出
[文档] def add_scalar(self, x: torch.Tensor, y: float) -> torch.Tensor: # fmt: off ```python # 输入文本 input_text = '"""' # 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API) def translate_to_simplified_chinese(text): # 假设的翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` ``` # 空文档块以使自动文档功能满意 # fmt: 开启格式化 输出 = self.orig_module.add_scalar(x, y) x = x.dequantize() shadow_output = self.shadow_module.add_scalar(x, y) self.logger(output, shadow_output) return output
[文档] def mul(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: # fmt: off """ """ # 空文档块以使自动文档功能正常 # fmt: 开启格式化 输出 = self.orig_module.mul(x, y) x = x 反量化() y = y.dequantize() shadow_output = self.shadow_module.mul(x, y) self.logger(output, shadow_output) return output
[文档] def mul_scalar(self, x: torch.Tensor, y: float) -> torch.Tensor: # fmt: off ```python # 输入文本 input_text = '"""' # 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API) def translate_to_simplified_chinese(text): # 假设的翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` ``` # 空文档块以使自动文档功能满意 # fmt: 开启格式化 output = self.orig_module.mul_scalar(x, y) x = x.dequantize() shadow_output = self.shadow_module.mul_scalar(x, y) self.logger(output, shadow_output) 返回输出
[文档] def cat(self, x: list[torch.Tensor], dim: int = 0) -> torch.Tensor: # fmt: off """ # 空的文档块以使 autodoc 高兴 # fmt: on output = self.orig_module.cat(x, dim) x = [y.dequantize() for y in x] shadow_output = self.shadow_module.cat(x, dim) self.logger(output, shadow_output) return output
[文档] def add_relu(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: # fmt: off ```python # 输入文本 input_text = '"""' # 翻译函数(此处为示例,实际翻译功能需调用真实的翻译 API) def translate_to_simplified_chinese(text): # 假设的翻译结果 return text # 输出翻译结果 translated_text = translate_to_simplified_chinese(input_text) print(translated_text) ``` ``` # 空文档块以使自动文档功能满意 # fmt: 开启格式化 output = self.orig_module.add_relu(x, y) x = x.dequantize() y = y.dequantize() shadow_output = self.shadow_module.add_relu(x, y) self.logger(输出, 阴影输出) 返回输出
[文档]def 准备模型_with_stubs( float_module: nn.Module, q_module: nn.Module, module_swap_list: set[type], logger_cls: Callable, ) -> None: 准备模型,将其匹配的量化模块附加到模型上 模块作为浮点模块类型在模块_swap_list 中的影子。 示例用法: 准备带有占位符的模型(float_model, q_model, module_swap_list, Logger) q_model(data) ob_dict = get_logger_dict(q_model) Args: float_module: 用于生成 q_module 的浮点模块 q_module:从浮点模块量化的模块 module_swap_list:附加阴影的浮点模块类型列表 logger_cls:阴影模块中使用的日志记录器类型,用于处理 量化和其浮点阴影模块的输出 """ torch._C._log_api_usage_once( "量化 API._numeric_suite.prepare_model_with_stubs" ) float_module_children = {} for name, mod in float_module.named_children(): float_module_children[name] = mod reassign = {} for name, mod in q_module.named_children(): if name not in float_module_children: continue float_mod = float_module_children[name] 如果类型 float_mod 不在 module_swap_list 中: 准备带有占位符的模型 prepare_model_with_stubs(float_mod, mod, module_swap_list, logger_cls) # 仅当模块类型与浮点模块不同时才插入阴影模块 # 不插入与浮点模块相同类型的模块 如果 type(float_mod) 在 module_swap_list 中,并且 not _is_identical_module_type( mod, float_mod ): reassign[name] = Shadow(mod, float_mod, logger_cls) for key, value in reassign.items(): q_module._modules[key] = value
def _is_identical_module_type(模块 1
, 模块 2): # 比较两个模块是否具有相同的 dtype mod1 模块类型 = [类型(模块) for 修饰 模块 1.模块()] mod2 模块类型 = [类型(模块) for 修饰 模块 2.模块()] 返回 mod1 模块类型 == mod2 模块类型
[文档]def compare_model_stub( float_model: nn.Module, q_model: nn.Module, module_swap_list: set[type], *data, logger_cls=ShadowLogger, ) -> dict[str, dict]: r"""比较模型中量化模块与其浮点数对应版本, 使用相同的输入对两者进行喂入。返回一个字典,键对应模块名称, 每个条目都是一个字典,包含两个键 'float' 和 '量化,包含量化及其匹配的输出张量' '浮点阴影模块。此字典可用于比较和计算模块' '量化误差级别' '此函数首先调用 prepare_model_with_stubs()以交换量化' 我们想要与 Shadow 模块进行比较的模块,该模块接收量化 模块、相应的浮点模块和记录器作为输入,并在内部创建 路径,以便浮点模块与量化阴影模块共享相同的输入。记录器 可自定义,默认记录器为 ShadowLogger 并且将保存量化模块和浮点模块的输出 可以用来计算模块级别的量化误差。 示例用法:: module_swap_list = [torchvision.models.quantization.resnet.QuantizableBasicBlock] ob_dict = compare_model_stub(float_model,qmodel,module_swap_list, data) for key in ob_dict: print(key, compute_error(ob_dict[key]['float'], ob_dict[key]['quantized'].dequantize())) Args: float_model:用于生成 q_model 的浮点模型 q_model:从 float_model 量化的模型 module_swap_list:将附加阴影模块的浮点模块类型列表 将被附加。 输入数据,用于运行准备好的 q_model 日志类,用于在阴影模块中处理量化模块及其浮点阴影模块的输出 量化模块及其浮点阴影模块 """ torch._C._log_api_usage_once("量化_api._numeric_suite.compare_model_stub") prepare_model_with_stubs(float_model, q_model, module_swap_list, logger_cls) q_model(*data) ob_dict = get_logger_dict(q_model) 返回 ob_dict
[文档]def 获取匹配的激活( 浮点模块:nn.Module, q 模块:nn.Module, ) -> dict[str, dict[str, torch.Tensor]]: 查找浮点模块和量化模块之间的匹配激活。 Args: float_module: 用于生成 q_module 的浮点模块 q_module:从浮点模块量化的模块 返回: act_dict:键对应量化模块名称的字典,每个条目都是一个包含 两个键 'float' 和 'quantized' 的字典 匹配浮点数和量化激活 """ torch._C._log_api_usage_once( "量化 API._numeric_suite.get_matching_activations" ) float_dict = 获取 float_module 的日志字典 quantized_dict = 获取 q_module 的日志字典 act_dict: dict[str, dict] = {} for key in quantized_dict: if len(quantized_dict[key]["tensor_val"]) == 0: continue match_key = _find_match(sorted(float_dict, reverse=True), key, "stats") 如果 match_key 不为空: act_dict[key] = {} act_dict[key]["float"] = float_dict[match_key]["tensor_val"] act_dict[key]["quantized"] = quantized_dict[key]["tensor_val"] 返回 act_dict
[文档]def prepare_model_outputs( float_module: nn.Module, q_module: nn.Module, logger_cls=OutputLogger, allow_list=None, ) -> None: r"""准备模型,将日志记录器附加到 float 模块和量化模块,如果它们在 allow_list 中。 并将日志记录器附加到 float 模块和量化模块,如果它们在 allow_list 中。 Args: float_module:用于生成 q_module 的浮点模块 q_module:从 float_module 量化的模块 logger_cls:附加到 float_module 和 q_module 的日志器类型 允许列表:附加日志的模块类型 """ torch._C._log_api_usage_once( "量化 API._numeric_suite.prepare_model_outputs" ) 如果 allow_list 为 None: allow_list = get_default_compare_output_module_list() qconfig_debug = torch.ao.quantization.QConfig(activation=logger_cls, weight=None) float_module.qconfig = qconfig_debug # 忽略[赋值]警告 prepare( float_module, inplace=True, allow_list=allow_list, prepare_custom_config_dict={} ) q_module.qconfig = qconfig_debug # 忽略[赋值]错误 prepare( q_module, inplace=True, allow_list=allow_list, observer_non_leaf_module_list=NON_LEAF_MODULE_TO_ADD_OBSERVER_ALLOW_LIST, prepare_custom_config_dict={}, )
[文档]def compare_model_outputs( float_model: nn.Module, q_model: nn.Module, *data, logger_cls=OutputLogger, allow_list=None, ) -> dict[str, dict[str, torch.Tensor]]: r"""比较浮点数和量化模型之间的输出激活 对应相同输入的位置。返回一个字典,键对应 到量化模块名称,每个条目都是一个包含两个键的字典 'float' 和 'quantized',包含量化模型的激活和 浮点模型在匹配位置的激活。此字典可用于比较和 计算传播量化误差。 示例用法:: act_compare_dict = compare_model_outputs(float_model, qmodel, data) for key in act_compare_dict: print( key, compute_error( act_compare_dict[key]['float'], act_compare_dict[key]['quantized'].反量化() ) ) Args: float_model:用于生成 q_model 的浮点模型 q_model:从 float_model 量化的模型 data:用于运行准备好的 float_model 和 q_model 的输入数据 logger_cls:附加到 float_module 和 q_module 的日志记录器类型 允许列表:附加日志记录器的模块类型列表 返回: act_compare_dict:与量化模块名称对应的键的字典 并且每个条目都是一个包含两个键 'float' 和 'quantized' 的字典 包含匹配的浮点数和量化激活 """ torch._C._log_api_usage_once( "量化 API._numeric_suite.compare_model_outputs" ) 如果 allow_list 为 None: allow_list = get_default_compare_output_module_list() prepare_model_outputs(float_model, q_model, logger_cls, allow_list) float_model(*data) q_model(*data) act_compare_dict = get_matching_activations(float_model, q_model) return act_compare_dict

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源