当前位置: 首页 > news >正文

【TVM 教程】交叉编译与 RPC

TVM 现已更新到 0.21.0 版本,TVM 中文文档已经和新版本对齐。

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

作者:Ziheng Jiang、Lianmin Zheng

本教程介绍了在 TVM 中使用交叉编译与 RPC 进行远程设备执行的方法。

通过交叉编译与 RPC,你可以在本地机器上编译程序,并在远程设备上运行。这对于资源有限的远程设备(如 Raspberry Pi 或移动平台)非常有用。本教程将以 Raspberry Pi 作为 CPU 示例,以 Firefly-RK3399 作为 OpenCL 示例。

在设备上构建 TVM Runtime

第一步是在远程设备上构建 TVM 运行时。

备注
本节与下一节中的所有命令都应在目标设备(例如 Raspberry Pi )上执行。我们假设目标设备运行的是 Linux 系统。

由于编译工作是在本地机器上完成的,远程设备仅用于运行生成的代码,因此只需要在远程设备上构建 TVM 的运行时部分。

git clone --recursive https://github.com/apache/tvm tvm cd tvm make runtime -j2

成功构建运行时后,需要在~/.bashrc文件中设置环境变量。可以使用vi ~/.bashrc编辑~/.bashrc,并添加以下行(假设你的 TVM 路径为~/tvm):

export PYTHONPATH=$PYTHONPATH:~/tvm/python

然后执行source ~/.bashrc命令以更新环境变量:

在设备上启动 RPC 服务端

在远程设备上(如 Raspberry Pi )运行以下命令以启动 RPC 服务器:

python -m tvm.exec.rpc_server --host 0.0.0.0 --port=9090

如果你看到如下输出,说明 RPC 服务器已成功启动:

INFO:root:RPCServer: bind to 0.0.0.0:9090

在本地机器上声明并交叉编译内核

备注
现在回到本地机器,假设本地已完整安装了 TVM(带 LLVM 支持)。

在本地机器上声明一个简单的计算内核:

import numpy as np import tvm from tvm import te from tvm import rpc from tvm.contrib import utils n = tvm.runtime.convert(1024) A = te.placeholder((n,), name="A") B = te.compute((n,), lambda i: A[i] + 1.0, name="B") mod = tvm.IRModule.from_expr(te.create_prim_func([A, B]).with_attr("global_symbol", "add_one"))

然后进行交叉编译。对于 Raspberry Pi 3B,目标应为「llvm -mtriple=armv7l-linux-gnueabihf」,但为了方便在网页构建服务器上运行示例,这里使用「llvm」作为默认目标。详细事项可参考下一块。

local_demo = True if local_demo: target = "llvm" else: target = "llvm -mtriple=armv7l-linux-gnueabihf" func = tvm.compile(mod, target=target) # 将库保存到临时目录 temp = utils.tempdir() path = temp.relpath("lib.tar") func.export_library(path)

备注
如果要使用真实的远程设备运行此教程,请将local_demo设置为 False,并将target替换为适用于你设备的目标三元组。不同设备的目标三元组可能有所不同。例如,对于 Raspberry Pi 3B,目标三元组是:「llvm -mtriple=armv7l-linux-gnueabihf」;对于 RK3399,目标三元组是:「llvm -mtriple=aarch64-linux-gnu」
你可以通过在目标设备上运行gcc -v来查询其目标三元组,查看输出中以Target:开头的行(但这也可能只是一个宽松的配置)。
除了-mtriple,你还可以设置其他编译选项,例如:

-mcpu=
指定要生成代码的具体芯片。默认情况下会根据目标三元组推断并自动检测

-mattr=a1,+a2,-a3,…
覆盖或控制目标的具体属性,例如是否启用 SIMD 操作。默认属性由当前 CPU 决定,你可以运行以下命令查看支持的属性:

llc -mtriple= -mattr=help

这些选项与 llc 工具 保持一致。建议设置目标三元组和特性集以包含具体设备可用的功能,以充分发挥硬件性能。更多交叉编译属性详见 LLVM 跨平台编译文档。

通过 RPC 远程运行 CPU 内核

本节展示如何在远程设备上运行生成的 CPU 内核。首先,我们需要从远程设备获取一个 RPC 会话:

if local_demo: remote = rpc.LocalSession() else: # 以下是我的环境,请替换为你的目标设备的 IP 地址 host = "10.77.1.162" port = 9090 remote = rpc.connect(host, port)

接下来将生成的库上传到远程设备,然后调用设备上的编译器进行重新链接。此时func就是一个远程模块对象。

remote.upload(path) func = remote.load_module("lib.tar") # 在远程设备上创建数组 dev = remote.cpu() a = tvm.runtime.tensor(np.random.uniform(size=1024).astype(A.dtype), dev) b = tvm.runtime.tensor(np.zeros(1024, dtype=A.dtype), dev) # 函数将在远程设备上运行 func(a, b) np.testing.assert_equal(b.numpy(), a.numpy() + 1)

