zoukankan      html  css  js  c++  java
  • TVM图优化(以Op Fusion为例)

    首先给出一个TVM 相关的介绍,这个是Tianqi Chen演讲在OSDI18上用的PPT https://files.cnblogs.com/files/jourluohua/Tianqi-Chen-TVM-Stack-Overview.rar

    对于图优化来说,位于整个软件编译栈比较高的层次:

    首先给出计算图的定义

    Computational graphs: a common way to represent programs in deep learning frameworks

    对于图优化来说,有很多种图优化手段:Operator Fusion
    Constant Parameter Path Pre-Computation
    Static Memory Reuse Analysis
    Data Layout Transformation
    AlterOpLayout
    SimplifyInference

    这里仅以Operator Fusion做例子介绍

    Operator fusion : combine multiple operators together into a single kernel without saving the intermediate results back into global memory

    也就说是说算子融合省掉了中间数据的store过程

    在TVM中,有三种融合规则:

    其中,算子属于哪一类是算子本身的特性(这个地方不是特别懂,这个属性有非常多的值),但是能融合的规则只有这三种。

    但是这种store是如何减少的,在IR上有明确的体现。

    下边的例子,我会使用tvm.relay来进行介绍,relay是TVM中实现的一种高级IR,可以简单理解为另一种计算图表示。其在TVM所处的位置如下图所示

    比如,我们假设我们要完成一个y = exp(x+1.0)的计算图

    给出测试代码(来自于源码中的test_pass_fuse_ops.py,有改动):

    import tvm
    from tvm import relay
    
    def test_fuse_simple():
        """Simple testcase."""
        def before():
            x = relay.var("x", shape=(10, 20))
            y = relay.add(x, relay.const(1, "float32"))
            z = relay.exp(y)
            return relay.Function([x], z)
    
        def expected():
            x = relay.var("p", shape=(10, 20))
            y = relay.add(x, relay.const(1, "float32"))
            z = relay.exp(y)
            f1 = relay.Function([x], z)
            x = relay.var("x", shape=(10, 20))
            y = relay.Call(f1, [x])
            return relay.Function([x], y)
    
        z = before()
        z = relay.ir_pass.infer_type(z)
        # print(z.astext())
        zz = relay.ir_pass.fuse_ops(z, opt_level=2)
        print(zz.astext())
        zz = relay.ir_pass.infer_type(zz)
        zz = relay.ir_pass.fuse_ops(zz)
        zz = relay.ir_pass.infer_type(zz)
        after = relay.ir_pass.infer_type(expected())
        # print(after.astext())
        assert relay.ir_pass.alpha_equal(zz, after)

    在融合前,其IR(方便用户看的一种形式,不是真正的IR)

    fn (%x: Tensor[(10, 20), float32])
        -> Tensor[(10, 20), float32] {
      %0 = fn(%p0: Tensor[(10, 20), float32],
              %p1: float32)
              -> Tensor[(10, 20), float32] {
        %1 = add(%p0, %p1)
        %1
      }
      %2 = %0(%x, 1f)
      %3 = fn(%p01: Tensor[(10, 20), float32])
              -> Tensor[(10, 20), float32] {
        %4 = exp(%p01)
        %4
      }
      %5 = %3(%2)
      %5
    }
    

     融合后:

    fn (%x: Tensor[(10, 20), float32])
        -> Tensor[(10, 20), float32] {
      %0 = fn(%p0: Tensor[(10, 20), float32])
              -> Tensor[(10, 20), float32] {
        %1 = add(%p0, 1f)
        %2 = exp(%1)
        %2
      }
      %3 = %0(%x)
      %3
    }
    

     可以很明显的发现,省掉了一次数据store过程

  • 相关阅读:
    探究操作系统的内存分配(malloc)对齐策略
    三十一个实用的小常识
    防止网页后退
    郁闷的一天
    脑袋不行
    家的开张
    猴子定律
    赴微软onsite!谁有C++/HTML/JavaScript开发工程师推荐?
    卡马克的求平方根函数代码的陷阱
    动作游戏自定义技能探讨
  • 原文地址:https://www.cnblogs.com/jourluohua/p/10774399.html
Copyright © 2011-2022 走看看