境配置到踩坑排錯(cuò)的實(shí)戰(zhàn)經(jīng)驗(yàn))
大概兩年前我第一次接觸TVM的時(shí)候光是環(huán)境搭建就折騰了整整一個(gè)周末當(dāng)時(shí)差點(diǎn)勸退。后來陸續(xù)給同事、學(xué)生在不同機(jī)器上裝了十幾次把踩過的坑一條條記錄下來才慢慢摸清楚這個(gè)框架的脾氣。這篇博客就是我這些次安裝經(jīng)驗(yàn)的完整匯總涵蓋了從代碼拉取、編譯配置到Python環(huán)境調(diào)試的全部過程按順序操作基本能一次過希望對(duì)第一次接觸TVM的讀者有實(shí)際幫助。1. 寫在前面TVM到底是個(gè)什么東西為什么安裝這么講究先說清楚TVM是干嘛的。它全稱是Apache TVM本質(zhì)上是一個(gè)深度學(xué)習(xí)編譯器棧解決的問題是“模型寫好了但跑不快”。它接收PyTorch、TensorFlow、ONNX等格式的訓(xùn)練模型經(jīng)過計(jì)算圖優(yōu)化、算子調(diào)度和代碼生成之后輸出能在CPU、GPU、FPGA甚至專用加速器上高效運(yùn)行的機(jī)器碼。簡(jiǎn)單說你把一個(gè)訓(xùn)練好的模型交給TVM它幫你針對(duì)具體硬件狠狠優(yōu)化一把推理速度往往比原框架直接跑要快不少。那為什么安裝環(huán)節(jié)這么容易翻車原因在于TVM的項(xiàng)目結(jié)構(gòu)比較特別它既有C寫的核心編譯引擎又要通過Python前端來調(diào)用安裝過程至少涉及編譯工具鏈、LLVM依賴、GPU驅(qū)動(dòng)和Python包管理這四套體系。任何一環(huán)版本不匹配后面跑起來就是一堆莫名其妙的問題。而且TVM本身更新節(jié)奏很快幾乎每個(gè)月都有新改動(dòng)老版本經(jīng)常遇到“某個(gè)依賴庫(kù)升了級(jí)舊版TVM就不兼容了”的情況。所以你會(huì)看到我在標(biāo)題里反復(fù)強(qiáng)調(diào)一個(gè)建議軟件版本盡量用最高的、最新的。這不只是懶人思路而是TVM這個(gè)項(xiàng)目確實(shí)對(duì)“落后版本”很不友好。舊版本不僅API和最新的Python、LLVM、CUDA對(duì)不上連官方文檔里的示例代碼都可能跑不通。用最新版本社區(qū)踩過的坑相對(duì)少搜問題也能搜到更多近期有效的答案。這篇文章適合誰來參考主要是兩類人一是科研和工程場(chǎng)景中需要部署模型、做推理加速的開發(fā)者二是想搞懂TVM編譯流程的學(xué)生。文章會(huì)從一個(gè)干凈的Linux環(huán)境開始講到如何完整地把TVM源碼版裝好并給出我在實(shí)操中遇到過的經(jīng)典報(bào)錯(cuò)和排查方法。2. 安裝前的環(huán)境評(píng)估與版本選型思路2.1 先摸清自己的硬件和系統(tǒng)底細(xì)有一句老話叫做“TVM本身不挑機(jī)器但你機(jī)器上已有的環(huán)境一定挑TVM的版本”。動(dòng)手之前先把下面幾項(xiàng)信息查清楚記錄下來。這幾條命令在Ubuntu/Debian系的系統(tǒng)上直接執(zhí)行即可。# 查看操作系統(tǒng)版本 cat /etc/os-release # 查看CPU信息 lscpu | grep Model name # 查看GPU型號(hào)與驅(qū)動(dòng)版本 nvidia-smi # 查看顯卡驅(qū)動(dòng)支持的CUDA版本 nvidia-smi | head -20 # 查看當(dāng)前gcc、g版本 gcc --version g --version # 查看cmake版本 cmake --version # 查看python版本 python3 --version以我實(shí)機(jī)為例常用的一套環(huán)境是Ubuntu 22.04 GCC 11.4 CMake 3.22 Python 3.10 CUDA 12.2最后TVM在0.16及以上版本跑得都很順。如果你用的是Ubuntu 20.04 Python 3.8 GCC 9也完全能裝但建議把CMake至少升到3.16以上太老的CMake不支持TVM構(gòu)建腳本里一些新語法。這里想強(qiáng)調(diào)一個(gè)點(diǎn)不要為了“穩(wěn)定”故意用舊版本編譯器。TVM的大量代碼依賴較新的C17標(biāo)準(zhǔn)GCC版本低于7基本沒戲GCC 8、9能編但有機(jī)會(huì)報(bào)奇怪的模板錯(cuò)誤。我在Ubuntu 18.04的機(jī)器上踩過GCC 7.5編譯TVM 0.14時(shí)模板實(shí)例化失敗的坑后來升級(jí)到GCC 9才解決。所以標(biāo)題里“版本盡量新”這一條第一步就體現(xiàn)在系統(tǒng)編譯器上。2.2 依賴組件哪些是必裝、哪些是可以先跳過的TVM的完整依賴列表很長(zhǎng)但對(duì)我們大多數(shù)用途來說真正必須的沒有想象中那么多。我按“不裝一定跑不了”“不裝也能跑但性能受限”“完全可選”三檔列一下依賴項(xiàng)必裝程度說明CMake必要構(gòu)建系統(tǒng)的核心版本建議3.16以上GCC/G必要C編譯器用于編譯TVM的C核心Python 3必要TVM的Python前端依賴3.7以上均可LLVM強(qiáng)烈推薦用于CPU代碼生成優(yōu)化有它性能好非常多CUDA Toolkit可選但推薦如果你要用NVIDIA GPU加速則必裝cuDNN可選某些GPU算子的加速庫(kù)非必須Vulkan/OpenCL可選特定硬件后端需要日常可以先不裝Node.js不需要那是TVM前端網(wǎng)頁版才用的東西這里重點(diǎn)說LLVM。很多教程會(huì)告訴你“USE_LLVM那里的路徑可以留空”意思是TVM能在沒有LLVM的情況下照常編譯。這話沒錯(cuò)但代價(jià)很大——沒有LLVM后端TVM在CPU上的代碼生成能力會(huì)被砍掉一大截很多優(yōu)化沒法做甚至部分模型直接編譯失敗。所以我的建議是LLVM必須裝而且盡量新版。安裝LLVM最簡(jiǎn)單的方式是用apt直接裝sudo apt update sudo apt install llvm-18 llvm-18-dev clang-18如果系統(tǒng)源里沒有LLVM 18可以先去apt源看有哪些版本apt-cache search llvm再選擇。理論上LLVM 10以上都能配TVM但LLVM 15以下可能會(huì)遇到底層API變化導(dǎo)致的告警甚至編譯錯(cuò)誤。實(shí)測(cè)LLVM 17、18都很穩(wěn)。2.3 為什么我堅(jiān)持建議“版本盡量新”——一條血的教訓(xùn)可能有人覺得我在偷懶遇事不決就讓人升級(jí)。這里分享一個(gè)親身經(jīng)歷有一次我在一臺(tái)服務(wù)器上裝TVM 0.12當(dāng)時(shí)的最新版配的是LLVM 10和GCC 9編一次花了快40分鐘最后跑模型的時(shí)候報(bào)了一個(gè)LLVM代碼生成器的內(nèi)部錯(cuò)誤隨機(jī)出現(xiàn)在某些算子上。找遍GitHub issues也沒看到完全一致的報(bào)錯(cuò)后來我干了一件笨事把TVM升到0.14同樣的模型同樣的硬件同樣的配置一次通過。事后分析原因是TVM低版本某個(gè)C代碼里用到了LLVM的某個(gè)接口那個(gè)接口在LLVM 10上有邊界情況沒有處理干凈高版本修復(fù)了編譯器端的問題TVM新版本又適配了新LLVM的接口兩層疊加就順理成章了。從那以后我養(yǎng)成了一個(gè)習(xí)慣裝TVM之前先檢查一遍所有依賴組件有沒有自己能升到的最新穩(wěn)定版能升就升升完再編譯TVM。這其實(shí)幫我在后續(xù)的部署里省下了大量排查時(shí)間。3. 從源碼編譯TVM的完整實(shí)操流程3.1 拉取代碼別漏了子模塊這是第一道坑TVM的代碼托管在GitHub上官方源碼倉(cāng)庫(kù)是apache/tvm。編譯源碼版的第一步當(dāng)然是clone倉(cāng)庫(kù)但這里就藏著第一道最常見的坑。直接用下面這行命令是不夠的git clone https://github.com/apache/tvm.git為什么不夠因?yàn)門VM依賴幾個(gè)外部子模塊包括dmlc-core核心工具庫(kù)、dlpack張量數(shù)據(jù)交換協(xié)議和rang第三方頭文件庫(kù)等這些不會(huì)跟著主倉(cāng)庫(kù)自動(dòng)下載。如果漏了子模塊編譯的時(shí)候會(huì)報(bào)“找不到dmlc/core/io.h”之類的錯(cuò)誤或者CMake配置階段直接失敗。正確命令是加一個(gè)--recursive參數(shù)git clone --recursive https://github.com/apache/tvm.git如果你已經(jīng)用了不帶參數(shù)的方式clone了也不用重新來一遍在倉(cāng)庫(kù)根目錄執(zhí)行下面的命令即可補(bǔ)救git submodule init git submodule update --recursive需要提醒的是子模塊拉取過程中網(wǎng)絡(luò)不穩(wěn)定很容易失敗失敗后繼續(xù)操作可能導(dǎo)致子模塊目錄為空。建議拉取完成后檢查一下3rdparty/dmlc-core/include/dmlc目錄下是否有io.h文件存在有才說明沒問題。另外我個(gè)人習(xí)慣clone之后切到一個(gè)具體的release tag而不是直接留在master分支上。TVM的master分支是開發(fā)版雖然功能最新但偶爾會(huì)有API調(diào)整帶來的不穩(wěn)定性。我用release分支更穩(wěn)cd tvm git checkout v0.17.0 # 如果提示子模塊版本不匹配再執(zhí)行一次 git submodule update --recursive如果你是在官方發(fā)布某個(gè)版本后才clone的默認(rèn)的master分支就是最新代碼也可以直接用問題不大。3.2 編譯配置config.cmake里最關(guān)鍵的幾個(gè)開關(guān)進(jìn)入TVM倉(cāng)庫(kù)的根目錄創(chuàng)建一個(gè)build目錄存放編譯配置和中間產(chǎn)物。官方的默認(rèn)配置會(huì)從cmake/config.cmake復(fù)制過來但默認(rèn)配置里L(fēng)LVM是關(guān)閉的所以必須手動(dòng)改。cd tvm mkdir -p build cp cmake/config.cmake build/然后用文本編輯器打開build/config.cmake重點(diǎn)檢查并修改下面這幾處# 找到這行將OFF改成ON這樣LLVM后端才會(huì)開啟 set(USE_LLVM OFF) # 改成類似下面這樣具體路徑以你系統(tǒng)里的llvm-config為準(zhǔn) set(USE_LLVM /usr/lib/llvm-18/bin/llvm-config) # 如果要用NVIDIA GPU把下面這行改為ON set(USE_CUDA OFF) # 改成 set(USE_CUDA ON) # 建議把編譯類型設(shè)為Release這會(huì)開啟編譯優(yōu)化TVM自身的運(yùn)行性能顯著提升 set(CMAKE_BUILD_TYPE Release)這里重點(diǎn)聊一下USE_LLVM的設(shè)置方式。很多教程寫的是“l(fā)lvm-config -prefix”之類的自動(dòng)探測(cè)其實(shí)你直接把llvm-config的完整路徑填進(jìn)去就行TVM的CMake腳本會(huì)自動(dòng)調(diào)用它獲取編譯參數(shù)。前提是你要裝了llvm-dev相關(guān)的包否則只有l(wèi)lvm-config沒有開發(fā)頭文件也是白搭。我自己在探究LLVM版本兼容性時(shí)發(fā)現(xiàn)TVM官方對(duì)LLVM版本的支持范圍其實(shí)相當(dāng)寬LLVM 12到18都認(rèn)但舊TVM配新LLVM或者新TVM配舊LLVM都會(huì)有些邊緣問題。所以最省心的組合是新TVM 新LLVM。比如TVM 0.16以上配LLVM 17或18是當(dāng)下最穩(wěn)的組合。CUDA那個(gè)開關(guān)如果開了CMake會(huì)自動(dòng)去找系統(tǒng)中已安裝的CUDA Toolkit如果找到的版本不對(duì)可以在配置里手動(dòng)指定CUDA路徑set(USE_CUDA /usr/local/cuda)如果機(jī)器上沒有NVIDIA顯卡這一項(xiàng)保持OFF即可不用糾結(jié)。開CUDA之后編譯時(shí)間會(huì)變長(zhǎng)這個(gè)要有心理準(zhǔn)備。3.3 編譯與Python包安裝等一條命令跑完配置改好后開始正式的編譯構(gòu)建。在build目錄下執(zhí)行下面的命令cd build cmake .. make -j$(nproc)nproc會(huì)讀取當(dāng)前機(jī)器的CPU核數(shù)-j參數(shù)的作用是并行編譯這樣可以大幅縮短編譯時(shí)間。但也不建議在低配機(jī)器上無腦用所有核內(nèi)存不夠會(huì)導(dǎo)致編譯中途被系統(tǒng)殺掉。我的經(jīng)驗(yàn)是8核16G內(nèi)存的機(jī)器用-j6或-j8都沒問題2核4G的輕量服務(wù)器用-j2就好穩(wěn)妥第一。整個(gè)編譯過程少則十幾分鐘多則四五十分鐘取決于機(jī)器的CPU性能和是否開啟了CUDA、Vulkan等冗余后端。期間屏幕上會(huì)刷大量C編譯輸出看到[100%]或者Built target tvm之類的字樣就說明編譯完成了。編譯完成后TVM的核心C庫(kù)會(huì)在build/目錄生成libtvm.so和libtvm_runtime.so這兩個(gè)文件Python前端需要找到這個(gè)庫(kù)才能工作。接著安裝Python包裝包c(diǎn)d .. pip install python/tvm # 或者如果你想以開發(fā)模式安裝改動(dòng)代碼即時(shí)生效 # pip install -e python/tvm這里有一個(gè)非常常見的坑pip install和pip install -e的區(qū)別。普通安裝是把TVM的Python代碼復(fù)制到site-packages里之后你修改源碼里的Python文件不會(huì)生效開發(fā)模式-e則是建立一個(gè)軟鏈接代碼改動(dòng)立即生效。做深度學(xué)習(xí)模型開發(fā)的人通常用普通安裝就夠了但如果想改TVM源碼做研究就用開發(fā)模式。還有一個(gè)依賴需要注意TVM的Python包運(yùn)行需要numpy、decorator、attrs、typing_extensions、psutil、scipy等庫(kù)。pip install python/tvm的時(shí)候這些依賴一般會(huì)自動(dòng)裝上但如果你用了--no-deps或者系統(tǒng)里存在版本沖突就需要手動(dòng)逐個(gè)補(bǔ)。我最常碰到的是numpy版本問題比如系統(tǒng)里已有一個(gè)numpy 1.xTVM新版本要求numpy 2.x解決方式很簡(jiǎn)單統(tǒng)一升級(jí)到numpy 2.x即可但要注意個(gè)別其他庫(kù)可能還不兼容numpy 2.x這需要權(quán)衡。3.4 快速驗(yàn)證如何判斷TVM真的裝好了裝好以后不要急著跑模型先做一個(gè)最基礎(chǔ)的健康檢查。打開Python終端輸入下面的代碼import tvm print(tvm.__version__) print(tvm.__file__)能打印出版本號(hào)和源碼路徑說明Python包和核心庫(kù)的動(dòng)態(tài)鏈接已經(jīng)通了。這時(shí)候可以再試一次簡(jiǎn)單的張量操作驗(yàn)證編譯鏈路是否正常import tvm from tvm import te n 1024 A te.placeholder((n,), nameA) B te.compute((n,), lambda i: A[i] * 2, nameB) s te.create_schedule(B.op) f tvm.build(s, [A, B], targetllvm) print(build succeeded)如果tvm.build沒有報(bào)錯(cuò)說明LLVM后端已經(jīng)被正確調(diào)用TVM已經(jīng)能夠完成一個(gè)完整的編譯流程這是整個(gè)安裝成功的最有力證據(jù)。4. 安裝Python前端tvmc和上層工具鏈之間的關(guān)系4.1 tvmc是什么要不要單獨(dú)裝在TVM源碼倉(cāng)庫(kù)里python/tvm/driver/目錄下有一個(gè)叫tvmc的命令行工具全稱是TVM Command Line也就是TVM的“命令行用戶界面”。它允許你通過命令行的方式完成模型編譯和調(diào)優(yōu)而不用寫Python代碼。安裝TVM的同時(shí)tvmc就會(huì)一并裝好。驗(yàn)證方式tvmc --help如果能打印出幫助信息說明命令行通道已經(jīng)打通。tvmc支持很多子命令比如tvmc compile編譯模型、tvmc run運(yùn)行模型、tvmc tune自動(dòng)調(diào)優(yōu)等熟練之后能極大提升工作效率不需要每次都進(jìn)入Python交互環(huán)境。不過在日常開發(fā)里我更習(xí)慣直接用Python API。因?yàn)門VM的大部分高級(jí)功能比如Relay IR的操作、AutoTVM的配置調(diào)整還是Python接口寫得比較完整命令行工具適合快速驗(yàn)證但不適合做深度定制。4.2 用TVM加載一個(gè)ONNX模型走一遍完整推理鏈裝完之后最關(guān)心的問題就是“能不能直接用”。這里我分享一個(gè)最簡(jiǎn)單的完整鏈路示例把PyTorch的模型先導(dǎo)出成ONNX再用TVM編譯推理import torch import torchvision.models as models import onnx from tvm import relay # 以ResNet18為例 model models.resnet18(pretrainedFalse) model.eval() # 導(dǎo)出ONNX dummy_input torch.randn(1, 3, 224, 224) torch.onnx.export(model, dummy_input, resnet18.onnx, opset_version11) # 加載ONNX到TVM onnx_model onnx.load(resnet18.onnx) input_name input.1 shape_list [(input_name, (1, 3, 224, 224))] mod, params relay.frontend.from_onnx(onnx_model, shape_list) # 編譯目標(biāo)為L(zhǎng)LVM target llvm with tvm.transform.PassContext(opt_level3): lib relay.build(mod, targettarget, paramsparams) print(compile done)這段代碼把整個(gè)流程串了一遍從ONNX前端解析Relay表達(dá)式到Relay IR優(yōu)化再到后端代碼生成。如果這一步能順利完成說明TVM的編譯管線是完全通的。后面的模型推理只是把編譯后的lib加載到runtime再跑問題不大。有的讀者可能在這一步遇到“ONNX包沒有安裝”的報(bào)錯(cuò)直接用pip install onnx即可不用特意指定版本。需要注意的倒是PyTorch和TVM版本之間的兼容性老版本TVM對(duì)PyTorch新導(dǎo)出的ONNX算子支持可能不完整這又是一個(gè)“用新版TVM更省心”的理由。5. 踩坑實(shí)錄與排查技巧這幾類問題占了我裝機(jī)問題的八成安裝過程中最磨人的往往不是大方向出錯(cuò)而是一些看起來不起眼的小問題。這里我把過去踩過的坑做成一個(gè)表格方便大家快速對(duì)照。表格后面挑三個(gè)最典型的問題單獨(dú)展開講。錯(cuò)誤現(xiàn)象根本原因解法提示找不到dmlc/io.hclone時(shí)漏了子模塊git submodule update --recursiveCMake階段提示找不到llvm-configLLVM開發(fā)包沒裝apt install llvm-18 llvm-18-devimport tvm后提示找不到.so文件Python包和動(dòng)態(tài)庫(kù)不在同一路徑確認(rèn)編譯生成的libtvm.so在build/下且環(huán)境變量PYTHONPATH沒覆蓋tvm.build報(bào)“LLVM version mismatch”LLVM相關(guān)頭文件與庫(kù)文件版本不一致完整升級(jí)LLVM到同一版本清理build目錄重新配置編譯過程中內(nèi)存不足被kill并行編譯任務(wù)太多降低-j參數(shù)比如-j2Python運(yùn)行時(shí)報(bào)numpy版本不滿足TVM新版本與舊numpy不兼容pip install -U numpy啟用CUDA后編譯報(bào)錯(cuò)找不到cuda_runtime.h系統(tǒng)CUDA未安裝或PATH未設(shè)置安裝CUDA Toolkit配置/usr/local/cuda路徑TVM運(yùn)行時(shí)提示“Cannot find libtvm_runtime.so”runtime庫(kù)路徑未加入LD_LIBRARY_PATH在.bashrc中導(dǎo)出LD_LIBRARY_PATH/path/to/tvm/build:$LD_LIBRARY_PATH5.1 找不到LLVM一半以上的安裝失敗都栽在這里我見過太多人在CMake階段卡住報(bào)錯(cuò)類似于Could NOT find LLVM (missing: LLVM_CONFIG_EXECUTABLE)這個(gè)問題的第一反應(yīng)不要是去改配置而是先確認(rèn)系統(tǒng)里到底裝沒裝LLVM開發(fā)版。llvm-config --version如果提示找不到命令說明連基礎(chǔ)LLVM都沒裝。這時(shí)候執(zhí)行sudo apt install llvm-18 llvm-18-dev如果llvm-config存在但版本打印出來是10、11之類的舊版我依然建議升級(jí)到LLVM 17以上的版本。舊版LLVM不僅可能觸發(fā)TVM編譯告警更關(guān)鍵的是代碼生成質(zhì)量不如新版。在CPU推理這種性能敏感的場(chǎng)景下用新版LLVM調(diào)優(yōu)后的代碼可能比舊版快5%到15%。裝好之后在config.cmake里寫set(USE_LLVM /usr/lib/llvm-18/bin/llvm-config)注意路徑要以llvm-config結(jié)尾而不是填一個(gè)目錄。這是CMake的約定很多新手會(huì)在這里填成/usr/lib/llvm-18導(dǎo)致CMake依然找不到LLVM。5.2 編譯成功了但運(yùn)行模型時(shí)各種“內(nèi)部錯(cuò)誤”的排查思路編譯通過不等于萬事大吉運(yùn)行時(shí)錯(cuò)誤同樣讓人頭疼。比如我遇到過這樣的報(bào)錯(cuò)Check failed: ret 0: TVMError: Internal compiler error這種問題有兩種常見來源。第一類是TVM自身的bug尤其是在舊版本上遇到新LLVM的情況第二類是GPU相關(guān)算子在CUDA版本不匹配時(shí)的內(nèi)核編譯失敗。排查思路按順序做先確認(rèn)LLVM版本。在Python里執(zhí)行print(tvm.target.codegen.llvm_version())看看TVM實(shí)際檢測(cè)到的LLVM版本如果和llvm-config --version對(duì)不上就是要重新編譯TVM的信號(hào)。清理build目錄重新編譯。不要在原build目錄上直接覆蓋把build文件夾整個(gè)刪掉重新cp cmake/config.cmake build/再做一遍能排除舊配置緩存干擾。用官方的最小復(fù)現(xiàn)代碼測(cè)試。比如跑到GitHub上找對(duì)應(yīng)版本文檔里的示例排除是自己代碼的問題。如果還不行去GitHub Issues搜原話報(bào)錯(cuò)。TVM社區(qū)很活躍搜到相同問題基本就搜到了答案。我遇到過的最折騰的一次是TVM 0.13配合LLVM 15時(shí)編譯模型老觸發(fā)一個(gè)很小概率的Segment Fault最后解決辦法是升級(jí)TVM到0.16問題徹底消失。所以遇到這種編譯內(nèi)部錯(cuò)誤最快速的解法往往是“升級(jí)到最新TVM版本重新試一把”而不是苦找根源除非你有必須鎖定舊版本的理由。5.3 版本兼容性的體系化檢查一條命令幫你看清全局既然強(qiáng)調(diào)了一路的“新版本原則”最后分享一個(gè)我自用的小腳本可以把TVM及其關(guān)鍵依賴的版本一次性打印出來排查版本沖突時(shí)特別有用import tvm import sys print(Python version:, sys.version) print(TVM version:, tvm.__version__) try: print(LLVM version:, tvm.target.codegen.llvm_version()) except Exception as e: print(LLVM version detection failed:, e) import numpy print(NumPy version:, numpy.__version__) import torch print(PyTorch version:, torch.__version__)如果LLVM version打印出來是空或者報(bào)錯(cuò)那大概率LLVM沒配好。PyTorch版本如果不是2.x建議升級(jí)因?yàn)榕f版PyTorch導(dǎo)出的ONNX模型在TVM的新版前端上偶發(fā)兼容問題。6. 再補(bǔ)充一些個(gè)人建議與經(jīng)驗(yàn)細(xì)節(jié)6.1 要不要用Docker鏡像來省事海外用戶使用官方Docker鏡像很方便但有些地區(qū)網(wǎng)絡(luò)拉取鏡像會(huì)遇到困難加上Docker里掛載GPU還需要額外配置對(duì)新手來說門檻并不低。我的觀點(diǎn)是如果只是學(xué)習(xí)驗(yàn)證直接用源碼編譯一次也好能幫你理解整個(gè)依賴關(guān)系如果是多臺(tái)機(jī)器重復(fù)部署Docker方案效率會(huì)高很多。Docker方案也有一個(gè)坑鏡像里的LLVM、CUDA版本和你宿主機(jī)上的驅(qū)動(dòng)版本可能不匹配跑模型時(shí)依然會(huì)有各種莫名其妙的問題。除非你用了與宿主機(jī)驅(qū)動(dòng)完全匹配的鏡像版本否則真不如老老實(shí)實(shí)在物理機(jī)里編譯一次干凈。6.2 雙環(huán)境隔離多版本Python會(huì)讓排查難度翻倍在裝TVM之前我建議用conda創(chuàng)建一個(gè)全新的虛擬環(huán)境隔離系統(tǒng)自帶的Pythonconda create -n tvm python3.10 conda activate tvm這樣即使系統(tǒng)的Python環(huán)境被其他項(xiàng)目搞得亂七八糟TVM這一套東西也不會(huì)受影響。尤其在服務(wù)器上多環(huán)境共存的場(chǎng)景十分常見虛擬環(huán)境能幫你少掉一半的報(bào)錯(cuò)。6.3 最后一個(gè)建議把常見命令存成一個(gè)變量省點(diǎn)時(shí)間如果你需要經(jīng)常在TVM的build目錄和python目錄之間切換可以像我一樣把下面的變量寫進(jìn)~/.bashrcexport TVM_HOME~/tvm export PYTHONPATH$TVM_HOME/python:$TVM_HOME/build:$PYTHONPATH export LD_LIBRARY_PATH$TVM_HOME/build:$LD_LIBRARY_PATHPYTHONPATH幫Python找到TVM的Python前端LD_LIBRARY_PATH幫動(dòng)態(tài)鏈接器找到libtvm.so。這兩個(gè)如果缺了即使編譯成功后面也會(huì)出現(xiàn)導(dǎo)入或運(yùn)行時(shí)找不到庫(kù)的錯(cuò)誤。我自己實(shí)際操作中發(fā)現(xiàn)很多人在這一步漏了LD_LIBRARY_PATH的配置導(dǎo)致模型編譯明明是好的一運(yùn)行就說找不到libtvm_runtime.so。這個(gè)問題排查起來一點(diǎn)都不難但第一次遇到時(shí)確實(shí)很困惑。7. 個(gè)人踩坑后的一點(diǎn)真心話整個(gè)TVM安裝過程說到底是和環(huán)境打交道的過程。如果以前沒接觸過C編譯鏈、動(dòng)態(tài)庫(kù)、CMake這些底層概念第一次會(huì)被各種報(bào)錯(cuò)整得有些頭大。但這些報(bào)錯(cuò)其實(shí)都在做同一件事告訴你某個(gè)環(huán)節(jié)的版本對(duì)不上。你只要記住一個(gè)核心原則——盡量使用最新的穩(wěn)定版本能省下至少一半的排查時(shí)間。為什么這么說因?yàn)門VM這種快速迭代的項(xiàng)目新版本會(huì)持續(xù)修復(fù)編譯器與外部庫(kù)的兼容問題也會(huì)跟進(jìn)最新的第三方依賴接口。追新版本不等于盲目而是在這個(gè)特定項(xiàng)目上性價(jià)比最高的選擇。按照這篇文章的步驟操作理論上從零到跑通一個(gè)模型半個(gè)工作日應(yīng)該夠用。過程中如果遇到本文沒有覆蓋的報(bào)錯(cuò)先不要慌去GitHub Issues搜索原話大部分情況都能找到解決方案。如果實(shí)在搜不到就把完整報(bào)錯(cuò)貼到社區(qū)問通常很快會(huì)有人回應(yīng)。TVM安裝只是入門的第一道坎裝好之后還有更多有趣的東西等著你去探索。祝順利地跨過這道坎接下來就好好享受編譯優(yōu)化帶來的性能提升吧。這篇文章基于個(gè)人實(shí)際安裝經(jīng)驗(yàn)整理具體版本號(hào)隨時(shí)間推移會(huì)有變化建議以 TVM官方文檔 發(fā)布的最新安裝指南為準(zhǔn)。