Comment on page
实践
Star是一种美德。
最近在做一个项目,要在树莓派上分析视频中的图片,检测目标,统计目标个数,这是一张样例图片:

当下效果最好的目标检测都是基于神经网络来做的,包括faster rcnn, ssd, yolo2等等,要在树莓派这种资源紧张的设备上运行检测模型,首先想到的就是用最轻量的MobileNet SSD,使用Tensorflow object detection api实现的MobileNet SSD虽然已经非常轻,但在树莓派上推导一张1280x720的图仍然需要2秒,有兴趣的同学可以参考这两个项目:
- Tensorflow Object detection API: https://github.com/tensorflow/models/tree/master/research/object_detection
具体的操作在Tensorflow文档里都说的很清楚了,在树莓派上的操作也是一样的,有问题可以评论区讨论
处理器 | Intel Movidius VPU |
支持框架 | TensorFlow, Caffe |
连接方式 | USB 3.0 Type-A |
尺寸 | USB stick (72.5mm X 27mm X 14mm) |
工作温度 | 0° - 40° C |
| |
| x86_64 Ubuntu 16.04主机 |
| Raspberry Pi 3B Stretch desktop |
| Ubuntu 16.04 虚拟机 |
系统要求 | USB 2.0 以上 (推荐 USB 3.0) |
| 1GB 内存 |
| 4GB 存储 |
| |
实际上这不是一个GPU,而是一个专用计算芯片,但能起到类似GPU对神经网络运算的加速作用。
京东上搜名字可以买到,只要500元左右,想想一块GPU都要几千块钱,就会觉得很值了。
虽然目前NCSDK支持的框架包含Tensorflow和Caffe,但并不是支持所有的模型,目前已支持的模型列表可以在这里查到:https://github.com/movidius/ncsdk/releases
截止到2018年3月15日,NCSDK还没有支持Tensorflow版的MobileNet SSD(比如
tf.cast
这个操作还未被支持),所以我们需要用Caffe来训练模型,部署到树莓派上。ncsdk的环境分为两部分,训练端和测试端。
- 训练端通常是一个Ubuntu 带GPU主机,训练Caffe或TensorFlow模型,编译成NCS可以执行的graph;
- 测试端则面向ncs python mvnc api编程,可以运行在树莓派上raspbian stretch版本,也可以运行在训练端这种机器上。
安装这个过程,说难不难,也就几行命令的事情,但也有很多坑
在训练端主机上,插入神经计算棒,然后:
git clone https://github.com/movidius/ncsdk
cd ncsdk
make install
其中,make install干的是这些事情:
- 检查安装Tensorflow
- 编译安装ncsdk(不包含inference模块,只包含mvNCCompile相关模块,用来将Caffe或Tensorflow模型转成NCS graph的)
注意,
- 这些库都是安装到
/opt/movidius/
这个目录下,并关联到系统python3里边的(/usr/bin/python3
),如果你电脑里原来有tf或caffe,也不会被关联上去 - NCSDK mvNCCompile模块目前只兼容python3,我尝试过将安装完的SDK改成兼容python2的版本,可以将模型编译出来,但是在运行时会报错,所以暂时放弃兼容python2了,也建议大家用默认的python3版本
- 这个步骤主要的坑来自万恶的Caffe,如果你装过python3版的caffe,大概会有经验一些,这里有几个小坑提示一下:
- 最好在ncsdk目录中的ncsdk.conf中,开启caffe的cuda支持,即设置
CAFFE_USE_CUDA=yes
,这样你之后也能用这个caffe来训练模型 - caffe的依赖会在脚本中安装,但有些Debian兼容问题要解决
- 开启CUDA支持后,编译caffe会找不到libboost-python3,因为在Ubuntu16.04里,它叫libboost-python3.5,所以要软链接一下:
cd /usr/lib/x86_64-linux-gnu/
sudo ln -s libboost_python-py35.so libboost_python3.so
一波操作之后,我们装好了ncsdk编译模块,可以下载我训练的caffe模型,尝试编译成ncs graph
git clone https://github.com/ahangchen/MobileNetSSD
mvNCCompile example/MobileNetSSD_deploy.prototxt -w MobileNetSSD_deploy.caffemodel -s 12 -is 300 300 -o ncs_mobilenet_ssd_graph
这里其实是调用python3去执行/usr/local/bin/ncsdk/mvNCCompile.py这个文件, 不出意外在当前版本(1.12.00)你会遇到这个错误:
[Error 17] Toolkit Error: Internal Error: Could not build graph. Missing link: conv11_mbox_conf
这是因为NCSDK在处理caffe模型的时候,会把conv11_mbox_conf_new节点叫做conv11_mbox_conf,所以build graph的时候就会找不着。因此需要为这种节点起一个别名,即,将conv11_mbox_conf_new起别名为conv11_mbox_conf,修改SDK代码中的/usr/local/bin/ncsdk/Models/NetworkStage.py,在第85行后面添加:
if ''_new' in name:
self.alias.append(name[:-4])
于是就能编译生成graph了,你会看到一个名为ncs_mobilenet_ssd_graph的文件。
上边这个bug我已经跟NCSDK的工程师讲了,他们在跟进修这个bug:

