部署一致性分析说明

从 qat.pt / qat model 到最终部署使用的 hbm,中间还会经过 export、convert、compile 以及部署适配等多个步骤。 如果这些步骤中的某一段引入了额外误差,就可能出现“训练侧结果正常,但部署侧结果不符合预期”的情况。 此章节主要介绍在 QAT 策略上如何避免这类问题,以及发生这类问题时如何定位并解决问题。

注意

训练部署无法做到比特一致,必然存在极少数 case 无法完全对齐, 因此,是否存在一致性问题,应当以数据集上的评测精度、稳定可复现的 badcase,以及多帧可视化结果作为判断依据,而不是只看单帧数值是否完全相同。

训练部署一致性问题分为两类:

  1. 用户侧问题。例如:前后处理不一致,模型版本不一致等。

  2. 工具侧问题。模型在 export / convert / compile 过程中引入了额外误差而产生的不一致。

无论问题最终属于用户侧还是工具侧,我们都建议您结合训练部署一致性分析方法,以及相关排查工具和调试产物完成定位。 对于用户侧问题,通常需要您根据排查结果自行修正。 而在完成明显用户侧问题的初步排除后,通常仍需按 export / convert / compile 阶段继续定位,不同类型问题的排查重点并不完全一样。 如果最终确认为工具侧问题,建议您保留对应阶段的调试产物、badcase 和关键模型产物,并提供给地平线技术支持人员,以便进一步分析并给出解决方案。

在一致性问题的排查过程中,涉及到以下几种模型:

产物类型获取阶段说明获取方法常见用途
qat.pttorch qat 模型Prepare / Calibration / QAT 后torch 侧的伪量化模型对浮点模型使用 prepare 接口作为训练侧精度基线,继续执行 pre_export / export
qat.export.pttorch qat export 模型pre_export 后仅完成查表转定点的 torch 模型,计算逻辑与 qat.bc 更接近对 qat.pt 模型使用 pre_export 接口export 阶段一致性分析、查表问题定位
qat.bc导出产生的 HBIR 模型export 后由 qat.pt 导出的 HBIR 模型对 qat.pt 模型使用 export 接口export 结果验证、convert 输入
quantized.bc转换生成的 HBIR 模型convert 后由 qat.bc 定点化得到的模型对 qat.bc 模型使用 convert 接口compile 前定点精度验证、convert 阶段排查
hbm编译产生的可部署模型compile 后最终部署模型对 quantized.bc 模型使用 compile 接口最终部署精度验证、compile / 板端问题排查

其中,比较容易混淆的两点如下:

  • qat.export.pt 不是部署主链路中的必选产物,但在 export 阶段排查时非常关键。它主要用于先判断问题是否由查表转定点引入。

  • quantized.bc 是进入 compile 之前最值得优先关注的定点精度基线。如果 quantized.bc 已经异常,就不应直接把问题归因到 compile 或板端部署。

pre_export 接口基本用法如下:

from horizon_plugin_pytorch.quantization.hbdk4 import pre_export
qat_export_pt = pre_export(qat_pt)

一致性问题定位起点

在进入 export / convert / compile 三个阶段的具体排查之前,建议您先完成下面几件事:

  1. 准备一份可稳定复现问题的数据集。通常建议至少包含 1000 帧,并且数据集上的评测结果相对稳定。

  2. 先适配好 bc 模型在 x86 侧的推理流程。

  3. 先排除明显的用户侧问题,再进入按 export / convert / compile 阶段进行的分阶段排查。

原始定位流程如下图所示:

在正式进入一致性排查前,建议您先用小数据集在 CPU 上比较 qat.export.pt 和 qat.bc,先验证 bc 推理流程是否正确。 这一步的目的不是直接定位 export、convert 或 compile 阶段的问题,而是先排除明显的用户侧问题,确认后续用于比较 bc 模型的输入输出处理、推理代码和评测流程本身没有明显错误。

如果两者精度不一致,建议先关闭伪量化,再重新验证 qat.export.pt 和 qat.bc 的结果是否一致:

from horizon_plugin_pytorch.quantization.hbdk4 import export, pre_export
from horizon_plugin_pytorch.quantization import FakeQuantState, set_fake_quantize

qat_pt.eval()
set_fake_quantize(qat_pt, FakeQuantState._FLOAT)
qat_bc = export(qat_pt, example_inputs)
qat_export_pt = pre_export(qat_pt)

