【caffe-windows】Linux至Windows平台的caffe移植
1、前言
主要參考兩篇博客以及很多論壇解決細節(jié)問題:
http://www.cnblogs.com/trantor/p/4570097.html
 
https://initialneil.wordpress.com/2015/01/11/build-caffe-in-windows-with-visual-studio-2013-cuda-6-5-opencv-2-4-9/
 
移植環(huán)境:Windows7 64位+原版caffe+opencv3.0。
本文主要在于移植原版caffe,而依賴庫采用的是比較穩(wěn)定的,而非最新版,比如未使用opencv3.1。如果想自己編譯新的依賴庫,可以私聊博主或者下方留言,我會根據(jù)情況看是否有必要寫一個編譯caffe依賴庫的博客。表示依賴庫用CMake編譯還是蠻多問題的,折騰了一周
【PS】讀者一定要注意路徑問題,因此本文教程也盡量采用圖片說明,且路徑都標示出來了。
2、依賴庫
2.1 安裝boost
原始下載地址:http://sourceforge.net/projects/boost/files/boost-binaries/1.56.0/boost_1_56_0-msvc-12.0-64.exe/download
百度云盤地址:鏈接:http://pan.baidu.com/s/1pK7PHcn 密碼:eu3v
我安裝時候是默認一直下一步的,安裝路徑也是默認的:C:\local\boost_1_56_0
無需修改環(huán)境變量
【PS】坑人的數(shù)字衛(wèi)士,建議關掉它,剛準備安裝就給我把安裝包刪掉了。
 
2.2 安裝opencv
原始下載地址:https://sourceforge.net/projects/opencvlibrary/files/opencv-win/3.0.0/opencv-3.0.0.exe/download
百度云盤地址:鏈接:http://pan.baidu.com/s/1sltOJm9 密碼:19u0
參考安裝文檔:http://jingyan.baidu.com/article/64d05a0245aa70de55f73b12.html
第一步:提取文件
 
第二步:配置環(huán)境變量
添加到path中的環(huán)境變量:C:\local\opencv\build\x64\vc12\bin;C:\local\opencv\build\x86\vc12\bin
 
 
2.3 安裝cuda
參考我前面安裝微軟版本caffe的GPU配置:http://blog.csdn.net/zb1165048017/article/details/51549105
2.4 下載其它依賴庫
可以自己參考fengbingchun的博客自行配置(可能會有部分問題),也可以下載NZ的博客提供的三方包,本文采用后者
原始下載地址:https://drive.google.com/file/d/0B_G5BUend20PRnFhMUlMelFEZW8/view
云盤下載地址:鏈接:http://pan.baidu.com/s/1bpJtOpp 密碼:dmsr
解壓以后會有兩個文件夾:
 
將第一個3rdparty拖入你想要編譯caffe的目錄,我這里新建了一個目錄稱為caffe-original
 
至此所有的依賴庫已準備好。
3、VS配置caffe工程
3.1 下載官方caffe
官方下載地址:https://github.com/BVLC/caffe
云盤下載地址:鏈接:http://pan.baidu.com/s/1pLnho0N 密碼:e580
直接將caffe-master內部所有文件拖入3rdparty所在文件夾中
 
然后在E:\caffe-original\caffe下新建一個文件夾bin
 
3.2 加入工程
3.2.1 新建空項目
 
然后修改配置管理器->活動解決方案平臺
 
 
3.2.2 更改環(huán)境變量
先把屬性管理器調出來:視圖->其它窗口->屬性管理器
然后右側會有如下窗口
 
分別對debug和release添加引用文件和庫目錄:
① Debug下右鍵屬性
通用屬性->常規(guī)->輸出目錄,選擇3.1中新建的bin文件夾
 
通用屬性->c/c++->常規(guī)->附加包含目錄,添加相應的包含(include)文件
 
