飞桨x昇腾生态适配方案:14_loop算子缺失(上):ONNX模型拆分

简介: 本文针对NPU不支持LOOP算子的问题,提出一种解决方案:将ONNX模型拆分为含LOOP算子和不含LOOP算子的子图,单独推理LOOP部分。通过构造包含LOOP算子的ONNX模型,将其转换为JSON格式提取子图,并对子图进行修改(如添加输入节点、删除无关节点)。最后,将JSON转回ONNX格式,完成模型切分与优化。此方法适用于关键路径上的LOOP算子,可有效解决离线推理中的兼容性问题。

方案背景

当在线推理的速度无法满足客户要求,使用atc工具将onnx转为om模型走离线推理路径时,遇到NPU不支持LOOP算子的问题,本文提供一种解决方案。
本方案的设计思路是,onnx文件分成loop算子和不含loop算子的两部分,把loop算子的子图提取出来,单独推理。
实际操作中可能需要分成3份乃至更多,因此,本方案使用于关键路径上的loop算子,否则工作量会很大。

构造包含loop算子的onnx模型

首先使用以下代码构造一个包含loop算子的onnx模型

# 文件名:hi.py
import torch

@torch.jit.script
def loop(x, y):
    for i in range(x.shape[0]):
        x = x + y
    return x

class SimpleModel(torch.nn.Module):
    def _mul(self, x, y = 20):
        return x * y

    def forward(self, x, y):
        x = x - y
        x = loop(x, y)
        return x

if __name__ == "__main__":

    input1 = torch.rand((2, 16, 32))
    input2 = torch.rand((2, 16, 32))
    model = SimpleModel()
    torch.onnx.export(
    model,
    (input1, input2),
    './model.onnx',
    input_names=['input1', 'input2'],
    dynamic_axes = {
        'input1': {0: 'batch'},
        'input2': {0: 'batch'},
    }
    )

执行以上脚本文件hi.py:

python3 hi.py

执行结束后生成model.onnx文件,使用netron工具打开后模型结构如图所示:
01.png

onnx文件转换为json格式

# 文件名:onnx_to_json.py
import onnx
from google.protobuf.json_format import MessageToJson
model = onnx.load("./model.onnx")  
message = MessageToJson(model)
with open("{}.json".format("./model.onnx"), "w") as fi:
    fi.write(message)

执行以上脚本文件onnx_to_json.py:

python3 onnx_to_json.py

执行结束后生成model.onnx.json文件,打开此文件可以看到,Loop算子包含了一个子图,后续的工作是将子图提取出来
02.png

提取子图

替换主图

用 loop["attribute"][0]["g"] 的内容替换主图 "graph"中的内容
03.png

json转换成onnx

把替换之后json转换成onnx,得到如下onnx文件:

# 文件名:jsonTo_onnx.py
import onnx
import numpy as np
from google.protobuf.json_format import MessageToJson, Parse
import json
import time

# json to onnx
with open("model_loop.onnx.json", "r") as fi:
    onnx_json = json.loads(fi.read())
    onnx_str = json.dumps(onnx_json)
    model2 = Parse(onnx_str, onnx.ModelProto())
    onnx.save(model2, "model_loop.onnx")

执行以上脚本文件jsonTo_onnx.py:

python3 jsonTo_onnx.py

执行结束后生成model_loop.onnx文件,使用netron工具打开后模型结构如图所示:
04.png

切分原图

原图分为:loop算子前面的图-A、loop算子-B、loop算子后的图-C,这三部分,需要加载3个图,然后在loop算子那块循环做infer
本例原图的这个loop在结尾的位置,那就不需要切分loop算子后的图-C,只需要切分成loop算子前面的图-A、loop算子-B

# 文件名:extract_model.py
import onnx
from onnx.utils import extract_model
onnx.utils.extract_model("model.onnx","model_dest1.onnx",['input1', 'input2'], ['/Sub_output_0', 'onnx::Loop_6'], check_model=False)

['input1', 'input2']:切分模型的输入节点
05.png

['/Sub_output_0', 'onnx::Loop_6']:切分模型的输出节点
06.png

执行以上脚本文件extract_model.py,生成loop算子前面的图-A:
07.png

修改json构造子图

由于Add算子的另一个输入直接来自主图的input2,但我们直接提取的子图中没有input2,故需要添加一个input2节点
在子图的json文件中添加来自主图的input2:
08.png

json转onnx文件

执行脚本文件jsonTo_onnx.py,生成新带有input2的子图:
09.png

构造子图输入

  • 输入 i,在实际在循环控制中发挥作用,此处不生效,任意传入一个值占位即可,可删除节点
  • 输入cond
  • inputs = {"i": 0 , cond: True, "x.13": outputs[0], "input2":input2}

    loop的执行逻辑

