Ubuntu 15.10/16.04 上安装Caffe——确保编译好的库相互兼容

前言:
    在Ubuntu14.04 LTS版本上编译安装Caffe的教程非常多,安装过程也较为顺利,然而在更新版本系统上编译安装Caffe的过程中,仍会遇到很多问题。其中,在make过程中遇到undefined reference to ‘xxx’,在make runtest 过程中遇到Segmentation faul这两个错误非常常见,在github的BVLC/caffe issues中有非常多类似的问题,e.g.
    Caffe 1.0.0-rc3 make failed on Ubuntu 16.04 / CUDA 8.0 #4492
    ubuntu16.04 runtest failed #4235
    它们的表现形式不同,但是最终都指向一个原因——用GCC4.9本地编译的Caffe和系统自带源中GCC 5.2 编译的库不兼容,无法正确链接。针对这个问题,我专门在github的BVLC/caffe issues中发了帖子指明问题:
    ubuntu 15.10 /16.04 runtest : Segmentation fault (core dumped)—— Be sure to link with compatible libraries #4499

一. CUDA编译安装的考量

    由于博主主机的CPU是六代skylake架构,经典的14.04LTS内核较旧不支持,因此选用Linux4.2内核的Ubuntu 15.10。在编译CUDA 7.5时发现:Ubuntu 15.10以及Ubuntu 16.04 LTS 采用gcc 5.X编译器,而cuda7.5不支持gcc5以上(默认不支持,实际支持),因此有两种选择安装CUDA 7.5:

    其中,降级GCC的方案网上教程用的最多,我也采用该方法,也导致了后来编译Caffe时出现的动态库因编译版本不兼容出现的链接错误。相较而言,我更推荐第二种方法:因为15.10 / 16.04 的默认源(repository)中预编译的库是采用GCC 5的。用GCC 5.x 编译CUDA和Caffe能避免库的兼容性问题。

    此外,cuda 8已经完全支持GCC 5编译,读者也可以直接使用CUDA 8.

二. Caffe安装过程中的问题与解决方案

    以下是我在Ubuntu 15.10上采用GCC 4.9.3 编译Caffe时遇到的问题几解决方案:

问题1: fatal error: libhdf5_hl.so.10: No such file or directory

完整报错信息:

.build_debug/tools/caffe: error while loading shared libraries: libhdf5_hl.so.10: cannot open shared object file: No such file or directory

    然而libhdf5.so实际是安装好的,只不过在Ubuntu 15.10中是安装到目录:

/usr/lib/x86_64-linux-gnu/hdf5/serial

解决方案:
    因此需要修改Caffe的Makefile.config文件,在INCLUDE_DIRS ,LIBRARY_DIRS中添加如下路径(不同路径间以空格隔开):

INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial/
LIBRARY_DIRS := $(PYTHON_LIB) /usr/lib /usr/local/cuda/lib64 /usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial

问题2:找不到 protoc.so.8

    apt-get命令下载的libprotobuf、glog、gflags,其共享库.so文件存于/usr/lib/x86-linux-gnu目录,但是make时会出现:
    找不到protoc.so.8
    使用find命令查找 protoc*,在/usr/lib/x86-linux-gnu中找到protoc.so.9共享库版本不匹配。
解决方法:
    下载protobuf源码,手动编译安装。
【注意】手动编译的库采用GCC 4.9编译器,共享库地址在/usr/local/lib, 需要将该路径配置到共享库搜索路径中。

问题3: undefined reference to ‘xxx’

apt-get安装了glog和gflag后,make时在链接阶段 –la 出现undefined reference to ‘xxx’的错误,部分报错信息如下:

