经过两个星期的掉坑再爬坑,终于将caffe成功移植到arm平台,这里记录一下整个的过程。
感谢知乎大神乌贼刘的热心帮助:https://www.zhihu.com/question/56437450
移植环境:
PC:Ubuntu14.04 x64
ARM:Ti ARM5728
toolchain:ti-processor-sdk-linux-arm57xx-evm-03.03.00.04
这里注意,虽然是交叉编译,但是一定需要有arm平台的开发板。因为hdf5暂时没有找到交叉编译的方法,只能在板子上直接编译。
caffe依赖的库很多,包括:glog,gflags,boost,hdf5,leveldb,lmdb,openBlas(或者ATLAS,MKL),opencv,protobuf,snappy。
下面记录所有这些依赖库的移植过程。
准备环境:cmake,cmake-gui,gcc,g++
所有库的source目录在:/home/ubuntu/arm-source
所有库的安装目录在:/home/ubuntu/arm-caffe
toolchain所在目录为:/home/ubuntu
cd /home/ubuntu/arm-source/glog-build
make
make install
同理,交叉编译gflags、snappy、
最后glog的安装结果如下:
.
├── include
│ └── glog
│ ├── config.h
│ ├── logging.h
│ ├── log_severity.h
│ ├── raw_logging.h
│ ├── stl_logging.h
│ └── vlog_is_on.h
└── lib
├── cmake
│ └── glog
│ ├── glog-config.cmake
│ ├── glog-config-version.cmake
│ ├── glog-targets.cmake
│ └── glog-targets-noconfig.cmake
└── libglog.a
最后gflags的安装结果如下:
.
├── include
│ └── gflags
│ ├── gflags_completions.h
│ ├── gflags_declare.h
│ ├── gflags_gflags.h
│ └── gflags.h
└── lib
├── cmake
│ └── gflags
│ ├── gflags-config.cmake
│ ├── gflags-config-version.cmake
│ ├── gflags-targets.cmake
│ └── gflags-targets-release.cmake
├── libgflags.a
├── libgflags_nothreads.a
└── pkgconfig
└── gflags.pc
最后snappy的安装结果如下:
.
├── include
│ ├── snappy-c.h
│ ├── snappy.h
│ ├── snappy-sinksource.h
│ └── snappy-stubs-public.h
└── lib
├── cmake
│ ├── Snappy
│ │ ├── SnappyTargets.cmake
│ │ └── SnappyTargets-noconfig.cmake
│ ├── SnappyConfig.cmake
│ └── SnappyConfigVersion.cmake
└── libsnappy.so
由于我板子里自带了protobuf,就没有另外在安装。如果板子里面没有protobuf,可以按照以下步骤编译安装protobuf。
在PC端:
./autoconf.sh
./configure
make
make check
make install
make clean
./configure --host=arm-linux CC=$toolchainPath/arm-linux-gnueabihf-gcc CXX=$toolchainPath/arm-linux-gnueabihf-g++ --with-protoc=protoc prefix=$installPath
make
make install
也有说protobuf要编译成静态库,那么在上面编译ARM版的时候,configure选项加上--disable-shared。
1.解压source code。
2.修改build_detect_platform文件,找到
if test -z "$CC"; then
CC=cc
fi
if test -z "$CXX"; then
CXX=g++
fi
修改为
CC=/home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc
if test -z "$CC"; then
CC=/home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc
fi
CXX=/home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-g++
if test -z "$CXX"; then
CXX=/home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-g++
fi
3.修改db/db_iter.h文件,在#endif前添加如下一行
typedef int ssize_t;
4.make
编译之后的库在当前目录的out-shared和out-static目录里面。
CC = /home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc
AR = /home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-ar
prefix = /home/ubuntu/arm-caffe/lmdb
2. make
3. make install
4. 使用readelf -h查看生成的.so文件,machine这一项显示的是ARM就是编译成功了。
最后编译安装后的目录如下:
.
├── bin
│ ├── mdb_copy
│ ├── mdb_dump
│ ├── mdb_load
│ └── mdb_stat
├── include
│ └── lmdb.h
├── lib
│ ├── liblmdb.a
│ └── liblmdb.so
└── share
└── man
└── man1
├── mdb_copy.1
├── mdb_dump.1
├── mdb_load.1
└── mdb_stat.1
如果有条件放在板子上直接编译hdf5,那么步骤如下:
./configure
make
make install
如果条件不允许直接编译hdf5,或者板子上的空间不够(我这里就是空间不够,导致无法直接在板子上编译),那么可以按照下面的方式在PC上编译hdf5:
cd /home/ubuntu/arm-source/hdf5
mkdir build
cd build
cmake ..
将生成的build文件夹下的东西打包并复制到板子上。
修改CMakeCache.txt文件,将其中所有CC,CXX,AR,LD等选项全部替换成板子上相应的路径。然后进行编译。
注意这里为什么不在PC上交叉编译HDF5,因为在编译HDF5的过程中,会生成一些与机器相关的依赖文件(具体是哪两个文件我忘了),如果直接在PC上进行交叉编译,会导致这些机器依赖文件的信息错误,最终编译失败。只能在板子上先编译一次生成这些依赖文件,然后将文件拷贝到PC端,继续交叉编译。那么问题来了,你有条件在板子上编译,为什么还要回去PC上做交叉编译呢。我在这个地方尝试了很多天,最终都以失败告终,如果谁交叉编译过了HDF5,还望告知。
1. 运行自带脚本./bootstrap.sh --prefix=/home/ubuntu/arm-caffe/boost
2. 修改project-config.jam文件,具体修改如下:
if ! gcc in [ feature.values
{
using gcc : arm : /home/ubuntu/ti-processor-sdk-linux-am57xx-evm-03.03.00.04/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc ;
}
3. 编译安装:./bjam install --layout=tagged --build-type=complete --prefix=/home/ubuntu/arm-caffe/boost
由于我板子自带了opencv,所以不需要编译。但是要在pkgconfig的opencv.pc文件中将opencv_dnn注释掉,不然会跟protobuf冲突。
如果板子没有带opencv,也可以自行交叉编译opncv。下面是自行交叉编译opencv的步骤。
2.进入build目录,打开CMakeCache.txt文件,找到CMAKE_CXX_FLAGS:STRING=修改如下
CMAKE_CXX_FLAGS:STRING=-lpthread -shared -fPIC
3.make
4.make到一半会报错,../../3rdparty/lib/libzlib.a(gzlib.c.obj): relocation R_ARM_THM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
这个时候进入到build/3rdparty/zlib/CMakeFiles/zlib.dir目录,找到flags.make文件,打开,在C_FLAGS这一行里面添加-fPIC。
同理在build/3rdparty目录下libjasper,libjpeg,libpng,libtiff,libwebp,openexr等也做同样的修改,加上-fPIC。
5.继续cd回build目录,make。
6.make install
1.编译环境:
* Ubuntu16.04 + arm-hisiv500-linux-gcc * 下载地址: https://github.com/xianyi/OpenBLAS/releases
2.移植步骤:
修改Makefile.arm
12 ifeq ($(CORE), ARMV7)
13 ifeq ($(OSNAME), Android)
14 CCOMMON_OPT += -marm -mfpu=neon -mfloat-abi=hard -march=armv7-a -Wl,--no-warn-mismatch
15 FCOMMON_OPT += -marm -mfpu=neon -mfloat-abi=hard -march=armv7-a -Wl,--no-warn-mismatch
16 else
17 #CCOMMON_OPT += -marm -mfpu=vfpv3 -mfloat-abi=hard -march=armv7-a
18 #FCOMMON_OPT += -marm -mfpu=vfpv3 -mfloat-abi=hard -march=armv7-a
19 CCOMMON_OPT += -mcpu=cortex-a17.cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations
20 FCOMMON_OPT += -mcpu=cortex-a17.cortex-a7 -mfloat-abi=softfp -mfpu=neon-vfpv4 -mno-unaligned-access -fno-aggressive-loop-optimizations
21 endif
22 endif
* 解压:
* 编译:make TARGET=ARMV7 HOSTCC=gcc CC=arm-hisiv500-linux-gcc CROSS=1 CROSS_SUFFIX=arm-hisiv500-linux- NO_LAPACKE=1 NO_SHARED=1 BINARY=32 NOFORTRAN=1 libs
* 安装:make PREFIX=/home/shunzhi/software/OpenBLAS-0.2.19/install install
1.将之前编译好的库全部移到板子上,并放入相应的系统路径下/usr/lib
2.修改caffe目录下MakeFile文件
1)BLAS ?= open
2)ifeq ($(LINUX), 1)
CXX := /usr/bin/arm-linux-gnueabihf-g++
3) USE_PKG_CONFIG ?= 1
3.修改MakeFile.config文件
1) CPU_ONLY := 1
2) OPENCV_VERSION := 3 #这个根据自己的opencv版本来定
3) CUSTOM_CXX := /usr/bin/arm-linux-gnueabihf-g++
4)BLAS := open
5)添加自己的openBlas的路径
# Homebrew puts openblas in a directory that is not on the standard search path
BLAS_INCLUDE := /home/root/openBLAS/include
BLAS_LIB := /home/root/openBLAS/lib
6)添加依赖库的目录,根据自己的情况而定
# Whatever else you find you need goes here.
INCLUDE_DIRS := /usr/include /run/media/mmcblk1p3/boost/include
LIBRARY_DIRS := /usr/lib /run/media/mmcblk1p3/boost/lib
7) USE_PKG_CONFIG := 1
4.cd /usr/lib/pkgconfig,修改opencv.pc文件
libs:里面,去掉-lopencv_dnn
5.make
移植成功后的caffe在TI arm5728上面运行GoogLeNet分类,CPU模式一帧大约需要2.5s。
1.
Q:编译完caffe后运行报错。[libprotobuf ERROR google/protobuf/descriptor_database.cc:57] File already exists in database: caffe.proto
A:这是因为protobuf同时被多个instance调用导致的,官方的解释是将protobuf编译成静态库的形式,就是上面说的在./configure加上--disable-shared选项。参考链接https://github.com/BVLC/caffe/issues/1917
我发现即使将protobuf编译成静态库,问题依然存在。最后我将opencv.pc文件中的libopencv_dnn注释掉之后就解决了。原来是opencv与caffe同时调用了protobuf导致的。