利用xcode编译CaffeApplication和CaffeSource

利用xcode编译Caffe Application和Caffe源代码

无论是搞科研和做工程,都会涉及到caffe应用,或者caffe源代码的修改和调试。

虽然可以在命令行可以使用gdb进行调试,但对于长期使用IDE开发的我来讲,依然有诸多不便。

利用IDE来Debug代码可以方便地设置断点进行调试,加快开发进程。

比如,在windows下使用VS,linux下使用Eclipse,mac下当然首选Xcode。

虽然,有blog介绍过(如下),但在配置过程中依然发现了一些问题,总结了一些经验。

  1. 在 Xcode 中编译和调试 Caffe 的 C++ 程序 (非 Caffe 源代码)
  2. 在 Xcode 中调试和研究 Caffe

1 原理

首先说一下编译Caffe Application 和 Caffe Source的区别。

1.1 Caffe Application

Caffe Application 含义就是指使用caffe,并不修改caffe的源代码。

如同使用opencv一样,我们只调用opencv,并不修改opencv的代码。

这种情况下,我们要预先将源代码编译完成,生成静态链接库(.lib .a)或者动态链接库(.dll .so)。

然后在Application工程中

  • 指定头文件路径;
  • 指定链接库的路径;
  • 引入链接库;

就可以完成对caffe或opencv的调用。

1.2 Caffe Source

编译Caffe源代码则不然,不用预先编译源码,但一定要确保系统配置好了编译源码所需要的一切环境。

要把所有的Caffe源代码加入到工程中,包括(.h .hpp .cpp)文件。注意某些IDE可能引入了代码文件,但并没有将代码文件加入到工程,这会导致工程找不到源代码,这种情况在xcode环境下按照教程2就遇到了,所以一定要清楚IDE的工作原理,才能够保证不出现问题。

之后,依然需要将Caffe所依赖的库配置好:

  • 指定头文件路径;
  • 指定链接库的路径;
  • 引入链接库;

但此时并不需要引入Caffe自己的链接库,因为caffe本身没有预先编译,该工程就是要编译caffe。

2 Xcode配置Caffe Application

2.1 首先,一定要预先在系统中编译好caffe。

按照官网教程,配置好caffe所依赖的各个依赖库,在OSX终端成功编译caffe。如果这一步完不成,后边的怎么也不会成功。

编译完成的caffe路径为CAFFE_ROOT=~/Dev/caffe

2.2 Xcode新建工程Command Line Tools

在这就不截图了。然后在main函数中写一个简单的caffeApp测试程序,测试caffe中的Blob。

测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <caffe/util/io.hpp>
#include <vector>
#include <iostream>
#include <caffe/blob.hpp>
using namespace caffe;
using namespace std;
int main(void)
{
Blob<float> a;
cout<<"Size:"<<a.shape_string()<<endl;
a.Reshape(1,2,3,4);
cout<<"Size:"<<a.shape_string()<<endl;
float* p = a.mutable_cpu_data();
float* q = a.mutable_cpu_diff();
for(int i=0;i<a.count();i++)
{
p[i]=i;
q[i]=a.count() - 1 - i;
}
a.Update();
for(int u=0;u<a.num();u++){
for(int v=0;v<a.channels();v++){
for(int w=0;w<a.height();w++){
for(int x=0;x<a.width();x++){
cout<<"a["<<u<<"]["<<v<<"]["<<w<<"]["<<x<<"]="<<a.data_at(u,v,w,x)<<endl;
}}}}
cout<<"ASUM="<<a.asum_data()<<endl;
cout<<"SUMSQ="<<a.sumsq_data()<<endl;
return 0;
}

此时,编译工程,可定会报错,找不到头文件‘caffe/*’。

2.3 配置Xcode工程

点击左侧导航栏工程名称->Targets->Build Setting,所有配置在该页完成。

主要分四步:

1.搜索Header Search Paths

设置如下

1
2
3
4
5
6
7
8
9
10
HEADER_SEARCH_PATHS = /usr/local/opt/boost/include
/usr/local/opt/gflags/include
/usr/local/opt/glog/include
/usr/local/opt/openblas/include
/usr/local/opt/protobuf/include
/usr/local/opt/hdf5/include
/usr/local/opt/opencv3/include
/usr/local/opt/lmdb/include
/usr/local/opt/leveldb/include
/Users/***/Dev/caffe_debug/build/include

2.搜索Library Search Paths

设置如下

1
2
3
4
5
6
7
8
9
LIBRARY_SEARCH_PATHS = /usr/local/opt/glog/lib
/usr/local/opt/boost/lib
/usr/local/opt/gflags/lib
/usr/local/opt/protobuf/lib
/usr/local/lib
/usr/local/opt/hdf5/lib
/usr/local/opt/openblas/lib
/usr/local/opt/opencv3/lib
CAFFE_ROOT/build/lib

3.搜索Other Linker Flags

设置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//:configuration = Debug
OTHER_LDFLAGS = -lglog
-lboost_thread-mt
-lboost_filesystem
-lboost_system
-lgflags
-lprotobuf
-lhdf5_hl
-lhdf5
-lopenblas
-lopencv_highgui
-lopencv_imgproc
-lopencv_core -lm
-lsnappy
-llmdb
-lleveldb
-lcaffe

