精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

【TVM 教程】如何使用 TVM Pass Infra 原創(chuàng)

發(fā)布于 2025-6-9 14:02
瀏覽
0收藏

Apache TVM 是一個深度的深度學習編譯框架,適用于 CPU、GPU 和各種機器學習加速芯片。更多 TVM 中文文檔可訪問 →https://tvm.hyper.ai/

作者Zhi Chen

隨著 Relay/tir 中優(yōu)化 Pass 數(shù)的增加,手動執(zhí)行并維護它們的依賴關(guān)系變得難以處理。因此我們引入了一個基礎(chǔ)架構(gòu)來管理優(yōu)化 Pass,并使其適用于 TVM 堆棧中 IR 的不同層。

Relay/tir 程序的優(yōu)化可以在各種粒度上應用,即分別使用?tvm.relay.transform.FunctionPass/?tvm.tir.transform.PrimFuncPass?和?tvm.transform.ModulePass?的功能級和模塊級,或者用戶可以依靠?tvm.transform.Sequential?在 Relay/tir 程序上應用一系列 Pass,其中 Pass 之間的依賴關(guān)系可以通過 pass infra 來解決。有關(guān)這些 Pass 類型的更多詳細信息,參閱?Pass Infrastructure

本教程主要演示開發(fā)者如何使用 pass infra 進行某種優(yōu)化,并為 Relay 程序創(chuàng)建優(yōu)化 Pass。同樣的方法也可以用于 tir。

import numpy as np
import tvm
from tvm import te
import tvm.relay as relay

創(chuàng)建 Relay 程序示例?

首先為教程創(chuàng)建一個簡單的 Relay 程序,該程序用于本教程中示例的各種優(yōu)化。同樣,用戶可以編寫 tir 原始函數(shù)并應用 tir pass。

def example():
    shape = (1, 64, 54, 54)
    c_data = np.empty(shape).astype("float32")
    c = relay.const(c_data)
    weight = relay.var("weight", shape=(64, 64, 3, 3))
    x = relay.var("x", relay.TensorType((1, 64, 56, 56), "float32"))
    conv = relay.nn.conv2d(x, weight)
    y = relay.add(c, c)
    y = relay.multiply(y, relay.const(2, "float32"))
    y = relay.add(conv, y)
    z = relay.add(y, c)
    z1 = relay.add(y, c)
    z2 = relay.add(z, z1)
    return relay.Function([x, weight], z2)

優(yōu)化程序?

接下來優(yōu)化程序,Relay 具有許多優(yōu)化功能,選擇其中一部分應用到這個示例程序中。

有多種方法可以優(yōu)化 Relay 程序。下面將逐一講解。

手動應用優(yōu)化 Pass

# 優(yōu)化函數(shù)。
f = example()
mod = tvm.IRModule.from_expr(f)

# 現(xiàn)在可以在模塊上應用常量折疊。
# fold_const 是一個不帶任何參數(shù)的回調(diào)函數(shù)。
fold_const = relay.transform.FoldConstant()
# 然后,在給定的模塊上調(diào)用 pass。注意,常數(shù)
# folding pass 在函數(shù)級別工作。話雖如此,每個
# 模塊中的函數(shù)將應用優(yōu)化。用戶無需迭代
# 通過各個函數(shù)手動應用此 pass。
mod = fold_const(mod)
# 從更新后的程序中可以看到常量被折疊了。
print(mod)

輸出結(jié)果:

  "target_host parameter is going to be deprecated. "
def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %3 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

可以以類似的方式應用更多優(yōu)化。例如,可以消除?z?和?z1?使用的常用表達式。

mod = relay.transform.EliminateCommonSubexpr()(mod)
print(mod)

輸出結(jié)果:

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

融合也是參數(shù)化的,例如,opt level 0 將不允許算子融合在一起。用戶可以通過 fuse_opt_level 來啟用它。

mod = relay.transform.FuseOps(fuse_opt_level=0)(mod)

# 可以觀察到優(yōu)化后的模塊包含的函數(shù)只有
# 一個單一的原始操作。
print(mod)

