【TVM 教程】外部张量函数

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

作者:Tianqi Chen

虽然 TVM 支持透明代码生成,但有时也需将手写的代码合并到流水线,例如对一些卷积核使用 cuDNN,并定义其余阶段。

原生 TVM 就支持黑盒函数调用。具体来说,TVM 支持所有与 DLPack 兼容的张量函数。这意味着可以使用 POD 类型(指针、整数、浮点数),或者将指向 DLTensor 的指针作为参数,调用任何函数。

c 复制代码
from __future__ import absolute_import, print_function

import tvm
from tvm import te
import numpy as np
from tvm.contrib import cblas
import tvm.testing

if not tvm.get_global_func("tvm.contrib.cblas.matmul", allow_missing=True):
    raise Exception("Not compiled with cblas support; can't build this tutorial")

使用外部张量函数

以下示例用 te.extern 来添加一个外部数组函数调用。外部调用声明了输出张量的 shape,第二个参数给出了输入列表。

用户需要提供一个描述如何对结果进行计算的函数。计算函数获取输入和输出的符号占位符列表,并返回执行语句。

这种情况只需调用一个注册的 TVM 函数,它会调用 CBLAS。TVM 不控制外部数组函数的内部,将其视为黑盒。可以进一步混合可调度的 TVM 函数,为结果添加偏差项。

c 复制代码
n = 1024
l = 128
m = 235
bias = te.var("bias", dtype="float32")
A = te.placeholder((n, l), name="A")
B = te.placeholder((l, m), name="B")
C = te.extern(
    (n, m),
    [A, B],
    lambda ins, outs: tvm.tir.call_packed(
        "tvm.contrib.cblas.matmul", ins[0], ins[1], outs[0], False, False
    ),
    name="C",
)
D = te.compute(C.shape, lambda i, j: C[i, j] + bias, name="D")
s = te.create_schedule(D.op)

验证结果

验证结果是否符合预期。

c 复制代码
dev = tvm.cpu(0)
f = tvm.build(s, [A, B, D, bias], "llvm")
a = tvm.nd.array(np.random.uniform(size=(n, l)).astype(A.dtype), dev)
b = tvm.nd.array(np.random.uniform(size=(l, m)).astype(B.dtype), dev)
d = tvm.nd.array(np.zeros((n, m), dtype=D.dtype), dev)
bb = 10.0
f(a, b, d, bb)
tvm.testing.assert_allclose(d.numpy(), np.dot(a.numpy(), b.numpy()) + 10, rtol=1e-5)

外部 Contrib Wrappers

TVM 为外部调用提供了外部contrib Wrappers,以下代码与前面的示例等效。

c 复制代码
from tvm.contrib import cblas

C = cblas.matmul(A, B)
D = te.compute(C.shape, lambda i, j: C[i, j] + bias, name="D")
s = te.create_schedule(D.op)

将 Python 函数 Hook 为 Extern

由于可以调用 TVM 中的任何 PackedFunc,所以可以用外部函数回调到 Python 中。

以下示例将一个 Python 函数注册到 TVM runtime 系统,并用它来完成一个阶段的计算,这使得 TVM 更加灵活。例如,可通过插入前端回调来检查中间结果,或将自定义代码与 TVM 混合。

c 复制代码
@tvm.register_func("tvm.contrib.my_tvm_addone")
def my_tvm_addone(x, y):
    print("my_tvm_addone signatures: %s, %s" % (type(x), type(y)))
    tvm.nd.array(x.numpy() + 1).copyto(y)

A = te.placeholder((n,), name="A")
B = te.extern(
    A.shape,
    [A],
    lambda ins, outs: tvm.tir.call_packed("tvm.contrib.my_tvm_addone", ins[0], outs[0]),
    name="C",
)
s = te.create_schedule(B.op)
f = tvm.build(s, [A, B], "llvm")
a = tvm.nd.array(np.random.uniform(size=(n,)).astype(A.dtype), dev)
b = tvm.nd.array(np.random.uniform(size=(n,)).astype(B.dtype), dev)
f(a, b)
tvm.testing.assert_allclose(b.numpy(), a.numpy() + 1, rtol=1e-5)

输出结果:

c 复制代码
my_tvm_addone signatures: <class 'tvm.runtime.ndarray.NDArray'>, <class 'tvm.runtime.ndarray.NDArray'>

总结

  • TVM 通过 te.extern 调用外部张量函数。
  • 对外部张量调用使用 contrib wrappers。
  • 将前端函数 hook 为外部张量的回调。

下载 Python 源代码:extern_op.py

下载 Jupyter Notebook:extern_op.ipynb

相关推荐
Shawn_Shawn5 小时前
人工智能入门概念介绍
人工智能
极限实验室5 小时前
程序员爆哭!我们让 COCO AI 接管 GitLab 审查后,团队直接起飞:连 CTO 都说“这玩意儿比人靠谱多了
人工智能·gitlab
Maynor9966 小时前
Z-Image: 100% Free AI Image Generator
人工智能
爬点儿啥6 小时前
[Ai Agent] 10 MCP基础:快速编写你自己的MCP服务器(Server)
人工智能·ai·langchain·agent·transport·mcp
张人玉6 小时前
百度 AI 图像识别 WinForms 应用代码分析笔记
人工智能·笔记·百度
测试人社区-小明7 小时前
智能弹性伸缩算法在测试环境中的实践与验证
人工智能·测试工具·算法·机器学习·金融·机器人·量子计算
Spring AI学习7 小时前
Spring AI深度解析(9/50):可观测性与监控体系实战
java·人工智能·spring
罗西的思考8 小时前
【Agent】MemOS 源码笔记---(5)---记忆分类
人工智能·深度学习·算法
dajun1811234568 小时前
反 AI 生成技术兴起:如何识别与过滤海量的 AI 伪造内容?
人工智能
人邮异步社区8 小时前
PRML为何是机器学习的经典书籍中的经典?
人工智能·机器学习