// 当迭代次数小于最大行程计数,并且条件的 ML 值所指向的布尔张量数据为 true 时,进入循环
while (iter_num_value < max_trip_count_ && *condition_mlvalue_.GetMutable<Tensor>()->MutableData<bool>()) {
    // 如果迭代次数不为 0
    if (iter_num_value != 0) {
        // 保存输出并更新输入
        SaveOutputsAndUpdateFeeds(fetches, feeds);
        // 清空 fetches 向量
        fetches.clear();
    }

    // 执行子图,将执行结果存储在 status 中
    status = utils::ExecuteSubgraph(session_state_, ffm, feeds, fetches, {},
                                    ExecutionMode::ORT_SEQUENTIAL, context_.GetTerminateFlag(), context_.Logger(),
                                    context_.GetComputeStream(),
                                    // 由于 fetches[0] 是循环条件,我们需要在 CPU 上访问该数据,
                                    // 因此必须进行流同步以确保数据已到达。
                                    true);
    // 如果执行子图过程中出现错误,则返回错误
    ORT_RETURN_IF_ERROR(status);

    // 将 fetches 向量中的第一个元素赋值给 condition_mlvalue_
    condition_mlvalue_ = fetches[0];

以上代码实现了一个循环,在满足特定条件时会持续执行子图。每次迭代时,若不是第一次迭代,就会保存输出并更新输入,接着执行子图,最后更新循环条件。

删除无关节点

循环控制分为循环次数和循环condition,子图的第一个输出为condition。本例中condition始终为True,可以删除这个节点。
在子图json文件中删除图中圈出的输入数据节点:
10.png

删除后执行脚本文件jsonTo_onnx.py,执行结束后生成mode_loop_input2_i_cond.onnx文件,使用netron工具打开后模型结构如图所示:
11.png

目录
相关文章
|
5月前
|
Python
飞桨x昇腾生态适配方案:15_loop算子缺失(下):for循环替换loop
本章节基于上一内容,将ONNX模型拆分为loop算子部分与非loop算子部分,分别转换为OM模型。通过使用for循环替换loop算子的计算逻辑,构造子图执行流程,并编写OM模型推理脚本进行验证。同时,编写ONNX模型推理脚本对比两者推理结果,确保一致性。实验结果表明,拆分后的OM模型与原始ONNX模型推理结果一致,证明方案可行。
194 27
|
机器学习/深度学习 人工智能 数据可视化
【好物分享】onnx-modifier:可视化操作助力模型更改,让你不再为更改模型烦恼!
【好物分享】onnx-modifier:可视化操作助力模型更改,让你不再为更改模型烦恼!
2065 0
【好物分享】onnx-modifier:可视化操作助力模型更改,让你不再为更改模型烦恼!
|
存储 SQL Web App开发
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
322 2
|
算法 数据库 计算机视觉
Dataset之COCO数据集:COCO数据集的简介、下载、使用方法之详细攻略
Dataset之COCO数据集:COCO数据集的简介、下载、使用方法之详细攻略
|
6月前
|
容器
vllm+vllm-ascend本地部署QwQ-32B
本指南介绍如何下载、安装和启动基于Ascend的vLLM模型。首先,可通过华为镜像或Hugging Face下载预训练模型;其次,安装vllm-ascend,支持通过基础镜像(如`quay.io/ascend/vllm-ascend:v0.7.3-dev`)或源码编译方式完成;最后,使用OpenAI兼容接口启动模型,例如运行`vllm serve`命令,设置模型路径、并行规模等参数。适用于大模型推理场景,需注意显存需求(如QwQ-32B需70G以上)。
2649 17
|
5月前
|
API Python
飞桨x昇腾生态适配方案:13_API离线推理
ais_bench 提供了基于昇腾硬件的 Python API,用于离线模型(.om模型)推理。支持静态与动态API场景,如单个或多个OM模型推理。通过 `InferSession` 类加载模型并执行推理,可灵活处理输入输出形状转换。示例代码涵盖图片读取、形状调整、多模型串联推理及资源释放等操作,满足多样化推理需求。
338 26
|
5月前
|
编解码 人工智能 JSON
飞桨x昇腾生态适配方案:10_ONNX转OM
本章节主要介绍如何将ONNX模型转化为昇腾AI处理器支持的OM模型,并进行离线推理。通过昇腾张量编译器(ATC),可实现静态OM、动态BatchSize、动态分辨率、动态维度及动态shape等多种模型转换。文中详细说明了ATC工具的使用方法、参数配置、命令格式以及常见问题解决方法,同时提供了具体示例和可视化工具辅助输入参数确认,帮助用户高效完成模型转换与部署。
728 0
|
5月前
|
编解码 人工智能 API
飞桨x昇腾生态适配方案:12_动态OM推理
本文介绍了基于Ascend AI平台的OM模型动态推理方法,包括动态BatchSize、动态分辨率、动态维度及动态Shape四种场景,支持固定模式与自动设置模式。通过`ais_bench`工具实现推理,提供示例命令及输出结果说明,并解决常见问题(如环境变量未设置、输入与模型不匹配等)。此外,还提供了API推理指南及参考链接,帮助用户深入了解ONNX离线推理流程、性能优化案例及工具使用方法。
319 0
|
5月前
|
人工智能 测试技术 API
飞桨x昇腾生态适配方案:11_静态OM推理
昇腾AI推理工具`ais_bench`基于ACL开发,支持命令行快速推理与性能测试(吞吐率、时延等),并提供相关API。用户需下载适配环境的`aclruntime`和`ais_bench`的whl包后通过pip安装。设置环境变量后,可通过多种场景使用工具:纯推理(默认输入全0数据)、调试模式(获取详细参数与耗时信息)、文件/文件夹输入(指定Numpy文件或目录)、以及多Device并行推理。例如,BERT模型需按顺序传入三个文件夹对应其输入参数。工具输出包括吞吐率、耗时等关键指标,助力高效模型性能评估。
313 0
|
8月前
|
算法 数据安全/隐私保护
基于ADRC自抗扰算法的UAV飞行姿态控制系统simulink建模与仿真
本课题基于ADRC自抗扰算法,使用MATLAB2022a在Simulink中建模与仿真UAV飞行姿态控制系统,分别对偏航(Yaw)、俯仰(Pitch)和滚转(Roll)进行控制。ADRC通过扩展状态观测器(ESO)实时估计并抵消扰动,结合非线性反馈控制策略,减少了对精确模型的依赖,增强了系统的鲁棒性和适应性。仿真结果显示该方法能有效实现UAV的姿态控制,确保其在复杂环境中的稳定飞行和精确操控。