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

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

目录

总结

图像图像

上面的示例图像和对象批注适用于杂货数据集 (左侧) ,以及本教程中使用的 Pascal VOC 数据集 (右) 。

更快的 R-CNN 是 2015 年 少庆任、凯明何、罗斯·吉希克和健孙 提出的对象检测算法。 这项研究论文名为“更快的 R-CNN:使用区域建议网络进行Real-Time对象检测”,并存档在 https://arxiv.org/abs/1506.01497。 更快的 R-CNN 基于以前的工作,使用深度卷积网络有效地对对象建议进行分类。 与以前的工作相比,更快的 R-CNN 采用 区域建议网络 ,不需要候选区域建议的外部方法。

本教程分为三个主要部分。 第一部分简要介绍了如何在提供的示例数据集上运行 CNTK 中的快速 R-CNN。 第二部分提供有关所有步骤的详细信息,包括快速 R-CNN 的设置和参数化。 最后一部分讨论了算法和区域建议网络的技术详细信息,读取和扩充输入数据,以及更快的 R-CNN 的不同训练选项。

快速入门

本部分假定你已将系统设置为使用 CNTK Python API。 我们进一步假设你在 Windows 上使用 Python 3.5,或在 Linux 上使用 3.5/3.6。 有关详细演练,请参阅 分步说明。 若要运行更快的 R-CNN,请在 cntk Python 环境中安装以下附加包

pip install opencv-python easydict pyyaml

运行玩具示例

我们使用从冰箱捕获的玩具数据集来演示更快的 R-CNN (与快速 R-CNN 示例) 相同。 可以通过从 Examples/Image/Detection/FastRCNN 文件夹运行以下命令,下载数据集和预先训练的 AlexNet 模型:

python install_data_and_model.py

运行脚本后,玩具数据集将安装在文件夹下 Examples/Image/DataSets/Grocery 。 AlexNet 模型将下载到 PretrainedModels 该文件夹。 建议将下载的数据保留在相应的文件夹中,因为配置文件默认假定该位置。

训练和评估更快的 R-CNN 运行

python run_faster_rcnn.py

使用 AlexNet 在杂货店进行端到端训练的结果应如下所示:

AP for          gerkin = 1.0000
AP for          butter = 1.0000
AP for         joghurt = 1.0000
AP for          eggBox = 1.0000
AP for         mustard = 1.0000
AP for       champagne = 1.0000
AP for          orange = 1.0000
AP for           water = 0.5000
AP for         avocado = 1.0000
AP for          tomato = 1.0000
AP for          pepper = 1.0000
AP for         tabasco = 1.0000
AP for           onion = 1.0000
AP for            milk = 1.0000
AP for         ketchup = 0.6667
AP for     orangeJuice = 1.0000
Mean AP = 0.9479

可视化从FasterRCNN文件夹打开FasterRCNN_config.py的图像上的预测边界框和标签并设置

__C.VISUALIZE_RESULTS = True

如果运行python run_faster_rcnn.py,图像将保存到FasterRCNN/Output/Grocery/文件夹中。

分步说明

设置

若要运行此示例中的代码,需要 CNTK Python 环境, (此处 获取设置帮助) 。 请在 cntk Python 环境中安装以下附加包

pip install opencv-python easydict pyyaml

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

该文件夹 Examples\Image\Detection\utils\cython_modules 包含运行更快的 R-CNN 所需的预编译二进制文件。 当前包含在存储库中的版本是 Python 3.5 for Windows 和 Python 3.5、3.6 for Linux,全部为 64 位。 如果需要其他版本,可以按照中所述的步骤编译它

将生成的cython_bbox和 (和/或gpu_nms) 二进制文件复制到 $FRCN_ROOT/lib/utils$CNTK_ROOT/Examples/Image/Detection/utils/cython_modulescpu_nms

示例数据和基线模型

