TVM Relay Pass探究

TVM前端研究--Pass 在 TVM 中,Pass 根据 IR 类型的不同分为 Relay 上的优化和 TIR 上的优化。因此,Relay 上的 Pass 包括通用的 pass,在 tvm.relay.transform 目录下,还有一些 Pass 包含系统信息或后端信息,在其他目录下如 AnnotateUsedMemory Pass 等。是包含了一个 Pass 所需的基本信息如 name 是 pass 名称,opt_level 表示将在哪个优化级别启用 pass,required 表示执行某个 pass 所需的 pass。 阅读详情

引言

 

Relay 是 TVM 中十分重要的基础组件之一,用于对接不同格式的深度学习模型以及进行模型的 transform。深度学习编译器的核心功能就是进行各种各样的 transform 变换,这个变换过程部分是由 Pass 来实现。当需要遍历计算图时,底层究竟是如何执行的?本文打算一探究竟。


1. 简介

Pass 两层设计:

  • TIR 层,基于 target 的优化,主要涉及 lower 到 target 时采用的优化策略,包括:VectorizeLoop、UnrollLoop、RemoveNoOp、SkipAssert、ThreadSync 等;此部分 Pass 有时可以直接复用底层编译器的 pass,如 LLVM/CUDA C 等编译器。TVM 主要关注和 ML 相关且底层编译器未考虑到的场景。

  • Relay 层:基于 计算图 的优化,主要通过对 AST 分析,进行 node 的修改来实现。

Pass 功能上可分为三类:

  • module level:tvm.transform.ModulePass,利用全局信息进行优化,可以增加或删除 module 内的 function;

    • 例如 FlattenNestedTuples, RemoveUnusedFunctions, PartitionGraph, InferType, dead code elimination, A-normal form conversion, lambda lifting;

  • function level:tvm.relay.transform.FunctionPass、tvm.tir.transform.PrimFuncPass,对 IRModule 内的单个或多个 function 进行改写,TVM 中绝大部分 Pass 都是这类;

    • 例如 comm subexpression elimination, vectorizition;

  • sequential level:tvm.transform.Sequential,是一个 container,可以装载多个 Pass,顺序执行;可以认为是前两个的一个封装而已。

TVM 中有较多的 Pass,运行我们在调用时可以创建一个 PassContext 上下文环境,调用优先级:disabled_pass > required_pass > opt_level。

首先检查该 Pass 是否被用户 disable,然后检查该 pass 是 required,最后检查 Pass 的 opt_level 是否低于 pass context 中的 opt_level。如上均满足条件后,该 pass 即为 enabled。对应代码如下:

bool PassContext::PassEnabled(const PassInfo& info) const {
  if (PassArrayContains(operator->()->disabled_pass, info->name)) {
    return false;
  }

  if (PassArrayContains(operator->()->required_pass, info->name)) {
    return true;
  }

  return operator->()->opt_level >= info->opt_level;
}

常用 Pass 的 opt_level见下面列表,可以看到 FuseOps 作为推理性能强相关的 Pass,其优先级默认设置为了最高(0,数字越小,优先级越高),FoldConstant 常量折叠的优先级也被设置为了 2。更为激进的性能优化 Pass 如 CombineParallelConv2d、FastMath、DenseToSparse 和 Conv2dToSparse2 等都被设置为了 4 和 5。由于 TVM demo 中大部分都是设置 opt_level=3,上面提到的更为激进的性能优化 Pass 并没有 enable。因此,我们可以设置更高的 opt_level,同时在 required_pass 参数列表中加入所需 pass,则可以进一步提升模型的推理性能哦。10 行代码改动,性能提升 10% 不是梦。

  • FuseOps:0

  • DeadCodeElimination:1

  • FoldConstant:2

  • ConvertLayout:3

  • EliminateCommonSubexpr:3

  • CombineParallelConv2d:4

  • CombineParallelDense:4

  • CombineParallelBatchMatmul:4

  • FastMath:4

  • DenseToSparse:4

  • Conv2dToSparse2:5

