Onnx 插入在Conv和ConvTranspose前自动插入Q/DQ算子

常见问题:

1.  weight中的scale Tensor 提示是empty,原因缺少init

graph.initializer.append(x_scale)  # x_scale为node中的tensor

2. 插入node节点之后进行model check的时候提示node没有这个属性例如:

"onnx.onnx_cpp2py_export.checker.ValidationError: Unrecognized attribute: axis for operator QuantizeLinear"

原因:当前onnx的optset版本太低或者太高了,应该先到onnx查看当前想插入的axis在optset哪个版本中存在,然后将onnx转换为你需要的版本后再插入对应的属性,转换方法:参考链接

import onnx
from onnx import version_converter, helper
 
# Preprocessing: load the model to be converted.
model_path = "path/to/the/model.onnx"
original_model = onnx.load(model_path)
 
print(f"The model before conversion:\n{original_model}")
 
# A full list of supported adapters can be found here:
# https://github.com/onnx/onnx/blob/main/onnx/version_converter.py#L21
# Apply the version conversion on the original model
converted_model = version_converter.convert_version(original_model, <int target_version>)
 
print(f"The model after conversion:\n{converted_model}")

3. 模型运行时提示

"oid onnxruntime::PrepareForQDQ(const TensorShape&, const Tensor&, const Tensor*, int64_t, int64_t, int64_t&, int64_t&, int64_t&) scale.Shape().NumDimensions() == 1 && scale.Shape()[0] == broadcast_dim was false. For per axis quantization, scale must be 1D tensor with size 256"

原因:  Q/DQ中默认的axis=1,需要调整axis为你的Channle维度

4.Q/DQ 自动添加脚本

def insert_weight_qdq(model, quant_type, graph, i, node_index, input_name, dim):
    quant_output_name = quant_type +"_"+ node_index +"_weight"
    tensor = np.random.rand(dim)
    x_scale = helper.make_tensor(
        name="x_scale"+quant_output_name,
        data_type=onnx.TensorProto.FLOAT,
        dims=[dim],
        vals=tensor
    )
    x_zero_point = helper.make_tensor(
        name="x_zero_point"+quant_output_name,
        data_type=onnx.TensorProto.INT8,
        dims=[dim],
        vals=tensor.astype(np.int8)
    )
    graph.initializer.append(x_scale) 
    graph.initializer.append(x_zero_point) 
    #attr = onnx.helper.make_attribute("axis", 0)
    quant_input_node = helper.make_node(
        quant_type,
        inputs=[input_name, "x_scale"+quant_output_name, "x_zero_point"+quant_output_name],
        outputs=[quant_output_name],
        name=quant_output_name+"_output",
    )
    #quant_input_node.attribute.insert(0,attr)
    graph.node.insert(i, quant_input_node)
    return quant_output_name

attention:

https://chromewebstore.google.com/detail/redium/aapiedkipcbeplicbbicchmdmpinhjdl?pli=1

https://medium.com/@DeeperAndCheaper/quantization-yolov8-qat-x2-speed-up-on-your-jetson-orin-nano-2-how-to-achieve-the-best-qat-c6069fb83ab7

### 插入 QDQ 节点ONNX 模型 为了在ONNX模型中插入QDZ节点以实现量化操作,通常采用如下方法: #### 使用工具自动转换 一些框架提供了自动化工具来处理这一过程。例如,在PyTorch环境中可以利用`torch.quantization.prepare`函数准备模型以便于后续的量化感知训练(QAT)[^1]。 然而,当目标是直接编辑ONNX文件时,则需手动向网络结构添加QuantizeDequantizeLinear(简称QDQ节点。这些节点应当被放置在网络中的特定位置——具体来说是在那些打算应用量化的层之及其权重上,如卷积(Convolution)或矩阵乘法(Fully Connected Layer, MatMul),以此确保数据流经由这些新加入的操作符完成从浮点数至整数表示形式之间的转变[^2]。 #### 手动修改ONNX模型定义 对于更细粒度控制的情况,开发者可以直接操纵ONNX图谱。这涉及到读取现有的.onnx文件作为起点,随后遍历整个计算图表并识别出所有待量化的运算单元;接着针对每一个选定的目标创建一对新的QDQ节点,并调整原有连接关系使之适应新增加的部分。最后保存更新后的版本供进一步使用。 ```python import onnx from onnx import helper as hlp def add_qdq_nodes(model_path, output_model_path): model = onnx.load(model_path) graph_def = model.graph # 遍历所有的node寻找convmatmul节点 for node in list(graph_def.node): if node.op_type == 'Conv' or node.op_type == 'MatMul': input_name = node.input[0] quant_node = hlp.make_node( "QuantizeLinear", ["input", "scale", "zero_point"], [f"{input_name}_q"] ) dequant_node = hlp.make_node( "DequantizeLinear", [f"{input_name}_q", "scale", "zero_point"], [f"{input_name}"] ) graph_def.node.extend([quant_node, dequant_node]) onnx.save(model, output_model_path) ``` 上述脚本展示了如何基于Python编程语言以及官方提供的onnx库接口去执行这样的任务。值得注意的是,实际部署还需验证所做更改不会破坏原始逻辑功能,并且确实达到了预期的效果—即成功实现了INT8级别的推理加速而不显著损失准确性[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值