你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用快速 R-CNN 进行对象检测

目录

摘要

图像图像

本教程介绍如何将 CNTK Fast R-CNN 与 BrainScript 和cntk.exe配合使用。 此处介绍了使用 CNTK Python API 的快速 R-CNN。

上面的示例图像和对象注释适用于杂货数据集 (第一个图像) 和 Pascal VOC 数据集 (本教程中使用的第二个图像) 。

快速 R-CNN 是 2015 年罗斯·吉尔希克 提议的对象检测算法。 该报被接受ICV 2015,并存档在 https://arxiv.org/abs/1504.08083。 快速 R-CNN 基于以前的工作,使用深度卷积网络有效地对对象建议进行分类。 与以前的工作相比,Fast R-CNN 采用 感兴趣的池方案区域 ,允许重复使用卷积层中的计算。

其他材料:有关使用 CNTK Fast R-CNN 和 BrainScript (的对象检测的详细教程,包括可选的 SVM 训练并将训练的模型发布为 Rest API) ,可 在此处找到。

安装

若要运行此示例中的代码,需要一个 CNTK Python 环境, (在此处 查看设置帮助) 。 此外,还需要安装一些其他包。 转到 FastRCNN 文件夹并运行:

pip install -r requirements.txt

已知问题:若要安装 scikit-learn,可能需要运行 conda install scikit-learn (如果使用 Anaconda Python)。 你还需要Scikit-Image和 OpenCV 才能运行这些示例。 请下载相应的滚轮包并手动安装它们。 在 Linux 上,可以 conda install scikit-image opencv。 对于 Windows 用户,请访问 http://www.lfd.uci.edu/~gohlke/pythonlibs/并下载:

  • Python 3.5
    • scikit_image-0.12.3-cp35-cp35m-win_amd64.whl
    • opencv_python-3.2.0-cp35-cp35m-win_amd64.whl

下载相应的滚轮二进制文件后,请使用以下命令安装它们:

pip install your_download_folder/scikit_image-0.12.3-cp35-cp35m-win_amd64.whl

[!注意]:如果看到运行脚本时 没有命名的模块 的消息,请执行 pip install future

本教程代码假定你使用的是 64 位版本的 Python 3.5 或 3.6,因为这些版本的预生成所需的快速 R-CNN DLL 文件。 如果任务需要使用其他 Python 版本,请在正确的环境中自行重新编译这些 DLL 文件, (请参阅以下) 。

本教程进一步假定 cntk.exe所在的文件夹位于 PATH 环境变量中。 (若要将文件夹添加到 PATH,可以从命令行 (运行以下命令,假设计算机上的cntk.exe所在的文件夹为 C:\src\CNTK\x64\Release) : set PATH=C:\src\CNTK\x64\Release;%PATH%.)

用于边界框回归和非最大抑制的预编译二进制文件

该文件夹 Examples\Image\Detection\FastRCNN\BrainScript\fastRCNN\utils 包含运行 Fast R-CNN 所需的预编译二进制文件。 当前包含在存储库中的版本是 Python 3.5 和 3.6,所有 64 位。 如果需要其他版本,可以按照以下步骤对其进行编译:

  • git clone --recursive https://github.com/rbgirshick/fast-rcnn.git

  • cd $FRCN_ROOT/lib

  • make

    • make不能从同一文件夹运行python setup.py build_ext --inplace。 在 Windows 上,可能需要注释掉 lib/setup.py 中的额外编译参数:
    ext_modules = [
      Extension(
          "utils.cython_bbox",
          ["utils/bbox.pyx"],
          #extra_compile_args=["-Wno-cpp", "-Wno-unused-function"],
      ),
      Extension(
          "utils.cython_nms",
          ["utils/nms.pyx"],
          #extra_compile_args=["-Wno-cpp", "-Wno-unused-function"],
      )
    ]
    
  • 将生成的cython_bbox二进制文件复制到 $FRCN_ROOT/lib/utils$CNTK_ROOT/Examples/Image/Detection/fastRCNN/utils.cython_nms

示例数据和基线模型