輸出結(jié)果:

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = fn (%p03: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %p12: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    nn.conv2d(%p03, %p12, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 56, 56), float32], Tensor[(64, 64, 3, 3), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %1 = %0(%x, %weight) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = fn (%p02: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p11: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    add(%p02, %p11) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %3 = %2(%1, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %4 = fn (%p01: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p1: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    add(%p01, %p1) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %5 = %4(%3, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %6 = fn (%p0: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    add(%p0, %p0) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %6(%5) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

使用 Sequential 應用一系列 Pass?

如上所述應用 Pass 實際上很乏味,并且可能需要用戶更好地了解它們之間的依賴關(guān)系。例如,融合目前在 let 綁定上效果不佳。因此,如果在融合之前應用了?relay.transform.ToANormalForm(),將無法融合可融合的算子,因為此過程會為每個表達式生成 let 綁定以規(guī)范 Relay 程序。

因此,Relay 提供了?tvm.transform.Sequential,使得開發(fā)者能夠更容易地處理這些問題。他們通過顯式指定每個 pass 所需的 pass,然后將它們打包為一個整體來實現(xiàn)。

例如,使用下面的 sequential 來應用相同的 pass。tvm.transform.Sequential?類似于?torch.nn.sequential?和?mxnet.gluon.block。例如,torch.nn.sequential 包含一系列 PyTorch 模塊,這些模塊將會用來構(gòu)建網(wǎng)絡(luò)。它側(cè)重于網(wǎng)絡(luò)層。相反,我們的 pass infra 中的?tvm.transform.Sequential?用于優(yōu)化 pass。

# 通過 :py:class:`tvm.transform.Sequential` 執(zhí)行一些傳遞
f = example()
mod = tvm.IRModule.from_expr(f)
# Glob 感興趣的 passes。
seq = tvm.transform.Sequential(
    [
        relay.transform.FoldConstant(),
        relay.transform.EliminateCommonSubexpr(),
        relay.transform.FuseOps(fuse_opt_level=2),
    ]
)
mod1 = seq(mod)
print(mod1)

輸出結(jié)果:

/workspace/python/tvm/driver/build_module.py:268: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
  "target_host parameter is going to be deprecated. "
def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %4 = fn (%p0: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %p1: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */, %p2: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p3: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    %0 = nn.conv2d(%p0, %p1, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %1 = add(%0, %p2) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %2 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %3 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 56, 56), float32], Tensor[(64, 64, 3, 3), float32], Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %4(%x, %weight, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

從改造后的 Relay 程序中,可以看到仍然有兩個相同的加法運算。這是因為?EliminateCommonSubexpr?并未實際執(zhí)行。原因是在?tvm.transform.Sequential?下,只有優(yōu)化級別小于或等于 2 的 pass 才會默認執(zhí)行。pass infra 為用戶提供了一個配置界面來自定義想要執(zhí)行的優(yōu)化級別。

with tvm.transform.PassContext(opt_level=3):
    mod2 = seq(mod)
print(mod2)

輸出結(jié)果:

/workspace/python/tvm/driver/build_module.py:268: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
  "target_host parameter is going to be deprecated. "
def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %3 = fn (%p0: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %p1: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */, %p2: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p3: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    %0 = nn.conv2d(%p0, %p1, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %1 = add(%0, %p2) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %2 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 56, 56), float32], Tensor[(64, 64, 3, 3), float32], Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %3(%x, %weight, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

現(xiàn)在可以看到兩個相同的加法只保留一個。

用戶可以使用?disabled_pass?配置選擇性地禁用某些 pass,這與 Clang 和 GCC 等通用編譯器使用的?-fno-xxx?選項類似。例如,可以禁用以下 EliminateCommonSubexpr,打印的模塊將再次顯示兩個相同的加法操作。

with tvm.transform.PassContext(opt_level=3, disabled_pass=["EliminateCommonSubexpr"]):
    mod3 = seq(mod)
print(mod3)

輸出結(jié)果:

/workspace/python/tvm/driver/build_module.py:268: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
  "target_host parameter is going to be deprecated. "
def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %4 = fn (%p0: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %p1: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */, %p2: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p3: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    %0 = nn.conv2d(%p0, %p1, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %1 = add(%0, %p2) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %2 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %3 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 56, 56), float32], Tensor[(64, 64, 3, 3), float32], Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %4(%x, %weight, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

使用 Python 裝飾器實現(xiàn) Pass?

下一個示例說明如何使用 Python 裝飾器通過 pass infra 來自定義優(yōu)化 pipeline。此功能極大地簡化了pass 的實現(xiàn)。例如,用戶可以簡單地定義一個裝飾類來進行函數(shù)級優(yōu)化,如下例所示。?transform_function?包裝了一個類,用 c 的倍數(shù)替換所有常量。稍后,訪問給定模塊中的每個函數(shù),并且調(diào)用自定義 pass 時,函數(shù)中的每個常量都將被替換。

@relay.transform.function_pass(opt_level=1)
class CustomPipeline:
    """Simple test function to replace one argument to another."""

    def __init__(self, multiplier):
        self.multiplier = multiplier

    # 這個函數(shù)可以定義一個pass。
    def transform_function(self, func, mod, ctx):
        obj = self

        class ReplaceConstant(tvm.relay.ExprMutator):
            def visit_constant(self, c):
                return relay.multiply(obj.multiplier, c)

        return ReplaceConstant().visit(func)

f = example()
mod = tvm.IRModule.from_expr(f)
custom_pass = CustomPipeline(multiplier=relay.const(3, "float32"))
assert custom_pass.info.name == "CustomPipeline"
mod3 = custom_pass(mod)
print(mod3)

輸出結(jié)果:

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = multiply(3f /* ty=float32 */, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, %0) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = multiply(3f /* ty=float32 */, 2f /* ty=float32 */) /* ty=float32 */;
  %3 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %4 = multiply(%1, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %5 = add(%3, %4) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %6 = add(%5, %0) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %7 = add(%5, %0) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%6, %7) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

調(diào)試 Pass?

TVM 為用戶提供了即插即用式調(diào)試 Pass,通過特殊 pass (PrintIR) 轉(zhuǎn)儲整個模塊的 IR,在完成某個 pass 后打印 IR。pass 序列示例的輕微修改版本如下所示,用于啟用 IR 轉(zhuǎn)儲以進行?FoldConstant?優(yōu)化。

f = example()
mod = tvm.IRModule.from_expr(f)
seq = tvm.transform.Sequential(
    [
        relay.transform.FoldConstant(),
        tvm.transform.PrintIR(),
        relay.transform.EliminateCommonSubexpr(),
        relay.transform.FuseOps(),
    ]
)

通過在?FoldConstant?之后插入?PrintIR?pass,pass infra 將在?FoldConstant?完成時轉(zhuǎn)儲模塊 IR。用戶可以在任何想要調(diào)試的 pass 之后插入這個 pass 來查看優(yōu)化效果。

此外,還有一個更靈活的調(diào)試機制,可以實現(xiàn)一個?PassInstrument?類來執(zhí)行任意代碼,不僅在每次傳遞之前和/或之后,而且在進入/退出?PassContext?時也可以。有關(guān)詳細信息,參閱?Pass Instrument

這里使用?tvm.instrument.pass_instrument?裝飾器來實現(xiàn)一個 PassInsturment 類,在每次執(zhí)行之前打印 IR:

@tvm.instrument.pass_instrument
class PrintIR:
    """僅在 pass 執(zhí)行之前打印 pass 的名稱,IR。"""

    def run_before_pass(self, mod, info):
        print("Running pass: {}", info)
        print(mod)

with tvm.transform.PassContext(opt_level=3, instruments=[PrintIR()]):
    with tvm.target.Target("llvm"):
        # 執(zhí)行優(yōu)化。
        mod = seq(mod)
print(mod)

print("done")

輸出結(jié)果:

Running pass: {} The meta data of the pass - pass name: sequential, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32], %weight: Tensor[(64, 64, 3, 3), float32]) {
  %0 = add(meta[relay.Constant][0], meta[relay.Constant][0]);
  %1 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]);
  %2 = multiply(%0, 2f);
  %3 = add(%1, %2);
  %4 = add(%3, meta[relay.Constant][0]);
  %5 = add(%3, meta[relay.Constant][0]);
  add(%4, %5)
}

Running pass: {} The meta data of the pass - pass name: FoldConstant, opt_level: 2, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32], %weight: Tensor[(64, 64, 3, 3), float32]) {
  %0 = add(meta[relay.Constant][0], meta[relay.Constant][0]);
  %1 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]);
  %2 = multiply(%0, 2f);
  %3 = add(%1, %2);
  %4 = add(%3, meta[relay.Constant][0]);
  %5 = add(%3, meta[relay.Constant][0]);
  add(%4, %5)
}

/workspace/python/tvm/driver/build_module.py:268: UserWarning: target_host parameter is going to be deprecated. Please pass in tvm.target.Target(target, host=target_host) instead.
  "target_host parameter is going to be deprecated. "
Running pass: {} The meta data of the pass - pass name: InferType, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32], %weight: Tensor[(64, 64, 3, 3), float32]) {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]);
  %1 = add(%0, meta[relay.Constant][0]);
  %2 = add(%1, meta[relay.Constant][1]);
  %3 = add(%1, meta[relay.Constant][1]);
  add(%2, %3)
}

