为 Caffe 添加 Python3 支持

Python2已近生命终点,然而 Caffe 却受硬件厂商的拥护。于是我们尝试在 Python3 环境下编译 Caffe。

Caffe Python 3.7 安装

对于 Python 3.3+而言,需要搭配 Protobuf 3。因此不再需要 apt 安装libprotobuf-devprotobuf-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")

编译会遇到
c++11protobuf-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+,还会遇到
opencv
需要为 Caffe 修改过时的宏定义。此山放过,则会遇到

 libboost_python.so: undefined reference to `PyString_Size'

boost
原因是 Caffe 的 Dependencies.cmake 链接了 boost 库的 python2 模块。这是本文关注的重点。使用 Makefile.config 文件进行配置的则不会出现此问题。

$ ll /usr/lib/x86_64-linux-gnu/libboost_python*.so
lrwxrwxrwx 1 root root 30 614  2016  /usr/lib/x86_64-linux-gnu/libboost_python3-py35.so -> libboost_python3-py35.so.1.58.0
lrwxrwxrwx 1 root root 30 614  2016  /usr/lib/x86_64-linux-gnu/libboost_python-py27.so -> libboost_python-py27.so.1.58.0
lrwxrwxrwx 1 root root 30 614  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 实现。
stringREGEX 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()

参考资料:

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值