ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

PyTorch ModelReport 量化诊断 API 实战:在 FX 工作流中用 Detector 生成可行动的量配置建议

2026/9/10 20:34:46 拓冰建站 浏览量
PyTorch ModelReport 量化诊断 API 实战:在 FX 工作流中用 Detector 生成可行动的量配置建议 PyTorch ModelReport 量化诊断 API 实战在 FX 工作流中用 Detector 生成可行动的量配置建议【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch导读本文围绕 PyTorch 官方量化工具包torch.ao.quantization.fx._model_report中的 ModelReport API 展开系统讲解如何在 FX Graph Mode 量化工作流Prepare → 校准 → Convert中插入诊断观察器Detector Observer在校准后自动生成关于per-channel vs per-tensor 量化、动态 vs 静态量化、输入-权重均衡Input-Weight Equalization、激活异常值Outlier四类问题的可读报告与结构化统计数据并可选地基于建议自动生成QConfigMapping与均衡配置。读完本文你将掌握 ModelReport、ModelReportVisualizer、DetectorBase 与 ModelReportObserver 的完整调用方式、各内置检测器的判定指标与参数语义以及如何编写自定义 Detector 扩展这套诊断体系。ModelReport 在 FX 量化工作流中的位置标准 FX Graph Mode 量化工作流参见 quantize_fx 相关实现通常是初始化模型 → Prepare 模型 → 校准模型 → Convert 模型 → ...而引入 ModelReport 之后工作流在 Prepare 与校准之间插入两个关键步骤初始化模型 → Prepare 模型 → 添加 detector observers → 校准模型 → 生成报告 → 移除 detector observers → Convert 模型 → ...⚠️重要提醒虽然下面的示例以 FX 工作流为背景但 ModelReport 类的使用并不依赖FX 工作流本身真正的依赖约束来自你选择的 Detector——大多数 Detector 要求模型是可被追踪的GraphModule但部分如PerChannelDetector只要求一个普通的nn.Module即可。⚠️单次使用限制同一个ModelReport实例只能执行一次prepare_detailed_calibration()和一次移除观察器的操作。一旦调用过prepare_detailed_calibration()就不能再次准备一旦以remove_inserted_observersTrue生成过报告就不能再对同一实例生成报告或配置映射。这一约束在 model_report.py 中通过_prepared_flag与_removed_observers两个标志强制执行。快速上手完整可运行示例下面的代码片段基本可以做到复制即用仅需替换标注了#TODO的部分模型定义、校准数据、期望使用的 Detector 集合等# 1) 按标准 FX 工作流准备模型 qconfig_mapping torch.ao.quantization.get_default_qconfig_mapping() model Model() # TODO 定义你的模型 example_input torch.randn((*args)) # TODO 准备用于校准的示例数据 prepared_model quantize_fx.prepare_fx(model, qconfig_mapping, example_input) # 2) 创建 ModelReport 实例并插入 detector 观察器 detector_set set([DynamicStaticDetector()]) # TODO 添加所有你想要的 Detector model_report ModelReport(model, detector_set) ready_for_callibrate model_report.prepare_detailed_callibration() # 3) 用代表性数据校准模型 ready_for_callibrate(example_input) # TODO 用与真实场景分布一致的数据完成校准 reports model_report.generate_model_report(remove_inserted_observersTrue) for report_name in report.keys(): # 注意此处应遍历 reports text_report, report_dict reports[report_name] print(text_report, report_dict) # 4) 可选获取 ModelReportVisualizer 实例进行可视化 mod_rep_visualizer tracer_reporter.generate_visualizer() mod_rep_visualizer.generate_table_visualization() # 以表格形式展示收集到的数据 # TODO 根据报告中的建议更新 qconfig关于代码中的两点细节说明prepare_detailed_callibration()方法实际名为prepare_detailed_calibration返回的是插入了观察器的同一个 GraphModule观察器既被加入了模块结构add_submodule也被加入了图结构graph.create_nodeop 为call_module随后会调用recompile()重新编译参见 model_report.py。generate_model_report(remove_inserted_observersTrue)返回一个Dict[str, Tuple[str, Dict]]每个 Detector 对应一个条目其中字符串报告用于直接阅读字典则保存了观察器收集的原始统计量与 Detector 计算出的指标方便做进一步分析或绘图。关键模块概览ModelReport工作流的调度中枢ModelReport类是用户在整个 ModelReport 工作流中直接交互的主类定义于 model_report.py需要重点掌握以下三个方法1.__init__(self, model: GraphModule, desired_report_detectors: Set[DetectorBase])构造器接收两个参数要生成报告的模型必须是可追踪的GraphModule以及一组初始化好的 Detector 实例。构造器内部会对每个 Detector 调用get_detector_name()记录期望生成的报告集合_desired_detector_names为每个 Detector 维护一个感兴趣的观察器 fqn 集合_detector_name_to_observer_fqns以便后续按 Detector 维度定位并移除观察器初始化_prepared_flag、_removed_observers两个状态标志与_generated_reports缓存。如果传入的 Detector 集合为空会抛出ValueError(Should include at least 1 desired report)。2.prepare_detailed_calibration(self) - GraphModule依次调用每个 Detector 的determine_observer_insert_points(model)获取观察器插入点字典再统一把观察器插入模块结构与图结构最后返回带观察器的 GraphModule。源码中还有一个值得注意的细节如果某个位置已经存在相同类型的观察器则不会重复插入因为同类观察器收集的信息是冗余的。3.generate_model_report(self, remove_inserted_observers: bool) - Dict[str, Tuple[str, Dict]]基于校准后的 GraphModule可选地移除已插入的观察器并针对初始化时指定的每一个 Detector 生成字符串报告易于理解、可直接阅读的结论与行动建议统计数据字典相关观察器收集的数据 Detector 计算出的指标供进一步分析或绘图。在移除观察器时ModelReport 会先通过delete_submodule删除模块结构中的观察器再通过erase_node删除图结构中的对应节点最后重新编译模型见 model_report.py。附加能力自动生成配置映射在生成报告之后还可以调用两个方法把 Detector 的建议直接落地为配置generate_qconfig_mapping() - QConfigMapping汇总各 Detector 的DetectorQConfigInfo如激活是否动态权重是否 per-channel通过DetectorQConfigInfo.generate_quantization_qconfig(module)为每个模块生成并校验合法的 QConfig校验失败会按优先级回退到次优组合参见 detector.pygenerate_equalization_mapping() - QConfigMapping汇总输入-权重均衡建议为推荐均衡的模块生成EqualizationQConfig当前直接返回default_equalization_qconfig。这两个方法同样受必须先准备、且未移除观察器的前置条件约束。ModelReportVisualizer报告的图形化呈现用ModelReport实例生成报告后可通过model_report.generate_visualizer()获得ModelReportVisualizer实例类定义于 model_report_visualizer.py。创建实例时它会把报告从以报告名为主键的格式report_name | -- module_fqn | -- feature_name | -- feature value重排为以模块为主键、跨报告合并的格式-- module_fqn [ordered] | -- feature_name | -- feature value即同一模块在不同报告中收集到的所有信息被合并到一起且模块按照它们在模型forward()方法中出现的先后顺序named_modules()的顺序排列。合并过程中如果不同 Detector 对同一 key 给出了冲突的值会抛出ValueError提示有 Detector 实现不正确见 model_report.py。拿到 Visualizer 实例后主要可以做两类事情获取可操作的数据调用generate_filtered_tables()得到一个可进一步处理的表格数据生成可视化输出不返回值直接打印或绘图generate_table_visualization()打印排版整齐的表格generate_plot_visualization()线图同时支持 per-tensor 与 per-channel 统计generate_histogram_visualization()直方图同样支持两种粒度。对于以上所有操作都可以按module_fqn或feature_name过滤数据用get_all_unique_module_fqns()获取全部模块名用get_all_unique_feature_names(plottable_features_onlyTrue)获取全部特征名——由于部分特征如布尔值、标量不可绘制该方法的plottable_features_only标志可以只返回可绘制的特征即值为torch.Tensor的特征见 model_report_visualizer.py。依赖提示表格渲染依赖tabulate绘图依赖matplotlib二者均可选未安装时对应功能会不可用源码以 try/except 捕获 ImportError。Detector可插拔的诊断单元给 ModelReport API 添加新能力的主要途径就是新增 Detector。每个 Detector 都有明确的关注点例如DynamicStaticDetector判断不同层适合动态还是静态量化而InputWeightEqualizationDetector判断每个层是否应该应用输入-权重均衡。DetectorBase抽象基类见 detector.py定义了三类抽象方法以及一个非常实用的工具方法determine_observer_insert_points(self, model) - Dictget_detector_name(self) - strget_qconfig_info(self, model) - Dict[str, DetectorQConfigInfo]用于配置映射生成generate_detector_report(self, model) - Tuple[str, Dict[str, Any]]_get_targeting_node(prepared_fx_model, target_fqn)在图中定位目标节点如果因算子融合导致找不到精确 fqn例如x.linear.0已融合为x.linear会逐级向上剥离 fqn 的后缀递归查找保证融合场景下也能正确定位。内置 Detector 一PerChannelDetector检测模型中的 Linear / Conv 层是否使用了 per-channel 量化构造函数可传入backend默认取torch.backends.quantized.engine源码内置了fbgemm、qnnpack、onednn、x86四种后端的 per-channel 支持模块表DEFAULT_BACKEND_PER_CHANNEL_SUPPORTED_MODULES传入未知后端会直接抛错该 Detector不需要插入任何观察器determine_observer_insert_points返回空字典因为它只检查各模块qconfig的 weight observer / fake-quant 是否带ch_axis即 per-channel只需要普通nn.Module即可工作报告会列出后端支持 per-channel 但当前未使用的模块并提示将 qconfig 换成带 per-channel weight observer 的配置。内置 Detector 二DynamicStaticDetector判断每个支持模块更适合动态量化还是静态量化目前支持nn.Linearnn.Conv1d/2d/3d被标记为未来支持基于ModelReportObserver记录的激活范围信息计算比较统计量S average_batch_activation_range / epoch_activation_range数据分布是平稳stationary的当且仅当 S 严格大于容差tolerance默认0.5否则视为非平稳non-stationary判定规则模块输出侧数据分布非平稳 → 推荐动态量化否则推荐静态量化观察器插入策略在支持的模块目前是 Linear前后各插一个ModelReportObserverpre-observer 与 post-observer命名分别为model_report_pre_observer与model_report_post_observer用于对比模块输入与输出的分布稳定性特别的建议逻辑若输入非平稳、输出平稳推荐静态量化报告还会额外建议在该模块前插入动态 per-tensor 量化层因为非平稳的输入用静态量化处理会引入误差。内置 Detector 三InputWeightEqualizationDetector判断每个支持模块Linear、Conv1d/2d/3d 及其 QAT 版本是否应该应用输入-权重均衡在模块前插入一个ModelReportObserverch_axis默认 1同时直接读取模块权重计算每通道范围基于每通道比较统计量做判定s_c sqrt(w_c / W) / sqrt(i_c / I)其中w_c是通道 c 的权重范围、W是所有通道的权重范围i_c/I是输入侧的对应值。若某通道满足s_c ratio_threshold且s_c 1 / ratio_threshold则该通道推荐均衡构造函数参数ratio_threshold必须严格位于 0 和 1 之间否则抛错、ch_axis默认 1最终报告按通道给出结论并统计有多少比例默认 0.4见DEFAULT_RECOMMEND_INPUT_WEIGHT_CHANNEL_RATIO的通道会受益只有超过该比例才整体建议应用均衡实现上对分组卷积做了兼容当输入通道数与权重通道数不一致且可整除时会按倍数复制权重通道的比率再计算。内置 Detector 四OutlierDetector检测各叶子层没有子模块、且本身不是激活后处理观察器的模块前置激活数据中是否存在显著异常值统计量定义p_r avg(100th percentile / reference_percentile th percentile)其中reference_percentile默认取 0.975。若p_r高于ratio_threshold默认 3.5则认为该通道存在显著异常值阈值取值依据来自正态分布百分位比率的推导构造函数参数ratio_threshold默认 3.5应 ≥ 1判定异常值的阈值reference_percentile默认 0.9750~1 之间百分位比率的分母百分位fraction_batches_used_threshold默认 0.950~1 之间每个通道参与统计的批次占比下限低于该值说明样本量不足会在报告中提醒用户重点关注该通道的结果ch_axis默认 1按通道统计所沿的轴报告会逐通道指出发现的异常值并附上该通道跨全部批次的最大值、常量批次数量并建议先运行静态/动态检测器确认前置激活分布是否平稳因为异常值检测只在平稳分布下可靠对 ReLU 前可能出现的100 百分位为正、参考百分位为负等导致比率异常的情况做了取绝对值/倒数修正。ModelReportObserverDetector 的数据采集器如Detector 实现要求一节所述实现 Detector 的关键一步是指定要插入的Observer。ModelReport API 中的所有内置 Detector 都使用 ModelReportObserver。与 PyTorch 量化 API 中大多数以收集 min/max 来求量化参数为主要目的的观察器不同ModelReportObserver额外收集以下统计量平均批次激活范围average_batch_activation_range各批次激活范围的滑动平均用于计算 S 指标Epoch 级激活范围epoch_activation_min/epoch_activation_max整个校准 epoch 的全局最小/最大值每通道 min/max 值min_val/max_val沿ch_axis默认 1计算100 百分位与第 n 百分位的比率average_percentile_ratio/comp_percentilecomp_percentile默认 0.9用于异常值分析通过每个通道的常量值批次数量constant_channels。在校准过程中ModelReportObserver.forward()会依次执行_calculate_range_stats、_calculate_min_max_stats、_calculate_percentile_stats三个内部更新见 model_report_observer.py并原样返回输入因此不会改变模型的计算结果。它通过torch.jit.export暴露了两个辅助方法get_batch_to_epoch_ratio()返回average_batch_activation_range / epoch_activation_range即 DynamicStaticDetector 使用的 S 指标epoch 范围为 0 或无穷时抛错reset_batch_and_epoch_values()将所有统计量重置回默认值便于开启新一轮校准统计。同时它重载了calculate_qparams()并直接抛出异常——因为它的职责是诊断而非求量化参数不应被当作普通观察器使用。扩展指南实现你自己的 Detector 与 ObserverDetector 的三个必须实现的方法所有 Detector 都继承自DetectorBase见 detector.py任何自定义 Detector 都需要实现以下三个方法1.determine_observer_insert_points(self, model) - Dict决定要向模型中插入哪些观察器、以及插在什么位置。返回一个字典以每个观察器的唯一全限定名fqn为键值为包含插入位置与参数信息的字典格式如下return_dict { [unique_observer_fqn_of_insert_location] : { target_node: ..., # 我们想用该观察器观察的目标节点 (torch.fx.node.Node) observer_to_insert: ..., # 要插入的已初始化观察器 (ObserverBase) is_post_observer: ..., # True 表示作为 target_node 的后置观察器False 表示前置 observer_args: ..., # 要传入观察器的参数 } }注意字典的四个键在源码中定义为DETECTOR_TARGET_NODE_KEY、DETECTOR_OBS_TO_INSERT_KEY、DETECTOR_IS_POST_OBS_KEY、DETECTOR_OBS_ARGS_KEY见 detector.py。2.get_detector_name(self) - str返回该 Detector 的名称作为报告字典的键。请为你的 Detector 取一个与现有 Detector 不同的唯一名称内置名称示例per_channel_detector、dynamic_vs_static_detector、input_weight_equalization_detector、outlier_detector。3.generate_detector_report(self, model) - Tuple[str, Dict[str, Any]]基于该 Detector 想收集的信息生成报告返回一个二元组可读的文本报告 收集/计算得到的统计数据字典。该报告会被返回给ModelReport实例由它汇总所有用户请求的 Detector 的报告。此外如果你的 Detector 想参与generate_qconfig_mapping()/generate_equalization_mapping()的自动配置生成还需要实现get_qconfig_info(self, model) - Dict[str, DetectorQConfigInfo]为每个相关模块返回一个DetectorQConfigInfo其中is_activation_dynamic、is_weight_per_channel、is_equalization_recommended三个字段分别对应三类建议。使用自定义 Observer 的注意事项如果你想为自己的自定义 Detector 实现自定义 Observer需要注意以下几点你的 Observer 必须继承自torch.ao.quantization.observer.ObserverBase在自定义 Detector 类中为前置/后置观察器定义有描述性且唯一的名称如PRE_OBSERVER_NAME/POST_OBSERVER_NAME用于拼接每个观察器的 fqn作为上文返回字典的键可参考 DynamicStaticDetector 的命名常量与 InputWeightEqualizationDetector 的插入点构造在determine_observer_insert_points()中初始化你的自定义 Observer并把它放入上述返回字典示例可参考 InputWeightEqualizationDetector 的 pre-observer 构造。由于此时 Detector 也是你自己实现的观察器应放在模型的哪些位置、要从它们身上提取哪些信息来生成报告完全由你决定——这正是该 API 的可扩展性所在。代码仓库结构ModelReport 全部代码位于torch/ao/quantization/fx/_model_report/目录下torch/ao/quantization/fx/_model_report/ ├── __init__.py # 将 ModelReport 标记为包目录 ├── detector.py # Detector 类所在文件 │ # - DetectorBase所有 Detector 的基类 │ # - PerChannelDetector │ # - DynamicStaticDetector │ # - InputWeightEqualizationDetector │ # - OutlierDetector │ # - DetectorQConfigInfo配置映射生成的载体 ├── model_report_observer.py # ModelReportObserver 类 │ # - Detector 插入的主要观察器收集生成报告所需信息 ├── model_report_visualizer.py # ModelReportVisualizer 类 │ # - 按模块在 forward 中的顺序重排报告 │ # - 组织方式module_fqn → feature_name → feature values │ # - 支持三类可视化格式化表格、线图per-tensor / per-channel、 │ # 直方图per-tensor / per-channel └── model_report.py # ModelReport 类 # - 用户进行 ModelReport 工作流时交互的主类测试ModelReport API 的测试位于 test/quantization/fx/test_model_report_fx.py测试覆盖包括ModelReportObserver的测试类含零张量报错、Relu 后观察器、随机 epoch 与 batch 等用例ModelReport类的测试类构造、prepare 校准、生成报告、生成 visualizer、qconfig mapping 与 equalization mapping 生成等ModelReportVisualizer类的测试类获取模块/特征名、表格与报告一致性校验等每个内置 Detector 各自的测试类per-channel 多模型场景、动态/静态多 qconfig 选项、输入-权重均衡插入点与报告生成、异常值检测多种分布场景等例如test_multi_linear_model_without_per_channel、test_input_weight_equalization_report_gen、test_all_outlier_report_gen等。如果你要新增 Detector请参照现有测试类编写对应的测试。由于用户是通过ModelReport类与 Detector 交互而非直接调用测试也应遵循这一使用方式即走完整的prepare → 校准 → 生成报告流程。未来任务与改进方向README 中列出了若干可以进一步完善该 API 的任务供感兴趣的开发者参考将DynamicStaticDetector的平稳性计算方法从方差改为方差的方差以更好地抵抗异常值干扰为数据增加更多类型的可视化增加对直方图观察器数据的直方图可视化能力根据建议自动生成 QConfig目前可通过generate_qconfig_mapping()半自动完成基于进一步的研究分析为各 Detector 调优默认阈值参数将生成报告与生成 qconfig两个步骤合并将大量返回字典改为对象类提升类型安全与可读性将均衡配置的类型从QConfigMapping改为更贴切的EqualizationMapping。小结ModelReport API 为 PyTorch 的量化调试提供了一条先诊断、后配置的实践路径通过ModelReport在校准阶段透明地插入诊断观察器让DynamicStaticDetector、PerChannelDetector、InputWeightEqualizationDetector、OutlierDetector分别从分布平稳性、per-channel 支持度、输入-权重均衡收益、激活异常值四个维度给出可行动的建议再借助ModelReportVisualizer把散落的统计量整理成表格、线图与直方图最后还能把建议自动落成QConfigMapping与均衡配置。无论你是在标准 FX Graph Mode 工作流中还是通过QuantizationTracer自行构造可追踪GraphModule这套 API 都适用——唯一需要记住的是每个ModelReport实例只能准备和清理一次观察器。【免费下载链接】pytorchTensors and Dynamic neural networks in Python with strong GPU acceleration项目地址: https://gitcode.com/GitHub_Trending/py/pytorch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考