我们使用预先训练的 AlexNet 模型作为 Fast-R-CNN 训练的基础。 预训练的 AlexNet 在 .https://www.cntk.ai/Models/AlexNet/AlexNet.model 请将模型 $CNTK_ROOT/PretrainedModels存储在 . 若要下载数据,请运行

python install_grocery.py

Examples/Image/DataSets/Grocery来自文件夹。

运行玩具示例

在玩具示例中,我们训练 CNTK Fast R-CNN 模型来检测冰箱中的杂货。 所有必需的脚本都位于 $CNTK_ROOT/Examples/Image/Detection/FastRCNN/BrainScript.

快速入门指南

若要运行玩具示例,请确保已将它 PARAMETERS.pydataset 设置为 "Grocery"

  • 运行 A1_GenerateInputROIs.py 以生成用于训练和测试的输入 ROIS。
  • 运行 A2_RunWithBSModel.py 以使用 cntk.exe 和 BrainScript 进行训练和测试。
  • 运行 A3_ParseAndEvaluateOutput.py 以计算已训练模型 的平均精度) mAP (。

脚本 A3 的输出应包含以下内容:

Evaluating detections
AP for         avocado = 1.0000
AP for          orange = 1.0000
AP for          butter = 1.0000
AP for       champagne = 1.0000
AP for          eggBox = 0.7500
AP for          gerkin = 1.0000
AP for         joghurt = 1.0000
AP for         ketchup = 0.6667
AP for     orangeJuice = 1.0000
AP for           onion = 1.0000
AP for          pepper = 1.0000
AP for          tomato = 0.7600
AP for           water = 0.5000
AP for            milk = 1.0000
AP for         tabasco = 1.0000
AP for         mustard = 1.0000
Mean AP = 0.9173
DONE.

若要可视化边界框和预测标签,可以运行 B3_VisualizeOutputROIs.py (单击图像放大) :

图像图像图像

步骤详细信息

A1: 该脚本 A1_GenerateInputROIs.py 首先使用 选择性搜索为每个图像生成 ROI 候选项。 然后,它将它们作为输入cntk.exe存储在 CNTK 文本格式中。 此外,生成图像和地面真相标签所需的 CNTK 输入文件。 该脚本在文件夹下 FastRCNN 生成以下文件夹和文件:

  • proc - 生成的内容的根文件夹。
    • grocery_2000- 包含使用 2000 ROIS 的示例的所有生成的文件夹和文件grocery。 如果使用不同数量的 RO 再次运行,则文件夹名称将相应地更改。
      • rois - 包含文本文件中存储的每个图像的原始 ROI 坐标。
      • cntkFiles- 包含图像 (train.txttest.txt) 的格式化 CNTK 输入文件、ROI 坐标 () xx.rois.txt 和 ROI 标签,xx.roilabels.txt () train) 。test 下面 提供了 (格式详细信息。)

所有参数都包含在内 PARAMETERS.py,例如,更改 cntk_nrRois = 2000 以设置用于训练和测试的 ROIS 数。 下面介绍“参数”部分中 的参数

A2: 该脚本 A2_RunWithBSModel.py 使用 cntk.exe 和 BrainScript 配置文件运行 cntk, (配置详细信息) 。 训练的模型存储在相应proc子文件夹的文件夹中cntkFiles/Output。 训练的模型在训练集和测试集上单独测试。 在测试每个图像和每个相应的 ROI 期间,会预测标签并将其存储在文件和 test.ztrain.zcntkFiles 文件夹中。

A3: 评估步骤分析 CNTK 输出并计算 mAP ,并将预测结果与地面实数注释进行比较。 非最大抑制 用于合并重叠的 ROIS。 可以在 (详细信息) 设置PARAMETERS.py非最大抑制阈值。

其他脚本

可以运行三个可选脚本来可视化和分析数据:

  • B1_VisualizeInputROIs.py 可视化候选输入 ROIS。
  • B2_EvaluateInputROIs.py 计算对候选 ROIS 的基础真相 ROIS 的召回。
  • B3_VisualizeOutputROIs.py 可视化边界框和预测标签。