关闭伪量化后,常见会出现两种情况:

  1. 如果关闭伪量化后结果一致,通常应优先检查关闭之前模型的 fake quant 和 observer 状态是否处于 validation 状态。
print(qat_pt)
# fake_quant_enabled 应为 True,observer_enabled 应为 False
GraphModuleImpl(
  (quant): QuantStub(
      (activation_post_process): FakeQuantize(
        dtype=qint8, fake_quant_enabled=True, observer_enabled=False,
        qscheme=torch.per_tensor_symmetric, ch_axis=-1,
        scale=tensor([0.1250]), zero_point=tensor([0])
        (activation_post_process): MinMaxObserver(
            min_val=-10.0,
            max_val=9.999998092651367,
            averaging_constant=1,
        )
      )
  )
  ...
)
  1. 如果关闭伪量化后结果仍不一致,建议先对 qat.export.pt 和 qat.bc 分别跑统计量,再做逐层对比。
from horizon_plugin_profiler import QuantAnalysis

qa = QuantAnalysis(qat_export_pt, qat_bc, "export")

# torch 与 bc 可接受同一格式输入时,一起跑统计量
qa.set_bad_case(badcase)
qa.run()

# torch 与 bc 不可接受同一格式输入时,分开跑统计量
# pt_badcase 与 bc_badcase 除格式外内容应保持一致
qa.set_bad_case(pt_badcase)
qa.run(run_baseline_model=True, run_analysis_model=False)
qa.set_bad_case(bc_badcase)
qa.run(run_baseline_model=False, run_analysis_model=True)

qa.compare_per_layer()

如果这一步已经暴露出明显的输入输出处理差异、状态设置问题或 bc 推理流程错误,建议先修正这些用户侧问题,再继续进入下文的分阶段排查。

快速判断问题更可能发生在哪一段

实际排查时,建议您先不要一上来就跑完整套工具,而是先用现象判断问题更可能落在哪一段。

当前现象优先怀疑阶段建议先做什么
qat.pt / qat model 正常,但 qat.bc 异常export 阶段先比较 qat.export.pt 与 qat.pt,再比较 qat.export.pt 与 qat.bc
qat.bc 正常,但 quantized.bc 异常convert 阶段直接比较 qat.bc 与 quantized.bc,做 badcase、逐层对比和敏感度分析
quantized.bc 正常,但 hbm 异常compile / 部署阶段重点检查输入输出处理、插入节点、前后处理适配和板端部署差异

如果还不能快速判断,也建议至少先完成下面两件事:

  1. 确认 plugin / profiler / hbdk 已升级到当前建议版本。

  2. 先验证 quantized.bc 的精度是否满足预期,再决定是否继续往 compile 或板端方向排查。

建议的排查顺序

如果您当前还不确定应该从哪开始,通常建议按下面的顺序处理:

  1. 先确认 qat.pt 和 quantized.bc 哪一个是当前最稳定的精度基线。

  2. 先排除明显的用户侧问题,再用“快速判断”表定位问题更可能发生在哪一段。

  3. 如果是 export 问题,先看 pre_export,再看 qat.export.pt 与 qat.bc。

  4. 如果是 convert 问题,先比较 qat.bc 与 quantized.bc,再做敏感度分析。

  5. 如果是 compile / 部署问题,先确认 quantized.bc 正常,再回看输入输出处理和板端部署差异。

  6. 如果常规方法仍无法定位,再使用 bc_editor 继续缩小范围。

如果您在排查过程中还不熟悉 model_check_result.txt、fx_graph.txt、compare_per_layer_out.txt、output_xxx_sensitive_ops.txt 等产物,建议继续阅读 调试产物解读 章节。

Export 一致性

当 qat.pt 正常,但 qat.bc 不符合预期时,通常应优先怀疑问题发生在 export 阶段。 这类问题最常见的来源包括:查表转定点引入误差、导出图与训练图不一致,以及 export 后某些算子的实现差异。

典型现象

  • qat.pt 的评测精度和多帧可视化正常,但 qat.bc 异常。

  • qat.export.pt 已经异常,说明问题很可能在 pre_export 这一步就开始出现。

  • qat.export.pt 正常,但 qat.bc 异常,说明更可能是 export 图或 HBIR 表达引入的问题。

