学习笔记:深度学习中的目标检测

在前面的学习中,关注的大多数是图像识别问题:输入一张图像,输出该图像对应的类别。这篇文章将讨论目标检测问题。目标检测的输入同样是一张图像,但输出不单单是图像的类别,而是该图像中所含的所高目标物体以及它们的位置。通常使用矩形框来标识物体的位置,如图5-1所示。深度学习已经被广泛应用在目标检测问题上,在性能上也远远超过了传统方法。这篇学习笔记会先介绍深度学习中的几个经典的目标检测方法, 再以Google 公司开源的TensorFlow Object Detection API 为例,介绍如何在Tensor Flow 中进行目标检测。

这里写图片描述

1. 深度学习中目标检测的原理

1.1 R-CNN的原理

R-C NN 的全称是Region-CNN, 它可以说是第一个成功地将深度学习应用到目标检测上的算法。后面将要学习的Fast R-CNN 、Faster R-CNN全部都是建立在R-CNN基础上的。

传统的目标检测方法大多以图像识别为基础。一般可以在图片上使用穷举法选出所高物体可能出现的区域框,对这些区域框提取特征并使用图像识别分法分类, 得到所高分类成功的区域后, 通过非极大值抑制( Non-maximum
suppression )输出结果。

R-CNN遵循传统目标检测的思路, 同样采用提取框、对每个框提取特征、图像分类、非极大值抑制四个步骤进行目标检测。只不过在提取特征这
一步,将传统的特征(如SIFT 、HOG 特征等);换成了深度卷积网络提取的特征。R-CNN 的整体框架如图5-2 所示。
这里写图片描述

对于原始图像,首先使用Selective Search搜寻可能存在物体的区域。Selective Search 可以从图像中启发式地搜索出可能包含额物体的区域。相比穷举而言,Selective Search可以减少一部分计算量。下一步,将取出可能含有物体的区域送入CNN中提取特征。CNN通常是接受一个固定大小的图像,而取出的区域大小却各有不同。对此,R-CNN的做法是将区域缩放到统一大小,再使用CNN提取特征。提取特征后使用SVM进行分类,最后通过非极大值抑制输出结果。

R-CNN的训练可以分成下面四步:

  • 在数据集上训练CNN。R-CNN论文中使用的CNN网络是AlexNet,数据集是ImageNet。
  • 在目标检测的数据集上,对训练好的CNN做微调。
  • 用Selective Search搜索候选区域,同意使用微调后的CNN对这些区域提取特征,并将提取到的特征存储起来。
  • 使用存储起来的特征,训练SVM分类器

尽管R-CNN的识别框架与传统区别不是很大,但是得益于CNN优异的特征提取能力,R-CNN的效果还是比传统方法好很多。如在VOC2007数据集上,传统方法最高的平均精确度mAP ( mean Average Precision )为40%左右,而R-CNN 的mAP 达到了58.5%!

R-CNN 的缺点是计算量太大。在一张图片中,通过Selective Search 得到的有效区域往往在1000个以上,这意昧着要重复计算1000 多次神经网络,非常耗时。另外,在训练、阶段,还需要把所高特征保存起来,再通过SVM进行训练,这也是非常耗时且麻烦的。下面将要介绍的Fast R-CNN和FasterR-CNN在一定程度上改进了R-CNN 计算量大的缺点,不仅速度变快不少,识别准确率也得到了提高。

1.2 SPPNet 的原理

在学习R-CNN 的改进版Fast R-CNN 之前,作为前置知识,再必要学习
SPPNet 的原理。SPPNet 的英文全称是Spatial Pyramid Pooling Convolutional Networks,翻译成中文是“空间金字塔油化卷积网络” 。听起来十分高深,实际上原理并不难,简单来讲, SPPNet 主要做了一件事情:将CNN的输入从固定尺寸改进为任意尺寸。例如,在普通的CNN结构中,输入图像的尺寸往往是固定的(如244*244像素)。输出层可以看做是一个固定维数的向量。SPPNet在普通的CNN结构中加入了ROI池化层(ROI Pooling),使得网络的输入图像可以使任意尺寸的,输出层不变,同样是一个固定维数的向量。

