境配置到MNIST實(shí)戰(zhàn)避坑指南)
簡介面向Windows平臺的Caffe深度學(xué)習(xí)框架資源包主要服務(wù)于需要在Windows環(huán)境中安裝、編譯和使用Caffe的深度學(xué)習(xí)開發(fā)者、科研人員及學(xué)生能夠顯著降低環(huán)境搭建門檻。壓縮包共包含888個(gè)文件容量約8.67MB文件類型覆蓋C源碼cpp/hpp、CUDA加速代碼cu/cuh、模型配置文件prototxt、Python與MATLAB腳本、CMake構(gòu)建腳本以及Visual Studio工程文件等從底層實(shí)現(xiàn)到上層調(diào)用均有涉及。目前已有292人學(xué)習(xí)下載目錄組織清晰適合不同基礎(chǔ)的用戶按需查閱。包內(nèi)不僅包含編譯好的可執(zhí)行程序和依賴庫還提供了構(gòu)建配置、依賴檢測腳本、測試用例和示例工程能夠幫助用戶快速理解Windows下Caffe的編譯流程與文件間的關(guān)系在遇到配置問題時(shí)也能借助相關(guān)腳本定位原因。對于希望在非Linux平臺開展深度學(xué)習(xí)實(shí)驗(yàn)的讀者這份資源具備較強(qiáng)的實(shí)用性和參考價(jià)值。 直接在Windows上把Caffe跑起來這事兒擱現(xiàn)在依然是不少人的心頭痛。明明是個(gè)深度學(xué)習(xí)框架裝起來卻像在搞硬件驅(qū)動動不動就編譯失敗報(bào)一堆宏錯(cuò)誤。但你如果是因?yàn)槔享?xiàng)目、課程作業(yè)、或者某些只提供了Caffe模型權(quán)重的算法源碼不得不回頭用Caffe那這篇文章就是給你準(zhǔn)備的。我用自己的經(jīng)歷幫你把caffe-windows這條路捋清楚告訴你哪些坑可以繞開哪些細(xì)節(jié)必須死磕。先說清楚Caffe是什么。它全稱是Convolutional Architecture for Fast Feature Embedding由伯克利視覺與學(xué)習(xí)中心BAIR開發(fā)在深度學(xué)習(xí)剛火起來那幾年幾乎是工業(yè)界和學(xué)術(shù)界用CNN做圖像分類、目標(biāo)檢測的事實(shí)標(biāo)準(zhǔn)。后來PyTorch和TensorFlow出來之后Caffe的社區(qū)熱度下降不少但它的經(jīng)典地位還在大量老模型文件.caffemodel和網(wǎng)絡(luò)定義文件.prototxt仍然活躍在產(chǎn)線上。你如果拿到一個(gè)老模型想在新機(jī)器上推理或者在一臺Windows機(jī)器上復(fù)現(xiàn)師兄的實(shí)驗(yàn)就得把Caffe這套老工具鏈重新搭起來。我在前兩年因?yàn)橐粋€(gè)OCR項(xiàng)目的維護(hù)需求被迫在一臺Windows Server上編譯Caffe整個(gè)過程踩了無數(shù)坑?,F(xiàn)在回頭看很多問題其實(shí)可以避免。這篇文章從環(huán)境配置講到編譯實(shí)操再到訓(xùn)練一個(gè)MNIST驗(yàn)證全流程最后附上常見問題排查表按順序走一遍你就能在Windows上把Caffe正常用起來。1. 項(xiàng)目定位為什么非要在Windows上折騰Caffe1.1 Caffe的核心設(shè)計(jì)思路與適用場景Caffe的設(shè)計(jì)哲學(xué)和現(xiàn)代框架差別很大。它把自己的核心抽象成了四個(gè)層Blob數(shù)據(jù)存儲、Layer計(jì)算單元、Net網(wǎng)絡(luò)結(jié)構(gòu)、Solver訓(xùn)練策略算法實(shí)現(xiàn)。你在Caffe里定義一個(gè)網(wǎng)絡(luò)不用寫代碼而是用一個(gè)純文本的.prototxt文件去描述網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)。比如你用層類型Convolution、Pooling再指定bottom和topCaffe就會自動把這些層串成一幅計(jì)算圖。這個(gè)設(shè)計(jì)的好處是做實(shí)驗(yàn)時(shí)想改網(wǎng)絡(luò)結(jié)構(gòu)改一個(gè)文本文件就行不用重新編譯整個(gè)項(xiàng)目。所以Caffe特別適合兩類人一類是做視覺算法研究、需要大量快速迭代網(wǎng)絡(luò)結(jié)構(gòu)的人另一類是手上有老模型權(quán)重需要在新環(huán)境下做推理部署的人。它不像PyTorch那樣“什么都得自己在Python里搭”Caffe把大部分事情都固化在C層跑起來比當(dāng)時(shí)的Python框架快很多尤其適合在嵌入式設(shè)備或服務(wù)器上批量跑圖片任務(wù)。1.2 為什么Windows移植版本是一個(gè)“獨(dú)立大陸”Caffe原生從Linux起家代碼里大量使用了POSIX接口比如文件鎖、dirent.h、unistd.h這類在Windows上根本不存在的頭文件。官方源碼的Windows分支長期處于“能用但沒人維護(hù)”的狀態(tài)。后來微軟內(nèi)部有人牽頭做了microsoft/caffe這個(gè)Windows遷移版后來社區(qū)里也陸續(xù)冒出一些fork。這些版本的共同點(diǎn)是改寫了底層文件操作和系統(tǒng)調(diào)用把所有第三方依賴boost、glog、gflags、protobuf、hdf5、leveldb等統(tǒng)一用NuGet或腳本拉取再通過CMake或Visual Studio的屬性表.props來組織構(gòu)建系統(tǒng)。這件事的本質(zhì)是你拿到的caffe-windows并不是一個(gè)普通源碼包它是一套“已經(jīng)被改造成Windows工程”的解決方案。你用Linux上那種“./configure make”的思路去套必死。在Windows上編譯Caffe核心就兩件事把依賴配齊、把構(gòu)建系統(tǒng)認(rèn)準(zhǔn)別自己發(fā)明流程。我接下來要講的每一步都是圍繞這兩件事展開的。2. 環(huán)境準(zhǔn)備版本匹配是生死線2.1 Visual Studio、CUDA、cuDNN的版本矩陣在Windows上編Caffe最容易翻車的就是版本不匹配。不是說拿最新版Visual Studio和最新版CUDA就能編過恰恰相反越新越容易失敗。Caffe-Windows項(xiàng)目在GitHub上有明確的版本對應(yīng)關(guān)系我這個(gè)項(xiàng)目用的是CUDA 8.0 cuDNN 5.1 Visual Studio 2013/2015。這套組合雖然老卻是微軟官方驗(yàn)證過最穩(wěn)定的一套。如果你用VS2017或者更高版本去編譯老源碼會在Protobuf生成代碼、CUDA編譯參數(shù)等環(huán)節(jié)遇到成片報(bào)錯(cuò)比如“C1001編譯器內(nèi)部錯(cuò)誤”“錯(cuò)誤C2220”改到心態(tài)爆炸。我個(gè)人的建議是如果不是非要在這臺機(jī)器上跑CUDA 11以上版本的項(xiàng)目盡量不要升級。我見過有人用VS2019硬編英文老版本最后改了兩百多行源碼才編過完全不值得。專門為Caffe這個(gè)項(xiàng)目準(zhǔn)備一個(gè)獨(dú)立的、版本適配的環(huán)境是成本最低的選擇。如果你電腦空間足夠裝一個(gè)VS2015和一個(gè)老版本CUDA和你的現(xiàn)代開發(fā)環(huán)境共存完全沒問題。2.2 依賴庫的三種獲取方式老版本Caffe-Windows的依賴庫可以從項(xiàng)目管網(wǎng)下載到預(yù)編譯包文件名通常是libraries_v140_x64_py35_1.1.0.tar.bz2這種格式。這個(gè)壓縮包里面已經(jīng)編譯好了boost、glog、gflags、protobuf、hdf5、leveldb、lmdb等一整套第三方庫解壓到指定目錄就行。還有第二種方式是用NuGet自動拉取打開項(xiàng)目目錄下的Caffe.sln之前先執(zhí)行NuGet Restore系統(tǒng)會按照packages.config把依賴下載到項(xiàng)目根目錄的packages文件夾里。第三種方式是自己手動編譯每個(gè)依賴這種方式最靈活但工程量太大我只在需要定制某個(gè)庫版本的時(shí)候才用。我實(shí)際用下來NuGet 預(yù)編譯包混合的方式最靠譜。你先解壓預(yù)編譯包把目錄名改為libraries放在Caffe工程根目錄下再執(zhí)行NuGet Restore最后用CMake生成工程時(shí)它會自動去libraries目錄里找頭文件和lib文件。順序不能反如果先執(zhí)行CMake再解壓庫CMake配置階段找不到庫就會報(bào)錯(cuò)。3. 源碼編譯從CMake到ALL_BUILD的完整過程3.1 拿到源碼并確認(rèn)目錄結(jié)構(gòu)第一步把microsoft/caffe這個(gè)倉庫的源碼clone下來。官方倉庫下有一個(gè)Windows文件夾里面有批處理腳本還有CommonSettings.props這個(gè)核心配置文件。整個(gè)目錄結(jié)構(gòu)我覺得有必要解釋一下因?yàn)楹芏嘈率謺盐募佩e(cuò)位置導(dǎo)致路徑出問題。倉庫根目錄下主要包含cmake存放CMake相關(guān)模塊負(fù)責(zé)找第三方庫include與srcCaffe的源碼本體包含caffe的頭文件和cpp文件tools編譯后會生成caffe.exe等可執(zhí)行工具pythonpycaffe的Python接口代碼models經(jīng)典的模型定義與權(quán)重下載地址examples官方示例其中mnist文件夾就是我們后面要用的手寫數(shù)字示例還有CommonSettings.props和Caffe.sln這兩個(gè)Windows工程核心文件3.2 編輯CommonSettings.props編譯前必須修改CommonSettings.props這個(gè)文件。它是一個(gè)MSBuild的屬性表定義了整個(gè)編譯過程中的關(guān)鍵宏。你需要按自己的環(huán)境開啟或關(guān)閉相應(yīng)的配置項(xiàng)。比如如果只用CPU環(huán)境把CpuOnlyBuild這個(gè)標(biāo)簽從false改為true這樣就不需要CUDA了如果要帶Python接口把PythonSupport從false改為true并且根據(jù)你裝的Python版本把PythonDir指向?qū)嶋H路徑比如C:\Python35要注意CUDA版本對應(yīng)的CUDA_PATH環(huán)境變量VS會自動讀取我寫過一篇總結(jié)建議第一次編譯時(shí)盡量先關(guān)掉Python和Matlab支持只編C核心等跑通了再加擴(kuò)展接口。這樣做是因?yàn)镻ython接口要額外編譯pycaffe的入口Matlab接口需要去配Mex文件如果這些一起編出錯(cuò)時(shí)日志會非常長很難定位問題。3.3 CMake生成VS工程在項(xiàng)目根目錄執(zhí)行CMake用CMake GUI或者命令行都行。關(guān)鍵參數(shù)是指定源碼目錄和構(gòu)建目錄build文件夾指定Visual Studio生成器比如Visual Studio 14 2015 Win64勾選或設(shè)置Python相關(guān)的選項(xiàng)如果第2步關(guān)閉了PythonSupport這里也可以不勾CMake配置階段如果提示找不到某些庫基本都是因?yàn)閘ibraries預(yù)編譯包沒放對位置或者版本不對。它找到所有依賴項(xiàng)后就會生成Caffe.sln和一堆.vcxproj項(xiàng)目文件。這一步的報(bào)錯(cuò)通常和路徑有關(guān)解決方案就是檢查libraries目錄是否存在、環(huán)境變量CUDA_PATH是否指向正確路徑。3.4 編譯并生成caffe.exe用Visual Studio打開生成的Caffe.sln在解決方案管理器里找到ALL_BUILD項(xiàng)目右鍵選擇生成。第一次編譯Caffe會花很長時(shí)間因?yàn)橐幾g數(shù)百個(gè)源文件還有Protobuf的生成代碼。如果你是四核以上的CPU可以在CMake時(shí)開啟多線程編譯或者直接在VS里調(diào)整“項(xiàng)目屬性 - C/C - 命令行”加上/MP參數(shù)。我自己用的是八核機(jī)器開啟多線程后大概20多分鐘能編完。編譯完成后所有可執(zhí)行文件會生成在build目錄下的x64/Release里其中包括caffe.exe這是Caffe的命令行入口。同時(shí)也會生成libcaffe.lib靜態(tài)庫和對應(yīng)的頭文件。到這里核心部分就編譯成功了。4. 實(shí)際驗(yàn)證用MNIST快速跑通第一個(gè)模型4.1 準(zhǔn)備MNIST數(shù)據(jù)集Caffe官方提供了一個(gè)腳本get_mnist.bat位于examples/mnist文件夾里。運(yùn)行它之后會自動從網(wǎng)上下載MNIST數(shù)據(jù)集并且調(diào)用convert_mnist_data.exe把原始二進(jìn)制文件轉(zhuǎn)成Caffe能夠直接讀取的LMDB格式數(shù)據(jù)庫。這個(gè)轉(zhuǎn)換過程要注意如果你編譯時(shí)不帶LMDB支持轉(zhuǎn)換工具就生成不了所以前面編譯依賴時(shí)一定要檢查leveldb和lmdb這兩個(gè)庫是否編譯進(jìn)去。轉(zhuǎn)完之后會在examples/mnist文件夾下生成mnist_train_lmdb和mnist_test_lmdb兩個(gè)文件夾。這兩個(gè)文件夾就是標(biāo)準(zhǔn)的數(shù)據(jù)源網(wǎng)絡(luò)定義文件里會引用它們。4.2 給出LeNet網(wǎng)絡(luò)定義和Solver配置Caffe官方在examples/mnist文件夾里已經(jīng)提供了兩個(gè)核心文件lenet_train_test.prototxt和lenet_solver.prototxt。前者定義了LeNet網(wǎng)絡(luò)結(jié)構(gòu)一個(gè)卷積層、一個(gè)池化層、再一個(gè)卷積層、一個(gè)池化層最后接兩個(gè)全連接層后者是訓(xùn)練超參數(shù)的配置。我截取lenet_solver.prototxt里最關(guān)鍵的一段來分析net: examples/mnist/lenet_train_test.prototxt test_iter: 100 test_interval: 500 base_lr: 0.01 momentum: 0.9 weight_decay: 0.0005 lr_policy: inv gamma: 0.0001 power: 0.75 max_iter: 10000 display: 100 type: SGD solver_mode: GPU這里的base_lr是初始學(xué)習(xí)率0.01是個(gè)經(jīng)驗(yàn)值用SGD做MNIST分類足夠。momentum設(shè)為0.9是沿用經(jīng)典策略目的是在梯度更新時(shí)保留上一次更新的方向減少震蕩。weight_decay設(shè)為0.0005是常用的L2正則化參數(shù)防止過擬合。max_iter設(shè)為10000表示訓(xùn)練一萬步。4.3 執(zhí)行訓(xùn)練并解讀日志輸出在命令行中運(yùn)行caffe.exe train --solverexamples/mnist/lenet_solver.prototxt如果你是CPU編譯版本記得先把solver_mode改成CPU。跑起來之后你會看到每100次迭代輸出一次當(dāng)前l(fā)oss比如I1012 10:23:45.678901 1234 solver.cpp:245] Iteration 100, loss 0.6234 I1012 10:23:45.678902 1234 solver.cpp:271] Train net output #0: loss 0.6234 (* 1 0.6234 loss)loss從初期的2.3左右逐漸下降到一萬次迭代后基本能到0.02以下測試準(zhǔn)確率在99%附近。這時(shí)候你的Caffe Windows環(huán)境就正式驗(yàn)證通過了。我實(shí)際操作時(shí)的經(jīng)驗(yàn)是第一次跑最好盯著loss下降曲線如果發(fā)現(xiàn)loss卡住不動或者直接變成NaN先檢查學(xué)習(xí)率設(shè)置把base_lr調(diào)小10倍再試。還有prototxt里數(shù)據(jù)層的路徑如果是從其他機(jī)器復(fù)制過來的記得用絕對路徑或相對路徑保持正確。5. 常見問題與避坑經(jīng)驗(yàn)我一次性幫你踩完5.1 編譯階段報(bào)錯(cuò)速查表報(bào)錯(cuò)信息可能原因解決方法找不到cuda_runtime.hCUDA未安裝或路徑不對檢查CUDA_PATH環(huán)境變量確認(rèn)CUDA版本與VS匹配cudnn.h找不到cuDNN未解壓到CUDA目錄把cuDNN的include和lib合并到CUDA安裝目錄MSB4062或MSB3723VS版本與CUDA工具集不兼容換用VS2013/2015搭配CUDA 8.0編譯Python接口失敗Python版本與依賴庫不匹配關(guān)閉PythonSupport先編核心LNK1104無法打開xxx.lib第三方庫路徑配置錯(cuò)誤重新檢查libraries目錄路徑是否在VC庫目錄里5.2 運(yùn)行階段出現(xiàn)的問題編譯成功后運(yùn)行時(shí)還會遇到幾個(gè)非常典型的坑我把它們單獨(dú)拿出來說。第一個(gè)是找不到動態(tài)庫。編譯好的caffe.exe雙擊運(yùn)行會閃退或者提示找不到cudart64_80.dll / cudnn64_5.dll。這是因?yàn)镃UDA和cuDNN的bin目錄沒有加入系統(tǒng)PATH。你把C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0\bin加進(jìn)PATH并把cuDNN的bin目錄里的cudnn64_5.dll復(fù)制到CUDA的bin目錄即可解決。第二個(gè)是命令行運(yùn)行提示“無法啟動此程序因?yàn)橛?jì)算機(jī)中丟失libglog.dll”。這個(gè)問題說明編譯時(shí)選擇的運(yùn)行庫是Debug版本或動態(tài)鏈接方式而運(yùn)行時(shí)沒有把對應(yīng)的依賴庫一起帶過來。libraries預(yù)編譯包里的bin目錄有這些動態(tài)庫把它們加進(jìn)PATH或者拷貝到caffe.exe的同目錄下就解決了。第三個(gè)是prototxt路徑問題。運(yùn)行時(shí)如果提示“Failed to open lmdb”或者“Check failed: file exists”要先檢查工作目錄。Caffe內(nèi)部解析相對路徑的口徑是以當(dāng)前命令行所在目錄為準(zhǔn)的所以如果你在build目錄下運(yùn)行caffe.exe就記得用相對路徑時(shí)帶上源碼目錄名或者干脆用絕對路徑。5.3 性能相關(guān)的建議Caffe跑在Windows上的性能一般不如Linux這是文件系統(tǒng)機(jī)制和編譯優(yōu)化的差異導(dǎo)致的。我在同一臺機(jī)器上做過對比Windows上的推理速度大約是Linux的80%到90%如果開了CPU模式差距更明顯。所以如果項(xiàng)目對延遲特別敏感我建議把訓(xùn)練放在Linux服務(wù)器上Windows這邊只做模型轉(zhuǎn)換和簡單驗(yàn)證。如果只能Windows上跑盡量把Caffe的編譯配置從Debug換成Release并從項(xiàng)目屬性里打開SSE2和AVX指令集優(yōu)化。5.4 Python接口的配置細(xì)節(jié)如果你需要pycaffe編譯完P(guān)ython支持后還需要把python目錄和build目錄里生成的caffe文件夾加入Python的搜索路徑。最簡單的方式是在系統(tǒng)環(huán)境變量PYTHONPATH里添加兩個(gè)路徑D:\caffe-windows\python D:\caffe-windows\build\x64\Release\pycaffe然后在終端測試import caffe print(caffe.__version__)如果能正常輸出版本號就說明接口沒問題。這里有個(gè)坑是Python版本位數(shù)必須是64位Python而且要和你編譯時(shí)PythonSupport指定的版本一致32位Python和64位Caffe庫絕對對不上。6. 寫在最后的個(gè)人經(jīng)驗(yàn)我在折騰caffe-windows的過程中最深的一個(gè)感受是“老技術(shù)不等于過時(shí)但你得按老技術(shù)的規(guī)則來玩”。這個(gè)框架的代碼結(jié)構(gòu)和現(xiàn)代深度學(xué)習(xí)框架完全不同它對系統(tǒng)環(huán)境的假設(shè)非常死板一個(gè)版本號不對就可能失敗。但當(dāng)你真正跑通之后你會發(fā)現(xiàn)它的速度和可定制性仍然有自己的優(yōu)勢。如果你現(xiàn)在也在為某個(gè)老模型不得不編譯Caffe別急著換框架按我上面的步驟一步步來大概率能順利搞定。最后再分享一個(gè)小技巧如果你只做推理不做訓(xùn)練其實(shí)可以直接用caffe.exe test命令去跑測試配合訓(xùn)練好的權(quán)重文件比寫一堆Python代碼簡單得多。這也是Caffe作為命令行工具最被人忽視的優(yōu)點(diǎn)。本文還有配套的精品資源點(diǎn)擊獲取