zoukankan      html  css  js  c++  java
  • hola** ONNX计算图修改神器

    做过部署的小伙伴都知道,在利用TensorRT部署到NVIDIA显卡上时,onnx模型的计算图不好修改,而看了人家NCNN开发者nihui大佬的操作就知道,很多时候大佬是将onnx转换成ncnn的.paran和.bin文件后对.param的计算图做调整的,看的我心痒痒,就想有没有一种工具可以修改onnx计算图,这样,我可以合并op后,自己写个TRT插件就好了嘛,今天,它来了

    安装onnx_graphsurgeon

    在新版本的TensoRT预编译包里有.whl的python包直接安装就可以了,笔者今天主要是讲怎么用这个工具,以官方的例子很好理解

    生成一个onnx计算图

    #
    # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    #
    
    import onnx_graphsurgeon as gs
    import numpy as np
    import onnx
    
    # Register functions to make graph generation easier
    @gs.Graph.register()
    def min(self, *args):
        return self.layer(op="Min", inputs=args, outputs=["min_out"])[0]
    
    @gs.Graph.register()
    def max(self, *args):
        return self.layer(op="Max", inputs=args, outputs=["max_out"])[0]
    
    @gs.Graph.register()
    def identity(self, inp):
        return self.layer(op="Identity", inputs=[inp], outputs=["identity_out"])[0]
    
    
    # Generate the graph
    graph = gs.Graph()
    
    graph.inputs = [gs.Variable("input", shape=(4, 4), dtype=np.float32)]
    
    # Clip values to [0, 6]
    MIN_VAL = np.array(0, np.float32)
    MAX_VAL = np.array(6, np.float32)
    
    # Add identity nodes to make the graph structure a bit more interesting
    inp = graph.identity(graph.inputs[0])
    max_out = graph.max(graph.min(inp, MAX_VAL), MIN_VAL)
    graph.outputs = [graph.identity(max_out), ]
    
    # Graph outputs must include dtype information
    graph.outputs[0].to_variable(dtype=np.float32, shape=(4, 4))
    
    onnx.save(gs.export_onnx(graph), "model.onnx")

    然后netron查看如下

     这不就是Clip操作嘛,你要问Clip是什么....e....看这个吧

    import numpy as np
    x=np.array([1,2,3,5,6,7,8,9])
    np.clip(x,3,8)
    Out[
    88]: array([3, 3, 3, 5, 6, 7, 8, 8])

    现在就是想使用onnx_graphsurgeon这个工具将OP Min和Max整合成一个叫Clip的心OP这样即使部署时也只需要写个Clip插件就好了,当然本文只是为了演示,Clip OP已经TensorRT支持了。

    修改开始

     方法非常简单,先把你想要合并的OP和外界所有联系切断,然后替换成新的ONNX OP保存就好了

    还不理解?上才艺

     就是把Min和Identity断开,Min和c2常数断开,Max和c5常数断开,Max和下面那个Identity断开,然后替换成新的OP就好

    看代码

    import onnx_graphsurgeon as gs
    import numpy as np
    import onnx
    
    
    # Here we'll register a function to do all the subgraph-replacement heavy-lifting.
    # NOTE: Since registered functions are entirely reusable, it may be a good idea to
    # refactor them into a separate module so you can use them across all your models.
    # 这里写成函数是为了,万一还需要这样的替换操作就可以重复利用了
    @gs.Graph.register() def replace_with_clip(self, inputs, outputs): # Disconnect output nodes of all input tensors for inp in inputs: inp.outputs.clear() # Disconnet input nodes of all output tensors for out in outputs: out.inputs.clear() # Insert the new node. return self.layer(op="Clip", inputs=inputs, outputs=outputs) # Now we'll do the actual replacement
    # 导入onnx模型 graph = gs.import_onnx(onnx.load("model.onnx")) tmap = graph.tensors() # You can figure out the input and output tensors using Netron. In our case: # Inputs: [inp, MIN_VAL, MAX_VAL] # Outputs: [max_out]
    # 子图的需要断开的输入name和子图需要断开的输出name inputs = [tmap["identity_out_0"], tmap["onnx_graphsurgeon_constant_5"], tmap["onnx_graphsurgeon_constant_2"]] outputs = [tmap["max_out_6"]]
    # 断开并替换成新的名叫Clip的 OP graph.replace_with_clip(inputs, outputs)
    # Remove the now-dangling subgraph. graph.cleanup().toposort() # That's it! onnx.save(gs.export_onnx(graph), "replaced.onnx")

    最后看下

     完成onnx计算图修改

  • 相关阅读:
    C++ delete file
    C++ get file size
    C++ file copy
    C++跨类调用类成员的方法之一
    Linux下C语言实现回调函数的例子
    error: atomic: 没有那个文件或目录
    libpng warning: iCCP: known incorrect sRGB profile告警处理
    picker多级选择器的使用————小程序
    JQ的简单使用(基础)——————JQ
    选择器与过滤器(全)————JQ
  • 原文地址:https://www.cnblogs.com/nanmi/p/14875678.html
Copyright © 2011-2022 走看看