2. 添加 Pass

作为推理性能优化开发者,免不了对 Pass 进行修改或新增。Relay 层主要有两种 Pass 添加方式:

  • 通过 Python 装饰器 @relay.transform.function_pass(opt_level=1),只能添加 function level 的 Pass:python/tvm/relay/transform/transform.py,这种方式下代码仓库中只有一个 Pass ChangeBatch 使用了这种方式;

  • 通过 C++ 方式,TVM 中几乎所有 Pass 都是采用这种方式实现。

    • 继承 ExprMutator 类,定义一个新的 Pass 类,重写 VisitExpr_(后序遍历AST, Post-DFS order) 和 Rewriter_ 成员函数,最后将该 Pass 注册到 Pass 管理器中;

    • 继承 ExprRewriter 类,定义一个新的 Pass 类,重写 Rewriter_ 成员函数,最后将该 Pass 注册到 Pass 管理器中;

    • 当然,还有其他组合方式,但上面 2 个是最常见的方式。

笔者个人推荐用 C++ 方式实现 Pass,原因:

  • Python 装饰器方式可参考代码少,TVM 中只有一个 Pass ChangeBatch 使用了这种方式,且这个 Pass 不常用。

  • Python 装饰器方式功能单一,Pass 基础类底层都是 C++ 实现的,一些基础方法并没有全部映射到 Python 端。

Pass 底层实现:

  • tvm::relay::ExprFunctor 类(核心基类),其有如下 2 个重要的派生类:

    • ExprVisitor 类:通过 VisitExpr_ 成员函数递归地后序遍历 AST,不修改 node 的成员函数

    • ExprMutator 类:通过 VisitExpr_ 成员函数递归地后序遍历 AST,通过 Rewriter_ 成员函数修改 AST

  • tvm::relay::ExprRewriter 也是十分重要的一个基类:只有 Rewriter_ 成员函数,用来非递归地后续遍历并修改 AST。

Pass 底层执行的逻辑都是与如上几个类强相关,如果仅阅读代码,很容易一头雾水。下面具体以一个例子(功能为获取模型中的所有 op),单步调试进入代码,看看其调用逻辑。

3. Pass 底层调用逻辑

基类 ExprFunctor 和 派生类 ExprVisitor、ExprMutator 代码定义在 python/tvm/relay/expr_functor.py 中,我们通过一个端到端 demo,实现一个读取 ResNet18 模型并输出其所有 op 信息的功能。这里不涉及到计算图修改,因此可以继承 ExprVisitor 实现一个 OpLister 类,测试代码如下:

import tvm
from tvm import relay
from tvm.relay import testing

def list_ops(expr):
    class OpLister(tvm.relay.ExprVisitor):
        def visit_op(self, expr):
            if expr not in self.node_memo_map:
                self.node_list.append(expr)
            return super().visit_op(expr)

        def list_nodes(self, expr):
            self.node_memo_map = {}
            self.node_list = []
            self.visit(expr)
            return self.node_list

    ins = OpLister()
    return ins.list_nodes(expr)

mod, params = tvm.relay.testing.resnet.get_workload(
    batch_size=1, num_classes=1000, num_layers=18)
op_names = list_ops(mod["main"])

print(op_names)

[Op(nn.softmax), Op(nn.bias_add), Op(nn.dense), Op(nn.batch_flatten), Op(nn.global_avg_pool2d), Op(nn.relu), Op(nn.batch_norm), Op(add), Op(nn.conv2d), Op(nn.max_pool2d)]

首先,在第 23 行设置断点,Debug 模式运行如图 1,params 是一个 dict 类型的变量,存储有模型权重信息;mod 是一个 IRModule 类实例,IRModule 内的数据结构是 Map<GlobalVar, BaseFunc>。

d87d20d18de1a4faa6c512af4a75a853.png

图 1

ac691b941f818ab9436d46f4411c736b.png

图2

继续单步执行 step,图 2 中可以看到执行 mod["main"] 时,实际在执行 IRModule 类的特殊方法 __getitem__,第 105 行会返回一个 Function 类型的变量 expr,图 3 中可以 expr 就是从 mod 中读取的,看到两个红框内的数据是一样的。

