如何利用python在yi'ge_【GE查找Python面试题】面试问题:使用 TVM … - 看准网
以下內容翻譯自:Remote Profile and Test Deep Learning Cross Compilation on Mobile Phones with TVM RPC
TVM 堆棧是端到端的編譯堆棧,可將深度學習工作負載部署到所有硬件后端。由于 NNVM 編譯器支持 TVM 堆棧,我們現在可以直接編譯來自深度學習框架的描述并生成裸機代碼。TVM 一個令人印象深刻的特性是它能夠在不同的平臺上部署計算工作負載,比如 GPU 和手機(將支持更多的硬件后端)。
然而,當我們想要測試和剖析交叉編譯時,很難在異構設備(如樹莓派或手機)上測試不同的計算工作負載。為了優化計算任務,必須在開發 PC 上 編輯代碼,編譯,部署到設備,測試,然后再次修改代碼以查看是否加速。工作流程看起來像:
有什么辦法可以加快這一過程嗎?
今天我們介紹一種在 Android 手機上部署和測試 TVM 工作負載的方法。我們為 Java 開發了一個 TVM 運行庫,并在其上構建了一個 Android 應用程序。Android APP 將共享庫作為輸入,并在手機上運行編譯后的函數。因此我們的工作流程簡化為:
借助 TVM RPC,我們可以在遠程設備上構建 TVM 函數和 NDArray。交叉編譯到不同平臺的能力使得在一個平臺上開發并在另一個平臺上進行測試變得容易。
該過程如下所示:
在 Android 手機上運行 TVM APP
你可以在 apps/android_rpc 中找到 Android RPC APP。請按照說明為您的 Android 設備構建。一旦生成了 APK,請使用 apps/android_rpc/dev_tools 對其進行簽名并將其安裝在手機上。該 APP 看起來像:
通常,我們無法在手機上啟動獨立服務器,為此啟動代理服務器并使用我們的應用進行連接。
python -m tvm.exec.rpc_proxy
在手機上創建 NDArray
現在我們可以從筆記本電腦連接到代理服務器:
from tvm.contrib import rpc
remote = rpc.connect("0.0.0.0", 9090, key="android")
這將給我們一個可以用與手機通信的遠程句柄。例如,以下幾行在手機的 GPU上 創建了一個1024x1024矩陣:
A = tvm.nd.array(
np.random.uniform(size=(1024, 1024)).astype(dtype),
ctx = remote.cl(0))
當筆記本電腦調用A.asnumpy()時,矩陣A將被復制到手機的 RAM,然后通過代理服務器傳輸到筆記本電腦。TVM RPC 接口對用戶是透明的。
手機上的 GEMM(矩陣乘法)
現在我們將介紹如何在 Android 手機上測試矩陣乘法。首先讓我們定義非常簡單的 GEMM 方案:
import tvm
def gemm(N, bn):
A = tvm.placeholder((N, N), name='A')
B = tvm.placeholder((N, N), name='B')
k = tvm.reduce_axis((0, N), name='k')
C = tvm.compute(
(N, N),
lambda ii, jj: tvm.sum(A[ii, k] * B[k, jj], axis=k),
name='C')
s = tvm.create_schedule(C.op)
block_x = tvm.thread_axis("blockIdx.x")
thread_x = tvm.thread_axis("threadIdx.x")
bo, bi = s[C].split(C.op.axis[0], factor=bn)
to, ti = s[C].split(C.op.axis[1], factor=bn)
s[C].bind(bi, block_x)
s[C].bind(ti, thread_x)
print(tvm.lower(s, [A, B, C], simple_mode=True))
return tvm.build(s, [A, B, C],
"opencl",
target_host="llvm -target=arm64-linux-android",
name="gemm_gpu")
除了最后一行,沒有什么特別的。這里我們將目標設置為opencl,因為這是 Mali GPU 支持的計算語言。請注意,我們將target_host設置為llvm -target = arm64-linux-android,這取決于您 Android 手機的架構。我們在配備 Mali-T760 GPU 的三星 Galaxy S6 Edge 上進行測試。這是這款手機的 CPU 信息:
$ adb shell
shell@zenltechn:/ $ cat /proc/cpuinfo
Processor: AArch64 Processor rev 2 (aarch64)
processor: 0
processor: 1
processor: 2
processor: 3
processor: 4
processor: 5
processor: 6
processor: 7
Features: fp asimd aes pmull sha1 sha2 crc32
CPU implementer: 0x41
CPU architecture: AArch64
CPU variant: 0x0
CPU part: 0xd03
CPU revision: 2
Hardware: SAMSUNG Exynos7420
請參閱 target triple 了解 LLVM 的編譯選項。我們使用 tvm.contrib.ndk 為 Android 系統創建共享庫:
from tvm.contrib import rpc, util, ndk
N = 1024
f = gemm(N, bn = 256)
temp = util.tempdir()
path_dso = temp.relpath("gemm_gpu.so")
f.export_library(path_dso, ndk.create_shared)
ndk.create_shared 讀取環境變量TVM_NDK_CC以查找 Android 設備的編譯器和鏈接器。我們可以很容易地使用 NDK 為我們的設備生成獨立的工具鏈。例如,以下命令為 ARM64 Android 設備生成獨立編譯器和連接器:
cd /opt/android-ndk/build/tools/
./make-standalone-toolchain.sh --platform=android-24 --use-llvm --arch=arm64 --install-dir=/opt/android-toolchain-arm64
如果一切順利,我們會有一個“gemm_gpu.so”共享庫。現在讓我們將其上傳到手機,使手機加載模塊并獲得遠程句柄:
remote = rpc.connect("0.0.0.0", 9090, key="android")
remote.upload(path_dso)
f = remote.load_module("gemm_gpu.so")
創建遠程陣列并打印運行時間:
ctx = remote.cl(0)
import numpy as np
a_np = np.random.uniform(size=(N, N)).astype("float32")
b_np = np.random.uniform(size=(N, N)).astype("float32")
a = tvm.nd.array(a_np, ctx)
b = tvm.nd.array(b_np, ctx)
c = tvm.nd.array(np.zeros((N, N), dtype="float32"), ctx)
time_f = f.time_evaluator(f.entry_name, ctx, number=5)
cost = time_f(a, b, c).mean
print('%g secs/op, %g GFLOPS' % (cost, ngflops(N) / cost))
現在我們可以在 PC 上驗證結果:
np.testing.assert_almost_equal(
c.asnumpy(),
a_np.dot(b_np),
decimal=3)
在上面的情況下,我們開發并交叉編譯為手機的二進制文件。通過代理服務器,上傳二進制文件到手機并運行在其 JVM 中。這種方法使得在 Android 上開發和測試不同的計算工作量變得很容易。
TVM 的 Java 運行時
Android APP 建立在 Java 運行時之上,它為 TVM 功能和 NDArray 提供了最低限度的支持。這是一個在 TVM4J 中注冊函數的例子:
Function func = Function.convertFunc(new Function.Callback() {
@Override public Object invoke(TVMValue... args) {
StringBuilder res = new StringBuilder();
for (TVMValue arg : args) {
res.append(arg.asString());
}
return res.toString();
}
});
TVMValue res = func.pushArg("Hello").pushArg(" ").pushArg("World!").invoke();
assertEquals("Hello World!", res.asString());
res.release();
func.release();
正如我們在 GEMM 部分看到的,可以通過 Python 構建共享庫并通過 Java 來執行:
import ml.dmlc.tvm.Module;
import ml.dmlc.tvm.NDArray;
import ml.dmlc.tvm.TVMContext;
import java.io.File;
import java.util.Arrays;
public class LoadAddFunc {
public static void main(String[] args) {
String loadingDir = args[0];
Module fadd = Module.load(loadingDir + File.separator + "add_cpu.so");
TVMContext ctx = TVMContext.cpu();
long[] shape = new long[]{2};
NDArray arr = NDArray.empty(shape, ctx);
arr.copyFrom(new float[]{3f, 4f});
NDArray res = NDArray.empty(shape, ctx);
fadd.entryFunc().pushArg(arr).pushArg(arr).pushArg(res).invoke();
System.out.println(Arrays.toString(res.asFloatArray()));
arr.release();
res.release();
fadd.release();
}
}
按照“安裝指南”構建 TVM 庫后,運行
make jvmpkg
make jvminstall
這將編譯、打包并安裝 tvm4j 到您的本地 maven 倉庫。 請參閱 TVM4J 了解更多信息。
iPhone/iPad 上的遠程配置和測試
除了 Android RPC 應用程序外,我們還提供 iOS RPC app,通過它我們可以輕松地在 iPhone 或 iPad 上分析和測試 TVM 計算工作負載。它的工作原理幾乎與 Android 相同,而 XCode 和 iOS 設備是必需的。
總結
以上是生活随笔為你收集整理的如何利用python在yi'ge_【GE查找Python面试题】面试问题:使用 TVM … - 看准网的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: k歌的录音伴奏合成技术如何实现_2019
- 下一篇: 用力和应变片计算弹性模量_实验力学实验讲