我们将预先训练的 AlexNet 模型用作 VGG 或其他基础模型的快速 R-CNN 训练 (的基础,请参阅 使用其他基本模型。 可以通过从 FastRCNN 文件夹运行以下 Python 命令,下载示例数据集和预训练的 AlexNet 模型:

python install_data_and_model.py

配置和参数

参数分为三个部分:

  • 检测器参数 (请参阅 FasterRCNN/FasterRCNN_config.py)
  • 数据集参数 (请参阅示例 utils/configs/Grocery_config.py)
  • (查看基础模型参数, utils/configs/AlexNet_config.py 例如)

在方法run_faster_rcnn.pyget_configuration()加载和合并这三个部分。 在本部分中,我们将介绍检测器参数。 此处介绍了数据集参数,此处提供了基本模型参数。 在下面,我们将浏览从上到下的内容 FasterRCNN_config.py 。 配置使用 EasyDict 包,允许轻松访问嵌套字典。

# If set to 'True' training will be skipped if a trained model exists already
__C.CNTK.MAKE_MODE = False
# E2E or 4-stage training
__C.CNTK.TRAIN_E2E = True
# set to 'True' to use deterministic algorithms
__C.CNTK.FORCE_DETERMINISTIC = False
# set to 'True' to run only a single epoch
__C.CNTK.FAST_MODE = False
# Debug parameters
__C.CNTK.DEBUG_OUTPUT = False
__C.CNTK.GRAPH_TYPE = "png" # "png" or "pdf"
# Set to True if you want to store an eval model with native UDFs (e.g. for inference using C++ or C#)
__C.STORE_EVAL_MODEL_WITH_NATIVE_UDF = False

第一个参数块包含有关训练过程的高级指令。 __C.CNTK.TRAIN_E2E 允许选择端到端或 4 阶段训练方案。 此处介绍了两个训练方案的详细信息。 __C.CNTK.FAST_MODE = True 仅运行单个纪元;测试设置是否正常工作,并且所有参数都正确,这很有用。 __C.CNTK.DEBUG_OUTPUT = True 在控制台输出中生成其他调试消息。 它还绘制训练模型和 eval 模型的 CNTK 计算图, (请注意 绘制 CNTK 图形) 的要求 。 生成的图形存储在 FasterRCNN/Output 文件夹中。 __C.STORE_EVAL_MODEL_WITH_NATIVE_UDF = True 将存储仅使用本机代码的第二个评估模型, (没有 python 层) 。 例如,可以从 C++ 或 C# 加载和评估此模型。

# Learning parameters
__C.CNTK.L2_REG_WEIGHT = 0.0005
__C.CNTK.MOMENTUM_PER_MB = 0.9
# The learning rate multiplier for all bias weights
__C.CNTK.BIAS_LR_MULT = 2.0

# E2E learning parameters
__C.CNTK.E2E_MAX_EPOCHS = 20
__C.CNTK.E2E_LR_PER_SAMPLE = [0.001] * 10 + [0.0001] * 10 + [0.00001]

第二个块包含学习参数。 这些大多是常规的 CNTK 学习参数。 唯一的例外是 __C.CNTK.BIAS_LR_MULT,这是用于网络中所有偏差的学习速率乘数。 它实质上是使用当前学习速率的两倍来训练偏差,这也是在原始的快速 R-CNN 代码中完成的。 每个样本的纪元数和学习速率分别为两种不同的学习方案指定, () 上方省略的 4 阶段参数。

# Maximum number of ground truth annotations per image
__C.INPUT_ROIS_PER_IMAGE = 50
__C.IMAGE_WIDTH = 850
__C.IMAGE_HEIGHT = 850

# Sigma parameter for smooth L1 loss in the RPN and the detector (DET)
__C.SIGMA_RPN_L1 = 3.0
__C.SIGMA_DET_L1 = 1.0

# NMS threshold used to discard overlapping predicted bounding boxes
__C.RESULTS_NMS_THRESHOLD = 0.5
# all bounding boxes with a score lower than this threshold will be considered background
__C.RESULTS_NMS_CONF_THRESHOLD = 0.0

# Enable plotting of results generally / also plot background boxes / also plot unregressed boxes
__C.VISUALIZE_RESULTS = False
__C.DRAW_NEGATIVE_ROIS = False
__C.DRAW_UNREGRESSED_ROIS = False
# only for plotting results: boxes with a score lower than this threshold will be considered background
__C.RESULTS_BGR_PLOT_THRESHOLD = 0.1

__C.INPUT_ROIS_PER_IMAGE 指定每个图像的最大地面实数批注数。 CNTK 当前需要设置最大数字。 如果批注较少,则它们将在内部填充。 __C.IMAGE_WIDTH 以及 __C.IMAGE_HEIGHT 用于调整大小并填充输入图像的维度。 __C.RESULTS_NMS_THRESHOLD 是用于放弃评估中重叠的预测边界框的 NMS 阈值。 较低的阈值会减少删除,因此在最终输出中预测的边界框越多。

# Use horizontally-flipped images during training?
__C.TRAIN.USE_FLIPPED = True
# If set to 'True' conv layers weights from the base model will be trained, too
__C.TRAIN_CONV_LAYERS = True

# RPN parameters
# IOU >= thresh: positive example
__C.TRAIN.RPN_POSITIVE_OVERLAP = 0.7
# IOU < thresh: negative example
__C.TRAIN.RPN_NEGATIVE_OVERLAP = 0.3
# If an anchor statisfied by positive and negative conditions set to negative
__C.TRAIN.RPN_CLOBBER_POSITIVES = False
# Max number of foreground examples
__C.TRAIN.RPN_FG_FRACTION = 0.5
# Total number of examples
__C.TRAIN.RPN_BATCHSIZE = 256
# NMS threshold used on RPN proposals
__C.TRAIN.RPN_NMS_THRESH = 0.7
# Number of top scoring boxes to keep before apply NMS to RPN proposals
__C.TRAIN.RPN_PRE_NMS_TOP_N = 12000
# Number of top scoring boxes to keep after applying NMS to RPN proposals
__C.TRAIN.RPN_POST_NMS_TOP_N = 2000
# Proposal height and width both need to be greater than RPN_MIN_SIZE (at orig image scale)
__C.TRAIN.RPN_MIN_SIZE = 16

__C.TRAIN.USE_FLIPPED = True 通过翻转所有其他纪元的所有图像来增强训练数据,即第一个纪元具有所有常规图像,第二个具有翻转的所有图像,依此类推。 __C.TRAIN_CONV_LAYERS 确定卷积层(从输入到卷积特征图)是否会训练或修复。 修复凸层权重意味着从基础模型获取权重,并在训练期间未修改。 (还可以指定要训练的凸层数,请参阅“ 使用不同的基本模型 ”部分) 。 有关 rpn 参数,请参阅其定义旁边的注释,或查阅原始研究论文以获取更多详细信息。 此外,对于以下检测器参数:

# Detector parameters
# Minibatch size (number of regions of interest [ROIs]) -- was: __C.TRAIN.BATCH_SIZE = 128
__C.NUM_ROI_PROPOSALS = 128
# Fraction of minibatch that is labeled foreground (i.e. class > 0)
__C.TRAIN.FG_FRACTION = 0.25
# Overlap threshold for an ROI to be considered foreground (if >= FG_THRESH)
__C.TRAIN.FG_THRESH = 0.5
# Overlap threshold for an ROI to be considered background (class = 0 if
# overlap in [LO, HI))
__C.TRAIN.BG_THRESH_HI = 0.5
__C.TRAIN.BG_THRESH_LO = 0.0

# Normalize the targets using "precomputed" (or made up) means and stdevs
__C.BBOX_NORMALIZE_TARGETS = True
__C.BBOX_NORMALIZE_MEANS = (0.0, 0.0, 0.0, 0.0)
__C.BBOX_NORMALIZE_STDS = (0.1, 0.1, 0.2, 0.2)

在 Pascal VOC 上运行更快的 R-CNN

若要下载 Pascal 数据并创建 CNTK 格式的 Pascal 注释文件,请运行以下脚本:

python Examples/Image/DataSets/Pascal/install_pascalvoc.py
python Examples/Image/DataSets/Pascal/mappings/create_mappings.py

Change the dataset_cfg in the get_configuration() method of run_faster_rcnn.py to

from utils.configs.Pascal_config import cfg as dataset_cfg

现在,你已设置为使用 python run_faster_rcnn.pyPascal VOC 2007 数据训练。 请注意,训练可能需要一段时间。

在自己的数据上运行更快的 R-CNN

使用快速 R-CNN 在对象检测中介绍了准备自己的数据,并使用地面事实边界框对其进行批注。 将图像存储在描述的文件夹结构中并批注后,请运行

python Examples/Image/Detection/utils/annotations/annotations_helper.py

将该脚本中的文件夹更改为数据文件夹后。 最后,按照现有示例在utils\configs文件夹中创建一个MyDataSet_config.py,如以下代码片段所示:

...

# data set config
__C.DATA.DATASET = "YourDataSet"
__C.DATA.MAP_FILE_PATH = "../../DataSets/YourDataSet"
__C.DATA.CLASS_MAP_FILE = "class_map.txt"
__C.DATA.TRAIN_MAP_FILE = "train_img_file.txt"
__C.DATA.TRAIN_ROI_FILE = "train_roi_file.txt"
__C.DATA.TEST_MAP_FILE = "test_img_file.txt"
__C.DATA.TEST_ROI_FILE = "test_roi_file.txt"
__C.DATA.NUM_TRAIN_IMAGES = 500
__C.DATA.NUM_TEST_IMAGES = 200
__C.DATA.PROPOSAL_LAYER_SCALES = [8, 16, 32]

...

__C.CNTK.PROPOSAL_LAYER_SCALES 在 (中看到 generate_anchors()utils/rpn/generate_anchors.py) 。 从具有纵横比0.5, 1.02.016三个定位点的基大小开始,创建 (8 x 24, 16 x 16, 24 x 8) 。 这些与每个建议层规模相乘,导致九个定位点 (64 x 192,..., 768 x 256) 。 这些是输入图像的绝对像素坐标 w.r.t。 所有定位点都应用于卷积特征映射的每个空间位置,以生成感兴趣的候选区域。 根据数据集中的对象大小以及所使用的输入图像大小调整这些建议层缩放。 例如,对于我们正在使用 __C.DATA.PROPOSAL_LAYER_SCALES = [4, 8, 12] 的杂货店数据集, (的输入图像大小 850 x 850 请参阅 utils/configs/Grocery_config.py) 。

若要在数据上训练和评估更快的 R-CNN,请dataset_cfgget_configuration()更改其方法run_faster_rcnn.py

from utils.configs.MyDataSet_config import cfg as dataset_cfg

并运行 python run_faster_rcnn.py

技术详细信息

由于大多数基于 DNN 的对象检测器更快 R-CNN 使用传输学习。 它从基本模型开始,该模型是为图像分类训练的模型。 基本模型分为两个部分,第一个部分是所有卷积层,最多 (,不包括最后一个池层) ,第二部分是 () 的网络的其余部分,不包括最后一个池层,最后一个池层最多 (再次排除) 最终预测层。 第一部分的输出有时称为 卷积特征图。 这用作 roi 池层的输入,该层在与原始图像中的区域建议相对应的输入映射的一部分执行池操作。 区域建议是 roi 池层的第二个输入。 在更快的 R-CNN 中,这些建议由名为 区域建议网络的 小型子网络 (RPN 生成,请参阅下一部分) 。

roi 池层的输出将始终具有相同的固定大小,因为它将任何输入 (卷积特征映射 + 区域建议) 池大小设置为相同的输出大小。 请注意,输入大小(即卷积 featute 映射的大小)可以是任意的输入图像大小。 为了训练算法使用四个损失函数,两个用于 RPN,两个用于检测器 (另请参阅下一部分) 。 以下方法包含在 FasterRCNN_train.py 其中,并显示更快的 R-CNN 模型的高级别构造。 请参阅 FasterRCNN_train.py 完整代码和 utils/rpn/rpn_helpers.py 完整代码。

def create_faster_rcnn_model(features, scaled_gt_boxes, dims_input, cfg):
    # Load the pre-trained classification net and clone layers
    base_model = load_model(cfg['BASE_MODEL_PATH'])
    conv_layers = clone_conv_layers(base_model, cfg)
    fc_layers = clone_model(base_model, [cfg["MODEL"].POOL_NODE_NAME], [cfg["MODEL"].LAST_HIDDEN_NODE_NAME], clone_method=CloneMethod.clone)

    # Normalization and conv layers
    feat_norm = features - Constant([[[v]] for v in cfg["MODEL"].IMG_PAD_COLOR])
    conv_out = conv_layers(feat_norm)

    # RPN and prediction targets
    rpn_rois, rpn_losses = create_rpn(conv_out, scaled_gt_boxes, dims_input, cfg)
    rois, label_targets, bbox_targets, bbox_inside_weights = \
        create_proposal_target_layer(rpn_rois, scaled_gt_boxes, cfg)

    # Fast RCNN and losses
    cls_score, bbox_pred = create_fast_rcnn_predictor(conv_out, rois, fc_layers, cfg)
    detection_losses = create_detection_losses(...)
    loss = rpn_losses + detection_losses
    pred_error = classification_error(cls_score, label_targets, axis=1)

    return loss, pred_error

训练网络后,通过删除评估不需要的所有部分(例如损失函数)转换为评估模型。 最终评估模型有三个输出, (查看 create_faster_rcnn_eval_model() 以获取 FasterRCNN_train.py 更多详细信息) :

  • rpn_rois - 候选 roi 的绝对像素坐标
  • cls_pred - 每个 ROI 的类概率
  • bbox_regr - 每个 ROI 的每个类 的回归系数

若要从 Python 使用评估模型,可以使用 FasterRCNN_Evaluator from FasterRCNN_eval.py. 可以加载模型一次,然后按原样评估单个图像。 计算器 process_image() 的方法将图像的路径作为其参数,评估该图像上的模型,并将边界框回归应用于生成的 RO。 它返回回归的 ROIS 和相应的类概率:

    evaluator = FasterRCNN_Evaluator(model, cfg)
    regressed_rois, cls_probs = evaluator.process_image(img_path)

区域建议网络

更快的 R-CNN 使用所谓的 区域建议 netwrok (RPN) ,根据输入图像生成感兴趣的候选区域 (RO) 。 这与 Fast R-CNN 相反,它要求外部源提供区域建议。 RPN 基本上由三个卷积层和一个名为 建议层的新层构建。 新层在 Python 或 C++ 中作为用户定义的函数 (UDF) 实现, (请参阅以下) 的详细信息。 在 CNTK 中创建 RPN 的 Python 代码位于 utils/rpn/rpn_helpers.py文件夹中,新层(如建议层)均位于 utils/rpn 文件夹中。

RPN 的输入是卷积特征图,与 ROI 池层的输入相同。 此输入将馈送到 RPN 的第一个卷积层,结果将传播到其他两个卷积层。 后者之一预测每个候选区域的类分数,即每个空间位置的每个定位点 (9 个定位点 x 2 分 x 宽度 x 高度) 。 两个分数使用 softmax 节点) 转换为每个候选 项的对象性分数 ,这些分数被解释为候选区域包含前景对象的概率 (。 另一个卷积层预测 ROI 的实际位置的回归系数,对于每个候选 (9 个定位点 x 4 系数 x 宽度 x 高度) 。

回归系数和对象性评分 (前景和背景概率) 馈送到建议层中。 此层首先将回归系数应用于生成的定位点,将结果剪辑到图像边界,并筛选出太小的候选区域。 然后,它按前景概率对候选项进行排序,应用非最大抑制 (NMS) ,以减少候选项的数量,最后对其输出的所需 RO 数采样。

在训练过程中,R-CNN 需要另外两个新层: 定位点目标层建议目标层。 定位点目标层为对象分数和 RPN 回归系数生成目标值,这些系数用于 RPN 的损失函数。 同样,建议目标层为 RO 和每个类的目标回归系数生成目标类标签,这些系数用于检测器的损失函数。

在评估期间,只需 (建议层,因为不需要) 损失函数的目标。 CNTK 中的建议层在 Python 和 C++ 中可用,目标层目前仅在 Python 中可用。 因此,训练速度更快的 R-CNN 目前必须通过 Python API 完成。 在训练后存储使用本机建议层实现集 __C.STORE_EVAL_MODEL_WITH_NATIVE_UDF = True的评估模型。

读取器和微型batch 源

当我们缩放图像或翻转图像进行数据扩充时,还需要将相同的转换应用于地面真相注释。 (翻转还必须应用于 4 阶段训练中的缓存建议,请参阅下一节。) 由于这些联接的图像和批注转换当前不受内置 CNTK 读取器支持,我们使用自定义 Python 读取器和 UserMinibatchSource 更快的 R-CNN。 这些内容分别包含在 utils/od_reader.py 其中和 utils/od_mb_source.py 中。

E2E 和 4 阶段训练

更快的 R-CNN 研究论文描述了两种方法来训练网络。 端到端训练使用所有四个损失函数在单个训练中训练整个网络, (rpn 回归损失、rpn 对象损失、检测器回归损失、检测器类损失) 。 默认情况下,我们使用端到端训练,可以通过相应地设置__C.CNTK.TRAIN_E2EFasterRCNN_config.py在两者之间进行选择。

4 阶段训练方案仅在训练区域建议网络之间交替, (保持检测器固定) ,并且仅训练检测器 (修复 RPN 权重) 。 This training scheme is implemented in train_faster_rcnn_alternating() in FasterRCNN_train.py. 它稍微详细一些,并经常使用克隆模型的部分,以便有选择地冻结和训练权重。 此外,在 4 阶段训练中,RPN 的建议在第一阶段和第三阶段后缓冲,并在后续阶段使用。

使用不同的基本模型

若要使用不同的基本模型,需要在方法run_faster_rcnn.py中选择get_configuration()不同的模型配置。 立即支持两种模型:

    # for VGG16 base model use:         from utils.configs.VGG16_config import cfg as network_cfg
    # for AlexNet base model use:       from utils.configs.AlexNet_config import cfg as network_cfg

若要下载 VGG16 模型,请使用以下中的 <cntkroot>/PretrainedModels下载脚本:

    python download_model.py VGG16_ImageNet_Caffe

如果要使用另一个不同的基本模型,则需要复制,例如,配置文件 utils/configs/VGG16_config.py 并根据基本模型对其进行修改:

# model config
__C.MODEL.BASE_MODEL = "VGG16"
__C.MODEL.BASE_MODEL_FILE = "VGG16_ImageNet_Caffe.model"
__C.MODEL.IMG_PAD_COLOR = [103, 116, 123]
__C.MODEL.FEATURE_NODE_NAME = "data"
__C.MODEL.LAST_CONV_NODE_NAME = "relu5_3"
__C.MODEL.START_TRAIN_CONV_NODE_NAME = "pool2" # __C.MODEL.FEATURE_NODE_NAME
__C.MODEL.POOL_NODE_NAME = "pool5"
__C.MODEL.LAST_HIDDEN_NODE_NAME = "drop7"
__C.MODEL.FEATURE_STRIDE = 16
__C.MODEL.RPN_NUM_CHANNELS = 512
__C.MODEL.ROI_DIM = 7

若要调查基本模型的节点名称,可以使用该方法plot()cntk.logging.graph 请注意,由于 CNTK 中的 roi 池尚不支持 Roi 平均池,因此目前不支持 ResNet 模型。