当你想评估内核在远程设备上的性能时,需要避免网络传输带来的开销。time_evaluator返回一个远程函数,该函数会运行多次并测量每次执行的耗时(不包括网络延迟):

time_f = func.time_evaluator(func.entry_name, dev, number=10) cost = time_f(a, b).mean print("%g secs/op" % cost)

输出:

1.452e-07 secs/op

通过 RPC 远程运行 OpenCL 内核

对于远程 OpenCL 设备,整体流程和前面几乎一致:定义内核、上传文件并通过 RPC 运行。

备注
Raspberry Pi 不支持 OpenCL,以下代码在 Firefly-RK3399 上测试通过。你可以参考这个 教程 设置 RK3399 的操作系统和 OpenCL 驱动。
同时,需要在 RK3399 上启用 OpenCL 构建 TVM 运行时。在 TVM 根目录下执行:

cp cmake/config.cmake . sed -i "s/USE_OPENCL OFF/USE_OPENCL ON/" config.cmake make runtime -j4

以下函数展示了如何远程运行一个 OpenCL 内核:

def run_opencl(): # 注意:这是我 rk3399 的设置,请根据你的设备环境进行修改 opencl_device_host = "10.77.1.145" opencl_device_port = 9090 target = tvm.target.Target("opencl", host="llvm -mtriple=aarch64-linux-gnu") # 创建上述「加一」计算的调度 mod = tvm.IRModule.from_expr(te.create_prim_func([A, B])) sch = tvm.tir.Schedule(mod) (x,) = sch.get_loops(block=sch.get_block("B")) xo, xi = sch.split(x, [None, 32]) sch.bind(xo, "blockIdx.x") sch.bind(xi, "threadIdx.x") func = tvm.compile(sch.mod, target=target) remote = rpc.connect(opencl_device_host, opencl_device_port) # 导出并上传 path = temp.relpath("lib_cl.tar") func.export_library(path) remote.upload(path) func = remote.load_module("lib_cl.tar") # 运行 dev = remote.cl() a = tvm.runtime.tensor(np.random.uniform(size=1024).astype(A.dtype), dev) b = tvm.runtime.tensor(np.zeros(1024, dtype=A.dtype), dev) func(a, b) np.testing.assert_equal(b.numpy(), a.numpy() + 1) print("OpenCL test passed!")

总结

本教程完整展示了 TVM 中交叉编译和 RPC 功能的使用流程:

可右键另存为下载。

下载 Jupyter notebook:cross_compilation_and_rpc.ipynb

下载 Python 源码:cross_compilation_and_rpc.py

下载压缩包:cross_compilation_and_rpc.zip

http://www.cnnetsun.cn/news/115128.html

相关文章:

  • 腾讯云国际站代理商的QAPM服务能提供哪些专属服务?
  • 网安副业怎么选?漏洞挖掘、技术博客、竞赛奖金实战,哪个更适配你?
  • 量子计算验证方法:软件测试从业者的转型指南
  • 突破 Oracle/MySQL 瓶颈:金仓数据库以三重革新,筑牢业务转型 “数据底座”
  • 【学习神器】NotebookLM“播客”功能实战指南:四六级、考研党高效复习秘籍
  • 如何解决 pip install 网络报错 ERROR: No matching distribution found for requests
  • 12 Ways to Find User Account Info and Login Details in Linux
  • 紧急警告:错误的导出格式正毁掉你的量子实验成果,速查正确方式
  • 35 岁职场焦虑蔓延?为什么网络安全行业越老越值钱?
  • 内网渗透实战干货:12 个优质靶场平台精选,附避坑指南 + 实操技巧合集!
  • 新型电力系统下多分布式电源接入配电网承载力评估方法研究附Matlab代码
  • 50天学习FPGA第16天-verilog的模块与端口
  • 50天学习FPGA第15天-verilog基本概念
  • 基于Docker容器化部署Lsky Pro私有图床系统
  • GRPO不香了?小米ICPO横空出世,专治大模型“不会思考”,推理能力飙升!
  • Windows找不到xenroll.dll文件 如何下载修复?
  • 软件测试文档标准化编写指南
  • Paperzz AI:毕业论文写作的 “隐形助攻”,让学术输出告别 “抓瞎”
  • BypassAV通过Patch白文件实现Bypass,没有添加其他免杀手法
  • 鸿蒙:一个操作系统的生态远征与多行业渗透之路
  • 游戏启动缺少X3DAudio1_3.dll文件问题 下载修复
  • java毕业设计之基于数据安全的旅游民宿租赁系统源代码(java+springboot+mysql)
  • 基于SpringAI构建大模型应用
  • 黑锋科技(HeifengTech)过压过流保护开关芯片全系列技术解析
  • DVWA -SQL Injection-通关教程-完结
  • AI大模型:未来就业的吞噬者还是创造者?揭秘其对普通人工作的影响!
  • 0x3f第七天 二叉搜索树
  • 扩容U盘,资料毁灭盘
  • 数据结构学习篇(5)---顺序表和链表的区别
  • 基于Vue.js和Spring Boot的新能源汽车充电站管理系统的设计与实现文献综述