caffe_2016版本+windows+vs2013+matlab接口配置

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/input1991/article/details/53001283

因爲要寫一個resnet架構,同時擁有HyperColumn功能以及RNN或者LSTM架構的Detection框架。正好caffe最新版擁有了RNN、LSTM的模塊,同時支持最新的cudnn。基於這些要求,我就在happynear的基礎上,重新配置了一個屬於自己的windows版本的caffe。

1、首先是第三方庫的提供。我們就使用happynear提供的就可以了。這裏附上鍊接:https://github.com/happynear/caffe-windows。這裏說一個小插曲,以及最新的happynear配置的一個小bug。

     小插曲:我本來以爲最新版本的caffe一定是使用的最新的protobuf,然後我就上google的github上下載了protobuffer的最新版3.10.結果按照happynear的辦法配置是有問題的。

問題就在於happynear所有的第三庫編譯時採用的代碼生成採用的運行庫是多線程DLL,但protobuff的原始配置是多線程MTD,結果就會導致兩者不匹配,編譯連接階段就會出錯。

 小bug:這個是happynear在配置glog時按照原始步驟配置,就會導致缺失signal.cc這個文件,這樣在編譯時就會報錯。我會在文後附上如何配置libglog.lib。

2、在VS2013上配置自己的項目。

     首先,新建一個空項目,名字可以寫爲MatCaffe。爲了使篩選器更加便利一點,我們可以刪除系統默認的頭文件、系統等篩選器(除了外部依賴項不要刪之外),自己定義一些篩選器,這樣更加便利看。如圖所示:


   之後就可以往各個篩選器裏添加相應的文件,例如,cu篩選器裏就加入後綴名是cu的文件。這裏要注意,我們還要建立一個mexfunction.def文件,這個主要是用來定義mexw64文件的。裏面的內容如下所示:

LIBRARY    "caffe_"
EXPORTS
        mexFunction

同時要注意,在main篩選器里加入,caffe文件夾裏matlab\+caffe\private\裏的caffe_.cpp。這個是寫入了matlab接口的文件,這個很關鍵。同時可以受到啓發,我們以後想編譯任何關於caffe的cpp文件,都可以按照這個流程來,例如,我們想編譯caffe原生.exe文件,就把caffe.cpp放入到main裏,同時在生成項目裏改爲exe,即可。

然後,就是對項目的配置。首先是release版本還是debug版本,我這裏建議使用release版本即可。(因爲release也可以跨平臺調試,我們只要在項目的屬性\配置屬性\c\c++中調試信息格式裏改爲“用於編輯並繼續的程序數據庫”,同時修改優化改爲禁用,下面的全程序優化改爲否,在鏈接器\調試裏生成調試信息改爲是。)在主界面的右上角(標紅下拉列表),點擊配置管理器,增加x64的平臺。





配置完畢後,進入項目屬性頁。配置include、bin、lib文件的歸屬。首先是常規標籤下的,如圖所示:


VC++目錄:

其中,包含目錄下:F:\caffe-master\src;D:\Program Files\MATLAB\R2014a\extern\include;D:\Program Files\MATLAB\R2014a\toolbox\distcomp\gpu\extern\include;F:\caffe-master\include;F:\caffe-master\include\caffe\proto;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(CUDA_PATH)\include;F:\caffe-master\3rdParty\include;F:\caffe-master\3rdParty\include\boost;F:\caffe-master\3rdParty\include\gflags;F:\caffe-master\3rdParty\include\glog;F:\caffe-master\3rdParty\include\google;F:\caffe-master\3rdParty\include\hdf5;F:\caffe-master\3rdParty\include\leveldb;F:\caffe-master\3rdParty\include\openBLAS;F:\caffe-master\3rdParty\include\opencv;F:\caffe-master\3rdParty\include\opencv2;$(IncludePath)

庫目錄:F:\caffe-master\3rdParty\bin;D:\Program Files\MATLAB\R2014a\bin\win64;D:\Program Files\MATLAB\R2014a\extern\lib\win64\microsoft;$(OutDir);$(VCInstallDir)lib\amd64;$(VCInstallDir)atlmfc\lib\amd64;$(WindowsSDK_LibraryPath_x64);$(CUDA_PATH)\lib\$(Platform);F:\caffe-master\3rdParty\lib

這裏要注意,這些都是我的電腦目錄下,你們要按照自己的目錄來改。

C/C++中常規標籤下:


這裏的附加包含目錄:D:\Program Files\MATLAB\R2014a\extern\include;%(AdditionalIncludeDirectories)

爲了加快對c++文件的編譯速度,這裏可以把多處理器編譯打開。