96da53428f319b48354c70ceedd1b0e9.png

图3

下面到了重点,要执行 list_ops 函数了。这里首先将相关类的继承关系再次列出来方便后续分析,ExprFunctor -> ExprVisitor ->OpLister。由于 list_ops 函数内有 OpLister 类定义,因此首先应该执行 OpLister 类的定义,而后执行第 18 行,调用 OpLister 的构造函数,由于 OpLister 没有显示定义构造函数,且继承了 ExprVisitor 类,因此这时会直接调用 ExprVisitor 类的构造函数。但是,ExprVisitor 类中也没有显示定义构造函数,因此会直接寻找其父类 ExprFunctor 中的构造函数并执行。我们 step 单步调试来验证下,如图 4,程序直接执行到 ExprFunctor 的构造函数,定义了一个 memo_map 成员变量,该变量的作用是存储已访问的 AST 信息,当遍历 AST 时,首先查找 expr 是否已经存在 memo_map 中,如果没有再根据 expr 的类型递归遍历。这样可以节省 AST 的遍历时间。

365a439d59504691b2408a863657c759.png

图4

继续单步执行,图 5 中可以看到 ins 实例中只有一个成员变量 memo_map,当前该变量是一个空字典。

878464773c13a5ea5818a0385ecb7c10.png

图5

继续单步执行,执行到 list_nodes 函数内部,新增了 OpLister 类的成员变量 node_memo_map 和 node_list,如图 6 所示。

64441dbc0e9db5016d68326a73db2bc7.png

图 6

下面又到了重点:执行 self.visit(expr),根据继承关系依次查找,OpLister 和 ExprVisitor 均没有该函数定义,在 ExprFunctor 类中有成员函数 visit,因此这里会执行到 ExprFunctor 类中的 visit 函数,如图 7 :

1760a3ebe3db6efd87343ccfa4d0e866.png

图7

ExprFunctor 类中的 visit 函数功能为根据传入的 expr 具体类型,调用 ExprVisitor 类中的具体类型 visit 函数,实现类型函数派发。比如,前面由 mod["main"] 获取到 Function 类型的 expr,这时调用 ExprVisitor 类中的 visit_function 函数。visit_function 函数功能为循环遍历访问 Function 中的 params,存储到 memo_map 中。例如图 8 中将 Var(data, ty=TensorT... float32) 写入到 mem_map 中。

3ebadc2505717a860adba4375d34301c.png

图8

执行 visit_function 函数内的 for 循环会将所有的 params 存储到 memo_map。图 9 中展示了循环 3 次后获取到的三个 Var:

45818667580bcbae88adab6c8337b517.png

图9

ResNet18 中含有 100 个 Var,这里不展示中间过程了。我们直接在 line 158 设置断点并执行到该行,self.visit(fn.body) 为遍历 fn 的函数体,即 N 多个 CallNode,见图 10。这时执行 self.visit(fn.body) 时,根据类型派发,会调用到 visit_call 函数(图 11)。

ac9db5a39a15a6f4203a083282d1bcee.png

图10

96080f08e988cb71538fce2ed2d4fbc1.png

图11

CallNode 中含有丰富的信息(代码片段如下),如被调用的算子、调用时的输入参数等。图 11 中,expr.op 为 Op(nn.softmax),expr.args 为 [CallNode(Op(nn.bias_add), [...])],需要留意的是 expr.args 中包含有 expr.op 依赖的所有前驱 CallNode 信息。

// include/tvm/relay/expr.h
class CallNode : public ExprNode {
 protected:
  // CallNode uses own deleter to indirectly call non-recursive destructor
  Object::FDeleter saved_deleter_;
  static void Deleter_(Object* ptr);

 public:
  /*!
   * \brief The operator(function) being invoked
   *
   *  - It can be tvm::Op which corresponds to the primitive operators.
   *  - It can also be user defined functions (Function, GlobalVar, Var).
   */
  Expr op;