运行 Pascal VOC

Pascal VOC (PASCAL 视觉对象类) 数据是一组已知的标准化图像,用于对象类识别。 在 Pascal VOC 数据上训练或测试 CNTK 快速 R-CNN 需要至少具有 4GB RAM 的 GPU。 或者,可以使用 CPU 运行,但需要 一些 时间。

获取 Pascal VOC 数据

你需要 2007 (定型和测试) 和 2012 (定型) 数据以及原始论文中使用的预计算 RO。 需要遵循下面所述的文件夹结构。 脚本假定 Pascal 数据驻留在 $CNTK_ROOT/Examples/Image/DataSets/Pascal内。 如果使用的是其他文件夹,请相应地进行设置pascalDataDirPARAMETERS.py

文件夹 VOCdevkit2007 应类似于 2012) (:

VOCdevkit2007/VOC2007
VOCdevkit2007/VOC2007/Annotations
VOCdevkit2007/VOC2007/ImageSets
VOCdevkit2007/VOC2007/JPEGImages

在 Pascal VOC 上运行 CNTK

若要在 Pascal VOC 数据上运行,请确保已 PARAMETERS.pydataset 设置为 "pascal"

  • 运行 A1_GenerateInputROIs.py 以生成 CNTK 格式的输入文件,以便从下载的 ROI 数据进行训练和测试。
  • 运行 A2_RunWithBSModel.py 以训练快速 R-CNN 模型和计算测试结果。
  • 运行 A3_ParseAndEvaluateOutput.py 以计算训练模型 的平均精度) mAP (。

根据自己的数据训练

准备自定义数据集

选项 #1:Visual 对象标记工具 (建议)

Visual 对象标记工具 (VOTT) 是用于标记视频和图像资产的跨平台注释工具。

Vott 屏幕截图

VOTT 提供以下 功能

  • 使用 Camshift 跟踪算法在视频中对对象进行计算机辅助标记和跟踪。
  • 将标记和资产导出到 CNTK Fast-RCNN 格式以训练对象检测模型。
  • 在新视频上运行和验证经过训练的 CNTK 对象检测模型,以生成更强大的模型。

如何使用 VOTT 批注:

  1. 下载 最新版本
  2. 按照 自述文件 运行标记作业
  3. 标记导出标记到数据集目录后

选项 #2:使用批注脚本

若要在自己的数据集上训练 CNTK Fast R-CNN 模型,我们提供了两个脚本来批注图像上的矩形区域,并将标签分配给这些区域。 脚本将按照运行 Fast R-CNN () A1_GenerateInputROIs.py 的第一步的要求,以正确的格式存储批注。 首先,将图像存储在以下文件夹结构中

  • <your_image_folder>/negative - 用于训练不包含任何对象的图像
  • <your_image_folder>/positive - 用于训练包含对象的图像
  • <your_image_folder>/testImages - 用于测试包含对象的图像

对于负图像,无需创建任何批注。 对于其他两个文件夹,请使用提供的脚本:

  • 运行 C1_DrawBboxesOnImages.py 以在图像上绘制边界框。
    • 在运行之前,/positive脚本集imgDir = <your_image_folder> (或/testImages) 。
    • 使用鼠标光标添加批注。 批注图像中的所有对象后,按键“n”将写入 .bboxes.txt 文件,然后继续下一个图像,“u”撤消 (,即删除最后一个矩形) ,“q”退出批注工具。
  • 运行 C2_AssignLabelsToBboxes.py 以将标签分配给边界框。
    • 在脚本集中 imgDir = <your_image_folder> (/positive/testImages) 运行...
    • ...并调整脚本中的 以反映对象类别,例如 classes = ("dog", "cat", "octopus")
    • 该脚本为每个图像加载这些手动批注矩形,并逐个显示它们,并要求用户通过单击窗口左侧的相应按钮来提供对象类。 标记为“未决定”或“排除”的地面真相注释被完全排除在进一步处理之外。

训练自定义数据集

在使用脚本 A1-A3 运行 CNTK Fast R-CNN 之前,需要将数据集添加到 PARAMETERS.py

  • 设置 dataset = "CustomDataset"
  • 在 Python 类 CustomDataset下添加数据集的参数。 可以从 复制参数开始 GroceryParameters
    • 调整 以反映对象类别。 如上例 self.classes = ('__background__', 'dog', 'cat', 'octopus')所示。
    • 设置 self.imgDir = <your_image_folder>
    • (可选)可以调整更多参数,例如用于 ROI 生成和修剪 (请参阅 “参数 ”部分) 。

准备好训练自己的数据了! (使用与玩具示例 相同的步骤 。)

技术详细信息

参数

PARAMETERS.py 的主要参数为

  • dataset - 要使用的数据集
  • cntk_nrRois - 要用于训练和测试的 RO 数量
  • nmsThreshold - 范围 [0,1]) 中的非最大抑制阈值 (。 将合并的 RO 越低。 它用于评估和可视化。

PYTHON 类Parameters下介绍了PARAMETERS.py用于 ROI 生成的所有参数,例如最小宽度和最大宽度和高度等。 它们都设置为一个默认值,这是合理的。 可以在与所使用的数据集对应的部分中覆盖它们 # project-specific parameters

CNTK 配置

用于训练和测试 Fast R-CNN 的 CNTK BrainScript 配置文件是 fastrcnn.cntk。 正在构造网络的部件是 BrainScriptNetworkBuilder 命令中的 Train 节:

BrainScriptNetworkBuilder = {
    network     = BS.Network.Load ("../../../../../../../PretrainedModels/AlexNet.model")
    convLayers  = BS.Network.CloneFunction(network.features, network.conv5_y, parameters = "constant")
    fcLayers    = BS.Network.CloneFunction(network.pool3, network.h2_d)

    model (features, rois) = {
        featNorm = features - 114
        convOut  = convLayers (featNorm)
        roiOut   = ROIPooling (convOut, rois, (6:6))
        fcOut    = fcLayers (roiOut)
        W        = ParameterTensor{($NumLabels$:4096), init="glorotUniform"}
        b        = ParameterTensor{$NumLabels$, init = 'zero'}
        z        = W * fcOut + b
    }.z

    imageShape = $ImageH$:$ImageW$:$ImageC$         # 1000:1000:3
    labelShape = $NumLabels$:$NumTrainROIs$         # 21:64
    ROIShape   = 4:$NumTrainROIs$                   # 4:64

    features = Input {imageShape}
    roiLabels = Input {labelShape}
    rois = Input {ROIShape}

    z = model (features, rois)

    ce = CrossEntropyWithSoftmax(roiLabels, z, axis = 1)
    errs = ClassificationError(roiLabels, z, axis = 1)

    featureNodes    = (features:rois)
    labelNodes      = (roiLabels)
    criterionNodes  = (ce)
    evaluationNodes = (errs)
    outputNodes     = (z)
}

在第一行中,预训练的 AlexNet 作为基本模型加载。 接下来的两部分将克隆网络: convLayers 包含具有常量权重的卷积层,即不会进一步训练它们。 fcLayers 包含具有预训练权重的完全连接层,这将进一步训练。 节点名称network.featuresnetwork.conv5_y等可以派生自查看脚本) 日志输出中包含的cntk.exe调用的日志输出A2_RunWithBSModel.py (。

模型定义 () model (features, rois) = ... 首先通过减去每个通道和像素的 114 来规范化特征。 然后,规范化功能将推送 convLayers 到后面 ROIPooling ,最后 fcLayers是。 输出形状 (width:height) 的 ROI 池层设置为, (6:6) 因为这是从 AlexNet 模型预训练 fcLayers 的形状大小。 fcLayers输出将馈送到一个密集层中,该层预测每个标签NumLabels (每个 ROI 的一个值) 。

以下六行定义输入:

  • 大小为 1000 x 1000 x 3 () $ImageH$:$ImageW$:$ImageC$ 的图像,
  • 每个 ROI () $NumLabels$:$NumTrainROIs$ 的基实标签
  • 和每个 ROI 的四个坐标 (4:$NumTrainROIs$) 对应于 (x、y、w、h) ,相对于图像的全宽和高度都相对。

z = model (features, rois) 将输入图像和 ROIS 馈送到定义的网络模型中,并将输出分配给该模型 z。 条件 () CrossEntropyWithSoftmax 和错误 (ClassificationError) 都指定 axis = 1 ,以考虑每个 ROI 的预测错误。

下面列出了 CNTK 配置的读取器部分。 它使用三个反序列化器:

  • ImageDeserializer 以读取图像数据。 它从 train.txt中选取图像文件名,将图像缩放为所需的宽度和高度,同时保留纵横比 (填充 114 空区域) ,并转置张量以具有正确的输入形状。
  • 从中读取 ROI 坐标train.rois.txt的一个CNTKTextFormatDeserializer
  • 第二个 CNTKTextFormatDeserializer 从中读取 ROI 标签 train.roislabels.txt

下一部分介绍了输入文件格式。

reader = {
    randomize = false
    verbosity = 2
    deserializers = ({
        type = "ImageDeserializer" ; module = "ImageReader"
        file = train.txt
        input = {
            features = { transforms = (
                { type = "Scale" ; width = $ImageW$ ; height = $ImageW$ ; channels = $ImageC$ ; scaleMode = "pad" ; padValue = 114 }:
                { type = "Transpose" }
            )}
            ignored = {labelDim = 1000}
        }
    }:{
        type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
        file = train.rois.txt
        input = { rois = { dim = $TrainROIDim$ ; format = "dense" } }
    }:{
        type = "CNTKTextFormatDeserializer" ; module = "CNTKTextFormatReader"
        file = train.roilabels.txt
        input = { roiLabels = { dim = $TrainROILabelDim$ ; format = "dense" } }
    })
}

CNTK 输入文件格式

CNTK Fast R-CNN 有三个输入文件对应于上述三个反序列化程序:

  1. train.txt 在第一行中包含一个序列号,然后是图像文件名,最后是一个 0 (,由于 ImageReader) 的旧原因,目前仍需要该 (。
0 image_01.jpg 0
1 image_02.jpg 0
...
  1. train.rois.txt (CNTK 文本格式) 在第一行中包含序列号,然后 |rois 是一系列数字的标识符。 这些数字组由四个数字组成,对应于 ROI 的 (x、y、w、h) ,均相对于图像的全宽和高度相对。 每行总共有 4 * 个 rois 编号。
0 |rois 0.2185 0.0 0.165 0.29 ...
  1. train.roilabels.txt (CNTK 文本格式) 在第一行中包含序列号,然后 |roiLabels 是一系列数字的标识符。 这些是一组标签数, (零个或一个) ,每个 ROI 编码一个热表示形式的地面真理类。 每个行的总标签数 * rois 数。
0 |roiLabels 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0  ...

算法详细信息

快速 R-CNN

R-CNN for Object Detection 于 2014 年首次由 罗斯·吉尔希克等人提出,并被展示为超越以往最先进的方法,了解了该领域的主要对象识别挑战之一: Pascal VOC。 此后,发表了两篇后续论文,其中包含显著速度改进: 快速 R-CNN更快的 R-CNN

R-CNN 的基本理念是采用深度神经网络,该神经网络最初使用数百万个批注图像进行图像分类训练,并对其进行修改,以便进行对象检测。 第一篇 R-CNN 论文的基本思路如下图所示, (从论文) 中获取: (1) 给定输入图像,第一步 (2) ,生成大量区域建议。 (3) 这些区域建议或 (RO) 区域,然后通过网络单独发送,从而为每个 ROI 输出一个矢量,例如 4096 个浮点值。 最后,了解分类器 (4) ,该分类器采用 4096 浮点 ROI 表示形式作为输入和输出标签,并为每个 ROI 输出一个标签和置信度。

图像

虽然此方法在准确性方面效果良好,但计算成本很高,因为神经网络必须针对每个 ROI 进行评估。 快速 R-CNN 通过仅评估大多数网络 (特定来解决此问题:卷积层) 每个映像一次。 据作者介绍,这会导致在测试期间加速213次,训练期间速度为9倍,而不会丢失准确性。 这是通过使用 ROI 池层来实现的,该层将 ROI 投影到卷积特征映射上,并执行最大池以生成以下层预期所需的输出大小。 在本教程中使用的 AlexNet 示例中,ROI 池层放置在最后一个卷积层与第一个完全连接的层之间, (请参阅 BrainScript 代码) 。

可以在 GitHub 中找到 R-CNN 论文中使用的原始 Caffe 实现: RCNN快速 R-CNN更快的 R-CNN。 本教程使用这些存储库中的一些代码,尤其是 (,但不专门) 用于 SVM 训练和模型评估。

SVM 与 NN 训练

帕特里克·布勒提供有关如何使用上一个完全连接的层中的 4096 功能 () 以及 此处的优缺点来训练 CNTK Fast R-CNN 输出上的 SVM 的说明。

选择性搜索 是用于在图像中查找大量可能的对象位置的方法,独立于实际对象的类。 它的工作原理是将图像像素聚类化为段,然后执行分层聚类分析,将同一对象中的段合并到对象建议中。

图像图像

为了补充选择性搜索中检测到的 RO,我们添加了统一覆盖图像的不同缩放比例和纵横比的 ROIS。 第一张图像显示了选择性搜索的示例输出,其中每个可能的对象位置都由绿色矩形可视化。 (第二个图像) 丢弃过小、太大等的 ROIs,最后将 (第三个图像) 添加统一覆盖图像的 RO。 然后,这些矩形用作 R-CNN 管道中 (ROIS) 的区域兴趣区域。

ROI 生成的目标是找到一小组 ROI,这些 URI 在图像中尽可能紧密地覆盖了尽可能多的对象。 此计算必须足够快,同时查找不同比例和纵横比的对象位置。 已显示选择性搜索可很好地执行此任务,并具有良好的准确性来加快权衡。

NMS (非最大抑制)

对象检测方法通常输出多个检测,这些检测完全或部分覆盖图像中的同一对象。 需要合并这些 ROIS 才能对对象进行计数并获取图像中的确切位置。 这传统上是使用称为“非最大抑制” (NMS) 的技术完成的。 我们使用 (的 NMS 版本,在 R-CNN 出版物中也使用了该版本,) 不会合并 ROIS,而是尝试确定哪些 ROIS 最能涵盖对象的实际位置,并丢弃所有其他 ROIS。 这是通过迭代地选择具有最高置信度 ROI 的 ROI 来实现的,并删除了其他所有显著重叠此 ROI 且分类为同一类的 ROI。 可以在 (详细信息) 中PARAMETERS.py设置重叠的阈值。

在 (第一个图像) 和 (第二个图像之后) 非最大抑制之前检测结果:

图像图像

mAP (平均精度)

训练后,可以使用不同的标准测量模型的质量,例如精度、召回率、准确性、曲线下面积等。用于 Pascal VOC 对象识别质询的常见指标是测量每个类的平均精度 (AP) 。 以下平均精度说明摘自 Everingham et. al. 平均平均精度 (mAP) 通过获取所有类的 AP 的平均值来计算。

对于给定的任务和类,精度/召回曲线是从方法的排名输出中计算的。 召回率定义为排名高于给定排名的所有正示例的比例。 精度是高于正类的所有示例的比例。 AP 总结精度/召回曲线的形状,定义为一组相同间距的召回级别 [0,0.1] 的平均值精度。 . . ,1]:

图像

每个召回级别 r 的精度通过为相应召回率超过 r 的方法测量的最大精度进行内插:

图像

其中 p (̃r) 是召回 ̃r 的测量精度。 以这种方式内插精度/召回曲线的意图是减少精度/召回曲线中“摇摆”的影响,这与示例排名的细微变化所致。 应指出,要获得高分,方法必须具有各级召回率的精度 -- 这惩罚方法只检索一部分具有高精度 (的示例,例如汽车) 的侧视图。