如何用TensorFlow追踪《星战》里的千年隼飞船?

685 阅读6分钟

戳这里看最终实现的效果视频(不然你可能看一半儿就没动力了)


现在很多科技巨头如 IBM、谷歌、微软和亚马逊都推出了简便易用的视觉识别 API,甚至一些小型公司如 Clarifai 等也推出的相似的 API。此外,Facebook今年年初宣布开源其物体检测平台 Detectron,用于推动计算机视觉领域的研究。

下面两幅照片都用 IBM 的 Watson Visual Recognition 中的默认分类器打上了标签,但第一幅图在此之前首先被一个物体检测模型标注过。

物体检测技术自身远比视觉识别先进,但如果你想使用这项技术,得自己下一番功夫。

根据自己的实际用途,你可能并不需要一个自定义的物体检测模型。TensorFlow 的物体检测 API 提供了几个模型,可以调整速度和准确率,都是基于 COCO 数据集

为了让大家方便一些,我(作者 Nick Bourdakos——译者注)做了一个列表,将用 COCO 模型可以检测出的物体放在了一起:

如果你想检测上述列表中没有的物体,比如 logo 什么的,你只能创建一个自定义物体检测器。我自己很喜欢看《星球大战》,尤其喜欢里面的千年隼飞船,所以我想搭建一个模型,识别电影里的千年隼飞船和一些钛战机。可能你觉得这算什么点子,但你不知道这对一个《星球大战》死忠粉来说,究竟有多重要······

某不知名的星战粉丝古先生

注释你的照片

训练你的模型需要做很多工作。看到这,你可能会想“哎,哎,哎!我最不想听的就是要干很多活!”如果你真的很不像自己搭建和训练模型,你可以找找相关教程,使用一些平台上提供的已经封装好的模型。

回归正题,谈谈怎么用 TensorFlow 追踪《星球大战》中的千年隼。

首先你需要收集很多照片,将它们全部注释,包括标记出对象坐标和相应的标签等。对于照片中有两架钛战机的情况,可以这样注释:

<annotation>
   <folder>images</folder>
   <filename>image1.jpg</filename>
   <size>
       <width>1000</width>
       <height>563</height>
   </size>
   <segmented>0</segmented>
   <object>
       <name>Tie Fighter</name>
       <bndbox>
           <xmin>112</xmin>
           <ymin>281</ymin>
           <xmax>122</xmax>
           <ymax>291</ymax>
       </bndbox>
   </object>
   <object>
       <name>Tie Fighter</name>
       <bndbox>
           <xmin>87</xmin>
           <ymin>260</ymin>
           <xmax>95</xmax>
           <ymax>268</ymax>
       </bndbox>
   </object>
</annotation>

在搭建我的这个《星球大战》追踪模型的时候,我收集了 308 张图像,每张图像中都有 2 个或 3 个对象。我建议你对每个物体试着找到 200-300 个样例。

你可能会想,“天呐,那我岂不要看成百上千张图像,给每张图像写一大堆的 XML?”

当然不用这样了!有很多注释工具可以让我们用,比如 LabelImg 和 RectLabel。我用的是RectLabel,但是它只有 macOS 版。不过 LabelImg 有Windows 版,用 Windows 系统的同学可以研究怎么用这个工具。

虽然有了注释工具,还是有不少的工作要做,将我的整个数据集注释完,前前后后花了 3 个小时。

如果嫌麻烦,土豪同学可以雇个实习生干这个活,也可以在 Mechanical Turk 上花钱请人众包帮你做。但你要是和我一样是个穷学生,那还是自己撸起袖子加油干吧。

在创建注释的时候,如果你不想写你自己的转换脚本,请确保将注释导出为 PASCAL VOC 格式。我和其他不少同学用的也是这个格式,所以你可以直接“偷师”我上面写的脚本(其实我也是从别人那里“偷师”来的)。

在我们运行脚本为 TensorFlow 准备数据之前,我们还需要做一点微小工作。

复制 Repo

首先点击这里,复制我的 repo

目录结构应该是这样:

