最近在最嵌入式的课程设计,跟同学借了一块Jetson TK1开发板,准备做一个嵌入式端的石头剪刀布小游戏,因为之前一直是在台式机和服务器上跑实验,这一次借这门课的机会试一试在嵌入式开发板上跑跑模型。
目前英伟达已经出了Jetson TX1 和 Jetson TX2,所以Jetson TK1已经算是比较老的开发板了,在网上找到的关于Jetson TK1的资料也都是一两年前甚至更久的,所以在配置开发环境的过程中也踩了一些坑,整理了一些教程。希望能对有需要的朋友(跟我一样用不起Jetson TX1 和 TX2~~)有所帮助。
我的最终目的是:在TK1上用QT Creator写一个石头剪刀布小游戏,过程中调用训练好的静态手势分类模型做前向。
我使用的是caffe,类比台式机,环境的配置过程无外乎:
- 装系统;
- CUDA和cudnn;
- opencv;
- caffe相关的各种依赖库安装;
- 编译caffe源码。
下面一步一步讲(本文的重点在于caffe源码版本和cudnn版本的匹配,所以其它部分就没有写得很细致了,如果有需要可以参考其它的博客):
1 关于系统
关于系统一般有下面的两种情况:
- 拿到全新的TK1:使用
sudo ./installer.sh
来安装板子自带的系统; - 借来的别人用过的TK1:可以直接使用原有的系统,或者使用Jetpack进行刷机,可以参考: link(我自己并没有试过刷机)。
2 关于CUDA和cudnn
- 安装CUDA。参照 link安装CUDA,教程中包括CUDA 6.0 和 6.5,我使用的是CUDA 6.5;
- 安装cudnn。TK1 支持的是cuDNN v2 Library for L4T (ARM) 21.1和cuDNN v1 Library for L4T (ARM) 21.1(下面简称cudnn v1 和 cudnn v2),可以直接到 link下载,配置cudnn的过程和普通台式机的ubuntu是一样的,就是对几个文件的拷贝还有建立软连接(下面没有特殊说明的话,我使用的是cudnn v2)。
3 关于opencv
在板子上安装opencv,参照: link,我参照的是:Prebuilt OpenCV4Tegra library for L4T部分。
4 关于caffe各种依赖库的安装
可以参照 link中的命令安装依赖库,安装依赖库的时候最好确保网速比较给力一点,不然可能等很久。如果缺少什么依赖库也不要紧,后面编译的时候发现再sudo apt-get install
一下就OK。
5 关于caffe的编译和使用(这是本文的重点)
如果上面的几个步骤都顺利完成,那么接下来就可以开始编译caffe啦,先喝杯水,上个厕所之类的,下面的过程才是本文的重点。
开始吧~~
编译的过程中有下面的公共性的操作:
- 在caffe的根目录下
cp Makefile.config.example Makefile.config
; - 将Makefile.config中的
# CUSTOM_CXX := g++
取消注释并改为CUSTOM_CXX := g++-4.7
; - 将Makefile.config中的
# USE_CUDNN := 1
取消注释(如果想使用cudnn进行加速的话);
我将按照我在TK1上开始编译caffe到最终成功使用编译好的caffe的时间顺序来讲解:
直接clone最新版本的caffe:
sudo apt-get install -y git git clone https://github.com/BVLC/caffe.git
编译的过程中报了关于cudnn函数的一系列错误,是因为cudnn v2的相关函数和最新版本的caffe的函数不对应,这意味着使用最新版使用cudnn加速的话无法在TK1上编译最新的caffe源码。
这里需要说明一下,在有一些教程中使用cd caffe && git checkout dev
将caffe切换到dev分支,但是注意,这是过时的方法了,dev 这个分支在caffe中已经不存在了,所以这个操作是无效的。
既然最新版本的caffe不能用,那就找一下以前的caffe版本来试试, link,下面是尝试的过程:
- 使用link中rc2即更早的版本(因为rc3之后不支持cudnn v1 和 cudnn v2了)的caffe+cudnn v2编译,编译的时候出现了关于cudnn的一大堆错误,尽管cudnn v2的名称叫cudnn-6.5-linux-ARMv7-R2-rc1.tgz,但是使用rc1版本的caffe编译同样出错(这一点还没有搞懂,报的是关于g++4.7的错误);
- 使用link中rc3及之后的版本+cudnn v2编译也出现cudnn的错误(这一点可以理解,因为rc3的说明中表示不再支持cudnn v1和v2);
既然cudnn v2和link中所有的caffe版本都不能编译成功,有点郁闷,看到教程link中说使用cuDNN v4 Library for L4T (ARMv7)(下面简称cudnn v4)可以编译成功,cuDNN v4 只能支持CUDA 7.0即以上版本,不过还是将信将疑的试了一下:
使用link中的1.0-rc3版本+cudnn v4可以编译成功,但是
make runtest
的时候都出现下面的错误(make runtest
出现下面的错误会导致后面测试build/tools/caffe time --model=models/bvlc_alexnet/deploy.prototxt --gpu=0
的时候出现同样的错误):Check failed: status == CUDNN_STATUS_SUCCESS (6 vs. 0) CUDNN_STATUS_NOT_INITIALIZED
所以,使用cudnn v4虽然可以编译成功,但是真正使用的时候还是出了问题。
- 使用link中rc2即更早的版本的caffe+cudnn v4编译,
make all -j4
出现了cudnn的报错,同样应该是cudnn中函数和caffe的版本冲突导致编译报错。
前面的尝试都失败了,我意识到最最关键的原因还是caffe源码版本的问题,那么如何才能找到合适的caffe源码版本呢?
- link中的tmkasun提到一个 caffe fork (caffe-for-cudnn-v2.5.48),这里的源码可以用于TK1上的cudnn v2(我下面就是使用这个版本的caffe源码+cudnn v2编译成功并正常使用)。
- 另外,caffe fork中hayday100还提到了另外的一个 caffe fork 2,也是使用于TK1的caffe源码(不过我并没有尝试这一源码,在这里把它贴出来供参考);
总结一下,最终,我使用下面的两种方法成功在TK1上正常使用caffe:
- caffe fork (caffe-for-cudnn-v2.5.48) + cudnn v2;
- 干脆不使用cudnn(将将Makefile.config中的
# USE_CUDNN := 1
注释加上),我使用目前caffe的master分支源码和link中1.0版本的caffe源码都能够编译测试通过(其它版本的caffe应该也可以,前面的问题主要都是cudnn造成的,不使用cudnn进行编译之后,很多个版本的caffe就能用起来了)。
Attention:使用上述的1方法,在TK1上,bvlc_alexnet的平均前向时间为226ms,而使用方法2(link中1.0版本)的时间为225ms,也就是说方法2没有cudnn加速,反而比方法1快了一点,可能是因为方法2的caffe源码的版本比较新,优化比较好(所以说,在TK1上不一定要用cudnn加速,毕竟cudnn v2也确实有点老了~~)。
编译成功后,可能还会遇到一些小问题,下面列举出来(这些问题在link中基本上都有覆盖到):
make runtest -j4
的过程中出现了下面的错误:F0202 10:28:31.158313 14086 db_lmdb.hpp:13] Check failed: mdb_status == 0 (-30792 vs. 0) MDB_MAP_FULL: Environment mapsize limit reached
这是因为caffe中
src/caffe/util/db_lmdb.cpp
中设置的LMDB_MAP_SIZE
变量的值为1TB远大于TK1上可接受的范围。因此需要修改该文件中LMDB_MAP_SIZE
的值,按照 link将1099511627776(1 TB)改成1073741824(1 GB)。如果要跑一下mnist的例程(
sudo sh examples/mnist/train_lenet.sh
),可能会下面的问题:过程中制作lmdb(
sudo sh examples/mnist/create_mnist.sh
)的时候出现了下面的错误:error while loading shared libraries: libcudart.so.6.5: cannot open shared object file: No such file
参考 link中移动相应的文件即可;
解决上述错误之后,可能还会出现下面的错误:
F0413 15:08:19.918817 9137 convert_mnist_data.cpp:132] Check failed: mdb_put(mdb_txn, mdb_dbi, &mdb_key, &mdb_data, 0) == 0 (-30792 vs. 0) mdb_put failed
同样,参照 link将
examples/mnist/convert_mnist_data.cpp
中的1099511627776 改为1073741824 即可。
解决了上述问题之后,基本上就可以正常在TK1上使用caffe了。
一些其他的东西:
- Jetson TK1上的CPU和GPU是共用2G的物理内存的( link),
nvidia-smi
命令无法使用,可以直接使用top
查看物理内存。 - 由于TK1CPU和GPU是共用物理内存的特点,可以参照 link使用Zero Copy加速GPU的内存读取速度。
上述就是我在TK1上配置caffe的整个过程,接下来就可以像在台式机上一样在TK1上使用caffe了,只是显存比较小~~
前面提到的石头剪刀布小游戏的代码: code