本篇文章譯自英文文件 Cross Compilation and RPC 作者是 Ziheng Jiang,Lianmin Zheng。更多 TVM 中文文件可訪問 →TVM 中文站
本教程介紹瞭如何在 TVM 中使用 RPC 進行交叉編譯和遠端裝置執行。
利用交叉編譯和 RPC,可以實現程式在本地機器編譯,在遠端裝置執行。這個特性在遠端裝置資源有限時(如在樹莓派和移動平臺上)尤其有用。本教程將把樹莓派作為 CPU 示例,把 Firefly-RK3399 作為 OpenCL 示例進行演示。
在裝置上構建 TVM Runtime
首先在遠端裝置上構建 TVM runtime。
注意 本節和下一節中的所有命令都應在目標裝置(例如樹莓派)上執行。假設目標裝置執行 Linux 系統。
由於在本地機器上只做編譯,而遠端裝置用於執行生成的程式碼。所以只需在遠端裝置上構建 TVM runtime。
git clone --recursive https://github.com/apache/tvm tvm
cd tvm
make runtime -j2
成功構建 runtime 後,要在 ~/.bashrc 檔案中設定環境變數。可以用 vi ~/.bashrc命令編輯 ~/.bashrc,在這個檔案裡新增下面這行程式碼(假設 TVM 目錄在 ~/tvm 中):
export PYTHONPATH=$PYTHONPATH:~/tvm/python
執行 source ~/.bashrc 來更新環境變數。
在裝置上設定 RPC 伺服器
在遠端裝置(本例為樹莓派)上執行以下命令來啟動 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
在本地機器上宣告和交叉編譯核心
備註 現在回到本地機器(已經用 LLVM 安裝了完整的 TVM)。
在本地機器上宣告一個簡單的核心:
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")
s = te.create_schedule(B.op)
然後交叉編譯核心。對於樹莓派 3B,target 是“llvm -mtriple=armv7l-linux-gnueabihf”,但這裡用的是“llvm”,使得本教程可以在網頁構建伺服器上執行。請參閱下面的詳細說明。
local_demo = True
if local_demo:
target = "llvm"
else:
target = "llvm -mtriple=armv7l-linux-gnueabihf"
func = tvm.build(s, [A, B], target=target, name="add_one")
# 將 lib 儲存在本地臨時資料夾
temp = utils.tempdir()
path = temp.relpath("lib.tar")
func.export_library(path)
備註
要使本教程執行在真正的遠端裝置上,需要將 local_demo 改為 False,並將 build 中的 target 替換為適合裝置的 target 三元組。不同裝置的 target 三元組可能不同。例如,對於樹莓派 3B,它是 llvm -mtriple=armv7l-linux-gnueabihf;對於 RK3399,它是 llvm -mtriple=aarch64-linux-gnu。
通常,可以在裝置上執行 gcc -v 來查詢 target,尋找以 Target 開頭的行:(儘管它可能仍然是一個鬆散的配置。)
除了 -mtriple,還可設定其他編譯選項,例如:
- -mcpu=< cpuname>
指定生成的程式碼執行的晶片架構。預設情況這是從 target 三元組推斷出來的,並自動檢測到當前架構。
- -mattr=a1,+a2,-a3,…
覆蓋或控制 target 的指定屬性,例如是否啟用 SIMD 操作。預設屬性集由當前 CPU 設定。要獲取可用屬性列表,執行:
llc -mtriple=<your device target triple> -mattr=help
這些選項與 llc 一致。建議設定 target 三元組和功能集,使其包含可用的特定功能,這樣我們可以充分利用單板的功能。檢視 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)
將 lib 上傳到遠端裝置,然後呼叫裝置的本地編譯器重新連結它們。其中 func 是一個遠端模組物件。
remote.upload(path)
func = remote.load_module("lib.tar")
# 在遠端裝置上建立陣列
dev = remote.cpu()
a = tvm.nd.array(np.random.uniform(size=1024).astype(A.dtype), dev)
b = tvm.nd.array(np.zeros(1024, dtype=A.dtype), dev)
# 這個函式將在遠端裝置上執行
func(a, b)
np.testing.assert_equal(b.numpy(), a.numpy() + 1)
要想評估核心在遠端裝置上的效能,避免網路開銷很重要。time_evaluator 返回一個遠端函式,這個遠端函式多次執行 func 函式,並測試每一次在遠端裝置上執行的成本,然後返回測試的成本(不包括網路開銷)。
time_f = func.time_evaluator(func.entry_name, dev, number=10)
cost = time_f(a, b).mean
print("%g secs/op" % cost)
輸出結果:
1.369e-07 secs/op
透過 RPC 遠端執行 OpenCL 核心
遠端 OpenCL 裝置的工作流程與上述內容基本相同。可以定義核心、上傳檔案,然後透過 RPC 執行。
備註
樹莓派不支援 OpenCL,下面的程式碼是在 Firefly-RK3399 上測試的。可以按照 教程 為 RK3399 設定 OS 及 OpenCL 驅動程式。
在 rk3399 板上構建 runtime 也需啟用 OpenCL。在 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")
# 為上面的計算宣告 "add one" 建立 schedule
s = te.create_schedule(B.op)
xo, xi = s[B].split(B.op.axis[0], factor=32)
s[B].bind(xo, te.thread_axis("blockIdx.x"))
s[B].bind(xi, te.thread_axis("threadIdx.x"))
func = tvm.build(s, [A, B], 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.nd.array(np.random.uniform(size=1024).astype(A.dtype), dev)
b = tvm.nd.array(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 功能。
- 在遠端裝置上設定 RPC 伺服器。
- 設定目標裝置配置,使得可在本地機器上交叉編譯核心。
- 透過 RPC API 遠端上傳和執行核心。
下載 Python 原始碼
下載 Jupyter Notebook
以上就是該文件的全部內容,檢視更多 TVM 中文文件,請訪問→TVM 中文站