分析前提

  • qat.pt 必须先 eval,并切换到 FakeQuantState.VALIDATION。

  • qat.pt、qat.export.pt 和 qat.bc 比较时,应尽量保证输入内容一致。

  • 如果 torch 和 bc 模型无法直接接受同一格式输入,也需要保证两边输入除格式外内容一致。

排查步骤

  1. 先看 qat.export.pt 是否正常。

    也就是说,先不要直接比较 qat.pt 和 qat.bc,而是先用 pre_export 将 qat.pt 转成 qat.export.pt,判断“查表转定点”这一步是否已经带来明显误差。

    • 如果 qat.export.pt 已经异常,优先判断问题是否由查表转定点引入。

    • 如果 qat.export.pt 正常,但 qat.bc 异常,优先判断问题是否来自 export 图不一致或 HBIR 导出阶段。

  2. 如果 qat.export.pt 已经异常,先定位是不是查表问题。

    此时建议使用 QuantAnalysis(qat_pt, qat_export_pt, "pre_export") 做逐层对比和敏感度分析,优先找出是哪些查表算子带来了明显误差。

from horizon_plugin_profiler import QuantAnalysis
from horizon_plugin_pytorch.quantization.hbdk4 import pre_export

qa = QuantAnalysis(qat_pt, qat_export_pt, "pre_export")
qa.auto_find_bad_case(dataloader)
qa.run()
qa.compare_per_layer()
qa.sensitivity()
  1. 如果常规方法仍然无法缩小范围,可以继续用 pre_export 做分段定位。
from horizon_plugin_pytorch.quantization.hbdk4 import pre_export

qat_pt.module_a = pre_export(qat_pt.module_a)
  1. 如果 qat.export.pt 正常,但 qat.bc 异常,继续比较 qat.export.pt 和 qat.bc。

    此时建议使用 QuantAnalysis(qat_export_pt, qat_bc, "export") 做 badcase 定位和逐层对比,确认问题是否来自 export 图、HBIR 表达或个别算子导出实现差异。

from horizon_plugin_profiler import QuantAnalysis

qa = QuantAnalysis(qat_export_pt, qat_bc, "export")

# torch 与 bc 可接受同一格式输入时,一起跑统计量
qa.set_bad_case(badcase)
qa.run()

# torch 与 bc 不可接受同一格式输入时,分开跑统计量
qa.set_bad_case(pt_badcase)
qa.run(run_baseline_model=True, run_analysis_model=False)
qa.set_bad_case(bc_badcase)
qa.run(run_baseline_model=False, run_analysis_model=True)

qa.compare_per_layer()
  1. 如果怀疑导出图本身与训练图不一致,再回看 Prepare 产物。

    尤其是存在 if deploy、动态分支、循环次数变化等情况时,建议结合 fx_graph.txt 和 model_check_result.txt 先确认图结构是否与预期一致。

使用工具

  • pre_export

    用于把 export 阶段拆成两段,先判断问题是否已经在查表转定点阶段出现。

  • QuantAnalysis

    用于 badcase 定位、逐层对比和敏感度分析。export 阶段最常见的两种用法是:

    • QuantAnalysis(qat_pt, qat_export_pt, "pre_export")

    • QuantAnalysis(qat_export_pt, qat_bc, "export")

  • fx_graph.txt / model_check_result.txt

    用于辅助判断 export 前后的图结构和 Prepare 结果是否一致。

需要保留的产物

  • qat.export.pt

  • qat.bc

  • compare_per_layer_out.txt

  • output_xxx_sensitive_ops.txt / .pt

  • model_check_result.txt

  • fx_graph.txt

如果仍无法判断问题所在,建议至少保留上述产物,以及对应 badcase,便于继续分析或向技术支持反馈。

Convert 一致性

当 qat.bc 正常,但 quantized.bc 不符合预期时,通常应优先怀疑问题发生在 convert 阶段。 这类问题的本质,是模型从伪量化表示进入真正定点表示后,某些算子的实现差异被放大了。

对于 J6E/M 平台,如果您主要遇到的是 convert 或部署阶段偏差,也可以结合高一致性 QAT 策略一起考虑。 它虽然需要在 prepare 之前设置,但主要作用仍然是降低 convert / 部署阶段偏差,因此我们放在这一节介绍方便您理解。

高一致性 QAT 策略

如果您当前的问题主要表现为:

  • qat.pt / qat.export.pt / qat.bc 基本正常,但 quantized.bc 开始掉点。

  • 已经基本确认问题不在查表转定点,而更像是 convert 前后的一致性偏差。

  • 当前使用平台为 J6E/M,并且希望优先用更低成本的方式改善 convert 一致性。