CXX/LD -o .build_debug/tools/device_query.bin
CXX/LD -o .build_debug/tools/upgrade_net_proto_binary.bin
.build_debug/lib/libcaffe.so: undefined reference to `google::base::CheckOpMessageBuilder::NewString()'
collect2: error: ld returned 1 exit status
Makefile:616: recipe for target '.build_debug/tools/upgrade_net_proto_binary.bin' failed
make: *** [.build_debug/tools/upgrade_net_proto_binary.bin] Error 1
make: *** Waiting for unfinished jobs....
.build_debug/tools/compute_image_mean.o: In function `std::string* google::MakeCheckOpString<int, int>(int const&, int const&, char const*)':
/usr/include/glog/logging.h:672: undefined reference to `google::base::CheckOpMessageBuilder::NewString()'

    分析: CheckOpMessageBuilder是glog库的类,这说明虽然glog , gflags 等库虽然已经安装(存储于 /usr/lib),但是没有正确链接。
解决方案:
    首先autoremove 原先安装的glog, gflags等依赖库;然后使用GCC 4.9 手动编译glob,gflags等依赖库。具体方法参考Caffe官方教程:Ubuntu Installation

问题4:Make runtest 出现‘Segmentation fault’

问题描述:
    在make和make test都成功通过后,运行make runtest进行单元测试。但是一些程序无法通过单元测试,报错信息如下:

[----------] 12 tests from SGDSolverTest/2, where TypeParam = caffe::GPUDevice<float>
[ RUN      ] SGDSolverTest/2.TestLeastSquaresUpdateWithWeightDecay
*** Aborted at 1468899438 (unix time) try "date -d @1468899438" if you are using GNU date ***
PC: @                0x0 (unknown)
*** SIGSEGV (@0x706d742f) received by PID 17550 (TID 0x7f0ef7016a80) from PID 1886221359; stack trace: ***
    @     0x7f0eeffc4d10 (unknown)
    @     0x7f0ef2a41263 boost::filesystem::path::operator/=()
    @           0x4b6dd4 caffe::MakeTempDir()
    @           0x4cf3cf caffe::GradientBasedSolverTest<>::RunLeastSquaresSolver()
    @           0x4e2410 caffe::GradientBasedSolverTest<>::TestLeastSquaresUpdate()
    @           0x4e26ff caffe::SGDSolverTest_TestLeastSquaresUpdateWithWeightDecay_Test<>::TestBody()
    @           0x9327c3 testing::internal::HandleExceptionsInMethodIfSupported<>()
    @           0x92a95a testing::Test::Run()
    @           0x92aaa8 testing::TestInfo::Run()
    @           0x92ab85 testing::TestCase::Run()
    @           0x92b518 testing::internal::UnitTestImpl::RunAllTests()
    @           0x92b7e3 testing::UnitTest::Run()
    @           0x46ea3f main
    @     0x7f0eefc0aac0 __libc_start_main
    @           0x476579 _start
    @                0x0 (unknown)
Makefile:523: recipe for target 'runtest' failed
make: *** [runtest] Segmentation fault (core dumped)

    这是一个很隐蔽的错误,在github的Caffe issues中可以搜索到很多类似的问题.
ubuntu16.04 runtest failed #4235中Sean Bell提出错误可能发生在 MakeTempDir,该函数位于caffe/include/caffe/util/io.hpp中
https://github.com/BVLC/caffe/blob/be163be0ea5befada208dbf0db29e6fa5811dc86/include/caffe/util/io.hpp#L24
这里写图片描述
问题分析与解决方案:
    发现函数MakeTempDir用于处理路径的字符串,相关的库有boost和protobuf。
    因此我怀疑是apt-get安装boost库出现了问题,于是删除原先安装的libboost-all-dev,下载源码用GCC 4.9手动编译。
最终make runtest 单元测试全部通过

三. 问题归纳总结:

    上述的问题存在一些共性:

1.已经按照教程,使用apt-get命令安装好了Caffe的依赖库protobuf,glog,gflags等,但是make过程中无法编译通过,主要是存在链接错误,未定义的函数。
2. 都是通过手动编译解决的问题。特别是make runtest中的Segmentation fault错误,看似与共享库的链接关系不大,但是最终还是由于boost库的错误引起的。

问题的本质原因:
    在Ubuntu 15.10/16.04中默认的编译器是GCC 5.x, 然而CUDA不能被GCC 5以上版本编译(目前最新的CUDA 8已经可以用GCC 5编译) 。于是我将GCC降级到GCC 4.9,但是Ubuntu 15.10/16.04的默认源(repository)中编译好的库采用GCC 5.x。GCC 4.9 和 GCC 5.x的C++ ABI(C++ 二进制兼容接口)不同,ABI::string 已经发生改变。因此,需要确保所链接的共享库具有兼容性!凡是export function中涉及到std::string, std::vector等的库,都必须用同一种编译器编译。
    综上,使用与编译Cafffe一致的GCC 4.9编译glog,gflags,boost库能够起作用的真正原因已经找到。

Reference:

ubuntu 15.10 /16.04 runtest : Segmentation fault (core dumped)—— Be sure to link with compatible libraries #4499
https://github.com/BVLC/caffe/issues/4499

Ubuntu16.04系统下CUDA7.5配置Caffe教程
http://blog.csdn.net/g0m3e/article/details/51420565

Ubuntu 16.04 or 15.10 Installation Guide
https://github.com/BVLC/caffe/wiki/Ubuntu-16.04-or-15.10-Installation-Guide

猜你喜欢

转载自blog.csdn.net/Solomon1558/article/details/52015754