  /*! \brief The arguments(inputs) of the call */
  tvm::Array<relay::Expr> args;

  /*! \brief The additional attributes */
  Attrs attrs;

  /*!
   * \brief The type arguments passed to polymorphic(template) function.
   *
   * This is the advance feature that is only used when the function is
   * polymorphic. It is safe to be ignored in most cases. For example, in the
   * following code, the type_args of addone call is [int].
   *
   * \code
   *
   * template<typename T>
   * T addone(T a) { return a + 1; }
   *
   * void main() {
   *   int x = addone<int>(10);
   * }
   *
   * \endcode
   */
  tvm::Array<Type> type_args;
  ...
};

继续单步调试,visit_call 函数功能为先访问 call.op,然后遍历访问所有的 call.args,见图 12。

b8e6f77a1ba0e0797be8991a2d276492.png

图12

当执行 self.visit(call.op) 时,根据类型派发,会执行到下图中的 visit_op(图 13)。这里需要注意了,visit_op 在 ExprFunctor、ExprVisitor 和 OpLister 中都有定义,self 是一个 OpLister 的实例,因此这里会实际跳转执行到 OpLister 类中的 visit_op 成员函数(图 14)。

3d105ef6b8570febd72f59a05bc2df35.png

图13

3ac512884792a50dd3cf51643eac9f47.png

图14

OpLister 类中的 visit_op 成员函数功能为记录当前访问到的算子,记录到 op_list 中,然后执行父类 ExprVisitor 中的 visit_op(expr). ExprVisitor 中的 visit_op(expr) 函数内只有一个 Pass 语句,没有实际执行的内容,因此这里也可以删除 super().visit_op(expr),见图 14。这时,我们获取到了模型中的一个算子 Op(nn.softmax)。

循环执行如下 for 循环,会依次获取到其他算子信息,见图 15。最终,会获得所有的 op 信息。

691d423cd7b1e4c89c0149f3b3100b61.png

图1 5

ResNet18 IRModule 尾部结构可视化如下,可以对照着查看模型遍历执行逻辑。

a4155394592c1947a7898ef45da8ff3e.png

图 16:ResNet18 IRModule 尾部结构可视化

4. 总结

针对从 torch 转入的模型,输入 mod 就已经包含有算子间的所有调用关系信息了,ExprVisitor 类只是递归遍历,依次递归遍历抽取出 Var、Call 等信息。通过单步调试,可以进一步加深对代码逻辑的理解。笔者个人知识水平有限,文中理解若有问题,欢迎各位大佬指点交流,一起学习提高。

最后给我们团队的开源项目打个广告,Adlik 是中兴通讯贡献的深度学习推理工具,已获得 Linux AI 基金会支持,目前仍在持续完善中,期待大家的支持和关注:Github Adlik;另外,我们也在做深度学习编译器方向的前沿技术研发工作,欢迎感兴趣的小伙伴加入我们 ~~

参考

  • https://tvm.apache.org/docs/arch/pass_infra.html

  • https://zhuanlan.zhihu.com/p/341334406

往期相关推荐:

面向ASIC设备的编译器框架:TVM or MLIR?

深度学习模型编译框架TVM概述

TVM Relay与Pass TVM Relay与Pass 本文介绍TVM的Relay,如何基于Relay构建一个Conv+BN+ReLU的小网络, TVM中的Pass的工作机制,并较为详细的介绍了RemoveUnusedFunctions,ToBasicBlockNormalForm,EliminateCommonSubexpr三种Pass。其中Relay部分的详细介绍大部分引用自官方文档: https://tvm.apache.org/docs/tutorials/get_started/introduction.html。 TVM 阅读详情

相关推荐

TVM前端研究--Relay

TVM前端之前用的NNVM,现在用的Relay,后面会往Relax和Unity方向转。先简单介绍一下。Relay的解释比较杂乱,按照论文和官方文档的解释它算是一个编译器框架或着IR(Intermediate Representation)。说是编译器框架有些大,说是IR他不单单可以做算子表示,还可以支持函数、类型等编程逻辑。