通用屬性->鏈接器->常規(guī)->附加庫目錄,添加相應的靜態(tài)庫(lib)所在文件夾
 
 
通用屬性->鏈接器->輸入->附加依賴項,添加相應的靜態(tài)庫(lib)文件
 
內容:
opencv_ts300d.lib;opencv_world300d.lib;gflagsd.lib;libglog.lib;libopenblas.dll.a;libprotobufd.lib;
libprotoc.lib;leveldbd.lib;lmdbd.lib;libhdf5_D.lib;libhdf5_hl_D.lib;Shlwapi.lib;cudart.lib;cuda.lib;
nppi.lib;cufft.lib;cublas.lib;curand.lib
 
② Release下右鍵屬性
通用屬性->常規(guī)->輸出目錄,選擇3.1中新建的bin文件夾
 
通用屬性->c/c++->常規(guī)->附加包含目錄,添加相應的包含(include)文件
 
通用屬性->鏈接器->常規(guī)->附加庫目錄,添加相應的靜態(tài)庫(lib)所在文件夾
 
上面這三個過程,直接把Debug下對應處文字拷貝過來放進去。
通用屬性->鏈接器->輸入->附加依賴項,添加相應的靜態(tài)庫(lib)文件
內容:
opencv_ts300.lib;opencv_world300.lib;gflags.lib;libglog.lib;libopenblas.dll.a;
libprotobuf.lib;libprotoc.lib;leveldb.lib;lmdb.lib;libhdf5.lib;
libhdf5_hl.lib;Shlwapi.lib;cudart.lib;cuda.lib;nppi.lib;cufft.lib;cublas.lib;curand.lib
3.2.3 將caffe相關文件加入工程
解決方案資源管理器->源文件->現(xiàn)有項中選擇?E:\caffe-original\src\caffe中的所有文件
 
4、逐步編譯三個cpp
【注】以下全是在Debug模式下操作4.1 common.cpp
解決fopen_s不安全問題:
解決方案->caffe右鍵屬性->配置屬性->c/c++->預處理器->預處理器定義添加
_CRT_SECURE_NO_WARNINGS
修復getpid()問題,打開common.cpp,
添加頭文件
#include<process.h>
注釋第36行,修改內容如下:
//pid = getpid(); #ifndef _MSC_VER pid = getpid(); #else pid = _getpid(); #endif
注釋第55行,不然最后總體編譯會有問題
//::google::InstallFailureSignalHandler();
檢查是否修改完畢:common.cpp右鍵->編譯,觀察是否生成成功
4.2 blob.cpp(重點)
在E:\caffe-original\scripts目錄下新建GeneratePB.bat,內容如下:if exist "../src/caffe/proto/caffe.pb.h" (echo caffe.pb.h remains the same as before ) else (echo caffe.pb.h is being generated"../3rdparty/bin/protoc" -I="../src/caffe/proto" --cpp_out="../src/caffe/proto" "../src/caffe/proto/caffe.proto" ) 也可以下載:
原始下載地址:https://drive.google.com/file/d/0B_G5BUend20PRDc3bXI0YkRLaUU/view
 云盤下載地址:鏈接:http://pan.baidu.com/s/1ge3wsMJ 密碼:ikd8
運行bat,會發(fā)現(xiàn)在E:\caffe-original\src\caffe\proto有三個文件了,caffe.pb.cc、caffe.pb.h、caffe.proto
嘗試blob.cpp右鍵->編譯,是否能通過。
一般來說Release模式不會出問題,但是Debug模式會出現(xiàn):
錯誤 35 error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility 2132 1 caffe 困擾了很久很久,解決方案:
在C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include路徑中的xutility(94kb左右的那個),右鍵屬性,取消其只讀屬性,在第14行加入:
#pragma warning(disable:4996)
 