测试端要安装ncsdk python api,用于inference,实际上测试端能做的操作,训练端也都能做
git clone https://github.com/movidius/ncsdk
cd api/src
make install
从输出日志可以发现,将ncsdk的lib和include文件分别和系统的python2(/usr/bin/python2)和python3(/usr/bin/python3)做了关联。
然后你可以下一个GitHub工程来跑一些测试:
git clone https://github.com/movidius/ncappzoo
cd ncappzoo/apps/hello_ncs_py
python3 hello_ncs.py
python2 hello_ncs.py
没报错就是装好了,测试端很简单。
就是正常的用caffe训练MobileNet-SSD,主要参考这个仓库:
README里将步骤讲得很清楚了
- 1.下载SSD-caffe(这个我们已经在NCSDK里装了)
- 2.
- 3.把MobileNet-SSD这个项目放到SSD-Caffe的examples目录下,这一步可以不做,但是要对应修改train.sh里的caffe目录位置
- 4.创建你自己的
labelmap.prototxt
,放到MobileNet-SSD目录下,比如说,你是在coco预训练模型上训练的话,可以把coco的标签文件复制过来,将其中与你的目标类(比如我的目标类是Cattle)相近的类(比如Coco中是Cow)改成对应的名字,并用它的label作为你的目标类的label。(比如我用21这个类代表Cattle) - 5.
- 6.假设你的打的标签是这样一个文件
raw_label.txt
,假装我们数据集只有两张图片:
data/strange_animal/1017.jpg 0.487500 0.320675 0.670000 0.433193
data/strange_animal/1018.jpg 0.215000 0.293952 0.617500 0.481013
- 我们的目标是将标签中涉及的
图片和位置信息
转成这样一个目录(在ssd-caffe/data/coco目录基础上生成的):coco_cattle├── all # 存放全部图片和xml标签文件│ ├── 1017.jpg│ ├── 1017.xml│ ├── 1018.jpg│ └── 1018.xml├── Annotations # 存放全部标签xml│ ├── 1017.xml│ └── 1018.xml├── create_data.sh # 将图片转为lmdb的脚本├── create_list.py # 根据ImageSets里的数据集划分文件,生成jpg和xml的对应关系文件到coco_cattle目录下,但我发现这个对应关系文件用不上├── images # 存放全部图片│ ├── 1017.jpg│ └── 1018.jpg├── ImageSets # 划分训练集,验证集和测试集等,如果只想分训练和验证的话,可以把minival.txt,testdev.txt,test.txt内容改成一样的│ ├── minival.txt│ ├── testdev.txt│ ├── test.txt│ └── train.txt├── labelmap_coco.prototxt # 如前所述的标签文件,改一下可以放到MobileNet-SSD目录下├── labels.txt├── lmdb # 手动创建这个目录│ ├── coco_cattle_minival_lmdb # 自动创建的,由图片和标签转换来的LMDB文件│ ├── coco_cattle_testdev_lmdb│ ├── coco_cattle_test_lmdb│ └── coco_cattle_train_lmdb├── minival.log├── README.md├── testdev.log├── test.log└── train.log - 其中,标签xml的格式如下:
<annotation>
<folder>train</folder>
<filename>86</filename>
<source>
<database>coco_cattle</database>
</source>
<size>
<width>720</width>
<height>1280</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>21</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>169</xmin>
<ymin>388</ymin>
<xmax>372</xmax>
<ymax>559</ymax>
</bndbox>
</object>
<object>
<name>21</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>169</xmin>
<ymin>388</ymin>
<xmax>372</xmax>
<ymax>559</ymax>
</bndbox>
</object>
</annotation>
代表一张图中多个对象所在位置(bndbox节点表示),以及类别(name)。
- 一开始,
all
,Annotations
,images
,ImageSets
,lmdb
四个目录都是空的,你可以把自己的图片放到随便哪个地方,只要在raw_label.txt里写好图片路径就行