欢迎订阅 -- 小源笔迹 1462

【TVM帮助文档学习】Relay的类型系统

本文翻译自Relay’s Type System — tvm 0.9.dev0 documentation 在介绍Relay表达式细节时,我们简单的涉及了Relay的类型,但是还没有详细描述整个类型系统。Relay是一种静态类型和类型推断语言,它在允许程序完全类型化的同时,只需要少量的显式的类型说明。 静态类型在执行编译器优化时非常有用,因为它们可以传递程序所处理的数据的属性,例如运行时形状、数据布局和存储,而无需运行程序。Relay的代数数据类型允许轻松、灵活地组合类型,以便构建可以归纳推理和用于编写递

zx_ros的博客 855

tvm relay inline pass的调研

tvm relay inline pass的调研 relay的流程;pass功能;cpu上跑通单元测例 tests/python/relay/test_pass_inline.py, 明确pass原理; 能否使用inline针对一个网络生成一个call func ,这种方式能很好支持当前bangc优化和代码生成 Relay Build ----------- Compile the graph to llvm target with given input specification. target = “

weixin_42432844的博客 1304

TVM Pass 总结

介绍 tvm.relay.transform

fwx_x的博客 3162

Outlook总是提示登录微软,怎么办?

Outlook 2021反复弹出Microsoft登录窗口,可能是由于Modern Authentication身份验证机制或凭据问题导致。解决方案包括:1)通过注册表关闭Modern Authentication(适用于本地Exchange);2)清理Windows凭据管理器中的旧认证信息;3)手动配置Exchange服务器地址;4)通过注册表阻止Microsoft登录窗口弹出(适用于非M365环境)。建议按顺序尝试,尤其前两步通常能解决问题。经测试,步骤1和2已有效解决该问题。

剪刀石头布 4674

2022(一等奖)B360基于Arcpy与SVM的滑坡易发性评价

此外,在ArcGIS平台下,“易发性图预测(多进程)”工具的运行时间为2h 48m 3s,“易发性图预测(单进程)”工具的运行时间为5h 19m 27s,运行时间缩短了近2h 31m 24s,运行效率提高了47.39%。在ArcGIS Pro平台下,“易发性图预测(多进程)”工具的运行时间为20m 12s,“易发性图预测(单进程)”工具的运行时间为1h 26m 47s,将运行时间缩短了近1h 6m 35s,运行效率提高了76.72%。滑坡的发生受各种影响因素的影响,目前,影响因素的选择没有一个统一的标准。

2301_77310370的博客 1467

【TVM帮助文档学习】TVM及模型优化综述

下图说明了使用TVM优化编译器框架转换机器学习模型的步骤。 1.从Tensorflow、PyTorch或Onnx等框架导入模型。导入层是TVM可以从其他框架(如Tensorflow、PyTorch或ONNX)中吸收模型的地方。TVM为每个前端提供的支持水平随着我们不断改进开源项目而提高。当导入模型到TVM有问题时,可以尝试将它先转换到ONNX。 2.转换为Relay。Relay是TVM的高级模型语言。导入TVM的模型用Relay表示。Relay是一种用于神经网络的函数式语言和中间表示。它支持:...

zx_ros的博客 1235

阿里云导出的镜像raw转换成vmdk格式工具

阿里云导出的镜像raw转换成vmdk格式工具 1.安装java环境,安装教程不介绍了 2.raw2vmdk软件下载: 在我的链接里面: 3.使用 打开cmd.bat软件: java -jar raw2vmdk.jar (原镜像)C:\\images\\raw\\disk.img (转换的镜像)D:\\images\\vmdk\\disk.vmdk 4.vmware打开vmdk文件 ...

3845

【从零开始学深度学习编译器】八,TVM的算符融合以及如何使用TVM Pass Infra自定义Pass

