
1. 報(bào)錯(cuò)現(xiàn)場(chǎng)engine 反序列化時(shí)版本斷言失敗你拿到的報(bào)錯(cuò)長(zhǎng)這樣[TensorRT] ERROR: 1: [stdArchiveReader.cpp::StdArchiveReader::35] Error Code 1: Serialization (Serialization assertion safeVersionRead safeSerializationVersion failed. Version tag does not match. Note: Current Version: 0, Serialized Engine Version: 89)這句話(huà)翻譯成人話(huà)就是你正在用的 TensorRT 運(yùn)行時(shí)和當(dāng)初生成這個(gè) engine 文件時(shí)的 TensorRT不是同一個(gè)版本。safeVersionRead是當(dāng)前運(yùn)行時(shí)讀到的版本號(hào)safeSerializationVersion是 engine 文件里寫(xiě)死的序列化版本號(hào)兩者對(duì)不上TensorRT 直接拒絕反序列化程序在deserializeCudaEngine這一步就崩了。這個(gè)坑最常出現(xiàn)在 tensorrtx 這類(lèi)工程里你在 A 機(jī)器上用 TensorRT 8.5 把 ONNX 轉(zhuǎn)成.engine拷到 B 機(jī)器上跑 demoB 機(jī)器裝的是 TensorRT 8.6 或者 10.x于是版本標(biāo)簽一個(gè) 0 一個(gè) 89斷言失敗。注意Current Version: 0不代表你裝的是 0 版本它表示運(yùn)行時(shí)沒(méi)能匹配到任何已知的序列化版本屬于「讀不懂」的狀態(tài)。面向在CMakeLists.txt里集成 TensorRT 的 C 工程這篇會(huì)給你三樣?xùn)|西一套能自動(dòng)探測(cè) TensorRT 版本并正確鏈接的 CMake 骨架、一段帶版本校驗(yàn)的序列化/反序列化代碼、以及用最小樣例復(fù)現(xiàn)并驗(yàn)證版本對(duì)齊的完整步驟。適合正在用 tensorrtx 或自研推理 demo、被這個(gè)斷言卡住的同學(xué)。2. 前置TaoToken 與 TensorRT 版本對(duì)齊的關(guān)系先說(shuō)清楚一件事這個(gè)報(bào)錯(cuò)本身是本地 TensorRT 版本問(wèn)題跟網(wǎng)絡(luò)服務(wù)無(wú)關(guān)。但在實(shí)際工程里很多人會(huì)用 TaoToken 這類(lèi)平臺(tái)來(lái)跑模型對(duì)話(huà)、驗(yàn)證推理結(jié)果、或者用 Coding Plan 輔助寫(xiě) CMake 和 C 代碼所以順手把環(huán)境說(shuō)清楚。TaoToken 是一個(gè)聚合多家大模型能力的 API 平臺(tái)官網(wǎng)在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。它能做什么統(tǒng)一接口調(diào)用不同模型適合做推理結(jié)果對(duì)照、寫(xiě)工程腳本、排查編譯報(bào)錯(cuò)。適合誰(shuí)需要多模型對(duì)比驗(yàn)證、或者想讓 AI 幫忙讀 CMake 報(bào)錯(cuò)和 C 編譯日志的開(kāi)發(fā)者。它和本篇的關(guān)系在于當(dāng)你搞不清 TensorRT 版本對(duì)應(yīng)關(guān)系、或者 CMake 鏈接報(bào)錯(cuò)看不懂時(shí)可以把報(bào)錯(cuò)貼給模型對(duì)話(huà)快速定位。模型對(duì)話(huà)入口在 https://taotoken.net/api API Keys 在 https://taotoken.net/api-keys 接入文檔在 https://taotoken.net/doc 。如果你長(zhǎng)期寫(xiě)推理工程、要反復(fù)調(diào) CMake 和 CUDA 代碼Coding Plan 會(huì)更順手https://taotoken.net/coding-plan 。注意TaoToken 是模型 API 服務(wù)不替代本地 TensorRT 安裝也不做 engine 轉(zhuǎn)換。版本對(duì)齊必須在你的機(jī)器上完成。3. 可復(fù)制配置CMakeLists.txt 版本探測(cè)與鏈接骨架核心思路不要硬編碼 TensorRT 路徑讓 CMake 去環(huán)境里探測(cè)真實(shí)版本并把版本號(hào)傳給編譯期宏這樣運(yùn)行時(shí)校驗(yàn)才有依據(jù)。3.1 探測(cè) TensorRT 安裝路徑與版本TensorRT 的頭文件里NvInferVersion.h定義了NV_TENSORRT_MAJOR/MINOR/PATCH我們可以讓 CMake 讀出來(lái)。cmake_minimum_required(VERSION 3.16) project(trt_version_check LANGUAGES CXX CUDA) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 允許外部傳入 TensorRT 根目錄默認(rèn)走環(huán)境變量 if(NOT DEFINED TENSORRT_ROOT) if(DEFINED ENV{TENSORRT_ROOT}) set(TENSORRT_ROOT $ENV{TENSORRT_ROOT}) else() set(TENSORRT_ROOT /usr/local/TensorRT) endif() endif() message(STATUS TENSORRT_ROOT ${TENSORRT_ROOT}) find_path(TENSORRT_INCLUDE_DIR NAMES NvInfer.h NvInferVersion.h HINTS ${TENSORRT_ROOT}/include PATHS /usr/include /usr/local/include ) find_library(TENSORRT_LIBRARY NAMES nvinfer HINTS ${TENSORRT_ROOT}/lib ${TENSORRT_ROOT}/lib64 PATHS /usr/lib /usr/local/lib ) if(NOT TENSORRT_INCLUDE_DIR OR NOT TENSORRT_LIBRARY) message(FATAL_ERROR TensorRT not found. Set TENSORRT_ROOT correctly.) endif() message(STATUS TensorRT include: ${TENSORRT_INCLUDE_DIR}) message(STATUS TensorRT library: ${TENSORRT_LIBRARY})3.2 從版本頭文件解析出版本號(hào)用 CMake 的file(STRINGS ...)把宏摳出來(lái)轉(zhuǎn)成編譯期定義。file(READ ${TENSORRT_INCLUDE_DIR}/NvInferVersion.h TRT_VERSION_HEADER) string(REGEX MATCH define NV_TENSORRT_MAJOR ([0-9]) _ ${TRT_VERSION_HEADER}) set(TRT_MAJOR ${CMAKE_MATCH_1}) string(REGEX MATCH define NV_TENSORRT_MINOR ([0-9]) _ ${TRT_VERSION_HEADER}) set(TRT_MINOR ${CMAKE_MATCH_1}) string(REGEX MATCH define NV_TENSORRT_PATCH ([0-9]) _ ${TRT_VERSION_HEADER}) set(TRT_PATCH ${CMAKE_MATCH_1}) message(STATUS Detected TensorRT version: ${TRT_MAJOR}.${TRT_MINOR}.${TRT_PATCH}) add_executable(trt_version_check main.cpp) target_include_directories(trt_version_check PRIVATE ${TENSORRT_INCLUDE_DIR}) target_link_libraries(trt_version_check PRIVATE ${TENSORRT_LIBRARY} cudart) target_compile_definitions(trt_version_check PRIVATE TRT_MAJOR${TRT_MAJOR} TRT_MINOR${TRT_MINOR} TRT_PATCH${TRT_PATCH} )這樣編譯出來(lái)的程序里TRT_MAJOR等宏就是當(dāng)前環(huán)境真實(shí)鏈接的版本而不是你手寫(xiě)的常量。這一步是解決斷言失敗的關(guān)鍵鏈接的庫(kù)和頭文件必須來(lái)自同一套安裝。3.3 關(guān)鍵參數(shù)對(duì)照表參數(shù)作用常見(jiàn)錯(cuò)誤TENSORRT_ROOT指定 TensorRT 安裝根目錄指向了舊版本目錄TENSORRT_INCLUDE_DIR頭文件路徑頭文件是新版庫(kù)是舊版TENSORRT_LIBRARYlibnvinfer.so路徑鏈接到系統(tǒng)殘留的舊 soTRT_MAJOR/MINOR/PATCH編譯期版本宏手寫(xiě)常量導(dǎo)致與實(shí)際不符提示頭文件和庫(kù)必須來(lái)自同一次安裝。混用是safeVersionRead斷言失敗的頭號(hào)原因。4. 序列化/反序列化版本校驗(yàn)代碼光靠 CMake 對(duì)齊還不夠運(yùn)行時(shí)也要主動(dòng)校驗(yàn)把問(wèn)題在反序列化之前暴露出來(lái)而不是等 TensorRT 拋斷言。4.1 打印運(yùn)行時(shí)版本并做前置檢查#include NvInfer.h #include NvInferVersion.h #include iostream #include fstream #include vector using namespace nvinfer1; int main(int argc, char** argv) { if (argc 2) { std::cerr usage: argv[0] model.engine std::endl; return 1; } // 編譯期版本來(lái)自 CMake 探測(cè) std::cout Compiled against TensorRT TRT_MAJOR . TRT_MINOR . TRT_PATCH std::endl; // 運(yùn)行時(shí)版本來(lái)自實(shí)際鏈接的庫(kù) std::cout Runtime TensorRT version: NV_TENSORRT_MAJOR . NV_TENSORRT_MINOR . NV_TENSORRT_PATCH std::endl; if (TRT_MAJOR ! NV_TENSORRT_MAJOR) { std::cerr [WARN] header/library major version mismatch! std::endl; } // 讀取 engine 文件 std::ifstream file(argv[1], std::ios::binary); if (!file) { std::cerr cannot open engine file std::endl; return 1; } file.seekg(0, std::ios::end); size_t size file.tellg(); file.seekg(0, std::ios::beg); std::vectorchar blob(size); file.read(blob.data(), size); std::cout engine file size: size bytes std::endl; // 反序列化 IRuntime* runtime createInferRuntime(gLogger); ICudaEngine* engine runtime-deserializeCudaEngine(blob.data(), size); if (!engine) { std::cerr [FAIL] deserializeCudaEngine returned nullptr. Check TensorRT version alignment. std::endl; return 1; } std::cout [OK] engine deserialized, nbBindings engine-getNbBindings() std::endl; delete engine; delete runtime; return 0; }4.2 一個(gè)簡(jiǎn)單的 loggerclass Logger : public ILogger { public: void log(Severity severity, const char* msg) noexcept override { if (severity Severity::kWARNING) { std::cout [TRT] msg std::endl; } } }; static Logger gLogger;把gLogger定義在main之前即可。這樣當(dāng)斷言失敗時(shí)你能在日志里同時(shí)看到編譯期版本和運(yùn)行時(shí)版本一眼判斷是不是版本錯(cuò)位。4.3 序列化側(cè)也要記錄版本如果你自己負(fù)責(zé)生成 engine建議在文件名或旁?huà)斓?meta里寫(xiě)上生成時(shí)的版本避免拷來(lái)拷去搞混。std::string engineName model_trt std::to_string(NV_TENSORRT_MAJOR) _ std::to_string(NV_TENSORRT_MINOR) _ std::to_string(NV_TENSORRT_PATCH) .engine;命名帶版本是成本最低的防呆手段。5. 最小樣例復(fù)現(xiàn)與版本對(duì)齊驗(yàn)證5.1 復(fù)現(xiàn)步驟第一步確認(rèn)當(dāng)前環(huán)境版本dpkg -l | grep -i tensorrt ls -l /usr/lib/x86_64-linux-gnu/libnvinfer.so*第二步用上面的 CMake 骨架編譯觀察輸出的Detected TensorRT version。第三步拿一個(gè)用不同版本生成的 engine去跑你會(huì)看到[TRT] Error Code 1: Serialization (Serialization assertion safeVersionRead safeSerializationVersion failed. Version tag does not match. Note: Current Version: 0, Serialized Engine Version: 89) [FAIL] deserializeCudaEngine returned nullptr.第四步用當(dāng)前版本重新生成 engine再跑同一個(gè)程序輸出變成[OK] engine deserialized, nbBindings55.2 版本對(duì)齊的三種做法做法操作適用場(chǎng)景統(tǒng)一運(yùn)行時(shí)把 demo 機(jī)器的 TensorRT 升/降到與生成機(jī)一致生產(chǎn)部署最穩(wěn)重新生成 engine在目標(biāo)機(jī)器上用當(dāng)前 TensorRT 重新轉(zhuǎn)版本無(wú)法改動(dòng)時(shí)容器隔離用固定版本鏡像跑生成和推理多項(xiàng)目共存注意engine 文件不跨大版本兼容。TensorRT 8.x 生成的 engine 拿到 10.x 上基本必掛這不是配置問(wèn)題是設(shè)計(jì)如此。5.3 驗(yàn)證版本是否真正對(duì)齊# 查看鏈接到的實(shí)際庫(kù) ldd ./trt_version_check | grep nvinfer # 查看庫(kù)內(nèi)版本字符串 strings /usr/lib/x86_64-linux-gnu/libnvinfer.so | grep -i TensorRT v如果ldd指向的 so 和你TENSORRT_ROOT里的不是同一個(gè)說(shuō)明系統(tǒng)里有多個(gè) TensorRTCMake 鏈接到了錯(cuò)誤的那個(gè)。這時(shí)候要么清理舊版本要么在 CMake 里用絕對(duì)路徑強(qiáng)制指定。6. 本篇常見(jiàn)錯(cuò)排查報(bào)錯(cuò)一Version tag does not match但版本號(hào)看起來(lái)一樣。多半是頭文件和庫(kù)不同源。檢查T(mén)ENSORRT_INCLUDE_DIR和TENSORRT_LIBRARY是否來(lái)自同一目錄用ldd確認(rèn)實(shí)際加載的 so。報(bào)錯(cuò)二CMake 探測(cè)到的版本和nvcc/dpkg顯示的不一致。說(shuō)明環(huán)境里有多個(gè) TensorRT。用find_library時(shí)加NO_DEFAULT_PATH只在你指定的TENSORRT_ROOT下找。報(bào)錯(cuò)三deserializeCudaEngine返回 nullptr 但沒(méi)有明顯日志。logger 的 severity 過(guò)濾太嚴(yán)把kWARNING以上都打出來(lái)。另外確認(rèn) engine 文件讀取時(shí)用的是二進(jìn)制模式std::ios::binary不能漏。報(bào)錯(cuò)四重新 cmake 后仍然報(bào)舊版本。構(gòu)建目錄有緩存。刪掉build/重新cmake ..或者cmake --fresh。報(bào)錯(cuò)五tensorrtx 生成的 engine 在 demo 上失敗。tensorrtx 的CMakeLists.txt里 TensorRT 路徑是寫(xiě)死的改成用find_library探測(cè)或者把TENSORRT_ROOT指到 demo 機(jī)器實(shí)際安裝的位置。排查時(shí)如果 CMake 報(bào)錯(cuò)看不懂可以把完整報(bào)錯(cuò)貼到模型對(duì)話(huà)里讓它幫你定位https://taotoken.net/api 。接入方式看文檔https://taotoken.net/doc Key 在 https://taotoken.net/api-keys 生成。長(zhǎng)期寫(xiě)這類(lèi)推理工程、要反復(fù)調(diào) CMake 和 CUDA 的Coding Plan 更省事https://taotoken.net/coding-plan 。最后給你一個(gè)我常用的判斷口訣engine 報(bào)版本斷言先看 ldd 再看頭文件兩者同源再談重新生成。絕大多數(shù)safeVersionRead safeSerializationVersion失敗都死在「頭文件一套、庫(kù)另一套」上而不是 TensorRT 本身有 bug。