Running pass: {} The meta data of the pass - pass name: PrintIR, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %3 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: InferType, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %3 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: EliminateCommonSubexpr, opt_level: 3, required passes: [
InferType, ]

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %3 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %3) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: InferType, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: InferType, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: FuseOps, opt_level: 0, required passes: [
InferType, ]

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %0 = nn.conv2d(%x, %weight, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %1 = add(%0, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  %2 = add(%1, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */;
  add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

Running pass: {} The meta data of the pass - pass name: InferType, opt_level: 0, required passes: []

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %3 = fn (%p0: Tensor[(1, 64, 56, 56), float32], %p1: Tensor[(64, 64, 3, 3), float32], %p2: Tensor[(1, 64, 54, 54), float32], %p3: Tensor[(1, 64, 54, 54), float32], Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    %0 = nn.conv2d(%p0, %p1, padding=[0, 0, 0, 0]);
    %1 = add(%0, %p2);
    %2 = add(%1, %p3);
    add(%2, %2)
  };
  %3(%x, %weight, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */)
}

def @main(%x: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %weight: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */) -> Tensor[(1, 64, 54, 54), float32] {
  %3 = fn (%p0: Tensor[(1, 64, 56, 56), float32] /* ty=Tensor[(1, 64, 56, 56), float32] */, %p1: Tensor[(64, 64, 3, 3), float32] /* ty=Tensor[(64, 64, 3, 3), float32] */, %p2: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, %p3: Tensor[(1, 64, 54, 54), float32] /* ty=Tensor[(1, 64, 54, 54), float32] */, Primitive=1) -> Tensor[(1, 64, 54, 54), float32] {
    %0 = nn.conv2d(%p0, %p1, padding=[0, 0, 0, 0]) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %1 = add(%0, %p2) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    %2 = add(%1, %p3) /* ty=Tensor[(1, 64, 54, 54), float32] */;
    add(%2, %2) /* ty=Tensor[(1, 64, 54, 54), float32] */
  } /* ty=fn (Tensor[(1, 64, 56, 56), float32], Tensor[(64, 64, 3, 3), float32], Tensor[(1, 64, 54, 54), float32], Tensor[(1, 64, 54, 54), float32]) -> Tensor[(1, 64, 54, 54), float32] */;
  %3(%x, %weight, meta[relay.Constant][0] /* ty=Tensor[(1, 64, 54, 54), float32] */, meta[relay.Constant][1] /* ty=Tensor[(1, 64, 54, 54), float32] */) /* ty=Tensor[(1, 64, 54, 54), float32] */
}

done

總結(jié)?

本教程介紹了如何使用 pass infra 更方便地在 TVM 中編寫和調(diào)用 pass。還討論了調(diào)用 pass 的不同方式。使用?tvm.transform.Sequential?可以在很大程度上幫助用戶簡化處理多個優(yōu)化過程及其依賴關(guān)系的工作。此外,還提供了一個示例來說明如何使用?PrintIR?和跟蹤來調(diào)試 pass。

下載 Python 源代碼:use_pass_infra.py

下載 Jupyter Notebook:use_pass_infra.ipynb

?著作權(quán)歸作者所有,如需轉(zhuǎn)載,請注明出處,否則將追究法律責任
收藏
回復
舉報
回復
相關(guān)推薦
美日韩一级片在线观看| av一区二区在线播放| 亚洲一区二区av在线| 国产一级特黄a大片99| 精产国品一区二区| 亚洲自拍偷拍网| 亚洲精品一区二区三区99| 久久久久久久久久福利| a级毛片免费观看在线 | 日韩久久久久久久久久久| av电影在线地址| 久久精品视频免费| 91手机在线播放| 五月婷婷激情五月| 激情久久综合| 中文字幕精品国产| 中文字幕无码人妻少妇免费| 粉嫩91精品久久久久久久99蜜桃| 亚洲国产一区二区a毛片| 天堂va久久久噜噜噜久久va| 免费a级片在线观看| 久久国产精品色| 欧美影院久久久| 激情五月少妇a| 不卡一区综合视频| 亚洲免费av电影| 四虎精品一区二区| 九九九九九九精品任你躁| 色婷婷综合久色| 国产黄视频在线| 免费污视频在线| 亚洲精品久久久久久国产精华液| 亚洲高清资源综合久久精品| 视频在线不卡| av男人天堂一区| 国产91视觉| 99精品视频在线播放免费| 青草国产精品久久久久久| 日本久久久久久久久久久| 日本一级黄色录像| 欧美福利专区| 欧美成人午夜激情| 疯狂试爱三2浴室激情视频| 欧美一区三区| 一本色道久久88综合亚洲精品ⅰ| 精品无人区无码乱码毛片国产| 免费看久久久| 精品视频在线播放免| 奇米777第四色| 精品久久ai| 亚洲国产日韩一区| 亚洲人人夜夜澡人人爽| 欧美91在线| 日韩精品www| 国产黄色三级网站| 亚洲精品3区| 亚洲欧美国产精品| 亚洲精品国产精品国自| 色999国产精品| 日韩中文视频免费在线观看| 夫妇交换中文字幕| 欧美aaaa视频| 久久久精品久久久| 免费在线一级片| 伊人久久亚洲美女图片| 午夜精品久久久久久久男人的天堂| 九九热国产视频| 国产精品腿扒开做爽爽爽挤奶网站| 97福利一区二区| av中文在线播放| 日韩国产欧美在线观看| 国产精品三级网站| va视频在线观看| 东方欧美亚洲色图在线| 精品视频一区在线| 电影在线一区| 亚洲日本在线天堂| 亚洲色成人www永久在线观看| 欧美激情网站| 欧美三片在线视频观看| 亚洲丝袜在线观看| 日韩欧美ww| 在线午夜精品自拍| 校园春色 亚洲| 99综合视频| 国产精品色悠悠| 亚洲a视频在线| 久久嫩草精品久久久精品| 亚洲一区二区高清视频| av黄色在线| 欧美性xxxx极品高清hd直播| 天天干天天操天天玩| av成人男女| 国产亚洲精品久久久久久牛牛 | 日本久久久久亚洲中字幕| 亚洲视频在线观看免费视频| 成人午夜伦理影院| 日产精品高清视频免费| 四虎亚洲精品| 在线观看欧美精品| 在线播放av网址| 国产亚洲一区| 欧美高清第一页| 免费黄色av片| 国产成人精品一区二区三区四区| 日本婷婷久久久久久久久一区二区| 成人直播在线| 色一区在线观看| 人妻 丝袜美腿 中文字幕| 欧美久久精品一级c片| 久久久久成人精品| 伊人22222| 91视视频在线观看入口直接观看www | 国产日韩成人内射视频| 99re91这里只有精品| 色爱av美腿丝袜综合粉嫩av| 色婷婷av国产精品| 国产精品伊人色| 午夜精品区一区二区三| 欧美日韩国产观看视频| 欧美一级欧美一级在线播放| 国产精品美女高潮无套| 伊人狠狠色j香婷婷综合| 91精品一区二区| 高清av在线| 日本久久一区二区| 怡红院一区二区| 欧美久久九九| 成人在线播放av| 拍真实国产伦偷精品| 日韩欧美在线免费| 午夜久久久久久久| 伊人成年综合电影网| 不卡视频一区| 污片视频在线免费观看| 制服丝袜国产精品| 人人爽人人爽人人片| 亚洲欧美清纯在线制服| 九九九九九精品| caoporn-草棚在线视频最| 欧美一区二区三区在线| 日韩欧美123区| 精品一区二区三区免费观看| 亚洲一区二区三区免费看| 美女网站视频一区| 一区二区欧美亚洲| 在线观看国产区| 欧美国产国产综合| 婷婷免费在线观看| 日韩精品一区二区三区免费观影| 国产精品亚洲第一区| 国产精品视频二区三区| 在线观看视频一区二区 | 亚洲产国偷v产偷v自拍涩爱| 亚洲免费观看高清| 99国产精品免费视频| 午夜精品久久久久99热蜜桃导演 | 亚洲综合成人在线| 久久久久99人妻一区二区三区| 欧美日韩国产高清| 国产欧美一区二区三区不卡高清| www成人免费观看| 亚洲精品999| 日韩欧美在线观看免费| 久久精品免费在线观看| 天天操天天爽天天射| 久久亚洲国产| 99在线看视频| 欧美私密网站| 中文亚洲视频在线| 国产日韩精品suv| 亚洲丶国产丶欧美一区二区三区| 性久久久久久久久久久| 久久九九免费| 国产一区一区三区| 国产精品tv| 国产精品久久久久久久久免费| 成人av免费| 亚洲精品成人网| 91视频在线视频| 亚洲色图在线播放| 91黄色免费视频| 蜜桃传媒麻豆第一区在线观看| 在线观看免费黄色片| 国产精品99久久免费观看| 日韩av观看网址| 黄色网址在线免费| 亚洲精品美女在线观看播放| 中文字幕在线观看欧美| 亚洲国产成人高清精品| 97在线观看免费视频| 国产一区二区在线观看免费| 日韩免费视频播放| 999精品视频| 国产伦理一区二区三区| 日本国产欧美| 欧美激情一区二区久久久| 国产精品秘入口| 亚洲高清色综合| 伊人久久亚洲综合| 亚洲成a人片在线不卡一二三区| 东方伊人免费在线观看| 成人丝袜视频网| 国产成人美女视频| 久久久噜噜噜| 国产精品三级一区二区| 日韩伦理视频| 激情小说网站亚洲综合网| 一级欧美视频| 国产成人精品免高潮在线观看| 中文字幕在线播放网址| 中文字幕欧美日韩| 外国精品视频在线观看| 欧美日韩国产成人在线免费| 国产精品第二十页| 亚洲精品国产无天堂网2021| 黄色片网站免费| 91片在线免费观看| 国内自拍偷拍视频| 黑人巨大精品欧美一区| 五月婷婷激情久久| 亚洲中字在线| 亚洲精品无码国产| 欧美99久久| 成人黄色三级视频| 亚洲一级影院| 只有这里有精品| 日韩国产欧美一区二区| 久久草.com| 久久激情av| 鬼打鬼之黄金道士1992林正英| 青娱乐极品盛宴一区二区| 国产成人avxxxxx在线看| av免费在线视| 欧美精品成人91久久久久久久| 国产一二区在线观看| 最新的欧美黄色| 999国产在线视频| 亚洲欧美日韩一区二区在线| 亚洲 欧美 自拍偷拍| 亚洲第一男人av| 亚洲国产综合网| 欧美成人激情免费网| aaa国产视频| 欧美一激情一区二区三区| 一级黄色小视频| 欧美日产在线观看| 国产精品欧美激情在线| 欧美顶级少妇做爰| 国产女人18毛片18精品| 69堂亚洲精品首页| 国产免费黄色片| 欧美电视剧在线看免费| 成人爽a毛片一区二区| 精品福利一区二区三区| 色哟哟国产精品色哟哟| 亚洲精美色品网站| 日韩电影免费| 宅男66日本亚洲欧美视频| av中文字幕一区二区三区| 深夜福利一区二区| 久草免费在线| 欧美国产日韩在线| xxxcom在线观看| 欧美在线激情网| 成人国产一区| 91美女高潮出水| 亚洲国产中文在线二区三区免| 国产精品久久国产精品| 五月综合久久| 亚洲三区在线观看| 一区二区三区在线| 一区二区传媒有限公司| 久久视频一区| 五月激情五月婷婷| 成人综合婷婷国产精品久久 | 欧美不卡视频在线观看| 色综合久久综合网欧美综合网| 性高潮视频在线观看| 51久久夜色精品国产麻豆| 91麻豆一区二区| 亚洲高清一二三区| 国产精品四虎| 美女撒尿一区二区三区| 色吧亚洲日本| 91精品中文在线| 激情小说亚洲图片| 视频一区视频二区视频| 红桃视频国产一区| 美女一区二区三区视频| 高清免费成人av| 在线观看国产精品一区| 一区二区三区在线看| 日韩精品成人免费观看视频| 欧美一区二区视频在线观看| 日本在线丨区| 久久精品99久久久久久久久| 日韩伦理福利| 亚洲999一在线观看www| 亚洲影院天堂中文av色| 国产精品免费看久久久无码| 久久国产主播| 日韩av成人网| 中文一区二区在线观看| 国产黄色片视频| 欧美日韩免费观看一区二区三区| 日韩一区免费视频| 久久精品中文字幕| 粉嫩一区二区| 国产精品我不卡| 欧美精品一二| 久色视频在线播放| 懂色av一区二区三区免费看| 综合 欧美 亚洲日本| 亚洲成人在线免费| 国产欧美日韩综合精品一区二区三区| 亚洲欧美精品一区| 欧美性爽视频| 成人h片在线播放免费网站| 欧美人与牛zoz0性行为| 91九色丨porny丨国产jk| 国产精品一区久久久久| 在线观看天堂av| 在线视频你懂得一区二区三区| 日批视频免费播放| 欧美激情2020午夜免费观看| 日韩成人一区| 亚洲一区二区免费视频软件合集| 久久在线精品| 日本黄色网址大全| 午夜电影一区二区| 黄色a在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 黄瓜视频成人app免费| 久久精品美女| 亚洲尤物在线| 国产精品300页| 午夜一区二区三区视频| 亚洲精品福利网站| 欧美激情三级免费| 日韩不卡在线视频| 日韩精品免费一区| 国产一区91精品张津瑜| 国产一区二区播放| 欧美一区二区国产| 香蕉成人app免费看片| 亚洲精品免费在线视频| 欧美日韩亚洲一区在线观看| 宇都宫紫苑在线播放| 一区二区三区四区不卡在线| 国产高清精品软件丝瓜软件| 欧美精品少妇videofree| 亚洲一区二区三区四区电影 | 日韩电影免费观看| 91丝袜脚交足在线播放| 国内视频精品| 国产精品伦子伦| 欧美丝袜第一区| 国产福利小视频在线| 国产视频观看一区| 亚洲乱码电影| 国产国语老龄妇女a片| 亚洲成人免费在线| 欧美高清电影在线| 国产精品视频一区国模私拍| 国产精品91一区二区三区| 男插女视频网站| 亚洲v中文字幕| 欧美孕妇孕交| 国产日韩欧美一二三区| 综合激情一区| 菠萝菠萝蜜网站| 色吊一区二区三区| 好了av在线| 国内精品久久久久久久果冻传媒| 国产亚洲精品bv在线观看| 国产高清一区二区三区四区| 欧美精品 国产精品| 国产极品人妖在线观看| 欧美日韩国产综合在线| 狠狠色丁香九九婷婷综合五月| 激情综合五月网| 精品夜色国产国偷在线| 欧洲精品久久久久毛片完整版| 欧美这里只有精品| 国产午夜亚洲精品不卡| 国产黄色片免费| 国产成人福利视频| 欧美一区二区三区久久精品| 精品人妻一区二区三区香蕉| 777a∨成人精品桃花网| 韩国成人二区| 在线综合视频网站| 91香蕉视频污在线| 国产乱子伦精品无码码专区| 国产91精品高潮白浆喷水| 日韩在线视屏| 国产肉体xxxx裸体784大胆| 欧美日韩国产影片| 国产传媒在线观看|