你当前正在访问 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.py
dataset
设置为 "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.txt
和test.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.z
train.z
cntkFiles
文件夹中。
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
内。
如果使用的是其他文件夹,请相应地进行设置pascalDataDir
PARAMETERS.py
。
- 将 2012 定型数据下载并解压缩到
DataSets/Pascal/VOCdevkit2012
- 将 2007 定型数据下载并解压缩到
DataSets/Pascal/VOCdevkit2007
- 将 2007 测试数据下载并解压缩到同一文件夹中
DataSets/Pascal/VOCdevkit2007
- 将预计算的 ROIS 下载并解压缩到
DataSets/Pascal/selective_search_data
* http://dl.dropboxusercontent.com/s/orrt7o6bp6ae0tc/selective_search_data.tgz?dl=0
文件夹 VOCdevkit2007
应类似于 2012) (:
VOCdevkit2007/VOC2007
VOCdevkit2007/VOC2007/Annotations
VOCdevkit2007/VOC2007/ImageSets
VOCdevkit2007/VOC2007/JPEGImages
在 Pascal VOC 上运行 CNTK
若要在 Pascal VOC 数据上运行,请确保已 PARAMETERS.py
dataset
设置为 "pascal"
。
- 运行
A1_GenerateInputROIs.py
以生成 CNTK 格式的输入文件,以便从下载的 ROI 数据进行训练和测试。 - 运行
A2_RunWithBSModel.py
以训练快速 R-CNN 模型和计算测试结果。 - 运行
A3_ParseAndEvaluateOutput.py
以计算训练模型 的平均精度) mAP (。- 请注意,这是正在进行的工作,结果是初步的,因为我们正在训练新的基线模型。
- 请确保具有 CNTK 主控版本的 文件 fastRCNN/pascal_voc.py 和 fastRCNN/voc_eval.py ,以避免编码错误。
根据自己的数据训练
准备自定义数据集
选项 #1:Visual 对象标记工具 (建议)
Visual 对象标记工具 (VOTT) 是用于标记视频和图像资产的跨平台注释工具。
VOTT 提供以下 功能:
- 使用 Camshift 跟踪算法在视频中对对象进行计算机辅助标记和跟踪。
- 将标记和资产导出到 CNTK Fast-RCNN 格式以训练对象检测模型。
- 在新视频上运行和验证经过训练的 CNTK 对象检测模型,以生成更强大的模型。
如何使用 VOTT 批注:
选项 #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.features
network.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 有三个输入文件对应于上述三个反序列化程序:
train.txt
在第一行中包含一个序列号,然后是图像文件名,最后是一个0
(,由于 ImageReader) 的旧原因,目前仍需要该 (。
0 image_01.jpg 0
1 image_02.jpg 0
...
train.rois.txt
(CNTK 文本格式) 在第一行中包含序列号,然后|rois
是一系列数字的标识符。 这些数字组由四个数字组成,对应于 ROI 的 (x、y、w、h) ,均相对于图像的全宽和高度相对。 每行总共有 4 * 个 rois 编号。
0 |rois 0.2185 0.0 0.165 0.29 ...
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 的测量精度。 以这种方式内插精度/召回曲线的意图是减少精度/召回曲线中“摇摆”的影响,这与示例排名的细微变化所致。 应指出,要获得高分,方法必须具有各级召回率的精度 -- 这惩罚方法只检索一部分具有高精度 (的示例,例如汽车) 的侧视图。