0
本文作者: skura | 2019-03-14 14:40 |
本文作者是阿萊克西斯,原載于知乎,雷鋒網(wǎng)獲得授權(quán)轉(zhuǎn)載。
(前排提醒,本文的人文內(nèi)容部分稍稍帶有藝術(shù)加工,請保持一定的幽默感進(jìn)行閱讀)
關(guān)注我最近想法的同學(xué)應(yīng)該知道我最近都在把玩 TVM,今天終于使用 TVM 得到了非常滿意的結(jié)果,而專欄也很長時(shí)間沒更新了,于是來安利 (水) 一篇。
本來可能用不到 TVM,項(xiàng)目其實(shí)進(jìn)展的很順利,我們初始的 tensorflow 模型在 android 端得到了滿意的 latency,我也可以照常一邊修煉我的仙, 繼續(xù)和有奶大定律, 自由單子, Kan-Extension 等邪魔外道搏斗... 一邊穩(wěn)穩(wěn)的推進(jìn)項(xiàng)目進(jìn)度。
無奈 scientist 一意孤行要上 Pytorch, 于是我們換了一個(gè) Pytorch 模型...
先不說同樣的 SSD 魔改模型,Pytorch 在 android 端比 tensorflow 整整慢了 5 倍,光是把 Pytorch 模型移植到 Android 上都讓開發(fā)團(tuán)隊(duì)整整褪層皮 (Pytorch 對 Android 的支持簡直為 0,tensorflow 的工程支持相對 pytorch 簡直無敵)。而這時(shí)候已經(jīng)花了好多時(shí)間,項(xiàng)目眼看要 delay....
頭都炸了的我在打算手?jǐn)] OpenCL 調(diào)優(yōu)之前,去問了下我們組的 CV 大神該怎么辦,大神微微一笑,轉(zhuǎn)身隨風(fēng)而去,只聽云端傳來 3 個(gè)字:「T~V~M~~~~~"
于是我就開始 TVM 的研究 (踩坑) 之路, 到今天為止終于把所有的路都踩平了之后,成功把我們的 Pytorch 模型用 Auto-TVM 調(diào)優(yōu)成功且部署在了我們的 android 系統(tǒng)上,性能整整提高了 8 倍,比我們之前的 tensorflow 模型還要快。更重要的是,通過 TVM,我們的調(diào)優(yōu)完全不 couple 與硬件和模型 Framework,就算以后換模型,換終端,或者哪天 scientist 想不開要換回 tensorflow 或是使用 MXNet 都無所謂,用 auto-TVM 自動(dòng)調(diào)調(diào)就行了(只可惜了我的 Cuda C 編程調(diào)優(yōu)都白學(xué)了)。
簡單介紹下 Auto-TVM 的調(diào)優(yōu)終端設(shè)備的用法
你可以有很多手機(jī)平板設(shè)備,安裝好 TVM RPC 這個(gè) App 之后,可以在 App 里輸入 Tracker 的 IP 和端口,進(jìn)行設(shè)備注冊 (另外輸入一個(gè)設(shè)備 ID 來讓 Auto-TVM tuning 程序找到)。
Tracker 是一個(gè) Python 的程序,git clone TVM 之后,按教程編譯好,就可以按這個(gè)教程啟動(dòng) Tracker。
Auto-TVM tuning 程序也是一個(gè) python 程序,它會(huì)連接 Tracker(也可以和 Tracker 是一臺(tái)機(jī)器) 找到相應(yīng)的設(shè)備 ID 的 IP,然后和設(shè)備直接用 RPC 通信,Auto-TVM 程序會(huì)根據(jù)程序預(yù)設(shè)的 target(比如是不是 arm cpu,要不要用 OpenCL...) 來把你想要優(yōu)化的 Deep Learning 模型直接編譯為設(shè)備的 machine code, 通過 TVM RPC 把 code 部署在終端,終端的 TVM RPC App 會(huì)測試這個(gè)模型的 inference performance,然后回報(bào)給 Auto-TVM tuning 程序,然后 Auto-TVM tuning 程序會(huì)根據(jù)反饋,重新計(jì)算該如何優(yōu)化編譯,重新生成新的模型的 machine code 再次部署... 如此循環(huán)... 直到達(dá)到預(yù)設(shè)的實(shí)驗(yàn)次數(shù) (比如 2000), 或太多次實(shí)驗(yàn)都沒有提高提前結(jié)束 (比如第一次就找到了最優(yōu)優(yōu)化結(jié)果)。最后 TVM 會(huì)根據(jù)調(diào)優(yōu)時(shí)得到的最佳「編譯參數(shù)」來最終編譯你的 deep learning 模型為終端模型的 machine code,最終完成優(yōu)化編譯過程。
以上只是簡單介紹,具體請看 TVM 的論文,和去 TVM 官網(wǎng)看 tutorial,寫得非常詳細(xì)切提供了很多很好理解的范例代碼。我的最終的 tuning 程序,就是魔改其中一個(gè)范例程序而來。
TVM 踩坑記錄
TVM 目前還只是 0.6 版本,很多東西還不穩(wěn)定,由于開發(fā)環(huán)境各異,有時(shí)候需要工程師自己解決一些開發(fā)團(tuán)隊(duì)在開發(fā)時(shí)沒有碰到的問題,但是這些問題相對與 TVM 提供的巨大優(yōu)勢相比,都是小問題啦(工程能力越強(qiáng),魔改力越強(qiáng),你就可以越早體驗(yàn)新技術(shù)帶來的好處呀。)。(我遇到的最坑的問題其實(shí)是公司網(wǎng)絡(luò)各種 IP 禁止訪問,封端口,使得 android 機(jī)和開發(fā)服務(wù)器一直連不上, 最終還是在自己的電腦上裝了虛擬機(jī),自建了一個(gè)小 LAN 才解決的這個(gè)問題)
1.編譯 tvm4j-core 出錯(cuò): cannot find symbol [ERROR] symbol: class SharedSecrets
JDK11 會(huì)遇到這個(gè)問題,因?yàn)?JDK11 已經(jīng)把 sun.misc.SharedSecrets 換到別的地方了,建議不要嘗試修改 TVM 源代碼來 fix 這個(gè)問題,因?yàn)槟銜?huì)遇到其他更多問題,請下載 JDK8,把 JAVA_HOME 設(shè)為 JDK8 的,一切就會(huì)很順利
2.Android TVM RPC 編譯出錯(cuò): #error "Unable to determine endianness of your machine; use CMake to compile"
Android RPC server fails to build
按上邊 link 里的修改 endian.h 文件即可,參見我下邊的修改
diff --git a/include/dmlc/endian.h b/include/dmlc/endian.h
index 5bf53fb..9422fce 100644
--- a/include/dmlc/endian.h
+++ b/include/dmlc/endian.h
@@ -23,7 +23,9 @@
#elif defined(__EMSCRIPTEN__)
#define DMLC_LITTLE_ENDIAN 1
#else
- #error "Unable to determine endianness of your machine; use CMake to compile"
+ #include <endian.h>
+ #define DMLC_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
+ /*!#error "Unable to determine endianness of your machine; use CMake to compile" */
#endif
#endif
3.Auto-TVM 運(yùn)行時(shí)出錯(cuò)"Do not know how to handle return type code 113"
可以根據(jù)我上邊在 TVM Discussion 里的自問自答來解決。
4.找不到 TVM_NDK_CC
[SOLVED] Android_rpc_test.py failed
按照 dayanandasiet 的回復(fù)設(shè)定 TVM_NDK_CC 即可
Follow the below steps to generate toolchian and try to generate application with below export
comand
Tool chain generate with below instruction
./make-standalone-toolchain.sh --platform=android-24 --use-llvm --arch=arm64
--install-dir=/home/user/software/android-toolchain-arm64/
Download Java and SDK, set proper path
export TVM_NDK_CC=/home/user/software/android-toolchain-arm64/bin/aarch64-
linux-android-g++
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export ANDROID_HOME=/home/user/software/android-sdk-linux
build mxnet model with nnvm with below config/parameter and use same library,
param and graph on your android application
target =‘llvm -target=arm64-linux-android’
target_host = None
reference mobile_darknet_save.py 2
Compile application android deploy 1 using this config.mk 2 configuration for CPU flavor
5.LLVM only Large Small are allowd on AArch64
https://github.com/dmlc/tvm/issues/2005 可解。
6.Auto-TVM 自動(dòng)優(yōu)化時(shí)出錯(cuò):Cannot find config for target=cuda
這個(gè)不是什么大問題,某 operator 不能調(diào),對我來說其他的可以調(diào)就行了。。。。
7.Auto-TVM 自動(dòng)優(yōu)化 OpenCL 時(shí)出錯(cuò): No OpenCL platform matched given existing options
No OpenCL platform matched given existing options
也是自己問最終自己解決的,很反直覺,編譯 TVM 的時(shí)候,選擇 OpenCL=OFF,就沒有這個(gè)問題,選擇 OpenCL=ON,為終端 Cross Compile OpenCL 就不 work 了... 應(yīng)該是 bug.
8.Auto-TVM 自動(dòng)優(yōu)化 OpenCL 時(shí)出錯(cuò): CL_INVALID_WORK_GROUP_SIZE
CL_INVALID_WORK_GROUP_SIZE error after auto-tuning for OpenCL on Android Device
應(yīng)該是我 trial number 設(shè)的太小了,以至于 TVM 找不到一個(gè) valid 的 kernel,順著這個(gè)問題,發(fā)現(xiàn)了 CL_INVALID_WORK_GROUP_SIZE 的一個(gè) undocumented 的錯(cuò)誤源,即 OpenCL kernel 使用過多的 register file 也會(huì)造成 CL_INVALID_WORK_GROUP_SIZE 錯(cuò)誤,這一點(diǎn)在查 OpenCL 文檔的時(shí)候是查不到的, 有點(diǎn) tricky。
9.Auto-TVM 自動(dòng)優(yōu)化時(shí) Android TVM RPC Crush,一切白調(diào)。。。
目前 TVM 還不支持 checkpoint,不過我們可以很簡單的魔改 measure_methods.py 這個(gè)文件,把 190 行 set_task(): 這個(gè)函數(shù)里的 check remote 失敗直接 raise RuntimeError 退出程序,改成循環(huán)多次 check 即可,這樣使得 Auto-TVM 一方持續(xù)等待 Android 程序上線,比一點(diǎn)網(wǎng)絡(luò)問題,或者終端問題,就廢掉之前 n 多個(gè)小時(shí)的 auto-tuning 成果要好的多。
最后感謝
@ 陳天奇
大神為我們帶來了這么方便的工具。
好了,今天就到這里,我繼續(xù)修仙煉丹去了~
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。