Windows下基于CMake编译配置Caffe/SSD
by ChrisZZ, imzhuo@foxmail.com
简要说明
最近需要在Windows下开发,在Windows下基于CMake编译配置了Caffe/PyCaffe,记录一下。
特点:
- 可以修改caffe依赖库存放目录
- 可以指定opencv版本
- 可以用于1080Ti等显卡的正确编译
- 给出了基于CMake调用Caffe.lib的例子
- 使用caffe.lib的项目中也可调试到caffe源码中
- 支持caffe-SSD,包括boost regex报错的正确处理
- 包括指定python可执行文件路径和多个pycaffe切换
[TOC]
1. 环境说明
系统: Win7/Win10 编译器:Visual Studio 2013 构建器:CMake 3.13 Python: python2.7,用anaconda装的。注意python.exe所在目录放到系统PATH环境变量中。 CUDA: 9.2 (可选) CuDNN:7.0(可选) 终端: cmd窗口 Caffe源码: 官方Caffe的windows分支 。后续考虑SSD代码
2. 配置官方Caffe
2.1 下载Caffe源码和Windows依赖包
Caffe源码 进cmd敲:
d:
cd work
git clone https://github.com/BVLC/caffe caffe-BVLC
cd caffe-BVLC
git checkout -b windows origin/windows
或者从官方网页 下载压缩包。
Caffe的Windows依赖包 源码中cmake脚本里会自动下载依赖包,但为了避免cmake下载遭遇网络问题,以及修改配置项的方便,根据scripts/download_prebuilt_dependencies.py
手动下载依赖文件: (如果你网路还可以,那么忽略这一小节,脚本会自动下载)
WIN_DEPENDENCIES_URLS = {
('v120', '2.7'):("https://github.com/willyd/caffe-builder/releases/download/v1.1.0/libraries_v120_x64_py27_1.1.0.tar.bz2",
"ba833d86d19b162a04d68b09b06df5e0dad947d4"),
('v140', '2.7'):("https://github.com/willyd/caffe-builder/releases/download/v1.1.0/libraries_v140_x64_py27_1.1.0.tar.bz2",
"17eecb095bd3b0774a87a38624a77ce35e497cd2"),
('v140', '3.5'):("https://github.com/willyd/caffe-builder/releases/download/v1.1.0/libraries_v140_x64_py35_1.1.0.tar.bz2",
"f060403fd1a7448d866d27c0e5b7dced39c0a607"),
}
依赖包存放目录:
-
默认方式下,放到
C:\Users\<UserName>\.caffe\dependencies\download\
目录。 -
如果怕C盘空间占用,也可以在别的目录存放依赖包,后续CMake阶段指定
-DCAFFE_DEPENDENCIES_ROOT_DIR=xxx
即可,例如我放到了D:/lib/caffe_windows_deps/download/libraries_v120_x64_py27_1.1.0.tar.bz2
。 -
为了方便讨论,我们把
C:\Users\<UserName>\.caffe\dependencies
目录或D:/lib/caffe_windows_deps/
记做CAFFE_DEPENDENCIES_ROOT_DIR
2.2 修改cuda配置(可选)
cpu模式编译的调过这一小节。
cmake/Cuda.cmake
,第7行,去掉20和21的算力支持(否则新版cuda会报错),改成:
set(Caffe_known_gpu_archs "30 35 50 52 60 61")
cmake/Cuda.cmake
,第40行左右,手动设定nvcc架构版本,例如我是1080Ti显卡,使用6.1:
# if(__nvcc_res EQUAL 0)
# # nvcc outputs text containing line breaks when building with MSVC.
# # The line below prevents CMake from inserting a variable with line
# # breaks in the cache
# string(REGEX MATCH "([1-9].[0-9])" __nvcc_out "${__nvcc_out}")
# string(REPLACE "2.1" "2.1(2.0)" __nvcc_out "${__nvcc_out}")
# set(CUDA_gpu_detect_output ${__nvcc_out} CACHE INTERNAL "Returned GPU architetures from caffe_detect_gpus tool" FORCE)
# endif()
set(__nvcc_out "6.1")
(为啥这里的自动获取计算能力版本有问题?大概是字符编码导致输出很多警告,警告信息影响了正确结果的获取) (每个Nvidia显卡型号对应的compute ability表见:https://blog.csdn.net/real_myth/article/details/44308169)
CAFFE_DEPENDENCIES_ROOT_DIR
目录下的libraries_v120_x64_py27_1.1.0\libraries\include\boost-1_61\boost\config\compiler\nvcc.hpp:注释掉最后三行:
#if !defined(__CUDACC_VER__) || (__CUDACC_VER__ < 70500)
# define BOOST_NO_CXX11_VARIADIC_TEMPLATES
#endif
(原因:cuda7.5以后,__CUDACC_VER__
被废除,应当使用__CUDACC_VER_MAJOR_
和__CUDACC_VER_MINOR__
等,如果不注释掉,会报错:
libraries_v140_x64_py35_1.1.0/libraries/include/boost-1_61\boost/config/compiler/nv cc.hpp(22): fatal error C1017: invalid integer constant expression
2.3 使用官方提供的步骤编译
这种方式下,调用的是.\scripts\build_win.cmd
脚本,CMake依赖包必须放到C:\Users\<UserName>\.caffe\dependencies\download\
目录。缺点是: 1.浪费C盘空间;
2.定制项被写死了,不灵活。 例如opencv版本被限定死了为3.1。例如imread读取jpg在[3.0.0, 3.4.1]
版本区间内的结果是一种,在2.4.x和>=3.4.2版本中的结果是另一种,输入数据的不一致会导致卷积网计算结果不一致。
因此,这种方式主要适合小白入门用用,实际项目开发中不方便。其具体操作为:
回到刚才的cmd,继续敲(#后面是注释,不用敲进去)
set PATH=%PATH%;C:\Windows\Microsoft.NET\Framework\v4.0.30319 #临时添加MSBuild.exe的路径
set MSVC_VERSION=12 #12对应到我用的vs2013. build_win.cmd中默认为vs2015,也就是13
set WITH_NINJA=0 # 不使用ninja,用visual studio。因为编译中间出了问题在vs里面好查看。
# set CPU_ONLY=1 # 如果没有GPU,或者就是想编译CPU版本,则开启
set RUN_INSTALL=1 #安装。默认走的非appveyor分支,RUN_INSTALL为0,这不是坑人么。
.\scripts\build_win.cmd # 前面我写明的修改项都完成后,本行会顺利执行。
编译期间出现“锟斤拷”的乱码可以忽略,最后:
build_win.cmd
脚本中的设定,默认编译的是release模式的。修改脚本,或者干脆打开cmake生成的build/Caffe.sln工程来编译debug版本。
2.4 手动CMake构建,使用官方依赖包
.\scripts\build_win.cmd
脚本包含了太多内容,对于本地开发来说没有用还干扰视线。
caffe根目录下创建编辑compile-xxx.bat
脚本,手动调用CMake,简化流程。
vs2013, cpu模式,使用官方依赖包 compile-vs2013-cpu.bat
set BUILD_DIR=build-vs2013
if exist %BUILD_DIR% rd /s /q %BUILD_DIR%
md %BUILD_DIR%
cd %BUILD_DIR%
set DEP_ROOT=F:/zhangzhuo/lib/caffe_windows_deps
cmake -G "Visual Studio 12 2013 Win64" ^
-DCAFFE_DEPENDENCIES_ROOT_DIR=%DEP_ROOT% ^
-DCPU_ONLY=ON ^
-DBLAS=Open ^
..
cd ..
vs2013, 手工指定opencv目录、动态库 经过测试,VS2015如果指定opencv为3.3.0或3.4.5版本,debug模式下编译tools这个target会提示cv::flip()和cv::resize()等函数为无法解析的符号,如果不指定opencv则其实使用的是opencv3.1.0,或者手动指定opencv为3.1.0,都没有这个问题。opencv的版本仍然是个问题。:
1>------ 已启动生成: 项目: caffe.bin, 配置: Debug x64 ------
1> 正在创建库 E:/toy/caffe/build/vs2015-x64-opencv330/lib/Debug/caffe-d.bin.lib 和对象 E:/toy/caffe/build/vs2015-x64-opencv330/lib/Debug/caffe-d.bin.exp
1>caffe-d.lib(window_data_layer.obj) : error LNK2019: 无法解析的外部符号 "void __cdecl cv::flip(class cv::_InputArray const &,class cv::_OutputArray const &,int)" (?flip@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@H@Z),该符号在函数 "protected: virtual void __cdecl caffe::WindowDataLayer<float>::load_batch(class caffe::Batch<float> *)" (?load_batch@?$WindowDataLayer@M@caffe@@MEAAXPEAV?$Batch@M@2@@Z) 中被引用
1>caffe-d.lib(window_data_layer.obj) : error LNK2019: 无法解析的外部符号 "void __cdecl cv::resize(class cv::_InputArray const &,class cv::_OutputArray const &,class cv::Size_<int>,double,double,int)" (?resize@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@V?$Size_@H@1@NNH@Z),该符号在函数 "protected: virtual void __cdecl caffe::WindowDataLayer<float>::load_batch(class caffe::Batch<float> *)" (?load_batch@?$WindowDataLayer@M@caffe@@MEAAXPEAV?$Batch@M@2@@Z) 中被引用
1>caffe-d.lib(io.obj) : error LNK2001: 无法解析的外部符号 "void __cdecl cv::resize(class cv::_InputArray const &,class cv::_OutputArray const &,class cv::Size_<int>,double,double,int)" (?resize@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@V?$Size_@H@1@NNH@Z)
1>caffe-d.lib(io.obj) : error LNK2019: 无法解析的外部符号 "class cv::Mat __cdecl cv::imdecode(class cv::_InputArray const &,int)" (?imdecode@cv@@YA?AVMat@1@AEBV_InputArray@1@H@Z),该符号在函数 "class cv::Mat __cdecl caffe::DecodeDatumToCVMatNative(class caffe::Datum const &)" (?DecodeDatumToCVMatNative@caffe@@YA?AVMat@cv@@AEBVDatum@1@@Z) 中被引用
1>caffe-d.lib(io.obj) : error LNK2019: 无法解析的外部符号 "bool __cdecl cv::imencode(class cv::String const &,class cv::_InputArray const &,class std::vector<unsigned char,class std::allocator<unsigned char> > &,class std::vector<int,class std::allocator<int> > const &)" (?imencode@cv@@YA_NAEBVString@1@AEBV_InputArray@1@AEAV?$vector@EV?$allocator@E@std@@@std@@AEBV?$vector@HV?$allocator@H@std@@@5@@Z),该符号在函数 "bool __cdecl caffe::ReadImageToDatum(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int,int,int,bool,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class caffe::Datum *)" (?ReadImageToDatum@caffe@@YA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@HHH_N0PEAVDatum@1@@Z) 中被引用
1>E:\toy\caffe\build\vs2015-x64-opencv330\tools\Debug\caffe-d.exe : fatal error LNK1120: 4 个无法解析的外部命令
========== 生成: 成功 0 个,失败 1 个,最新 3 个,跳过 0 个 ==========
opencv249的windows pack同时提供动态共享库和静态库,默认静态库。编译caffe需要共享库,需要手动开启:OpenCV_STATIC=OFF
。
set BUILD_DIR=build-vs2013-opencv249
if exist %BUILD_DIR% rd /s /q %BUILD_DIR%
md %BUILD_DIR%
cd %BUILD_DIR%
set DEP_ROOT=D:/lib/caffe_windows_deps
set OpenCV_DIR=D:/lib/opencv_249/build
cmake -G "Visual Studio 12 2013 Win64" ^
-DCAFFE_DEPENDENCIES_ROOT_DIR=%DEP_ROOT% ^
-DCPU_ONLY=ON ^
-DBLAS=Open ^
-DOpenCV_DIR=%OpenCV_DIR% ^
-DOpenCV_STATIC=OFF ^
..
cd ..
opencv310windows pack只提供了动态库,所以不用指定-DOpenCV_STATIC=OFF
set BUILD_DIR=build-vs2013-opencv310
if exist %BUILD_DIR% rd /s /q %BUILD_DIR%
md %BUILD_DIR%
cd %BUILD_DIR%
set DEP_ROOT=F:/zhangzhuo/lib/caffe_windows_deps
set OpenCV_DIR=F:/zhangzhuo/lib/opencv_310/build
cmake -G "Visual Studio 12 2013 Win64" ^
-DCAFFE_DEPENDENCIES_ROOT_DIR=%DEP_ROOT% ^
-DCPU_ONLY=ON ^
-DBLAS=Open ^
-DOpenCV_DIR=%OpenCV_DIR% ^
..
cd ..
执行完compile-xxx.bat
脚本后,打开生成的.sln文件,分别Release和Debug模式,执行CMakeTargets/INSTALL
。
2.5 python版本问题
现在通常安装anaconda或miniconda来安装python、管理python环境,然后用pip安装下载python包。往往系统存在python2和python3两个版本。装两个Anaconda不如装一个Anaconda然后再创建一个虚拟环境方便。编译Pycaffe需要指定python版本,由于我依赖的opencv是2.4.9,其cv2.pyd只支持python2.7,因而pycaffe也只能支持python2.7。需要指定Python.exe路径以免找不到或找错成python3的exe:在执行cmake时指定-DPYTHON_EXECUTABLE=xxxx
,例如:
set BUILD_DIR=vs2013-x64
set BUILD_PLATFORM=x64
set BUILD_COMPILER=vc12
if exist %BUILD_DIR% rd /s /q %BUILD_DIR%
md %BUILD_DIR%
cd %BUILD_DIR%
set DEP_ROOT=F:/zhangzhuo/lib/caffe_windows_deps
set OpenCV_DIR=D:/lib/opencv/2.4.9
set PYTHON_DIR=e:/soft/Miniconda3/envs/py27
set PYTHON_EXECUTABLE=%PYTHON_DIR%/python.exe
set INSTALL_PREFIX=D:/lib/caffe/bvlc
cmake -G "Visual Studio 12 2013 Win64" ^
-DCAFFE_DEPENDENCIES_ROOT_DIR=%DEP_ROOT% ^
-DCPU_ONLY=ON ^
-DBLAS=Open ^
-DOpenCV_DIR=%OpenCV_DIR% ^
-DOpenCV_STATIC=OFF ^
-DPYTHON_EXECUTABLE=%PYTHON_EXECUTABLE% ^
-DCMAKE_INSTALL_PREFIX=D:/lib/caffe/bvlc/%BUILD_PLATFORM%/%BUILD_COMPILER% ^
../..
cd ..
2.6 配置pycaffe
如果系统只有一个pycaffe版本 方便点,把build/install/python/caffe文件夹,拷贝到D:\soft\Anaconda2\Lib下。以后再开VSCode时,import caffe
再也不会报红了。
系统有多个版本的pycaffe
#coding: utf-8
import sys
sys.path.insert(0, '/path/to/caffe/build/pycaffe')
测试一下:import caffe
,可能会出现缺少protobuf的情况:
E:\lib\caffe\bvlc\x64\vc14\python>python
Python 3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import caffe
Failed to include caffe_pb2, things might go wrong!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "E:\lib\caffe\bvlc\x64\vc14\python\caffe\__init__.py", line 4, in <module>
from .proto.caffe_pb2 import TRAIN, TEST
File "E:\lib\caffe\bvlc\x64\vc14\python\caffe\proto\caffe_pb2.py", line 6, in <module>
from google.protobuf.internal import enum_type_wrapper
ImportError: No module named 'google'
解决:
pip install protobuf
<hr/>
3. 配置Caffe-SSD
目标检测算法SSD,其论文作者官方代码是基于Caffe的魔改版本,我称其为Caffe-SSD。在Windows上基于CMake编译Caffe-SSD,步骤与Caffe-BVLC的windows分支思路一致,都需要排查编译错误、修改少量源码从而编译成功。在前面一步中成功的在Windows下基于CMake和官方依赖包进行构建的基础上,编译配置Caffe-SSD不难,步骤如下:
3.1 下载代码、依赖项
cd /d/work
git clone https://github.com/weiliu89/caffe caffe-SSD
cd caffe-SSD
git checkout -b ssd origin/ssd
依赖包的话,使用Caffe-BVLC官方windows分支的依赖包,下载地址、存放目录见前一节。
3.2 替换CMake脚本
鉴于Caffe-BVLC的windows分支已经为windows适配做了很多,这里直接拿来用。从Caffe-BVLC的windows分支里,拷贝并替换下列文件到Caffe-SSD中:
- 整个cmake子目录
- 根目录CMakeLists.txt
- src/caffe/CMakeLists.txt
- src/gtest/CMakeLists.txt
- tools/CMakeLists.txt
- python/CMakeLists.txt
3.3 编写编译脚本
参考本文 2.4小节 "手动CMake构建,使用官方依赖包"。
3.4 CPU编译相关的报错和解决办法
我遇到的编译报错和解决办法如下。如果你希望省时间,那么先按照我的解决方案改一遍再编译;如果你希望体验自行修改Caffe-SSD以在windows下成功编译的快感,不妨先编译,遇到报错按照我下面的方法来修改。(个人还是比较推崇reproducable的modification的)
D:\work\caffe-SSD\src\caffe\common.cpp(36): error C3861: “getpid”: 找不到标识符
解决办法:common.cpp添加
#ifdef _MSC_VER
#include <process.h>
#endif
fatal error C1083: 无法打开包括文件: “gtest/gtest.h”: No such file or directory
解决办法:net.cpp,注释掉:
//#include "caffe/test/test_caffe_main.hpp"
error C3861: “snprintf”: 找不到标识符
解决办法:bbox_util.hpp添加:
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
error C3861: “mkdir”: 找不到标识符
解决办法:在db_lmdb.cpp头部添加:
#if defined(_MSC_VER)
#include <direct.h>
#define mkdir(X, Y) _mkdir(X)
#endif
src\caffe\util\hdf5.cpp(34): error C2360: “occurrences_32”的初始化操作由“case”标签跳过
原因:使用的LOG_FIRST_N
宏,逐层展开后有定义变量。在switch-case的case后如果定义了变量,应当使用花括号包起来。 解决办法: src/caffe/util/hdf5.cpp
中找到LOG_FIRST_N
宏,使用花括号包裹case后的语句块:
case H5T_INTEGER:
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_INTEGER";
break;
case H5T_INTEGER:
{
LOG_FIRST_N(INFO, 1) << "Datatype class: H5T_INTEGER";
}
break;
src\caffe\util\io.cpp(44): error C3861: “open”: 找不到标识符
解决办法:src/caffe/util/io.cpp
,#include <fcntl.h>
后添加:
#if defined(_MSC_VER)
#include <io.h>
#endif
src\caffe\util\signal_handler.cpp(16): error C2065: “SIGHUP”: 未声明的标识符 解决办法:src/caffe/util/signal_handler.cpp
,16行开始几行,原有的:
case SIGHUP:
got_sighup = true;
break;
修改为:
#ifdef _MSC_VER
case SIGBREAK: // there is no SIGHUP in windows, take SIGBREAK instead.
got_sighup = true;
break;
#else
case SIGHUP:
got_sighup = true;
break;
#endif
src\caffe\util\signal_handler.cpp(37): error C2079: “sa”使用未定义的 struct“`anonymous-namespace'::HookupHandler::sigaction”
解决办法:src/caffe/util/signal_handler.cpp
,37行开始几行,原有的:
struct sigaction sa;
// Setup the handler
sa.sa_handler = &handle_signal;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot install SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot install SIGINT handler.";
}
修改为:
#ifdef _MSC_VER
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.";
}
#else
struct sigaction sa;
// Setup the handler
sa.sa_handler = &handle_signal;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot install SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot install SIGINT handler.";
}
#endif
同样的,UnhookHandler
函数也做类似修改:原来的:
struct sigaction sa;
// Setup the sighub handler
sa.sa_handler = SIG_DFL;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot uninstall SIGINT handler.";
}
修改为:
#ifdef _MSC_VER
if (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.";
}
#else
struct sigaction sa;
// Setup the sighub handler
sa.sa_handler = SIG_DFL;
// Restart the system call, if at all possible
sa.sa_flags = SA_RESTART;
// Block every signal during the handler
sigfillset(&sa.sa_mask);
// Intercept SIGHUP and SIGINT
if (sigaction(SIGHUP, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot uninstall SIGHUP handler.";
}
if (sigaction(SIGINT, &sa, NULL) == -1) {
LOG(FATAL) << "Cannot uninstall SIGINT handler.";
}
#endif
LINK : fatal error LNK1149: 输出文件名匹配输入文件名“D:\work\caffe-SSD\build-vs2013-opencv249\lib\Debug\caffe-d.lib”
报错的意思是,目标输出的文件与输入的文件重名了。 解决办法:使用caffe-BVLC-windows/tools/CMakeLists.txt进行替换
common.obj) : error LNK2019: 无法解析的外部符号 "__declspec(dllimport) void __cdecl google::InstallFailureSignalHandler(void 解决办法: common.cpp
,56行左右,原来的:
::google::InstallFailureSignalHandler();
修改为:
#if !defined(_MSC_VER)
::google::InstallFailureSignalHandler();
#endif
LINK : fatal error LNK1104: 无法打开文件“python27_d.lib” 原因:间接的包含了pyconfig.h
(anaconda安装路径下的),这个文件里面有这样几行:
# ifdef _DEBUG
# pragma comment(lib,"python27_d.lib")
# else
# pragma comment(lib,"python27.lib")
# endif /* _DEBUG */
看到网上有人说“修改pyconfig.h”,显然这没有必要也不正确。
解决方法: _caffe.cpp
,去掉第一行的:
#include <Python.h> // NOLINT(build/include_alpha)
Python.h
会间接的包含pyconfig.h
导致引入python27_d.lib
。
如果你是VS2015,那么很可能还需要在_caffe.cpp
中,#define BP_REGISTER_SHARED_PTR_TO_PYTHON(PTR)
后面,添加这个:
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 190024210)
// Workaround for VS 2015 Update 3 which breaks boost python
// See: http://stackoverflow.com/questions/38261530/unresolved-external-symbols-since-visual-studio-2015-update-3-boost-python-link
// and https://msdn.microsoft.com/vs-knownissues/vs2015-update3
#define BP_GET_POINTER(cls) \
namespace boost { \
template <> \
const volatile caffe::cls * \
get_pointer(const volatile caffe::cls *c) { \
return c; \
} \
}
#define BP_GET_POINTER_T(cls, dtype) BP_GET_POINTER(cls<dtype>)
// forward declare the NCCL class
// in case we are not using NCCL
namespace caffe {
template <typename Dtype> class NCCL;
}
BP_GET_POINTER_T(Net, float);
BP_GET_POINTER_T(Layer, float);
BP_GET_POINTER_T(Solver, float);
BP_GET_POINTER_T(SGDSolver, float);
BP_GET_POINTER_T(NesterovSolver, float);
BP_GET_POINTER_T(AdaGradSolver, float);
BP_GET_POINTER_T(RMSPropSolver, float);
BP_GET_POINTER_T(AdaDeltaSolver, float);
BP_GET_POINTER_T(AdamSolver, float);
BP_GET_POINTER_T(NCCL, float);
BP_GET_POINTER(Timer);
#endif
3.5 GPU(cuda)编译相关的报错和解决办法
src/caffe/layers/bnll_layer.cu(35): error : identifier "caffe::kBNLL_THRESHOLD" is undefined in device code 解决办法: 修改kBNLL_THRESHOLD
的定义,从:
const float kBNLL_THRESHOLD = 50.;
修改为
#ifdef _MSC_VER
__constant__ float kBNLL_THRESHOLD = 50.;
#else
const float kBNLL_THRESHOLD = 50.;
#endif
**libraries_v120_x64_py27_1.1.0\libraries\include\boost-1_61\boost/regex/v4/perl_matcher.hpp(362): error C2292: 'boost::re_detail_106100::perl_matcher<const char ,std::allocator<boost::sub_match<const char >>,boost::regex_traits<char,boost::w32_regex_traits<charT>>>': best case inheritance representation: 'virtual_inheritance' declared but 'single_inheritance' required
这个错误,网上绝大多数博客给出的解决办法是“注释掉regex和rv相关的代码”。但我觉得这就像是“干掉了提出问题的人”,过于粗暴。我的解决办法: 在caffe windows依赖包中修改libraries_v120_x64_py27_1.1.0\libraries\include\boost-1_61\boost\regex\v4\perl_matcher.hpp
文件: #include <boost/regex/v4/iterator_category.hpp>
后,添加:
#ifdef _MSC_VER
#pragma pointers_to_members( full_generality, single_inheritance )
#endif
解释一下:
在 MSDN上对于
pointer_to_memmers
的解释 提到,其语法为:#pragma pointers_to_members( pointer-declaration, [most-general-representation] )
并且,
most-general-representation
的默认值为best_case
。 通过google检索#pragma pointers_to_members
发现,这个宏应该是cl.exe特有的,gcc的话我没有找到,llvm的话似乎有人提issue要去实现。
以上是我遇到的编译报错和解决方法。全部修改掉后,Visual Studio里分别在Debug和Release模式下执行"CMakeTargets/INSTALL"这一目标,完成编译和安装。
<hr/>
4. 在C++项目中使用Caffe
比如不想在原始的caffe工程中添加自己的代码,这样保持了caffe自身代码不变,只要在自己的使用了caffe库的工程中正确设定,就独立的开发自己的代码了。
假设自己的这个工程也是基于cmake构建,最关键的一点是,正确配置了前面编译的caffe的依赖项,而不是自己再去重新配一遍..
注意使用caffe-builder-config.cmake
文件
set(CAFFE_DEPENDENCIES_DIR "C:/Users/Administrator/.caffe/dependencies/libraries_v120_x64_py27_1.1.0")
include(${CAFFE_DEPENDENCIES_DIR}/libraries/caffe-builder-config.cmake)
注意opencv版本一致 编译Caffe用的opencv版本,和需要使用caffe.lib的项目中的opencv版本,应当保持一致。
样例CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(caffe_cpp_play)
set (CMAKE_CXX_STANDARD 11)
#--- caffe dependencies ---
#set(CAFFE_DEPENDENCIES_DIR "D:/work/caffe_windows_deps/libraries_v120_x64_py27_1.1.0")
set(CAFFE_DEPENDENCIES_DIR "F:/zhangzhuo/lib/caffe_windows_deps/libraries_v120_x64_py27_1.1.0")
include(${CAFFE_DEPENDENCIES_DIR}/libraries/caffe-builder-config.cmake)
set(PROJ_LINKER_LIBS "")
set(PROJ_INCLUDE_DIR "")
set(CMAKE_VERBOSE_MAKEFILE OFF)
# --- options ---
option(use_opencv "Use OpenCV?" ON)
option(use_cuda "Use CUDA?" OFF)
option(use_glog "Use Glog?" ON)
option(use_gflags "Use GFlags?" ON)
option(use_protobuf "Use Protobuf?" ON)
option(use_caffe "Use Caffe?" ON)
option(use_boost "Use Boost?" ON)
# --- pthread ---
# windows does not need it
#find_package(Threads REQUIRED)
#message("CMAKE_THREAD_LIBS_INIT: ${CMAKE_THREAD_LIBS_INIT}")
# --- opencv ---
if (use_opencv)
set(OpenCV_DIR "D:/lib/opencv/2.4.9")
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
list(APPEND PROJ_LINKER_LIBS ${OpenCV_LIBS})
endif()
# --- cuda ---
if (use_cuda)
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(CUDA_DIR "$ENV{CUDA_PATH}")
else()
set(CUDA_DIR "/usr/local/cuda")
endif()
find_package(CUDA REQUIRED)
include_directories(${CUDA_DIR}/include)
endif()
#--- Glog & GFlags & Protobuf ---
if (use_glog)
find_package (Glog REQUIRED) #OK
list(APPEND PROJ_LINKER_LIBS ${GLOG_LIBRARIES})
endif()
if (use_gflags)
find_package (GFlags REQUIRED) #OK
list(APPEND PROJ_LINKER_LIBS ${GFLAGS_LIBRARIES})
endif()
if (use_protobuf)
find_package(Protobuf REQUIRED) #OK
list(APPEND PROJ_LINKER_LIBS ${PROTOBUF_LIBRARIES})
endif()
#--- caffe ---
if (use_caffe)
# set Caffe_DIR to the directory that contains 'CaffeConfig.cmake'
#list(APPEND CMAKE_PREFIX_PATH "D:/work/caffe-BVLC/build-vs2013-opencv249-cuda/install")
set(Caffe_ROOT "D:/lib/caffe/bvlc/x64/vc12")
set(Caffe_DIR "${Caffe_ROOT}/share/Caffe")
find_package (Caffe REQUIRED)
message(STATUS "Caffe library status:")
message(STATUS " Caffe_DIR: ${Caffe_DIR}")
message(STATUS " Caffe_LIBRARIES: ${Caffe_LIBRARIES}")
#message(STATUS " CAFFE_INCLUDE_DIRS: ${Caffe_INCLUDE_DIRS}")
list(APPEND PROJ_LINKER_LIBS ${Caffe_LIBRARIES})
endif()
# --- boost ---
if (use_boost)
find_package(Boost 1.54 REQUIRED COMPONENTS system thread filesystem regex)
message(STATUS "Boost library status:")
message(STATUS " Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
message(STATUS " Boost_LIBRARIES: ${Boost_LIBRARIES}")
list(APPEND PROJ_LINKER_LIBS ${Boost_LIBRARIES})
endif()
# 添加头文件搜索路径
#include_directories(${Caffe_INCLUDE_DIRS})
# 添加可执行文件
add_executable(net_demo src/classification.cpp)
# Link your application with OpenCV libraries
target_link_libraries(net_demo ${PROJ_LINKER_LIBS})
完整的例子见: https://github.com/zchrissirhcz/z-toolbox/tree/master/cmake_examples/caffe_cpp_play_better
值得注意的是:前面编译出来的caffe-BVLC的,其构建类型要与自己的工程一致,也就是debug搭配debug,release搭配release。我这里实验发现debug模式下个别库名字不对,缺少“d”或者"-d",在Visual Studio里手动改一下就可以了。
5. reference
6. changelog
2018-08-24 23:35:41 创建博客,支持Caffe-BVLC Windows分支的编译 2019-04-06 11:58:08 增加”指定opencv版本和依赖包路径“相关内容 2019-04-07 14:49:58 增加Caffe-SSD的Windows CPU编译 2019-04-12 09:13:11 增加Caffe-SSD的Windows GPU编译 2019-07-02 16:23:22 增加指定python可执行路径
来源:oschina
链接:https://my.oschina.net/u/4381479/blog/3851829