ROI池化层一般跟在卷积层后面,它的输入是任意大小的卷积,输出是固定维数的向量, 如图5-3 所示。
这里写图片描述

为了说清楚为什么ROI池化层能够把任意大小的卷积特征转换成固定长度的向量,不妨假设卷积层的输出宽度为w,高度为h,通道为c。不管输入的图像尺寸是多少,卷积层的通道数不会变,也就是说c是一个常数。而w,h会随着输入图像尺寸的变化而变化,可以看做是两个变量。以上图中的ROI池化层为例,他首先将卷积层划分为4*4的网格,每个网格的宽度是w/4、高度是h/4、通道数为c。当不能整除时,需要取整。接着,对每个网格中的每个通道,都取出最大值,换句话说,就是对每个网格内的特征做最大值池化(Max Pooling)。这个4*4的网格最终形成了16c维的特征。接着,再把网络划分成2*2的网格,用同样的方法提取特征,提取的特征的长度为4c。再把网络划分为1*1的网格,提取的特征的长度就是c,最后的1*1的划分实际是取出卷积每个通道的最大值。最后,将得到的特征拼接起来,得到的特征是16c+4c+c=21c维的特征。很显然,这个输出特征的长度与w、h两个值是无关的,因此ROI池化层可以把任意宽度、高度的卷积特征转换为固定长度的向量。

应该怎么把ROI 池化层用到目标检测中来呢?其实,可以这样考虑该问题网络的输入是一张图像,中间经过若干卷积形成了卷积特征, 这个卷积特征实际上和原始图像在位置上是高一定对应关系的。如图5-4 所示, 原始图像中有一辆汽车,它使得卷积特征在同样位置产生了激活。因此,原始图像中的候选框,实际上也可以对应到卷积特征中相同位置的框。由于候选框的大小千变万化,对应到卷积特征的区域形状也各不相同,但是不用担心,利用ROI池化层可以把卷积特征中的不同形状的区域对应到同样长度的向量特征。综合上述步骤,就可以将原始图像中的不同长宽区域都对应到固定长度的向量特征,这就完成了各个区域的特征提取工作。
这里写图片描述

在R-CNN中,对于原始图像的各种候选区域框,必须把框中的图像缩放到统一大小,再对每一张缩放后的图片提取特征。使用ROI池化层后,就可以先对图像进行一遍卷积计算,得到整个图像的卷积特征;接着,对于原始图像中的各种候选框,只需要在卷积特征中找到对应的位置框,再使用ROI池化层对位置框中的卷积提取特征,就可以完成特征提取工作

R-CNN和SPPNet的不同点在于,R-CNN要对每个区域计算卷积,而SPPNet只需要计算一次,因此SPPNet的效率比R-CNN高得多。

R-CNN和SPPNet的相同点在于,他们都遵循这提取候选框、提取特征、分类这几个步骤。提取特征后,他们都是用了SVM进行分类。

1.3 Fast R-CNN的原理

在SPPNet中,实际上特征提取和区域分类两个步骤还是分离的。只是使用ROI池化层提取了每个区域的特征,再对这些区域分类时,还是使用传统的SVM作为分类器。Fast R-CNN相比SPPNet更进一步,不再使用SVM作为分类器,而是使用神经网络进行分类,这样就可以同时训练特征提取网络和分类网络,从而取得比SPPNet更高的准确度。如图5-5所示:

这里写图片描述

对于原始图片中的候选框区域,和SPPNet中的做法一样,都是将包映射到卷积特征的对应区域(即图5-5中的ROI projection),然后使用ROI池化层对该区域提取特征。在这之后, SPPNet 是使用SVM 对特征进行分类,而Fast R-CNN 则是直接使用全连接层。全连接层高两个输出,一个输出负责分类( 即图5-5 中的Softmax),另一个输出负责框回归(即图5-5中的bbox regressor )。

先说分类,假设要在图像中检测K类物体,那么最终的输出应该是K+1个数,每个数都代表该区域为某个类别的概率。之所以是K+1个输出而不是K个输出,是因为还需要一类“背景类”,针对该区域无目标物体的情况。