再編譯一遍,果斷成功。
4.3 solver.cpp
第11行也就是剛include完畢所有頭文件的地方,添加
//port fir win32 #ifdef _MSC_VER #define snprintf sprintf_s #endif嘗試編譯一下5、源文件編譯——layer文件夾
①解決方案資源管理器->caffe->右鍵源文件->添加->新建篩選器->重命名為layers
②從E:\caffe-original\src\caffe\layers隨便拖一個cu文件到源文件的layers文件中,此處拖入的是absval_layer.cu
③解決方案資源管理器->caffe右鍵->生成依賴項->生成自定義->選擇第一項cuda7.5
 
④對著②中拖入的absval_layer.cu右鍵屬性->常規(guī)->項類型-CUDA C/C++(此處有幾個長得很像,一定要看清,CUDA C/C++是在最后一個,否則選錯了以后再編譯caffe時會出現(xiàn)obj連接問題)
⑤源文件->layers右鍵->添加->現(xiàn)有項->添加E:\caffe-original\src\caffe\layers文件夾所有文件;
? ?然后檢查一下是不是所有的cu文件都是項類型為CUDA/C++(一般來說操作順序對了,這一步可以忽視)
⑥打開bnll_layer.cu,注釋第8行,并添加:
//const float kBNLL_THRESHOLD = 50.; #define kBNLL_THRESHOLD 50.06、源文件編譯——util文件夾
①解決方案資源管理器->caffe->右鍵源文件->添加->新建篩選器->重命名為util
 ②源文件->util右鍵->添加->現(xiàn)有項->添加E:\caffe-original\src\caffe\util文件夾所有文件;
 
③修改io.cpp的相關部分
第35行和53行中的O_RDONLY修改為O_RDONLY | O_BINARY
第1行后面添加
#if defined(_MSC_VER) #include<io.h> #define open _open #endif也就是說#include <google/protobuf/io/coded_stream.h>編程第6行了。
第44、53、67行的close(fd)全部改為_close(fd)
編譯一下io.cpp看看成功了沒有。
④修改math_functions.cpp內容
在第9行添加
#define __builtin_popcount __popcnt #define __builtin_popcountl __popcnt編譯試試成功了沒有。
7、源文件編譯——proto文件夾
①解決方案資源管理器->caffe->右鍵源文件->添加->新建篩選器->重命名為proto
 ②源文件->util右鍵->添加->現(xiàn)有項->添加E:\caffe-original\src\caffe\proto文件夾所有文件;
 
8、編譯caffe
①解決方案資源管理器->caffe->右鍵源文件->添加->現(xiàn)有項->選擇E:\caffe-original\tools下的caffe.cpp
 
②解決方案資源管理器->caffe->右鍵生成,會出現(xiàn):
>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppBuild.targets(364,5): warning MSB8004: Output Directory does not end with a trailing slash. This build instance will add the slash as it is required to allow proper evaluation of the Output Directory. ③上方工具欄->生成->取消
④解決方案資源管理器->caffe->屬性->配置屬性->常規(guī)->輸出目錄改為..\bin\
⑤同樣Release也需要改為..\bin\
⑥解決方案資源管理器->caffe->右鍵重新生成
 
