Python2已近生命终点,然而 Caffe 却受硬件厂商的拥护。于是我们尝试在 Python3 环境下编译 Caffe。
Caffe Python 3.7 安装
对于 Python 3.3+而言,需要搭配 Protobuf 3。因此不再需要 apt 安装libprotobuf-dev
和protobuf-compiler
,这二者是 Protobuf 2 的。
首先修改 CMakeLists.txt
#set(python_version "2" CACHE STRING "Specify which Python version to use")
set(python_version "3" CACHE STRING "Specify which Python version to use")
编译会遇到
protobuf-3.6.0之后的版本需要 C++11支持。
# ---[ Flags
if(UNIX OR APPLE)
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -std=c++11")
endif()
如果使用 OpenCV3+,还会遇到
需要为 Caffe 修改过时的宏定义。此山放过,则会遇到
libboost_python.so: undefined reference to `PyString_Size'
原因是 Caffe 的 Dependencies.cmake 链接了 boost 库的 python2 模块。这是本文关注的重点。使用 Makefile.config 文件进行配置的则不会出现此问题。
$ ll /usr/lib/x86_64-linux-gnu/libboost_python*.so
lrwxrwxrwx 1 root root 30 6月 14 2016 /usr/lib/x86_64-linux-gnu/libboost_python3-py35.so -> libboost_python3-py35.so.1.58.0
lrwxrwxrwx 1 root root 30 6月 14 2016 /usr/lib/x86_64-linux-gnu/libboost_python-py27.so -> libboost_python-py27.so.1.58.0
lrwxrwxrwx 1 root root 30 6月 14 2016 /usr/lib/x86_64-linux-gnu/libboost_python.so -> libboost_python2.7.so
一个较为简单的方法是手动创建链接:
$ cd /usr/lib/x86_64-linux-gnu
$ sudo ln -s libboost_python-py35.so libboost_python3.so
Dependencies.cmake
下面分析问题的原因。Dependencies.cmake 中为 Python 的依赖库进行配置。
VERSION_LESS 比较版本字符串的值。
如果指定 Python3,首先查找匹配的 boost python 实现。
string 的REGEX REPLACE
尽可能地多次匹配正则表达式,并用replace_expression
取代输出中的匹配项。在匹配之前连接所有<input>
参数。替换表达式可以使用\1, \2, …, \9
引用匹配的括号分隔的子表达式。
注意,在 cmake 代码中需要两个反斜杠(
\\1
)才能通过参数解析获得反斜杠。
以查找到的 Python 库为基准,取出其版本号保存到boost_py_version
中。据此查找相应的 boost 库模块。
# ---[ Python
if(BUILD_python)
if(NOT "${python_version}" VERSION_LESS "3.0.0")
# use python3
find_package(PythonInterp 3.0)
find_package(PythonLibs 3.0)
find_package(NumPy 1.7.1)
# Find the matching boost python implementation
set(version ${PYTHONLIBS_VERSION_STRING})
STRING( REGEX REPLACE "[^0-9]" "" boost_py_version ${version} )
find_package(Boost 1.46 COMPONENTS "python-py${boost_py_version}")
set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND})
如果 Python 找到了,而相应的 boost 库模块没找到,则缩短版本号进行寻找。假使 Python 版本与 boost 库支持的不一致就会找不到。
while(NOT "${version}" STREQUAL "" AND NOT Boost_PYTHON_FOUND)
STRING( REGEX REPLACE "([0-9.]+).[0-9]+" "\\1" version ${version} )
STRING( REGEX REPLACE "[^0-9]" "" boost_py_version ${version} )
find_package(Boost 1.46 COMPONENTS "python-py${boost_py_version}")
set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND})
STRING( REGEX MATCHALL "([0-9.]+).[0-9]+" has_more_version ${version} )
if("${has_more_version}" STREQUAL "")
break()
endif()
endwhile()
最后仍然没找到则放弃治疗,直接链接python
,也就是 Python2 模块。
if(NOT Boost_PYTHON_FOUND)
find_package(Boost 1.46 COMPONENTS python)
endif()
Python2 的依赖处理。
else()
# disable Python 3 search
find_package(PythonInterp 2.7)
find_package(PythonLibs 2.7)
find_package(NumPy 1.7.1)
find_package(Boost 1.46 COMPONENTS python)
endif()
if(PYTHONLIBS_FOUND AND NUMPY_FOUND AND Boost_PYTHON_FOUND)
set(HAVE_PYTHON TRUE)
if(BUILD_python_layer)
list(APPEND Caffe_DEFINITIONS PRIVATE -DWITH_PYTHON_LAYER)
list(APPEND Caffe_INCLUDE_DIRS PRIVATE ${PYTHON_INCLUDE_DIRS} ${NUMPY_INCLUDE_DIR} PUBLIC ${Boost_INCLUDE_DIRS})
list(APPEND Caffe_LINKER_LIBS PRIVATE ${PYTHON_LIBRARIES} PUBLIC ${Boost_LIBRARIES})
endif()
endif()
endif()
参考资料:
- Ubuntu16.04 python3 caffe安装
- 正则表达式的正选与反选
- Finding boost-python3 with Anaconda cmake prefix
- boost_python3 missing from ubuntu 16.04
- cmake link with libboost_python-py32.so instead of libboost_python.so
- Unable to link against Boost.Python on OS X
- where can I find the list of boost component that I can use in cmake?
- Find all available modules from GroupIO
- CMake 手册详解(二十二)
- Build MPICH with CMake - cmake
- How to Install Caffe and PyCaffe on Jetson TX2
- Looping over a string list
- caffe-python3-install/install-caffe.md
- 在 python3.5 下使用 Caffe
- Python3 support #293
- Compiled google protocol buffers are not working (C++)
- OpenCV Tutorial: Load and Display an Image (codeblocks, fedora20)
- python3外部库boost介绍 用c++为python编写扩展