再说框回归,框回归实际上要做的是对原始的检测框进行某种程度的“校准”。因为使用Selective Search获得的框有时存在一定的偏差。设通过
Selective Search 得到的框的四个参数为(x,y,w,h),其中( x,y ) 表示框左上角的坐标位置,( w,h)的表示框的宽度和高度。而真正的框的位置用 ( x , y , w , h ) 表示。框回归就是要学习参数 ( x x w , y y h , l n w w , l n h h ) ,其中, x x w , y y h 两个数表示与尺度无关的平移量,而 l n w w , l n h h 表示的是和尺度无关的缩放量。

Fast R-CNN 与SPPNet 最大的区别就在于, Fast R-CNN 不再使用SVM进行分类,而是使用一个网络同时完成了提取特征、判断类别、框回归三项工作

1.4 Faste R-CNN 的原理

Fast R-CNN 看似很完美了,但在Fast R-CNN 中还存在着一个有点尴尬的问题:它需要先使用Selective Search提取框,这个方法比较慢,有时,检
测一张图片,大部分时间不是花在计算神经网络分类上,而是花在Selective
Search 提取框上!在Fast R-CNN 升级版Faster R-CNN 中,用RPN 网络
( Region Proposal Network )取代了Selective Search ,不仅速度得到大大提高,而且还获得了更加精确的结果。RPN 网络的结构如图5-6 所示。
这里写图片描述

RPN还是需要先使用一个CNN网络对原始图片提取特征。为了方便理解,不妨设这个前置的CNN提取的特征为5lx39x256,即高为51、宽为39 、通道数为256。对这个卷积特征再进行一次卷积计算,保持宽、高、通道不变,再次得到一个51x39x256 的特征。为了方便叙述, 先来定义一个“位置” 的概念:对于一个51×39×256的卷积特征,称它一共有51×39 个“位置”。让新的卷积特征的每一个“位置”都“负责”原图中对应位置9种尺寸的框的检测,检测的目标是判断框中是否存在一个物体,因此共有5lx39×9个“框”。在Faster R-CNN 的原论文中,将这些框都统一称为“anchor” 。

anchor 的9 种尺寸如图5-7 所示,官们的面积分别 128 2 256 2 512 2 。每种面积又分为3 种长宽比,分别是2:1 、1:2 、1:1 。anchor 的尺寸实际是属于可调的参数,不同任务可以选择不同的尺寸。
这里写图片描述

对于这51x39个位置和5lx39×9个anchor,图5-8展示了接下来每个位置的计算步骤。设k为单个位置对应的anchor的个数,此时k=9 。首先使用一个3x3 的滑动窗口,将每个位置转换为一个统一的256 维的特征,这个特征对应了两部分的输出。一部分表示该位置的anchor 为物体的概率, 这部分的总输出长度为2xk(一个anchor 对应两个输出·是物体的概率+不是物体的概率) 。另一部分为框回归,框回归的含义与Fast R-CNN中一样,一个anchor对应4个框回归参数,因此框回归部分的总输出的长度为4k。
这里写图片描述

Faster R-CNN 使用RPN生成候选框后,剩下的网络结构和Fast R-CNN中的结构一模一样。在训练过程中,需要训练两个网络,一个是RPN网络,一个是在得到框之后使用的分类网络。通常的做法是交替训练,即在一个batch 内,先训练RPN网络一次,再训练分类网络一次。

R-CNN 、Fast R-CNN 、Faster R-CNN 的对比见表5-1 。
这里写图片描述

从R-CNN,到Fast R-CNN ,再到Faster R-CNN ,不仅检测速度越来越快,而且检测的精确度也在不断提升。在出现R-CNN方法前,VOC 2007数据集上传统方法所能达到的最高平均精确度( mAP )为40% 左右, R-CNN将该值提高到了58.5%, Fast R-CNN 在VOC 2007 上的平均精确度为70%,Faster R-CNN 又将该值提高到了78.8% 。这几种方法既一脉相承,又不断改进,值得仔细研究。

2 TensorFlow Object Detection API