預處理器標籤下:


這裏預處理定義中的內容是:

USE_LEVELDB;WIN32;_CRT_SECURE_NO_WARNINGS;_VARIADIC_MAX=10;_WINDLL;NDEBUG;_CONSOLE;BUILD_MEX_INTERFACE;USE_CUDNN;%(PreprocessorDefinitions)

如果你要使用CUDNN,就加上USE_CUDNN

代碼生成標籤下:


在是cuda C/C++的配置。 到這裏,應該是沒有這個選項的。我們此時關閉屬性頁界面。右擊項目,在下拉列表裏找到生成依賴項,選擇生成自定義,在如圖裏選擇CUDA7.5


這之後,在屬性頁裏就會出現cuda C++的選項。

在Common項裏:


在Device裏:

其中,代碼生成項裏的數字按照自己顯卡型號對應的數值來填寫。我的顯卡是titan black X 我就寫30、35 其實可以寫55但是我使用55會發現報錯,這裏暫時需要研究。

最後,鏈接器裏常規選項卡:


附加庫目錄裏:D:\Program Files\MATLAB\R2014a\extern\lib\win64\microsoft;F:\caffe-master\3rdParty\lib;F:\caffe-master\3rdParty\bin;%(AdditionalLibraryDirectories)

此外在輸入選項:


附加依賴庫:libmx.lib;libmex.lib;libmat.lib;gpu.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib;cublas.lib;cuda.lib;curand.lib;cudart.lib;gflags.lib;libglog.lib;opencv_world300.lib;libopenblas.dll.a;leveldb.lib;lmdb.lib;hdf5.lib;hdf5_hl_cpp.lib;hdf5_cpp.lib;hdf5_f90cstub.lib;hdf5_fortran.lib;hdf5_hl.lib;hdf5_hl_f90cstub.lib;hdf5_hl_fortran.lib;hdf5_tools.lib;szip.lib;zlib.lib;cudnn.lib;libprotobuf.lib;libprotoc.lib;%(AdditionalDependencies)

這是就結束上述填寫。

之後需要用protobuf生成在src裏的proto文件,把第三方庫裏的protoc.exe放到src\proto文件中去,寫一個Gen.bat。具體代碼我寫在下面:

pushd %~dp0

echo "copying .proto and generated .cc and .h"

protoc caffe.proto --cpp_out=.\ 
copy caffe.pb.h F:\caffe-master\include\caffe\proto\caffe.pb.h

::protoc caffe.proto --matlab_out=.\
pause

popd
注意,具體路徑改成你自己的。

右擊生成,等待。

此時會出現幾個問題:

1、在signal_handler.cpp裏,代碼需要修改成我寫在下面的,原因是註釋掉的代碼都是linux裏的,windows沒有這些。

#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) {
		  //case SIGHUP://there is no SIGHUP in windows
		  //  got_sighup = true;
		  //  break;
	  case SIGBREAK:
		  got_sighup = true;
		  break;
	  case 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;

    // Setup the handler
	if (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.";
	}
  }

  // Set the signal handlers to the default.
  void UnhookHandler() {
    if (already_hooked_up) {
		if (signal(SIGBREAK, SIG_DFL) == SIG_ERR) {
			LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
		}
		if (signal(SIGINT, SIG_DFL) == SIG_ERR) {
			LOG(FATAL) << "Cannot uninstall SIGINT handler.";
		}
		already_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;
  }
}  // namespace

namespace 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

2、io.hpp裏增加頭文件:#include <io.h>

3、在common,cpp裏增加頭文件#include <process.h>,同時修改第36行的pid後的代碼,改爲pid = _getpid(); 原因在於windows的線程頭文件不支持linux的。

4、我使用的是CUDNN V5版本。但是在caffe提供的cudnn.hpp頭文件裏,windows不支持轉換。網上有幾種解決方法,我自己認爲應該把這句話註釋掉:


5、我之前提過,happynear的一個小bug。這裏提供解決辦法。

下載glog 版本的文件,解壓後,用vs打開裏面的sln文件,將 signalhandler.cc 文件加入到src裏,編譯後生成的libglog代替3rdparty即可。

6、這個問題很重要。就是在編譯好後,將caffe_.mexw64放入相應的文件夾後,總是會有一定機率,報錯說找不到這個文件,這個原因很簡單,就是由於我們的第三方庫,只是在文件的當前下編譯的,沒有指定到系統路徑下去。所以要用dependencywalker,去找一下我們的生成文件,是不是有些dll文件漏了。關於windows一律不看,就只看我們編譯過的。

祝你成功。有問題可以在我的博客下留言交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章