0x00. 前言 上篇文章系统的介绍了TVM Pass Infra,并解析了Relay树结构以及Constant Folding Pass的具体做法。这一节,我想先补充一下TVM Pass Infra的用法,然后再解析一下TVM中的一个非常重要的Pass即算符融合。 0x01. 如何使用TVM Pass Infra 关于TVM Pass Infra的介绍可以移步【从零开始学深度学习编译器】七,万字长文入门TVM Pass查看。 ...

I good vegetable a! 2095

Cursor设置界面汉化保姆级教程:手把手教你修改JS文件实现中文界面(附避坑指南)

本文提供Cursor编辑器设置界面汉化的详细教程,从定位JS文件到安全修改实现中文界面,包含必备工具清单、文件路径指引和常见问题解决方案。通过手把手教学帮助用户轻松完成汉化,提升使用体验,特别适合不熟悉英文界面的开发者。

weixin_29007809的博客 1414

一种4位sar adc仿真验证

4位sar adc采用下图的电容阵列,电路如下图:所有电容的正端(也称为上极板)与比较器的反相端连接,比较器同相端接Vin,其工作过程进行大致分析见之前的文章《一种4位sar adc工作过程推导(三)》,下面对这个电路进行仿真验证。 两个参考电压VrefPV_{refP}VrefP​和VrefNV_{refN}VrefN​,V+=VinV_{+}=V_{in}V+​=Vin​,假设1116(VrefP−VrefN)+VrefN<Vin<1216(VrefP−VrefN)+VrefN\frac{

大学生视野 1955

在Relay中添加一个编译pass

本文翻译自Adding a Compiler Pass to Relay — tvm 0.9.dev0 documentation编译器pass是扩展Relay特性集和对Relay程序进行优化的主要接口。通过编写编译器pass,您可以修改AST或收集有关AST的信息,这取决于您的目标。事实上,Relay的一些最重要的内部特性(例如自动微分和类型推断)只不过是“标准的”编译器pass。从较高的层次上讲,编写pass有两个关键组件:首先,我们将概述编写编译器pass的关键机制。然后,我们将分析一个Relay常量

zx_ros的博客 727

MATLAB出现”警告: 名称不存在或不是目录“的解决方案

MATLAB出现 警告: 名称不存在或不是目录 的解决方案1. 出现错误2. 问题解释3. 解决方法4. 特殊情况5. 问题解决6. 多多点赞交流 1. 出现错误 打开MATLAB突然发现,出现下面的错误: 提示我们不存在这样的路径。 2. 问题解释 这样的错误很明显,我们曾经在预设路径中添加了这个文件夹。 在某种情况下,我们把它删除了,现在MATLAB找不到它了。 (这里我在桌面上添加了新建文件夹,然后将其添加到MATLAB的搜索路径中。之后把新建文件夹删除了,所以就会出现这样的报错) 3. 解决方法

qq_18820125的博客 5万+

【从零开始学深度学习编译器】五,TVM Relay以及Pass简介

在前面几节的介绍中我们了解到了TVM是如何将ONNX前端模型转换为IR Module的,并且还剖析了TVM中的Relay算子和TOPI算子的扭转过程,知道了Relay算子的最终计算也是基于TOPI算子集合完成的。这几行代码展示了TVM的编译流程,在这个编译流程里面不仅包含了基于Relay IR进行的优化策略来去除冗余的算子(也叫Pass)还包含了将Relay程序编译成特定后端(这里是llvm)可以执行的代码(codegen)。

生活需要深度 960

超大规模系统(千万级用户)中实现字段级权限控制

摘要:本文提出了一套分布式架构下的字段级权限优化方案,结合RBAC+ABAC混合模型与技术手段实现性能与安全的平衡。方案包括:1)权限模型优化,采用RBAC预计算基础权限与ABAC动态校验敏感字段;2)数据层优化,实现动态字段过滤与加密存储;3)多级缓存策略与预计算机制提升性能;4)分布式架构设计,通过网关校验和策略引擎集群保证扩展性。最终在千万级用户系统中实现99.9%可用性,权限校验延迟控制在50ms以内。

从技术实践立足,从项目管理方法论延伸思考 1350

RFSoC全面解析(八)—— ZCU111 RFSoC评估工具的上位机界面