9、余下問題解決
可見編譯貌似沒這么成功,在源文件->util->signal_handler.cpp和hdf5.cpp出現(xiàn)了問題
9.1 解決signal_handler.cpp問題
直接用我們前面微軟版本的替換就行,代碼如下:
#include <boost/bind.hpp> #include <glog/logging.h>#include <signal.h> #include <csignal>#include "caffe/util/signal_handler.h"namespace {static volatile sig_atomic_t got_sigint = false;static volatile sig_atomic_t got_sighup = false;static bool already_hooked_up = false;void handle_signal(int signal) {switch (signal) { #ifdef _MSC_VERcase SIGBREAK: // there is no SIGHUP in windows, take SIGBREAK instead.got_sighup = true;break; #elsecase SIGHUP:got_sighup = true;break; #endifcase SIGINT:got_sigint = true;break;}}void HookupHandler() {if (already_hooked_up) {LOG(FATAL) << "Tried to hookup signal handlers more than once.";}already_hooked_up = true; #ifdef _MSC_VERif (signal(SIGBREAK, handle_signal) == SIG_ERR) {LOG(FATAL) << "Cannot install SIGBREAK handler.";}if (signal(SIGINT, handle_signal) == SIG_ERR) {LOG(FATAL) << "Cannot install SIGINT handler.";} #elsestruct sigaction sa;// Setup the handlersa.sa_handler = &handle_signal;// Restart the system call, if at all possiblesa.sa_flags = SA_RESTART;// Block every signal during the handlersigfillset(&sa.sa_mask);// Intercept SIGHUP and SIGINTif (sigaction(SIGHUP, &sa, NULL) == -1) {LOG(FATAL) << "Cannot install SIGHUP handler.";}if (sigaction(SIGINT, &sa, NULL) == -1) {LOG(FATAL) << "Cannot install SIGINT handler.";} #endif}// Set the signal handlers to the default.void UnhookHandler() {if (already_hooked_up) { #ifdef _MSC_VERif (signal(SIGBREAK, SIG_DFL) == SIG_ERR) {LOG(FATAL) << "Cannot uninstall SIGBREAK handler.";}if (signal(SIGINT, SIG_DFL) == SIG_ERR) {LOG(FATAL) << "Cannot uninstall SIGINT handler.";} #elsestruct sigaction sa;// Setup the sighub handlersa.sa_handler = SIG_DFL;// Restart the system call, if at all possiblesa.sa_flags = SA_RESTART;// Block every signal during the handlersigfillset(&sa.sa_mask);// Intercept SIGHUP and SIGINTif (sigaction(SIGHUP, &sa, NULL) == -1) {LOG(FATAL) << "Cannot uninstall SIGHUP handler.";}if (sigaction(SIGINT, &sa, NULL) == -1) {LOG(FATAL) << "Cannot uninstall SIGINT handler.";} #endifalready_hooked_up = false;}}// Return true iff a SIGINT has been received since the last time this// function was called.bool GotSIGINT() {bool result = got_sigint;got_sigint = false;return result;}// Return true iff a SIGHUP has been received since the last time this// function was called.bool GotSIGHUP() {bool result = got_sighup;got_sighup = false;return result;} } // namespacenamespace caffe {SignalHandler::SignalHandler(SolverAction::Enum SIGINT_action,SolverAction::Enum SIGHUP_action):SIGINT_action_(SIGINT_action),SIGHUP_action_(SIGHUP_action) {HookupHandler(); }SignalHandler::~SignalHandler() {UnhookHandler(); }SolverAction::Enum SignalHandler::CheckForSignals() const {if (GotSIGHUP()) {return SIGHUP_action_;}if (GotSIGINT()) {return SIGINT_action_;}return SolverAction::NONE; }// Return the function that the solver can use to find out if a snapshot or // early exit is being requested. ActionCallback SignalHandler::GetActionFunction() {return boost::bind(&SignalHandler::CheckForSignals, this); }} // namespace caffe
9.2 解決hdf5.cpp問題
直接用我們前面微軟版本的替換就行,代碼如下:
#include "caffe/util/hdf5.hpp"#include <string> #include <vector>namespace caffe {// Verifies format of data stored in HDF5 file and reshapes blob accordingly. template <typename Dtype> void hdf5_load_nd_dataset_helper(hid_t file_id, const char* dataset_name_, int min_dim, int max_dim,Blob<Dtype>* blob) {// Verify that the dataset exists.CHECK(H5LTfind_dataset(file_id, dataset_name_))<< "Failed to find HDF5 dataset " << dataset_name_;// Verify that the number of dimensions is in the accepted range.herr_t status;int ndims;status = H5LTget_dataset_ndims(file_id, dataset_name_, &ndims);CHECK_GE(status, 0) << "Failed to get dataset ndims for " << dataset_name_;CHECK_GE(ndims, min_dim);CHECK_LE(ndims, max_dim);// Verify that the data format is what we expect: float or double.std::vector<hsize_t> dims(ndims);H5T_class_t class_;status = H5LTget_dataset_info(file_id, dataset_name_, dims.data(), &class_, NULL);CHECK_GE(status, 0) << "Failed to get dataset info for " << dataset_name_;switch (class_) {case H5T_FLOAT:// In VC++ declaring and initializing variables in case statement without// curly braces (new scope), cause compiler error C2360// https://msdn.microsoft.com/en-us/library/61af7cx3.aspx{LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_FLOAT";break;}case H5T_INTEGER:{LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_INTEGER";break;}case H5T_TIME:{LOG(FATAL) << "Unsupported datatype class: H5T_TIME";}case H5T_STRING:{LOG(FATAL) << "Unsupported datatype class: H5T_STRING";}case H5T_BITFIELD:{LOG(FATAL) << "Unsupported datatype class: H5T_BITFIELD";}case H5T_OPAQUE:{LOG(FATAL) << "Unsupported datatype class: H5T_OPAQUE";}case H5T_COMPOUND:{LOG(FATAL) << "Unsupported datatype class: H5T_COMPOUND";}case H5T_REFERENCE:{LOG(FATAL) << "Unsupported datatype class: H5T_REFERENCE";}case H5T_ENUM:{LOG(FATAL) << "Unsupported datatype class: H5T_ENUM";}case H5T_VLEN:{LOG(FATAL) << "Unsupported datatype class: H5T_VLEN";}case H5T_ARRAY:{LOG(FATAL) << "Unsupported datatype class: H5T_ARRAY";}default:{LOG(FATAL) << "Datatype class unknown";}}vector<int> blob_dims(dims.size());for (int i = 0; i < dims.size(); ++i) {blob_dims[i] = dims[i];}blob->Reshape(blob_dims); }template <> void hdf5_load_nd_dataset<float>(hid_t file_id, const char* dataset_name_,int min_dim, int max_dim, Blob<float>* blob) {hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);herr_t status = H5LTread_dataset_float(file_id, dataset_name_, blob->mutable_cpu_data());CHECK_GE(status, 0) << "Failed to read float dataset " << dataset_name_; }template <> void hdf5_load_nd_dataset<double>(hid_t file_id, const char* dataset_name_,int min_dim, int max_dim, Blob<double>* blob) {hdf5_load_nd_dataset_helper(file_id, dataset_name_, min_dim, max_dim, blob);herr_t status = H5LTread_dataset_double(file_id, dataset_name_, blob->mutable_cpu_data());CHECK_GE(status, 0) << "Failed to read double dataset " << dataset_name_; }template <> void hdf5_save_nd_dataset<float>(const hid_t file_id, const string& dataset_name, const Blob<float>& blob,bool write_diff) {int num_axes = blob.num_axes();hsize_t *dims = new hsize_t[num_axes];for (int i = 0; i < num_axes; ++i) {dims[i] = blob.shape(i);}const float* data;if (write_diff) {data = blob.cpu_diff();} else {data = blob.cpu_data();}herr_t status = H5LTmake_dataset_float(file_id, dataset_name.c_str(), num_axes, dims, data);CHECK_GE(status, 0) << "Failed to make float dataset " << dataset_name;delete[] dims; }template <> void hdf5_save_nd_dataset<double>(hid_t file_id, const string& dataset_name, const Blob<double>& blob,bool write_diff) {int num_axes = blob.num_axes();hsize_t *dims = new hsize_t[num_axes];for (int i = 0; i < num_axes; ++i) {dims[i] = blob.shape(i);}const double* data;if (write_diff) {data = blob.cpu_diff();} else {data = blob.cpu_data();}herr_t status = H5LTmake_dataset_double(file_id, dataset_name.c_str(), num_axes, dims, data);CHECK_GE(status, 0) << "Failed to make double dataset " << dataset_name;delete[] dims; }string hdf5_load_string(hid_t loc_id, const string& dataset_name) {// Get size of datasetsize_t size;H5T_class_t class_;herr_t status = \H5LTget_dataset_info(loc_id, dataset_name.c_str(), NULL, &class_, &size);CHECK_GE(status, 0) << "Failed to get dataset info for " << dataset_name;char *buf = new char[size];status = H5LTread_dataset_string(loc_id, dataset_name.c_str(), buf);CHECK_GE(status, 0)<< "Failed to load int dataset with name " << dataset_name;string val(buf);delete[] buf;return val; }void hdf5_save_string(hid_t loc_id, const string& dataset_name,const string& s) {herr_t status = \H5LTmake_dataset_string(loc_id, dataset_name.c_str(), s.c_str());CHECK_GE(status, 0)<< "Failed to save string dataset with name " << dataset_name; }int hdf5_load_int(hid_t loc_id, const string& dataset_name) {int val;herr_t status = H5LTread_dataset_int(loc_id, dataset_name.c_str(), &val);CHECK_GE(status, 0)<< "Failed to load int dataset with name " << dataset_name;return val; }void hdf5_save_int(hid_t loc_id, const string& dataset_name, int i) {hsize_t one = 1;herr_t status = \H5LTmake_dataset_int(loc_id, dataset_name.c_str(), 1, &one, &i);CHECK_GE(status, 0)<< "Failed to save int dataset with name " << dataset_name; }int hdf5_get_num_links(hid_t loc_id) {H5G_info_t info;herr_t status = H5Gget_info(loc_id, &info);CHECK_GE(status, 0) << "Error while counting HDF5 links.";return info.nlinks; }string hdf5_get_name_by_idx(hid_t loc_id, int idx) {ssize_t str_size = H5Lget_name_by_idx(loc_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, idx, NULL, 0, H5P_DEFAULT);CHECK_GE(str_size, 0) << "Error retrieving HDF5 dataset at index " << idx;char *c_str = new char[str_size+1];ssize_t status = H5Lget_name_by_idx(loc_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, idx, c_str, str_size+1,H5P_DEFAULT);CHECK_GE(status, 0) << "Error retrieving HDF5 dataset at index " << idx;string result(c_str);delete[] c_str;return result; }} // namespace caffe編譯這兩個cpp試試,直接對著cpp右鍵編譯。
9.3 解決steam問題
出現(xiàn)了問題
錯誤 20 error C4703: 使用了可能未初始化的本地指針變量“stream” e:\caffe-original\src\caffe\layers\base_data_layer.cpp 101 1 caffe 解決方法解決方案資源管理器->caffe->右鍵屬性->配置屬性->C/C++->SDL檢查,選擇“否”
9.4 重新編譯
解決方案資源管理器->caffe->右鍵生成
9.5 最終問題
可以發(fā)現(xiàn)生成成功了,但是ctrl+F5卻發(fā)現(xiàn)缺少dll
 
好吧,dll一般來說可以在E:\caffe-original\3rdparty\bin下找到,但是可能不全,這里我提供一下下載地址
鏈接:http://pan.baidu.com/s/1jI7AoRk 密碼:9teo
 
宿舍筆記本出現(xiàn)了libgfortran-3.dll丟失問題,讀者電腦如果無此問題可以無需下載:
鏈接:http://pan.baidu.com/s/1bpr92hh 密碼:de8q
 
解壓以后得到的dll全部丟到C:\Windows\System32里面就行了,好像丟C:\Windows\SysWOW64這里面沒用貌似
然后ctrl+F5,看到了心滿意足的答案。。。。
 
總結
以上是生活随笔為你收集整理的【caffe-windows】Linux至Windows平台的caffe移植的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 微信亲属卡解绑不了是怎么回事?解绑亲属卡
- 下一篇: 微信亲属卡怎么领取?亲属卡领取不了是为什