那么高一致性策略通常值得您优先评估。

反过来说,如果问题主要发生在 pre_export 或 export 阶段,例如查表转定点本身已经引入明显误差,那么高一致性策略通常不会带来直接帮助,此时仍应优先回到 export 阶段继续分析。

注意
  • 由于 J6E/M 平台浮点算力有限,更容易遇到训练部署一致性问题,为解决此类问题,我们提供了高一致性 QAT 策略,此策略仅对用于 J6E/M 平台生效,其他的平台不推荐您使用。

  • 使用前请确认 hbdk 版本不低于 4.4.2,plugin 版本不低于 3.1.2。

  • 对于不重训的场景,只有 level 0 有效,level 1 / level 2 需要在设置后重新训练。

  • 高一致性 QAT 策略对查表转定点无影响,主要影响 convert 前后的一致性。

高一致性 QAT 策略封装在 horizon_plugin_pytorch.qat_mode.ConsistencyStrategy 中,用法如下:

from horizon_plugin_pytorch.qat_mode import ConsistencyStrategy

# 必须在 prepare 之前设置一致性策略
ConsistencyStrategy.set_consistency_level(1)
...
qat_pt = prepare(float_model)
...
qat_bc = export(qat_pt, example_inputs)

# 如果设置 ConsistencyStrategy.set_consistency_level(0),可以做如下检查
print(qat_bc._high_precision_qpp)  # 值应为 true
print(qat_bc._fuse_requantize)     # 值应为 False

quantized_bc = convert(qat_bc, march)

当前支持三个等级(0 - 2)的策略。等级越高,一致性越好,但 QAT 精度可能受到轻微影响,因此,我们并不建议一开始就直接使用最高等级。 我们推荐您优先尝试使用 level 1,在大多数情况下对 QAT 精度无影响,且对性能和一致性可以有正向收益。

下表中:

  • POT(Power Of Two)scale,可简单理解为 scale 取值被约束到 2 的幂次形式。

  • A_POT(activation_pot)表示 activation 使用 POT scale,而 weight 仍使用统计型 scale。

结合现有实现,可以先这样理解它们的差异:

level主要特点更适合什么场景
0保持常规统计型 scale 策略,不开启高一致性算子路径,但会开启高精度 qpp,并关闭 requantize fuse。这里的高精度 qpp 可先理解为量化参数传播时尽量保留更高精度的中间结果,以减少参数传递过程中的附加误差。关闭 requantize fuse 则是避免重定点相关逻辑被提前融合进相邻算子,减少 convert 前后因融合方式不同带来的偏差已经完成训练、不希望重训,但希望先尽量改善 convert 一致性的场景
1将 compute_scale_strategy 切到 A_POT,也就是激活侧使用 POT scale、weight 侧仍保持统计型 scale。同时开启 resize / gridsample / mean / mod_centered 的高一致性路径,并关闭 requantize fuse。核心目的,是先把激活侧 scale 收敛到更接近 convert 行为的形式,减少激活 scale 抖动和边界变化带来的偏差J6E/M 上遇到 convert 一致性问题时,最推荐优先尝试的起点
2将 compute_scale_strategy 进一步切到 POT,也就是 activation / weight 都使用 POT scale。同时保持 resize / gridsample / mean / mod_centered 的高一致性路径开启,并关闭 requantize fuse。和 level 1 相比,主要多出来的是 weight 侧也切到 POT scale。经验上这通常会进一步压低 Linear / Conv 在 convert 阶段残留的一个 scale 级别误差概率level 1 仍不能满足一致性要求时,继续提高一致性的方案

关于 POT / A_POT,还建议您先这样理解:

  • 它们首先是为了让 scale 形式更接近 convert 侧的实际行为,因此主要作用在训练部署一致性上,而不是直接替代常规精度调优手段。

  • 一致性改善并不等于数据集精度一定同步提升。是否真正带来收益,仍建议回到 quantized.bc / hbm 的评测结果和 badcase 复现情况判断。

  • POT / A_POT 也不应默认理解为性能优化开关。它们更偏向一致性策略,是否带来额外收益或代价,仍需结合实际模型和部署结果确认。

