引言
在进行caffe编译的时候遇到一个问题,就是在编译出了caffe.so文件后,导入会由于版本问题出错 importerror,具体为:
>>> import caffe
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jcole/Git/caffe/python/caffe/__init__.py", line 1, in <module>
from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
File "/home/jcole/Git/caffe/python/caffe/pycaffe.py", line 13, in <module>
from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \
ImportError: /xxxxx/caffe/python/caffe/_caffe.so: undefined symbol: _ZN5boost6python6detail11init_moduleER11PyModuleDefPFvvE
出现这个的原因是因为centos默认用的是python2.7,即使我caffe上路径写的是3的版本路径,但yum仓库提供的最高版本的boost也才1.53,达不到caffe需要的至少1.55,并且当前系统的boost绑定的是python2.7编译后的libboost,所以需要安装高版本的重新编译并添加软链接。
boost编译
关于boost,在centos中,安装方式为:
yum install boost-devel
而官方比较推荐的ubuntu安装方式为:
sudo apt-get install --no-install-recommends libboost-all-dev
但上面两种方式安装的版本均为1.53或者1.54,而不是大于1.55,所以下面将是源码编译。
首先在caffe文件夹下修改makefile.config中的PYTHON_LIBRARIES为:
PYTHON_LIBRARIES := boost_python3 python3.6m
这里一定要确认前面pythonlib给的路径能不能找到python3.6m,如果是安装的anaconda3,需要去确认一下主环境是不是python3.6,最好不要建立虚拟环境,因为虚拟环境的很多头文件和包都继承自主环境,那样会出现很多矛盾的地方,比如说:
上面连续两个找不到lboost_python3和3.6m,但我有在动态库里添加相关的so文件,所以环境和版本的问题一定要注意。
下载boost可以去 www.boost.org 的下载页安装1.74版本的,也可以在anaocnda中找到1.68版本的:
Boost provides free peer-reviewed portable C++ source libraries.
下载好解压完成后,进入boost源文件目录boost_1_xx_0:
cd boost_1_67_0/
./bootstrap.sh --with-libraries=python --with-toolset=gcc
./b2 cflags='-fPIC' cxxflags='-fPIC' --with-python include="/root/anaconda3/bin/python3.6m"
./b2 install
上图是编译过程中抛出的编译状态,可以看到因为我只是指定了python,而没有对其余的依赖加编译,所以都是not building状态,但需要的也只是python的libboost依赖。
编译成功后,编译的动态库会位于boost_1_67_0/xxxx/zlib下,因为没有指定prefix位置,所以根据编译输出的日志找到libboost_python3然后移过去:
sudo ln -s libboost_python-py36.so /usr/lib64/libboost_python3.so
sudo ln -s libboost_python-numpy36.so /usr/lib64/libboost__python-numpy3.so
然后ldconfig,再回头重新编译caffe:
make all -j12
make test -j12
make runtest
关于make具体的参数为:
make:无效选项 -- /
make:无效选项 -- u
make:无效选项 -- /
用法:make [选项] [目标] ...
选项:
-b, -m 忽略兼容性。
-B, --always-make 无条件 make 所有目标。
-C DIRECTORY, --directory=DIRECTORY
在执行钱先切换到 DIRECTORY 目录。
-d 打印大量调试信息。
--debug[=FLAGS] 打印各种调试信息。
-e, --environment-overrides
环境变量覆盖 makefile 中的变量。
--eval=STRING Evaluate STRING as a makefile statement.
-f FILE, --file=FILE, --makefile=FILE
从 FILE 中读入 makefile。
-h, --help 打印该消息并退出。
-i, --ignore-errors Ignore errors from recipes.
-I DIRECTORY, --include-dir=DIRECTORY
在 DIRECTORY 中搜索被包含的 makefile。
-j [N], --jobs[=N] 同时允许 N 个任务;无参数表明允许无限个任务。
-k, --keep-going 当某些目标无法创建时仍然继续。
-l [N], --load-average[=N], --max-load[=N]
在系统负载高于 N 时不启动多任务。
-L, --check-symlink-times 使用软链接及软链接目标中修改时间较晚的一个。
-n, --just-print, --dry-run, --recon
Don't actually run any recipe; just print them.
-o FILE, --old-file=FILE, --assume-old=FILE
将 FILE 当做很旧,不必重新生成。
-p, --print-data-base 打印 make 的内部数据库。
-q, --question Run no recipe; exit status says if up to date.
-r, --no-builtin-rules 禁用内置隐含规则。
-R, --no-builtin-variables 禁用内置变量设置。
-s, --silent, --quiet Don't echo recipes.
-S, --no-keep-going, --stop
关闭 -k。
-t, --touch touch 目标而不是重新创建它们。
-v, --version 打印 make 的版本号并退出。
-w, --print-directory 打印当前目录。
--no-print-directory 关闭 -w,即使 -w 默认开启。
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
将 FILE 当做最新。
--warn-undefined-variables 当引用未定义变量的时候发出警告。
--warn-undefined-functions Warn when an undefined user function is called.
如果不将动态库加进库目录下,可以在make的时候,加-L,但具体的我也没试过。