境搭建實戰(zhàn):源碼編譯避坑與依賴版本選型指南)
1. 為什么今天還要折騰Caffe環(huán)境如果你最近打算復現(xiàn)一篇老論文或者接手了一個遺留的深度學習項目打開代碼倉庫發(fā)現(xiàn)里面全是.prototxt和.solver文件那你大概率繞不開Caffe。這東西在深度學習框架的上古時代幾乎是統(tǒng)治級的存在雖然現(xiàn)在大家張口閉口都是PyTorch和TensorFlow但工業(yè)界很多已經(jīng)落地跑了好幾年的模型底層依然是Caffe訓練出來的。我身邊就有做安防和工業(yè)質(zhì)檢的朋友產(chǎn)線上的模型到現(xiàn)在還在用Caffe推理原因很簡單穩(wěn)定、快、部署鏈路成熟。但問題也恰恰出在這里。Caffe的黃金時代是2014到2017年那個年代的編譯環(huán)境、依賴版本、CUDA版本跟現(xiàn)在完全不是一回事。你拿一臺2024年新裝的機器照著當年的教程一步步敲大概率會在某個依賴報錯上卡住半天。我自己第一次搭Caffe環(huán)境的時候光是protobuf版本沖突就折騰了整整一個下午最后發(fā)現(xiàn)是系統(tǒng)自帶的版本和Caffe要求的版本打架。所以這篇內(nèi)容的核心目標很明確幫你在當前環(huán)境下用最少的彎路把Caffe跑起來。我會從依賴選型講起把每個關鍵決策背后的原因說清楚然后給出經(jīng)過實測的完整步驟最后把幾個高頻踩坑點單獨拎出來講。適合兩類人看一是需要復現(xiàn)老項目但沒接觸過Caffe的開發(fā)者二是以前用過Caffe但換機器后重新搭建時被環(huán)境問題卡住的人。整個過程我會盡量用為什么這么做來解釋每一步而不是甩一堆命令讓你照抄。需要提前說明的是Caffe的安裝方式有好幾種——源碼編譯、Docker鏡像、conda安裝。這三種我都試過各有各的適用場景后面會詳細對比。本文主要走源碼編譯這條路因為它是理解Caffe依賴關系最透徹的方式也是遇到問題時最容易排查的方式。如果你只是想快速跑個推理Docker可能是更省事的選擇我也會給出對應的思路。2. 編譯之前必須想清楚的幾件事2.1 CPU版還是GPU版這個決定影響后面所有步驟很多人一上來就問怎么裝Caffe但更該先問的是我要用CPU還是GPU。這個選擇直接決定了你的依賴清單、編譯參數(shù)和后續(xù)能不能跑訓練。GPU版需要CUDA和cuDNN編譯出來的Caffe可以利用顯卡做并行計算訓練速度比CPU快幾十倍甚至上百倍。但代價是CUDA版本和Caffe的兼容性非常挑剔。Caffe官方最后活躍的版本大概支持到CUDA 8到9左右如果你機器上裝的是CUDA 11或12直接編譯大概率會報一堆API不匹配的錯誤。我實測下來CUDA 8.0配合cuDNN 5或6是最穩(wěn)的組合但這個版本的CUDA在新顯卡上又裝不了因為新顯卡的驅(qū)動要求更高版本的CUDA。這就形成一個尷尬的局面新機器裝不了老CUDA老CUDA配不了新顯卡。所以如果你用的是比較新的顯卡比如30系、40系我的建議是先老老實實裝CPU版把流程跑通確認代碼邏輯沒問題之后再考慮用Docker或者找一臺老機器來跑GPU訓練。CPU版雖然慢但編譯過程干凈不會因為CUDA的各種版本問題把你勸退。判斷方法很簡單打開終端敲nvcc --version如果有輸出說明裝了CUDA再看看版本號。如果版本在9以下可以嘗試GPU編譯如果是10以上建議直接走CPU路線或者Docker路線。2.2 依賴庫的版本選擇為什么最新版往往是坑Caffe的依賴清單不算長但每一個都有版本講究。我列一個表把關鍵依賴和推薦版本說清楚依賴庫作用推薦版本踩坑說明protobuf定義網(wǎng)絡結構的數(shù)據(jù)格式2.6.1 或 3.6.x3.0以上某些API有變化容易編譯報錯boost提供C基礎庫支持1.65以下1.70以上部分頭文件路徑變了glog日志記錄0.3.5版本要求不嚴但別用太新的gflags命令行參數(shù)解析2.2.2相對穩(wěn)定hdf5數(shù)據(jù)存儲格式支持1.8.x 或 1.10.x1.12以上有API變動opencv圖像處理3.x4.x的某些接口不兼容BLAS矩陣運算加速OpenBLAS或MKL選一個就行別同時裝這張表里的推薦版本不是我隨便寫的是反復編譯失敗后總結出來的。核心邏輯是Caffe的代碼寫于那個年代它調(diào)用的API就是那個年代的API。你用最新版的庫頭文件路徑變了、函數(shù)簽名變了、甚至某些功能被移除了編譯自然過不去。舉個具體的例子。protobuf從3.0開始把google/protobuf/stubs/common.h里的一些宏定義改了而Caffe的代碼里大量引用了這些宏。你裝個protobuf 3.20編譯到一半就會報未定義的標識符。解決辦法要么是降級protobuf要么是手動改Caffe源碼打補丁。前者省事后者費勁我一般選前者。還有一個容易忽略的點系統(tǒng)自帶的庫和手動安裝的庫可能沖突。比如Ubuntu系統(tǒng)里可能預裝了某個版本的protobuf你用apt又裝了一個然后手動編譯又裝了一個最后編譯器找到的是哪個版本完全看運氣。所以我的習慣是編譯Caffe之前先用apt list --installed | grep protobuf查一下系統(tǒng)里有什么該卸的卸干凈避免多個版本打架。2.3 三種安裝路線的取舍在動手之前先把三條路擺出來對比一下你根據(jù)自己的情況選源碼編譯最靈活能改代碼、能調(diào)參數(shù)、能精確控制依賴版本。缺點是耗時長第一次編譯加上解決依賴問題兩三個小時很正常。適合需要深入定制或者要理解Caffe內(nèi)部機制的人。Docker鏡像最省事拉一個別人配好的鏡像里面環(huán)境都是現(xiàn)成的。缺點是鏡像質(zhì)量參差不齊有些鏡像里的Caffe版本很老有些缺少GPU支持。適合只想快速跑通、不想折騰環(huán)境的人。Conda安裝通過conda-forge頻道可以裝到Caffe命令就一行。缺點是conda版的Caffe可能缺少某些功能模塊而且和系統(tǒng)里的Python環(huán)境容易沖突。適合做快速原型驗證。我個人的建議是第一次接觸Caffe走源碼編譯。雖然麻煩但走完一遍之后你對Caffe的依賴關系、編譯流程、配置文件都會有清晰的認識后面遇到問題也知道從哪查。如果你已經(jīng)用過Caffe只是換機器要重新搭那Docker是更高效的選擇。3. 從零開始的完整編譯流程3.1 系統(tǒng)環(huán)境確認與基礎依賴安裝我以Ubuntu 18.04為例來走一遍這個版本是Caffe編譯成功率比較高的。Ubuntu 20.04也可以但有些包的名字變了需要微調(diào)。先確認系統(tǒng)版本lsb_release -a然后安裝基礎編譯工具sudo apt-get update sudo apt-get install -y build-essential cmake git pkg-config這幾樣是編譯任何C項目都需要的。build-essential里包含了gcc、g和makecmake用來生成編譯配置pkg-config幫編譯器找到庫文件的位置。接下來裝Caffe的核心依賴。這里我給的命令是經(jīng)過篩選的把版本沖突的風險降到最低sudo apt-get install -y libprotobuf-dev libleveldb-dev libsnappy-dev \ libopencv-dev libhdf5-serial-dev protobuf-compiler sudo apt-get install -y --no-install-recommends libboost-all-dev sudo apt-get install -y libgflags-dev libgoogle-glog-dev liblmdb-dev注意libhdf5-serial-dev這個包名在有些系統(tǒng)上叫l(wèi)ibhdf5-dev如果報找不到就換一個試試。--no-install-recommends是為了避免boost裝一堆用不上的推薦包能省不少空間。BLAS的選擇上我推薦用OpenBLAS安裝簡單且性能不錯sudo apt-get install -y libopenblas-dev如果你有Intel的CPU并且追求極致性能可以換成MKL但MKL的安裝稍微麻煩一些需要去官網(wǎng)下載并配置環(huán)境變量。對于大多數(shù)場景OpenBLAS夠用了。3.2 獲取Caffe源碼與配置文件調(diào)整源碼從官方倉庫克隆git clone https://github.com/BVLC/caffe.git cd caffe克隆下來之后先別急著編譯。Caffe的編譯配置是通過Makefile.config控制的倉庫里給了一個示例文件Makefile.config.example你需要復制一份并修改cp Makefile.config.example Makefile.config然后打開這個文件逐項檢查。以下是幾個必須改的地方CPU/GPU開關如果你走CPU路線把# CPU_ONLY : 1前面的注釋去掉變成CPU_ONLY : 1。這一行決定了編譯時是否鏈接CUDA庫。BLAS配置找到BLAS : atlas這一行改成BLAS : open因為我們裝的是OpenBLAS。同時確認BLAS_INCLUDE和BLAS_LIB的路徑指向正確OpenBLAS一般裝在/usr/include和/usr/lib下。Python路徑如果你需要Python接口比如用pycaffe寫腳本要確保Python的include和lib路徑正確。找到PYTHON_INCLUDE和PYTHON_LIB部分根據(jù)你的Python版本調(diào)整。比如Python 3.6的話路徑大概是/usr/include/python3.6m和/usr/lib/x86_64-linux-gnu/libpython3.6m.so。HDF5路徑這是個高頻坑點。Ubuntu 18.04的HDF5頭文件在/usr/include/hdf5/serial/庫文件在/usr/lib/x86_64-linux-gnu/hdf5/serial/。你需要在Makefile.config里把這兩個路徑加到INCLUDE_DIRS和LIBRARY_DIRS里。具體做法是找到這兩行在末尾追加路徑INCLUDE_DIRS : $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial LIBRARY_DIRS : $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial這一步不做的話編譯到使用HDF5的模塊時會報找不到hdf5.h。3.3 編譯過程中的參數(shù)調(diào)優(yōu)與并行加速配置改好之后就可以編譯了。但在敲make之前先做一件事確認你的CPU核心數(shù)用nproc命令查看。然后編譯時加上-j參數(shù)來并行編譯能大幅縮短時間make all -j$(nproc) make test -j$(nproc) make runtest -j$(nproc)make all編譯核心庫和工具make test編譯測試程序make runtest跑測試。如果只是自己用make all就夠了后面兩個可選。但建議至少跑一下make test確保編譯出來的東西是完整的。編譯過程中如果報錯不要慌先看錯誤信息的第一行。Caffe的編譯錯誤往往是一連串的但根因通常在最開始那幾行。常見的錯誤類型和處理方式我整理一下找不到頭文件說明某個依賴的include路徑?jīng)]配好回到Makefile.config檢查對應的INCLUDE_DIRS。未定義的引用鏈接階段找不到庫文件檢查LIBRARY_DIRS和LDFLAGS。protobuf相關錯誤大概率是版本沖突用protoc --version確認版本必要時降級。內(nèi)存不足被殺并行編譯時如果內(nèi)存不夠系統(tǒng)會殺掉編譯進程。減少-j后面的數(shù)字比如改成-j2。我實測在一臺8核16G的機器上make all -j8大概需要15到20分鐘。如果超過半小時還沒完可能是某個模塊卡住了檢查一下是不是在編譯OpenCV相關的代碼那部分特別慢。3.4 編譯后的驗證怎么確認真的裝好了編譯完成后在caffe目錄下會生成build/文件夾里面有l(wèi)ib/和tools/。驗證分三步第一步檢查核心庫文件是否存在ls build/lib/應該能看到libcaffe.so、libcaffe.so.1.0.0這些文件。第二步運行Caffe自帶的命令行工具./build/tools/caffe如果輸出一堆用法說明說明工具編譯成功了。如果報error while loading shared libraries說明動態(tài)庫路徑?jīng)]配好需要把build/lib加到LD_LIBRARY_PATH里或者直接寫進/etc/ld.so.conf.d/。第三步如果你編譯了Python接口驗證一下cd python export PYTHONPATH$(pwd):$PYTHONPATH python -c import caffe; print(caffe.__version__)能打印出版本號就說明pycaffe可用了。如果報ImportError: No module named caffe檢查PYTHONPATH是否設置正確以及caffe/python/caffe/目錄下是否有_caffe.so文件。4. 那些讓我熬夜的報錯與解決思路4.1 protobuf版本沖突的完整排查鏈路這是我遇到最多的坑也是很多人卡住的地方。癥狀通常是編譯時報一堆undefined reference to google::protobuf::...或者運行時報This program was compiled against version X of the Protocol Buffer runtime library, which is not compatible with the installed version Y。排查思路是這樣的先確認系統(tǒng)里裝了哪些protobuf版本。用dpkg -l | grep protobuf看apt裝的用which protoc看當前用的是哪個用protoc --version看版本號。如果發(fā)現(xiàn)apt裝了一個版本手動編譯又裝了一個版本那基本就是沖突了。解決辦法有兩種。第一種是統(tǒng)一版本把手動裝的卸掉只用apt的版本或者反過來。第二種是讓Caffe明確使用某個版本在Makefile.config里把PROTOBUF_INCLUDE和PROTOBUF_LIB指向你想要的版本路徑。我個人的做法是編譯Caffe之前先把系統(tǒng)里的protobuf清理干凈然后手動編譯安裝一個2.6.1版本。雖然老但和Caffe的兼容性最好。安裝步驟是下載源碼、./configure、make、make install然后ldconfig刷新庫緩存。4.2 OpenCV 4.x帶來的接口不兼容如果你系統(tǒng)里裝的是OpenCV 4.x編譯Caffe時大概率會遇到CV_LOAD_IMAGE_COLOR未定義的錯誤。這個宏在OpenCV 4里被改成了cv::IMREAD_COLOR。Caffe的代碼里用的是老寫法所以編譯不過。解決辦法有兩個一是降級到OpenCV 3.x二是手動改Caffe源碼。我選的是后者因為降級OpenCV可能影響系統(tǒng)里其他依賴OpenCV的程序。具體改法是找到報錯的文件通常是src/caffe/util/io.cpp和src/caffe/layers/image_data_layer.cpp把CV_LOAD_IMAGE_COLOR替換成cv::IMREAD_COLOR把CV_LOAD_IMAGE_GRAYSCALE替換成cv::IMREAD_GRAYSCALE。改完之后重新編譯即可。這個坑的教訓是Caffe的代碼和現(xiàn)代庫之間存在代溝遇到類似問題不要死磕要么降版本要么改代碼兩條路都能走通。4.3 鏈接階段的未定義引用怎么定位鏈接錯誤比編譯錯誤更難查因為報錯信息往往是一大串符號名看不出是哪個庫的問題。我的經(jīng)驗是從報錯信息里找關鍵詞。比如看到cblas_開頭的符號說明BLAS庫沒鏈接上看到H5開頭的說明HDF5沒配好看到cv::開頭的說明OpenCV路徑有問題。定位到是哪個庫之后回到Makefile.config檢查對應的LIBRARY_DIRS和LDFLAGS。有時候庫文件確實存在但名字不對比如你裝的是libopenblas.so但Makefile里找的是libcblas.so那就需要建一個軟鏈接或者改Makefile。還有一個隱蔽的情況庫的架構不匹配。比如你的系統(tǒng)是64位的但某個庫只有32位版本鏈接時就會報錯。用file命令檢查庫文件的架構確認是ELF 64-bit。5. 環(huán)境跑通之后的一些實用建議5.1 把Caffe集成到你的工作流里編譯完只是第一步真正用起來還需要一些配置。如果你用Python寫腳本建議把Caffe的Python路徑寫進.bashrcexport CAFFE_ROOT/path/to/your/caffe export PYTHONPATH$CAFFE_ROOT/python:$PYTHONPATH export LD_LIBRARY_PATH$CAFFE_ROOT/build/lib:$LD_LIBRARY_PATH這樣每次打開終端都自動生效不用手動export。注意LD_LIBRARY_PATH這一行很多人只配了PYTHONPATH結果運行時報找不到libcaffe.so就是漏了這個。如果你用CMake管理自己的項目可以在CMakeLists.txt里這樣引用Caffefind_package(Caffe REQUIRED) include_directories(${Caffe_INCLUDE_DIRS}) target_link_libraries(your_project ${Caffe_LIBRARIES})前提是Caffe安裝時生成了CaffeConfig.cmake如果沒有就需要手動指定路徑。5.2 模型轉(zhuǎn)換與跨框架協(xié)作的現(xiàn)實問題現(xiàn)在純用Caffe訓新模型的人已經(jīng)不多了更常見的場景是拿PyTorch訓練好的模型轉(zhuǎn)成Caffe格式去部署。這個轉(zhuǎn)換過程有不少坑比如層類型對不上、參數(shù)命名不一致、某些算子Caffe不支持等。我的建議是轉(zhuǎn)換之前先確認目標Caffe版本支持哪些層。Caffe的層類型是固定的那些PyTorch里一些新奇的算子比如各種注意力機制在Caffe里根本沒有對應實現(xiàn)。遇到這種情況要么用Caffe的自定義層功能自己寫要么換部署方案。轉(zhuǎn)換工具方面有開源的pytorch2caffe之類的腳本但質(zhì)量參差不齊很多只支持基本的卷積網(wǎng)絡。我試過幾個對ResNet這種標準結構還行稍微復雜一點的網(wǎng)絡就各種報錯。所以如果你的模型結構比較新做好手動改轉(zhuǎn)換腳本的心理準備。5.3 關于Caffe是否還值得學的個人看法最后說點實在的。Caffe作為一個框架它的生命周期確實已經(jīng)進入尾聲了官方倉庫好幾年沒更新了。但這不代表學它沒意義。理解Caffe的架構設計對理解深度學習框架的演進很有幫助。它的prototxt定義網(wǎng)絡的方式、blob作為數(shù)據(jù)載體的設計、layer作為計算單元的組織方式這些思想在后來的框架里都能看到影子。而且現(xiàn)實情況是很多工業(yè)項目還在用Caffe你接手了就得會。與其抱怨怎么還在用這老古董不如花半天時間把環(huán)境搭好把流程跑通。我自己的經(jīng)驗是Caffe環(huán)境搭一次之后后面換機器照著筆記走半小時就能搞定。真正花時間的是第一次踩坑的過程而這個過程一旦走完你對Linux編譯、依賴管理、動態(tài)鏈接這些底層知識的理解會上一個臺階。如果你在搭建過程中遇到了本文沒覆蓋的報錯我的建議是去翻Caffe的GitHub Issues里面幾乎能找到所有常見問題的討論。搜索的時候用報錯信息里的關鍵詞不要用整句話搜命中率更高。另外編譯日志一定要保存下來make all 21 | tee build.log出問題的時候可以慢慢翻。