最近在学习caffe,首先在服务器(Ubuntu 14.04)上安装测试,使用的BLAS是atlas。Intel的parallel studio太大了(3.9G),安装的时候没下载好,所以就没有用了。然后又在自己的笔记本上安装试一下,这次使用intel MKL库,结果就给一个错误耽误了好久。问题是这样的:
安装完所有依赖,修改Makefie.config以及Makefile(增加模块openv_imgcodecs for OpenCV 3.0),make all报错:
CXX src/caffe/util/io.cpp
src/caffe/util/io.cpp:5:33: fatal error: opencv2/core/core.hpp: 没有那个文件或目录
#includecore core.hpp>
这个容易知道是include路径问题。因为我的opencv安装到了/opt/opencv,所以设置USE_PKG_CONFIG := 1,终端执行命令pkg-config opencv –cflags结果是OK的,说明Makefile有问题。这个问题有两个解决方法
1. 修改Makefile.config,添加opencv的两个路径
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /opt/opencv/include
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /opt/opencv/lib
2. 修改Makefile,搜索USE_PKG_CONFIG,添加下面一行(红色),并将整个部分移动到 INCLUDE_DIRS 展开成 COMMON_FLAGS 之后,大致如下:
COMMON_FLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir))
USE_PKG_CONFIG ?= 0
ifeq ($(USE_PKG_CONFIG), 1)
PKG_CONFIG := $(shell pkg-config opencv –libs)
COMMON_FLAGS += $(shell pkg-config opencv –cflags)
else
PKG_CONFIG :=
endifCXXFLAGS += -pthread -fPIC $(COMMON_FLAGS) $(WARNINGS)
NVCCFLAGS += -ccbin=$(CXX) -Xcompiler -fPIC $(COMMON_FLAGS)
继续make all,又报错:
CXX/LD -o .build_release/tools/convert_imageset.bin
.build_release/lib/libcaffe.so:对‘cblas_ddot’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_daxpy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dasum’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dcopy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sdot’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dscal’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sgemm’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dgemm’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sgemv’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sscal’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_scopy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_saxpy’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_dgemv’未定义的引用
.build_release/lib/libcaffe.so:对‘cblas_sasum’未定义的引用
undefined reference好像一般出现在源码编译的时候,如果是这样,应该去查看源代码是不是写错了。但是到这一步libcaffe.a, libcaffe.so都已经编译好了,目前正在tools阶段。参见Makefile
all: $(STATIC_NAME) $(DYNAMIC_NAME) tools examples
这里在链接动态库,问题就是莫名其妙啦。
首先搜索错误提示信息,英文的关键字可能更靠谱些,虽然找到了一些结果,但是没有解决办法。有些人提示用cmake,试了下貌似可以,但是这个问题应该解决。。。
首先找到出错的地方,搜索发现可以用make -n输出编译命令,找到出错语句。
echo CXX/LD -o .build_release/tools/upgrade_net_proto_text.bin
g++ .build_release/tools/upgrade_net_proto_text.o -o .build_release/tools/upgrade_net_proto_text.bin -pthread -fPIC -DNDEBUG -O2 -DUSE_CUDNN -I/usr/include/python2.7 -I/usr/lib/python2.7/dist-packages/numpy/core/include -I/usr/local/include -I/opt/opencv/include -I.build_release/src -I./src -I./include -I/usr/local/cuda/include -Wall -Wno-sign-compare -lcaffe -L/usr/lib -L/usr/local/lib -L/usr/lib -L/opt/opencv/lib -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L.build_release/lib -lcudart -lcublas -lcurand -lglog -lgflags -lprotobuf -lleveldb -lsnappy -llmdb -lboost_system -lhdf5_hl -lhdf5 -lm -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs -lboost_thread -lstdc++ -lcudnn \
-Wl,-rpath,\$ORIGIN/../lib
好长一条语句(虽然去除-L,-l,-I部分就不多了),得搞懂这条语句在干什么,各选项的含义(目前对那个rpath,$ORIGIN还不是怎么懂)。
另一方面,错误出在cblas_*,所以在caffe目录搜索用到这些函数的hpp/cpp文件:
find . -name *.[hc]pp |xargs grep cblas
vi include/caffe/util/mkl_alternate.hpp
#ifdef USE_MKL
#include
#else // If use MKL, simply include the MKL header
Makefile搜索 USE_MKL,
# BLAS configuration (default = ATLAS)
BLAS ?= atlas
ifeq ($(BLAS), mkl)
# MKL
LIBRARIES += mkl_rt
COMMON_FLAGS += -DUSE_MKL
MKL_DIR ?= /opt/intel/mkl
BLAS_INCLUDE ?= $(MKL_DIR)/include
BLAS_LIB ?= $(MKL_DIR)/lib $(MKL_DIR)/lib/intel64
else ifeq ($(BLAS), open)
看仔细了,就会发现没什么问题!
在到Intel MKL目录/opt/intel里看看,权限没有问题,头文件也在,把相关路径加到系统变量,加到Makefile的INCLUDE_DIRS/LIBRARY_DIRS都不行。。。
再回到出错命令,仔细想想应该是so文件有问题,去除-lcaffe参数,出错信息就变了,所以基本确定是libcaffe.so有问题。搜索更普遍的错误,“link error so undefined reference to”,这个页面的问题有点类似,可能是这个so依赖的其他库找不到。
这里用到了两个分析so库文件的命令,ldd分析依赖,nm列出symbol。
我发现编译出的libcaffe.so的依赖里竟然没有找到blas或intel的关键字,分析symbol里确实有一大串出错函数。学习了下nm输出结果的Undefined symbol的含义,这些symbol应该由其他库来定义,虽然这里连依赖都没有!
到/opt/intel/mkl/lib/intel64目录下,nm -A *.so | grep cblas_ddot,找到了3个so,然后好不容易搜索找到一个页面,列出mkl里各个so文件的用途,我们要用的应该是libmkl_rt.so。(其实应该搜索intel mkl user guide)
在出错命令相应位置加入-L/opt/intel/mkl/lib/intel64 -lmkl_rt,运行成功!
可是为什么mkl的相关参数没有在Makefile中自动生成呢,ifeq的判断也好像没什么问题。
又多学习了一点Makefile的命令,包括?= (question equal), :=, =, +=的区别。找到出错节点,一个个echo变量内容,最后的最后定位了问题所在:Makefile.config设置BLAS,vim编辑的时候,dw删除 atlas,光标移动到空格位置,按i插入,按空格,输入mkl。mkl后面多了一个空格啊!这里应该按a插入。。。
总结:低级错误,经验学习,耗时,结合一定的系统性学习效果更佳。。。
后话:应该找点Makefile调试工具,可以方便的输出各种变量。等makefile都很熟悉了,果断用起cmake,省时省力。