如果您只想先抓住这三档策略的核心区别,也可以简单理解为:level 0 主要是在不重训前提下,减少量化参数传播和 requantize 融合带来的额外偏差。level 1 主要是 activation 用 POT scale,weight 仍保持统计型 scale。level 2 则是在 level 1 基础上进一步把 weight 侧也切到 POT scale,并继续压低 Linear / Conv 等关键算子剩余的一致性误差。

如上表所示,实际上:

  • level 0 更像“不重训前提下的补救方案”。

  • level 1 更像“推荐优先尝试的常规方案”。

  • level 2 更像“在 level 1 基础上进一步提高一致性”的加强方案。

使用时还建议您注意下面几点:

  • 如果当前模型原本没有启用高一致性策略,而您又不希望重新训练,那么只能尝试 level 0,在 prepare 模型前设置一致性策略等级为 0。

  • 如果准备正式使用 level 1 / level 2,请在设置策略后重新执行后续训练流程,而不要只在已有 checkpoint 基础上直接套用。

  • 即使启用了高一致性策略,最终仍建议回到 quantized.bc / hbm 的结果做验证,而不是只看训练侧模型是否改善。

使用时,还可以将下面这些现象作为辅助参考:

  • 在 level 1 下,convert 阶段的 Linear / Conv 通常仍可能存在一个 scale 级别的误差,其他算子通常更容易对齐。

  • 在 level 2 下,Linear / Conv 的这类误差概率通常会进一步下降到很低的水平。

  • 对于 Linear / Conv,如果去掉 bias,在 level 2 下 convert 阶段通常更容易做到无误差或近似无误差。

这些现象更适合作为理解策略效果的辅助参考,而不是绝对判断标准。实际项目中,仍建议以数据集评测结果和 badcase 复现情况为准。

如果您希望进一步了解 level 0 / 1 / 2 在实现层面的具体差异,例如各级别分别调整了哪些 scale 策略、哪些高一致性开关以及哪些导出行为,建议结合当前版本源码继续确认。不同版本之间,这部分实现细节可能存在调整。

典型现象

  • qat.bc 的评测精度或可视化结果正常,但 quantized.bc 异常。

  • qat.export.pt 与 qat.pt 没有明显问题,但 quantized.bc 与前两者相比开始掉点。

分析前提

  • qat.bc 本身应已经确认精度正常,否则不要直接进入 convert 排查。

  • 比较 qat.bc 和 quantized.bc 时,必须使用同一套输入和后处理。

  • 建议先在数据集上稳定复现 convert 前后一致性问题,再开始 badcase 和逐层分析。

排查步骤

  1. 先确认 quantized.bc 的异常是稳定可复现的。

    如果 convert 后的精度波动不稳定,或 badcase 不可复现,建议先回到数据集和验证流程,确保比较过程本身可靠。

  2. 对 qat.bc 和 quantized.bc 做 badcase 定位与逐层对比。

    这是 convert 阶段最核心的一步。建议使用 QuantAnalysis(qat_bc, quantized_bc, "convert") 先找 badcase,再看逐层对比结果。

from horizon_plugin_profiler import QuantAnalysis

qa = QuantAnalysis(qat_bc, quantized_bc, "convert")
qa.auto_find_bad_case(dataloader)
qa.run()
qa.compare_per_layer()
  1. 再结合 qat.export.pt 做敏感度分析。

    在 convert 阶段,敏感度分析通常仍然建议基于 torch 侧更易分析的 qat.export.pt 来做,同时复用 qat.bc 与 quantized.bc 对比中找到的 badcase。

from horizon_plugin_profiler import QuantAnalysis

qa = QuantAnalysis(qat_export_pt, quantized_bc, "convert")
qa.load_bad_case()
qa.sensitivity()
  1. 如果已经确认问题主要来自 convert,但常规逐层分析仍然无法缩小范围,再考虑使用更细粒度工具继续分段定位。

使用工具

  • QuantAnalysis

    convert 阶段最常用的用法是:

    • QuantAnalysis(qat_bc, quantized_bc, "convert"):查 badcase、跑逐层对比
    • QuantAnalysis(qat_export_pt, quantized_bc, "convert"):基于同一 badcase 跑敏感度分析
  • 高一致性 QAT 策略

    对 J6E/M 平台,如果您当前主要遇到的是 convert 前后一致性问题,可以优先评估是否需要使用高一致性策略降低 convert 阶段偏差。

  • bc_editor

    当常规分析无法定位问题时,可通过编辑 bc 模型,把部分算子退回 CPU 执行,进一步缩小 convert 问题范围。

