分割 dominator

分割 dominator#

from testing import viz_expr # 可视化 relay
import tvm
from tvm import relay
from tvm.relay.dataflow_pattern import *

构建计算图:

def generate_diamond(inp, weight):
    conv2d = relay.op.nn.conv2d(inp, weight)
    relu = relay.op.nn.relu(conv2d)
    relu = relay.op.nn.relu(relu)
    leaky_relu = relay.op.nn.leaky_relu(conv2d, alpha=0)
    return relu + leaky_relu
# Classic Diamond
inp = relay.var("input")
weight = relay.var("weight")
out = generate_diamond(inp * inp, weight * weight)
viz_expr(out)
../../../../_images/67cca8cee787b65dd207b7f172d1e10acf9453dd3cd993c6aadf97850fda29e0.svg
print(tvm.IRModule.from_expr(out))
def @main(%input, %weight) {
  %0 = multiply(%input, %input);
  %1 = multiply(%weight, %weight);
  %2 = nn.conv2d(%0, %1, padding=[0, 0, 0, 0]);
  %3 = nn.relu(%2);
  %4 = nn.relu(%3);
  %5 = nn.leaky_relu(%2, alpha=0f);
  add(%4, %5)
}

构建模式:

# NB: 1 corresponds to the C++ enum that specicfies this
# we loose the type safety due to the Python/C++ calling
# convention.
K_ELEMWISE = 0
K_BROADCAST = 1

# Pattern
is_conv2d = is_op("nn.conv2d")(wildcard(), wildcard())
is_unary_elemwise = (wildcard().has_attr({"TOpPattern": K_ELEMWISE}))(wildcard())
reduction = is_op("add")(wildcard(), wildcard())
diamond = dominates(is_conv2d, is_unary_elemwise, reduction)

分割计算图:

partitioned = diamond.partition(out)
print(tvm.IRModule.from_expr(partitioned))
def @main(%input, %weight) {
  %4 = multiply(%input, %input);
  %5 = multiply(%weight, %weight);
  %6 = fn (%FunctionVar_0_0, %FunctionVar_0_1, PartitionedFromPattern="nn.conv2d_nn.relu_nn.relu_nn.leaky_relu_add_") {
    %0 = nn.conv2d(%FunctionVar_0_0, %FunctionVar_0_1, padding=[0, 0, 0, 0]);
    %1 = nn.relu(%0);
    %2 = nn.relu(%1);
    %3 = nn.leaky_relu(%0, alpha=0f);
    add(%2, %3)
  };
  %6(%4, %5)
}