2017 年6 月, Google 公司开放了TensorFlow Object Detection API 。这个项目使用TensorFlow 实现了大多数深度学习目标检测框架,真中就包括
Faster R-CNN 。在本节中,首先介绍如何安装TensorF lo w Object Detection API,再介绍如何使用已经训练好的模型进行物体检测3 最后介绍如何训练自己的模型。

2.1 安装TensorFlow Object Detection API

在GitHub上, TensorFlow Object Detection API 是存放在tensorflow /models 项目(地址: https://github.com/tensorflow/models )下的。可以通过git来下载tensorflow/models:

下载tensorflow/models 代码后,应该得到一个models 文件夹。models文件夹中还高一个research文件夹。下面的安装命令都是以research文件夹为根目录执行的, 所说的目录也都是以research文件夹为相对目录。

安装TensorFlow Object Detection API的步骤如下( 以research文件夹为相对目录):
第一步:安装或升级protoc
在object_detection/protos/中,可以看到一些proto文件,需要使用protoc
程序将这些proto文件编译为Python文件。TensorFlow Object Detection API
必须使用2.6.0以上的protoc进行编译,否则会报错。可以使用命令protoc–version 查看protoc的版本。如果发现版本低于2.6.0 或运行命令错误,就
需要安装或升级protoc 。

安装或升级的方法是登录protobuf的发布页面: https ://github.com/
google/protobuf/releases 下载已经编译好的文件包。

如图5-9所示,默认再多种版本的预编译包。需要自行找到对应机器应该使用的文件。如64 位的ubun阳系统应下载文件protoc-3.3.0-linux-x86_64.zip, 64 位的OS X 系统应下载文件protoc-3 .3. 0-osx-x86_64 .zip 。下载文件后解压,会得到一个protoc 文件,将官复制到系统的可执行目录即可,如在ubuntu 系统中,可以执行以下命令:

sudo cp bin/protoc /usr/bin/protoc

这里写图片描述

第二步:编译proto文件
使用protoc对proto文件进行编译。具体来说,应当在research文件夹下,运行下面的命令:

# From models/research
protoc object_detection/ptotos/*.proto --python_out=.

运行完成后,可以检查object_detection/protos/文件夹,如果每个proto文件都生成了对应的以py为后缀的python源代码,就说明编译成功了。

第三步:将Slim加入PYTHONPATH
TensorFlow Object Detection API是以Slim为基础实现的,需要将Slim的目录加入PYTHONPATH后才能正确运行。具体来说,还是在research文件夹下, 执行下面的命令:

export PYTHONPATH=$PATHONPATH:'pwd':'pwd'/slim

执行命令完成后,可以使用python 命令打开一个python shell ,如果运行import slim 成功则说明已经正确设置好了。

第四步:安装完成测试
在research文件夹下,执行:

python object_detecion/builders/model_builder_test.py

这条命令会自动检查TensorFlow Object Detection API 是否正确安装,如果出现下面的信息,说明己安装成功:

2.2 执行已经训练好的模型

TensorFlow Object Detection API默认提供了5 个预训练模型,官们都是使用coco数据集训练完成的,结构分别为SSD+MobileNet、SSD+Inception、R-FCN+ResNet101、Faster RCNN+ResNet101、Faster RCNN+Inception_ResNet

如何使用这些预训练模型呢?官方已经给了一个用Jupyter Notebook 编写好的例子。首先在research文件夹下,运行命令: jupyter-notebook 。如果提示不存在该命令,可能是因为没高安装Jupyter Notebook ,需要自行安装。

运行命令jupyter-notebook后,打开http://localhost:8888,接着打开
object_ detection文件夹,井单击object_detection_tutorial.ipynb运行示例文件,如图5-10所示。
这里写图片描述

使用组合键”shift+ Enter “,可以依次执行这些命令。在这里介绍Notebook 中的命令,并给出相应的中文注释。

首先是导入一些需要的包和设置环境:

# 导入基本包
import numpy as np
import os
import six.moves.urllib as urllib
import sys
import tarfile
import tensorflow as tf
import zipfile

from collections import defaultdict
from io import StringIO
from matplotlib import pyplot as plt
from PIL import Image

# 这条命令让在使用matplotlib绘图时,不再使用窗口展示出来,而是直接在notebook中显示
%matplotlib inline

# 将上层目录导入进来,这样才可以执行这下面的三条导入命令
sys.path.append("..")
from object_detection.utils import ops as utils_ops
from utils import label_map_util
from utils import visualization_utils as vis_util

导入包后,设置需要使用的模型:

# What model to download.使用模型的名称,下面就会下载这个模型
MODEL_NAME = 'ssd_mobilenet_v1_coco_2017_11_17'
MODEL_FILE = MODEL_NAME + '.tar.gz'
DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'

# Path to frozen detection graph. This is the actual model that is used for the object detection.
# 这个文件保存了网络的结构和数据
PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb'

# List of the strings that is used to add correct label for each box.
# mscoco_label_map.pbtxt保存了index到类别映射的名称,它在object_detection/data文件下
PATH_TO_LABELS = os.path.join('data', 'mscoco_label_map.pbtxt')

NUM_CLASSES = 90

接下来下载预训练模型,根据网络环境的不同,下载的时间可能会有长有短。

opener = urllib.request.URLopener()
opener.retrieve(DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE)
tar_file = tarfile.open(MODEL_FILE)
for file in tar_file.getmembers():
  file_name = os.path.basename(file.name)
  if 'frozen_inference_graph.pb' in file_name:
    tar_file.extract(file, os.getcwd())

这里程序组合了DOWNLOAD_BASE和MODEL_FILE两个变量得到了下载地址。很显然,由于MODEL_FILE的值是‘ssd_mobilenet_v1_coco_11_06_2017’,因此下载的模型SSD+MobileNet。如何下载其他预训练模型并执行呢?实际上也很简单,可以打开TensorFlow detection model zoo,找到其他模型的下载地址。根据这些下载地址,只需要改变MODEL_FILE的值就可以下载不同的模型。为方便查阅,在此处也列出这些值:

MODEL_NAME = 'ssd_inception_v2_coco_11_06_2017'
MODEL NAME = 'rfcn_resnet101_coco_11_06_2017'
MODEL NAME = 'faster_rcnn_resne101_coco_11_06_2017'
MODEL NAME = ' faster_rcnn_inception_resnet_v2_atrous_coco_11_062017'

回到示例代码,下载模型后,程序就直接将读取到默认的计算图中(实际读取的是frozen_inference_graph.pb 文件),使用的代码如下所示:

# 新建一个图
detection_graph = tf.Graph()
with detection_graph.as_default():
  od_graph_def = tf.GraphDef()
  # PATH_TO_CKPT指向了文件frozen_inference_graph.pb
  with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
    serialized_graph = fid.read()
    od_graph_def.ParseFromString(serialized_graph)
    tf.import_graph_def(od_graph_def, name='')

在进行真正的检测之前,还得定义一些帮助函数:

# 这部分代码的功能是将神经网络监测得到的index(数字)转换为类别名(字符串)
label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)

# 这个函数也是一个方便使用的帮助函数,功能是将图片转换成numpy数组的形式
def load_image_into_numpy_array(image):
  (im_width, im_height) = image.size
  return np.array(image.getdata()).reshape(
      (im_height, im_width, 3)).astype(np.uint8)

下面开始检测图片!先定义要检测的图片:

# For the sake of simplicity we will use only 2 images:
# image1.jpg
# image2.jpg
# If you want to test the code with your images, just add path to the images to the TEST_IMAGE_PATHS.
# 只检测两张图片
PATH_TO_TEST_IMAGES_DIR = 'test_images'
TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 3) ]

# Size, in inches, of the output images.
# 输出图像的大小(单位是 in)
IMAGE_SIZE = (12, 8)

TEST_IMAGE_PATHS 是一个列表,它保存了需要检测的图片。这里检测的图片是官方提供的示例图片。如果想要检测自己的图片,只要将这些图片的路径以列表形式保存在TEST_IMAGE_PATHS中就可以了。

最后是检测的代码,同样给出中文注释:

# 最后就是检测代码了
# detection_graph是之前就定义好的计算图,已经将模型导入到内存中了,此处直接使用
with detection_graph.as_default():
  with tf.Session(graph=detection_graph) as sess:
    # Definite input and output Tensors for detection_graph
    image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
    # Each box represents a part of the image where a particular object was detected.
    # detection_boxes变量存放了所有检测框
    detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
    # Each score represent how level of confidence for each of the objects.
    # Score is shown on the result image, together with the class label.
    # detection_scores表示了每个检测结果的confidence
    detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
    # detection_classes表示每个框对应的类别
    detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')
    # num_detections表示检测框的个数
    num_detections = detection_graph.get_tensor_by_name('num_detections:0')
    for image_path in TEST_IMAGE_PATHS:
      image = Image.open(image_path)
      # 将图片转成Numpy形式
      # the array based representation of the image will be used later in order to prepare the
      # result image with boxes and labels on it.
      image_np = load_image_into_numpy_array(image)
      # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
      # 将图片扩展一维,最后进入神经网络的图片格式应该为[1, ?, ?, 3]
      image_np_expanded = np.expand_dims(image_np, axis=0)
      # Actual detection.
      # 使用sess.run,真正开始计算
      (boxes, scores, classes, num) = sess.run(
          [detection_boxes, detection_scores, detection_classes, num_detections],
          feed_dict={image_tensor: image_np_expanded})
      # Visualization of the results of a detection.
      # 对得到的检测结果进行可视化
      vis_util.visualize_boxes_and_labels_on_image_array(
          image_np,
          np.squeeze(boxes),
          np.squeeze(classes).astype(np.int32),
          np.squeeze(scores),
          category_index,
          use_normalized_coordinates=True,
          line_thickness=8)
      plt.figure(figsize=IMAGE_SIZE)
      plt.imshow(image_np)

# 显示最终的图像
plt.show()

这里写图片描述

这里写图片描述

2.3 训练新模型

以VOC 2012 数据集为例,介绍如何使用TensorFlow Object DetectionAPI 训练新的模型。VOC 2012 是VOC 2007 数据集的升级版,一共高11530张图片,每张图片都高标注,标洼的物体包括人、动物(如猫、狗、岛等)、交通工具(如车、船飞机等)、家具(如椅子、桌子、沙发等)在内的20 个类别。圈子12 展示了VOC 2012 中的一张图片。
这里写图片描述

首先下载数据集,并将其转换为tfrecord格式。voe 2012数据集的下载地址点击这

为了不影响代码的结构,不妨在object_detection 文件夹中, 再新建一个voc 文件夹,并将下载的数据集压缩包复制至voc/中。解压后,就得到一个VOCdevkit 文件夹,最终的文件夹结构应该为:
这里写图片描述

JPEGlmages文件夹中存储了所高的图像数据。对于每一张图片,都在
Annotations文件夹中有其物体框的标注。

在object_detection文件夹中,执行以下命令可以将VOC 2012数据集转
换为tfrecord格式,转换好的tfrecord保存在新建的voc文件夹下,分别为pascal_train.record和pascal_val.record :

python create_pascal_tf_record.py --data_dir voc/VOCdevkit/ --year=VOC2012 --set=train --output_path=voc/pascal_train.record

python create_pascal_tf_record.py --data_dir voc/VOCdevkit/ --year=VOC2012 --set=val --output_path=voc/pascal_val.record

此外,将pascal_label_map.pbtxt 数据复制到voc文件夹下:

cp data/pascal_label_map.pbtxt voc/

这里的转换代码是为VOC 2012数据集提前编写好的。如果希望使用自己的数据集,有两种方法,第一种方法是修改自己的数据集的标注格式,使其和VOC 2012一模一样,然后就可以直接使用create_pascal_tf_record.py脚本转换了,另外一种方法是修改create_pascal_ tf_ record.py ,对读取标签的代码进行修改。

回到VOC 2012数据集的训练。下载数据集后,需要选择合适的模型。这里以Faster R-CNN+Inception_ResNet_v2模型为例进行介绍。首先下载在coco 上预训练的Faster R-CNN+Inception_ResNet_v2,该模型的下载地址点击这
解压后得到frozen _inference_graph.pb、graph.pbtxt、model.ckpt. data-00000-of-00001、model.ckpt.index、model.ckpt.meta5 个文件。在voc文件夹中新建一个pretrained文件夹,并将这5 个文件复制进去。TensorFlow Object Detection API 是依赖一个特殊的设置文件进行训练
的。在object_detection/samples/configs/文件夹下,有一些设置文件的示例。可以参考faster_rcnn_inception_resnet_v2_atrous_pets.config 文件创建的设置文件。先将faster_rcnn_inception_resnet_v2_atrous_pets.config 复制一份到voc文件夹下:

cp samples/configs/faster_rcnn_inception_resnet_v2_atrous_pets.config voc/voc.config

voc.config 一共有7处需要修改的地方:

  • 第一处为num classes ,需要将包修改为voe 2012 中的物体类别数,即20 类。
  • 第二处为eval_con fig 中的num_examples, ‘8 表示在验证阶段需要执行的图片数量,修改为voe 2012 验证集的图片数5823(可以在
    create_pascal_tf_record.py中,输出对应的examples_list的长度,就可以知道这个大小)。
  • 还高5 处为所高含有PATH_TO_BE_CONFIGURED的地方。这些地方
    需要修改为自己的目录。它们应该分别被修改为:
train_input_reader: {
  tf_record_input_reader {
    input_path: "voc/pascal_train.record"
  }
  label_map_path: "voc/pascal_label_map.pbtxt"
}

eval_input_reader: {
  tf_record_input_reader {
    input_path: "voc/pascal_val.record"
  }
  label_map_path: "voc/pascal_label_map.pbtxt"
  shuffle: false
  num_readers: 1
}

最后,在VOC文件夹中新建一个train_dir作为保存模型和日志的目录,使用下面的命令就可以开始训练了:

python train.py --train_dir voc/train_dir --pipeline_config_path voc/voc.config

训练的日志和最终的模型都会被保存在train dir 中,因此,同样可以使
用TensorBoard来监控训练情况:

tensorboard --logdir voc/train_dir/

需要注意的是,如果发生内存和显存不足报错的情况,除了换用较小的模型进行训练外,还可以修改配置文件中的以下部分:

image_resizer {
  keep_aspect_ratio_resizer {
    min_dimension: 600
    max_dimension: 1024
  }
}

这个部分表示将输入图像进行等比例缩放再开始训练,缩放后最大边长为1024,最小边长为600。可以将这两个数值改小(如分别改成512和300),使用的显存就会变小。不过这样做也很高可能导致模型的精度下降,还需根据自己的情况选择适合的处理方法。

2.4 导出模型并预测单张图片

如何将train_dir中的checkpoint文件导出并用于单张图片的目标检测?
TensorFlow Object Detection API提供了一个export_inference_graph. py脚本用于导出训练好的模型。具体方法是执行:

python export_inference_graph.py \
  --input_type image_tensor \
  --pipeline_config_path voc/voc.fig \
  --trained_checkpoint_prefix voc/train_dir/model.ckpt-1582
  --output_directory voc/export/

其中, model.ckpt-1582 表示使用第1582步保存的模型。读者需要根据
voc/train_dir/里实际保存的checkpoint,将1582改为合适的数值。导出的模型是voc/export/ frozen_ inference graph.pb 文件。

我们可以参考第2.2 节中Jupyter Notebook 的代码,自行编写利用导出
模型对单张图片做目标检测的脚本。首先去掉无用的下载模型的部分,然后将PATH_TO_CKPT 的值赋值为“ voc/export /frozen_inference graph.pb ”,即导出的模型文件。将PATH_TO_LABELS 修改为“ voc/pascal_label_map.pbtxt ”,即各个类别的名称。其他代码都可以不改变,别的效果如图5-13 所示。
这里写图片描述

3 总结

我们首先以R- CNN 、SPPNet 、Fast R-CNN、Faster R-CNN四种算法为例,介绍了深度学习中常用的目标检测方法。接着, 介绍了Google 公司开源的TensorFlow Object Detection API的安装和使用,主要分为执行已经训练好的模型和训练自己的模型两部分。希望能够通过这篇文章,了解到深度学习中目标检测方法的基本原理,并掌握TensorFlow Object Detection API的使用方法。

猜你喜欢

转载自blog.csdn.net/czp_374/article/details/81148063