需要保留的产物

  • quantized.bc

  • compare_per_layer_out.txt

  • abnormal_layer_advisor.txt

  • output_xxx_sensitive_ops.txt / .pt

  • badcase.txt 或可稳定复现问题的输入样本

如果仍无法判断问题所在,建议至少保留上述产物,以及对应 badcase,便于继续分析或向技术支持反馈。

Compile / 部署一致性

当 quantized.bc 已经正常,但 hbm 或板端结果不符合预期时,通常应优先怀疑问题发生在 compile 或部署适配阶段。 这一阶段的问题,往往不再只是模型内部数值实现差异,还可能涉及输入输出处理、插入节点、前后处理适配和板端部署方式。

典型现象

  • quantized.bc 精度正常,但 hbm 异常。

  • x86 上的 hbm 结果与板端结果不一致。

  • 插入前处理节点、删除首尾节点或板端接入后结果开始变差。

分析前提

  • 进入 compile / 部署排查前,必须先确认 quantized.bc 自身已经正常。

  • 确保 compile 前后的输入输出定义、layout、前后处理以及 padding / 对齐策略保持一致。

  • 如果板端结果异常,建议先区分是 hbm 仿真就异常,还是仅板端接入异常。

排查步骤

  1. 先确认问题是否真的发生在 compile 之后。

    也就是说,要先明确 quantized.bc 是正常的。如果 quantized.bc 也异常,应回到 convert 阶段继续排查。

  2. 检查输入输出处理是否一致。

    这一阶段最常见的问题,不是算子本身,而是输入输出形式、前后处理、插入节点、删除节点以及部署接口适配不一致。

  3. 如果涉及插入前处理节点、删除首尾节点或其他图修改,建议分别对修改前后结果做比较。

  4. 如果是板端异常但 x86 仿真正常,优先怀疑板端部署接入、数据准备或运行方式差异,而不是直接怀疑模型转换本身。

使用工具

  • hb_verifier 或等效比对方式:用于比较 HBIR 与 HBM、x86 与板端结果之间的一致性。

  • 部署侧日志、输入输出 dump、板端推理脚本:用于确认问题是否来自部署接入而非模型本身。

需要保留的产物

  • quantized.bc

  • hbm

  • compile 配置

  • 板端输入输出样本

  • 对应 badcase 的前后处理输入、输出和日志

如果仍无法判断问题所在,建议至少保留上述产物,以及对应 badcase,便于继续分析或向技术支持反馈。

常规分析仍无法定位时

如果您已经完成 badcase、逐层对比和敏感度分析,仍然无法判断 convert 阶段问题具体落在哪些算子上,可以继续使用 bc_editor 做分段定位。

bc_editor 位于 horizon_plugin_profiler/bc_editor/bc_editor.py,同一目录下通常会提供配置示例。

它的核心思路是:

  1. 先查看 qat.bc 的文本表示,定位可疑算子的 HBIR 编号。

  2. 通过配置文件删除指定范围的 fake quant。

  3. 重新得到修改后的 bc,并再次 convert。

  4. 对比编辑前后的 quantized.bc 表现,判断哪些算子退回 CPU 后能明显改善一致性。

示例如下:

# 查看 qat.bc 模型文本
print(qat_bc.module.get_asm(enable_debug_info=True))

# “%” 后面的数字为 hbir 算子编号
module attributes {hbdk.legacy_round = true} {
  func.func @bev_gkt_mixvargenet_multitask_nuscenes(%arg0: tensor<6x3x512x960...
    %0 = "qnt.const_fake_quant"(%arg0) <{bits = 8 : i64, illegal = true, max...
    %1 = "hbir.constant"() <{values = dense<"0xC27B5D3DFF6DE33C1822093DDA9642...
    %2 = "qnt.const_fake_quant"(%1) <{axis = 0 : i64, bits = 8 : i64, illegal...
......

# config.json
{
    "remove_fake_quant": [[1, 100], 102]  # 删除 hbir 中编号 1~100 和 102 的伪量化
}

# 编辑后得到 qat_modified.bc,再 convert 可以得到部分算子退回 CPU 的 quantized.bc
python3 bc_editor.py --bc_path qat.bc --config_path config.json --new_bc_path qat_modified.bc

对比编辑前后 quantized.bc 的结果,可以进一步看出哪些算子退回 CPU 后能明显提高一致性。