张量形状符号

张量形状符号#

接下来以张量加法为例探讨使用张量表达式定义不定形状的张量。

不定形状的张量算子#

%cd ../..
import set_env
import numpy as np
import tvm
from tvm import te
from tvm.ir.module import IRModule

声明用于记录张量形状的符号变量(var()):

N = te.var(name='N')
print(type(N), N.dtype)
N
<class 'tvm.tir.expr.Var'> int32
N

声明两个张量占位符:

A = te.placeholder((N,), name='A')
B = te.placeholder((N,), name='B')
A
Tensor(shape=[N], op.name=A)

定义张量加法运算:

C = te.compute(A.shape, lambda i: A[i] + B[i], name='C')

构建张量原语函数:

te_func = te.create_prim_func([A, B, C])
te_func.show()
# from tvm.script import tir as T
@T.prim_func
def func(var_A: T.handle, var_B: T.handle, var_C: T.handle):
    # function attr dict
    T.func_attr({"global_symbol": "main", "tir.noalias": True})
    N = T.var("int32")
    A = T.match_buffer(var_A, [N], dtype="float32")
    B = T.match_buffer(var_B, [N], dtype="float32")
    C = T.match_buffer(var_C, [N], dtype="float32")
    # body
    # with T.block("root")
    for i0 in T.serial(N):
        with T.block("C"):
            i = T.axis.spatial(N, i0)
            T.reads(A[i], B[i])
            T.writes(C[i])
            C[i] = A[i] + B[i]

将张量原语函数变换为模块:

Module = IRModule({"add": te_func})
Module.show()
# from tvm.script import tir as T
@tvm.script.ir_module
class Module:
    @T.prim_func
    def add(var_A: T.handle, var_B: T.handle, var_C: T.handle):
        # function attr dict
        T.func_attr({"global_symbol": "main", "tir.noalias": True})
        N = T.var("int32")
        A = T.match_buffer(var_A, [N], dtype="float32")
        B = T.match_buffer(var_B, [N], dtype="float32")
        C = T.match_buffer(var_C, [N], dtype="float32")
        # body
        # with T.block("root")
        for i0 in T.serial(N):
            with T.block("C"):
                i = T.axis.spatial(N, i0)
                T.reads(A[i], B[i])
                T.writes(C[i])
                C[i] = A[i] + B[i]
    

测试一致性#

构建运行时库:

rt_lib = tvm.build(Module, target="llvm")
rt_lib
Module(llvm, 55cdd2c145a8)

定义数据:

a_np = np.arange(16, dtype="float32")
b_np = np.arange(16, 0, -1, dtype="float32")
c_np = a_np + b_np # 基准结果
c_np
array([16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16.,
       16., 16., 16.], dtype=float32)

将 numpy 数组变换为 tvm 数组:

a_nd = tvm.nd.array(a_np)
b_nd = tvm.nd.array(b_np)
c_nd = tvm.nd.empty((16,), dtype="float32")
type(c_nd)
tvm.runtime.ndarray.NDArray

验证结果:

rt_lib(a_nd, b_nd, c_nd)
c_nd
<tvm.nd.NDArray shape=(16,), cpu(0)>
array([16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16., 16.,
       16., 16., 16.], dtype=float32)

可以对不同形状张量计算:

a_np = np.arange(10, dtype="float32")
b_np = np.arange(10, 0, -1, dtype="float32")
c_np = a_np + b_np # 基准结果
a_nd = tvm.nd.array(a_np)
b_nd = tvm.nd.array(b_np)
c_nd = tvm.nd.empty((10,), dtype="float32")
rt_lib(a_nd, b_nd, c_nd)
c_nd
<tvm.nd.NDArray shape=(10,), cpu(0)>
array([10., 10., 10., 10., 10., 10., 10., 10., 10., 10.], dtype=float32)