下面的内容的参考文献为:XILINX公司文档UG1287。 XILINX公司提供了一个RFSoC的ADC/DAC性能的评估工具或者叫评估系统,这个文档就是讲如何使用这个评估工具的。 整个评估系统总的框图如上图所示,评估系统由上位机、ZCU111开发板、子卡以及网线、射频线缆组成。 ZCU111开发板内主要使用的RFSoC外设为时钟驱动和DDR4,RFSoC的PS部分和PL部分都使用了。 PS部分发挥的功能为通过网口与上位机通信,通过IIC总线控制时钟驱动芯片以及数据流控制等;PL部分发挥的功能为

4381

【TVM 教程】向 Relay 中添加 Compiler Pass

Apache TVM 是一个深度的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 →https://tvm.hyper.ai/

HyperAI超神经 960

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

TVM,Relay,Pass

TVM,Relay,Pass Relay介绍 主要结合TVM的文档(https://tvm.apache.org/docs/dev/relay_intro.html),介绍一下NNVM的第二代Relay。Relay的设计目标有以下几点: 支持传统的数据流(DataFlow)风格编程。支持functional-style scoping,并融合了编程语言领域的一些知识,带了一些新的特性(支持Let表达式,支持递归等等)支持数据流风格和函数式风格混合编程。 使用Relay建立一个计算图 传统的深度学习框架使用计

吴建明wujianming_110117 722

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

TVM 实践指南:向 Relay 框架添加自定义 Compiler Pass 的完整流程

摘要:本文详细介绍了TVM深度学习编译器中Relay中间表示层自定义CompilerPass的开发方法。文章从RelayCompilerPass的架构解析入手,阐明其函数级和模块级Pass的分层设计及注册机制。通过代码示例展示了自定义Pass的核心开发流程,包括IR遍历、模式匹配、节点转换等关键技术,并以Conv2D-BatchNorm融合为例演示具体实现。最后探讨了Pass的调试、性能评估及集成优化最佳实践,为开发者提供了TVM中间表示优化的完整技术指南。

jingpide9527的博客 835

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【TVM 教程】如何使用 TVM Pass Infra

Apache TVM 是一个深度的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 →<https://tvm.hyper.ai/>

HyperAI超神经 832

如何使用TVM Pass Relay

如何使用TVM Pass红外线 随着Relay / tir中优化遍数的增加,执行并手动维护其依赖关系变得很棘手。引入了一个基础结构来管理优化过程,将其应用于TVM堆栈中IR的不同层。 Relay / tir程序的优化可以以各种粒度应用,分别使用tvm.relay.transform.FunctionPass/ tvm.tir.transform.PrimFuncPass和的功能级别和模块级别tvm.transform.ModulePass 。用户可以依靠在tvm.transform.Sequential r

吴建明wujianming_110117 679

TVM Pass概述

use pass infra Design and Architecture Pass又称transform,每一个transform要么把现有程序转换并优化为一个等价的程序,要么把程序lower到下层。relay/transform包括很多优化模型用的pass,包括常量折叠(constant folding)和死代码删除(dead-code elimination)等。 这里拿tests/python/relay/test_pass_fold_constant.py里的单测作为例子: import num

Eurypterid的博客 1353

【TVM 教程】如何使用 TVM Pass Instrument

​可以使用装饰器创建自定义 instrument 类。创建一个工具类(计算每次 Pass 引起的每个算子出现次数的变化)。可以在 Pass 之前和之后查看op.name来找到每个算子的名称,从而计算差异。# Pass 可以嵌套。# 使用堆栈来确保得到之前/之后正确的 pairs。# 弹出最新记录的 Pass。# 只记导致差异的 Pass。"""return ["""ret = {}else:# 某些 CallNode 可能没有“名称”,例如 relay.Functionreturn。

HyperAI超神经 1038
上一篇: 通用视觉大模型综述
下一篇: Adlik招聘啦!
Linux基金会AI&Data基金会
博客等级 码龄6年 103粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux基金会AI&Data基金会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值