models
|-- annotations
|   |-- label_map.pbtxt
|   |-- trainval.txt
|   `-- xmls
|       |-- 1.xml
|       |-- 2.xml
|       |-- 3.xml
|       `-- ...
|-- images
|   |-- 1.jpg
|   |-- 2.jpg
|   |-- 3.jpg
|   `-- ...
|-- object_detection
|   `-- ...
`-- ...

我在 Repo 里包含了训练数据,你可以直接拿去用。但是如果你想用自己的训练数据搭建一个模型,你需要将训练图像添加至 images,将 XML 注释添加至 annotations/xmls,更新 trainval.txt 和 label_map.pbtxt。

trainval.txt 是一列文件名,能让我们发现和将 JPG 文件与 XML 文件关联。比如,下面的 trainval.txt 列表会让我们找到 abc.jpg,abc.xml,123.jpg,123.xml,xyz.jpg 和 xyz.xml 文件:

abc
123
Xyz

注意:一定确保你的 JPG 文件和 XML 文件名一致,不包含扩展名。

label_map.pbtxt 是一列我们想要检测的对象,该列应该看起来如下:

item {
 id: 1
 name: 'Millennium Falcon'
}
item {
 id: 2
 name: 'Tie Fighter'
}

运行脚本

首先,使用电脑上已安装的 Python 和 pip 安装脚本要求:

pip install -r requirements.txt

向 PYTHONPATH 中添加 models 和 models/slim:

export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

重要提醒:每次打开终端都必须这样运行,或添加至你的 ~/.bashrc 文件。

运行脚本:

python object_detection/create_tf_record.py

一旦脚本完成运行,你会得到一个 train.record 文件和一个 val.record 文件。我们训练模型会用到它们。

下载一个基本模型

从零训练一个物体检测器要花好几天,即便是在使用多个 GPU 的情况下也是如此。为了加快训练速度,我们会用一个由多种不同数据集上训练得来的模型,将该模型的参数重新用于初始化我们的新模型。

你可以从这个动物园模型上下载一个模型。每个模型的准确率和速度都各有不同,我用的是 faster_rcnn_resnet101_coco。

将所有的 model.ckpt 文件提取并转移至我们的 repo 中的根目录。

你会看到一个叫 faster_rcnn_resnet101.config 的文件。它被设定用于处理 faster_rcnn_resnet101_coco 模型。如果你用的是另一种模型,你可以点击这里,获取相应的配置文件

准备训练

运行如下语句,就会开始训练了!

python object_detection/train.py \
       --logtostderr \
       --train_dir=train \
       --pipeline_config_path=faster_rcnn_resnet101.config

注意:用你的配置文件的位置替换 pipeline_config_path。

global step 1:
global step 2:
global step 3:
global step 4:
...

耶!凑效了!

10分钟后:

global step 41:
global step 42:
global step 43:
global step 44:
...

电脑都快冒烟了······

global step 71:
global step 72:
global step 73:
global step 74:
...

这究竟要多久啊?

我用的模型运行了 2 万 2 千步。

等等,你说啥?!

enter_image_description_here

我用的是一台老旧的 MacBook Pro。如果你也是在类似配置的电脑上训练,我估计你的速度也是 15 秒每步,差不多就是这个速度。那么按照这个数据,你得花上 3 到 4 天不停的训练才能得到一个差不多的模型。

好吧,这太让人无语了,我可没时间等这个。

PowerAI 前来救驾!!

PowerAI

PowerAI 能让我们在 IBM P 系列服务器上以 P100 GPU 快速地训练我们的模型!

有了 PowerAI,训练 1 万步只需 1 个小时。但是,这只是用了 1 个GPU。PowerAI 的真正力量源自它能以高达 95% 的效率在数百个 GPU 上进行分布式的深度学习。

速度很快!

因为我不需要训练几百万个图像,所有我也就不需要用几百个 GPU,有1个就够了。

创建 Nimbix 账户

开发者可以在 Nimbix 创建一个账户,每个账户可以在 PowerAI 上免费处理数据10小时。点击这里注册

注意:这个注册过程不是自动的,需要24小时等候审核和批准,所以想免费用这10小时的同学请规划好时间。

一旦申请获批,你会收到一封邮件,确认和创建你的 Nimbix 账户。邮件里会问你要一个优惠码,不用管它,空着就行。

现在你应该可以在这里登录了。

部署 PowerAI Notebooks 应用

首先搜索 PowerAI Notebooks。

点击它,然后选择 TensorFlow。

选择机器类型为 32 thread POWER8, 128GB RAM, 1x P100 GPU w/NVLink (np8g1)。

一旦开始,就会出现下面的控制面板。当服务器的 status 变为 processing 时,就开始访问服务器了。

点击(click to show),获取密码。

然后点击 Click here to connect 启动 Notebook。

使用用户名 nimbix 和刚才获取的密码登录。

开始训练

点击 New 下拉菜单,选择 Terminal,得到一个新的终端窗口:

然后你会看到一个熟悉的模样:

注意:终端可能在 Safari 上不适用。

训练这一步和我们在本地环境下运行的步骤一样。如果你使用的是我用的训练数据,那么你只需运行如下语句复制我的 repo(如果不是用的我的训练数据,那就复制你自己的 repo):

git clone https://github.com/bourdakos1/Custom-Object-Detection.git

然后通过 cd 进入根目录:

cd Custom-Object-Detection

运行下面的代码段,它会下载下来我们之前下载的预训练模型

faster_rcnn_resnet101_coco:

wget 

http://storage.googleapis.com/download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_coco_11_06_2017.tar.gz
tar -xvf faster_rcnn_resnet101_coco_11_06_2017.tar.gz
mv faster_rcnn_resnet101_coco_11_06_2017/model.ckpt.* .

然后我们需要再次更新 PYTHONPATH,因为这是在新的终端中:

export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

接着我们终于能再次执行训练命令了:

python object_detection/train.py \
       --logtostderr \
       --train_dir=train \
       --pipeline_config_path=faster_rcnn_resnet101.config

下载你的模型

模型什么时候能准备好呀?这要根据你的训练数据的多少。数据越多,你需要的步骤就越多。我的模型差不过在 4500 步左右时趋于平稳,在 20000 步左右时达到顶峰。我继续训练,一直训练了 20 万步,但是效果没有进一步改善。

我建议你每 5000 步下载一次模型,然后进行评估,以确保你训练的方式是正确的。

点击左上角的 Jupyter 的 logo,然后导航文件树至 Custom-Object-Detection/train。

下载所有数字最高的 model.ckpt 文件:

  • model.ckpt-STEP_NUMBER.data-00000-of-00001
  • model.ckpt-STEP_NUMBER.index
  • model.ckpt-STEP_NUMBER.meta

注:你可以每次只下载一个。

注:一定在训练完成后点击电脑上的那个红色按钮,否则计时器会一直计算时间。

导出推理图

要想用我们的代码使用整个模型,我们需要将检查点文件( model.ckpt-STEP_NUMBER.* )转换成一个冻结的推理图(inference graph)。

将刚才下载到的检查点文件转移至你一直在用的 repo 中的根文件夹里。

然后运行如下命令:

python object_detection/export_inference_graph.py \
       --input_type image_tensor \
       --pipeline_config_path faster_rcnn_resnet101.config \
       --trained_checkpoint_prefix model.ckpt-STEP_NUMBER \
       --output_directory output_inference_graph

记得 export PYTHONPATH=$PYTHONPATH:pwd:pwd/slim。

你应该会看到一个新的 output_inference_graph 目录,包含一个 frozen_inference_graph.pb 文件。这就是我们需要的文件。

测试模型

现在,运行如下命令:

python object_detection/object_detection_runner.py

然后就会在 test_images 目录里的所有图像上运行在 output_inference_graph/frozen_inference_graph.pb 中发现的对象检测模型,并将结果导出在 output/test_images 目录中。

结果

我们把搭建的模型运行于《星球大战:原力觉醒》中的片段,就得到如开头视频的检测结果了。

从视频中可以看到,我们搭建的模型成功地追踪到了影片中的千年隼飞船和钛战机。

enter_image_description_here

当然也欢迎你在其他作品上进行练习,完成以后分享出来并@景略集智 我们一起看看。