4.另外,还有一些宏需要设置,搜索Preprocesser Macro

设置如下

GCC_PREPROCESSOR_DEFINITIONS = CPU_ONLY

这样设置,如果路径没有错误,肯定能够编译通过。

若出现问题,查看问题,查找哪个路径设置错了。

2.4 程序运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Size:(0)
Size:1 2 3 4 (24)
a[0][0][0][0]=-23
a[0][0][0][1]=-21
a[0][0][0][2]=-19
a[0][0][0][3]=-17
a[0][0][1][0]=-15
a[0][0][1][1]=-13
a[0][0][1][2]=-11
a[0][0][1][3]=-9
a[0][0][2][0]=-7
a[0][0][2][1]=-5
a[0][0][2][2]=-3
a[0][0][2][3]=-1
a[0][1][0][0]=1
a[0][1][0][1]=3
a[0][1][0][2]=5
a[0][1][0][3]=7
a[0][1][1][0]=9
a[0][1][1][1]=11
a[0][1][1][2]=13
a[0][1][1][3]=15
a[0][1][2][0]=17
a[0][1][2][1]=19
a[0][1][2][2]=21
a[0][1][2][3]=23
ASUM=288
SUMSQ=4600

3 Xcode编译Caffe源码

3.1 同上述一样,一定要配置好caffe所依赖的环境

3.2 新建Xcode工程

3.3 将caffe源码导入到工程中

所需要的源码部分是

1
2
CAFFE_ROOT/include/*
CAFFE_ROOT/src/*

这一步并不一定需要将源码copy到工程目录下,直接将这两部分引入到工程中也是可以的。
截个图:

xcodeconfig1

注意:一定要让文件夹称为黄色group,才算导入到了xcode工程,是蓝色文件夹会报错。

删除

1
2
CAFFE_ROOT/src/test/test_caffe_main.cpp
CAFFE_ROOT/src/gtest/gtest-all.cpp

因为这两个函数包含main,同一个工程只能包含一个main,否则会引起冲突。

main函数将可以自己写,同上;或者将CAFFE_ROOT/tools/caffe.cpp复制过来。

3.4 接下来的设置与上述大同小异,有几点不同

1. 工程include路径要加入include和src的路径
2. 工程other linker中,不要包含caffe的链接库-lcaffe
3. 添加额外的宏GTEST_USE_OWN_TR1_TUPLE

最终,配置文件为

1
2
3
4
5
6
7
8
9
10
OTHER_LDFLAGS = -lglog
-lboost_thread-mt -lboost_filesystem -lboost_system -lgflags -lprotobuf -lhdf5_hl -lhdf5 -lopenblas -lopencv_highgui -lopencv_imgproc -lopencv_core -lm -lsnappy -llmdb -lleveldb
HEADER_SEARCH_PATHS = /usr/local/opt/boost/include
/usr/local/opt/gflags/include /usr/local/opt/glog/include /usr/local/opt/openblas/include /usr/local/opt/protobuf/include /usr/local/opt/hdf5/include /usr/local/opt/opencv3/include /usr/local/opt/lmdb/include /usr/local/opt/leveldb/include CAFFE_ROOT/include CAFFE_ROOT/src
LIBRARY_SEARCH_PATHS = /usr/local/opt/glog/lib
/usr/local/opt/boost/lib /usr/local/opt/gflags/lib /usr/local/opt/protobuf/lib /usr/local/lib CAFFE_ROOT/build/lib /usr/local/opt/hdf5/lib /usr/local/opt/openblas/lib /usr/local/opt/opencv3/lib
GCC_PREPROCESSOR_DEFINITIONS = CPU_ONLY GTEST_USE_OWN_TR1_TUPLE

编译完成。可以在caffe源码的任意位置设置断点,调试。

4. 利用.xcconfig文件保存配置

另外,利用xcode配置文件xcconfig可以保存配置,在新工程中直接导入即可,一劳永逸。

  • 在配置好的工程的配置页面Build etting中,选中所有的修改过的条目(按下Command,可以选中多条),再按Command+C复制。
  • 在新工程中,新建文件,选择configuration setting file,如图:
    xcodeconfig2
  • 按Command+V 粘贴过来,可以有选择的删除一下。格式如上文所示。
  • 最后为该工程选择该配置文件,在工程属性Info页面,如图:
    xcodeconfig3

5. 总结

所以,无论任何的程序配置,归根到底都是路径的问题,只要路径配置正确,就能够解决一切问题。

正如同caffe21天所说的一样,了解了低层次的原理,就能够达到高层次的自由:掌握了c++的原理,就能够达到caffe的自由;掌握了caffe的原理,就能够达到深度学习的自由。同理,掌握的操作系统程序编译的原理,就能够达到程序配置的自由,无论任何的库函数,任何的IDE,任何的操作系统,都不会对我们造成困扰。凡事要了解事情的来龙去脉,才能够达到更广阔的自由。