caffe移植到arm平台

经过两个星期的掉坑再爬坑,终于将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

一、glog、gflags、snappy

  1. 启动cmake-gui
  2. 点击Browse Source选择glog的source code目录
  3. 点击Browse Build选择glog的MakeFile的编译目录,我这里是/home/ubuntu/arm-source/glog-build
  4. 点击Configure,选择交叉编译
  5. 设定好编译器后点击Finish
  6. 在生成的规则中修改glog库的安装路径,即上面的/home/ubuntu/arm-caffe/glog
  7. 点击Generate生成MakeFile。
  8. 然后编译安装

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,可以按照以下步骤编译安装protobuf。


在PC端:

./autoconf.sh
./configure
make
make check
make install

上面编译的是是PC版的protobuf,为的是生成protoc.bin文件。接下来编译ARM版的protobuf。

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。


三、leveldb

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目录里面。


四、lmdb


1.修改MakeFile文件

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

最好的方式就是直接放在板子上编译。

如果有条件放在板子上直接编译hdf5,那么步骤如下:

./configure
make
make install

编译好的库在当前目录的hdf5文件夹下。

如果条件不允许直接编译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,还望告知。

六、boost

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

由于我板子自带了opencv,所以不需要编译。但是要在pkgconfig的opencv.pc文件中将opencv_dnn注释掉,不然会跟protobuf冲突。

如果板子没有带opencv,也可以自行交叉编译opncv。下面是自行交叉编译opencv的步骤。


1.打开cmake-gui,选择opencv相应的source和build,然后configure,取消勾选WITH_CUDA选项,并选择好prefix目录,点击generate生成MakeFile。

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

八、openBlas

 openBlas的移植工作公司之前已经有同事做了,我就直接拿来用了。没有自行再去编译。这里照搬知乎大神的工作吧


作者:乌贼刘
链接:https://www.zhihu.com/question/56437450/answer/163330266
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1.编译环境:


* Ubuntu16.04 + arm-hisiv500-linux-gcc * 下载地址: github.com/xianyi/OpenB

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





九、编译caffe

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。

十、Q&A

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导致的。



你可能感兴趣的:(Deep,Learning)