Tensorflow检测API中的SSD锚点

jea*_*ean 3 python object-detection tensorflow

我想在N x N图像的自定义数据集上训练SSD检测器。因此,我研究了Tensorflow对象检测API,并在基于MobileNet v2的COCO上找到了SSD300x300的预训练模型。

在查看用于训练的配置文件时:字段anchor_generator看起来像这样:(紧随本文之后)

anchor_generator {
  ssd_anchor_generator {
    num_layers: 6
    min_scale: 0.2
    max_scale: 0.9
    aspect_ratios: 1.0
    aspect_ratios: 2.0
    aspect_ratios: 0.5
    aspect_ratios: 3.0
    aspect_ratios: 0.33
    }
}
Run Code Online (Sandbox Code Playgroud)

当寻找SSD锚发电机原我是正确的假设,因此:base_anchor_height=base_anchor_width=1

如果是的话,我假设通过读取多个网格锚点生成器(如果图像是300x300 square)得到的锚点是:大小从0.2 * 300 = 60 * 60像素到0.9 * 300 = 270 * 270像素(不同的宽高比)?

因此,如果要通过固定场来训练NxN图像:

fixed_shape_resizer {
  height: N
  width: N
}
Run Code Online (Sandbox Code Playgroud)

他会使用相同的配置文件锚点,范围从(0.2 * N,0.2 * N)像素到(0.9 * N,0.9 * N)像素(具有不同的宽高比)?

我做了很多假设,因为代码很难掌握,而且似乎还没有文档。我对么 ?是否有一种简单的方法可以可视化使用的锚,而无需训练模型?

mac*_*udy 9

这是一些无需训练模型即可用于生成和可视化锚框坐标的函数。我们在这里所做的只是调用训练/推论期间图中使用的相关操作。

首先,我们需要知道组成给定尺寸的输入图像的对象检测层的特征图的分辨率(形状)是多少。

import tensorflow as tf 
from object_detection.anchor_generators.multiple_grid_anchor_generator import create_ssd_anchors
from object_detection.models.ssd_mobilenet_v2_feature_extractor_test import SsdMobilenetV2FeatureExtractorTest

def get_feature_map_shapes(image_height, image_width):
    """
    :param image_height: height in pixels
    :param image_width: width in pixels
    :returns: list of tuples containing feature map resolutions
    """
    feature_extractor = SsdMobilenetV2FeatureExtractorTest()._create_feature_extractor(
        depth_multiplier=1,
        pad_to_multiple=1,
    )
    image_batch_tensor = tf.zeros([1, image_height, image_width, 1])

    return [tuple(feature_map.get_shape().as_list()[1:3])
            for feature_map in feature_extractor.extract_features(image_batch_tensor)]
Run Code Online (Sandbox Code Playgroud)

这将返回要素地图形状的列表,例如[(19,19), (10,10), (5,5), (3,3), (2,2), (1,1)],您可以将其传递给第二个函数,该函数返回锚点框的坐标。

def get_feature_map_anchor_boxes(feature_map_shape_list, **anchor_kwargs):
    """
    :param feature_map_shape_list: list of tuples containing feature map resolutions
    :returns: dict with feature map shape tuple as key and list of [ymin, xmin, ymax, xmax] box co-ordinates
    """
    anchor_generator = create_ssd_anchors(**anchor_kwargs)

    anchor_box_lists = anchor_generator.generate(feature_map_shape_list)

    feature_map_boxes = {}

    with tf.Session() as sess:
        for shape, box_list in zip(feature_map_shape_list, anchor_box_lists):
            feature_map_boxes[shape] = sess.run(box_list.data['boxes'])

    return feature_map_boxes
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您可以这样称呼它:

boxes = get_feature_map_boxes(
    min_scale=0.2,
    max_scale=0.9,
    feature_map_shape_list=get_feature_map_shapes(300, 300)
)
Run Code Online (Sandbox Code Playgroud)

您无需指定纵横比,因为配置中的纵横比与的默认值相同create_ssd_anchors

最后,我们在显示给定图层分辨率的网格上绘制锚框。请注意,锚定框和模型中的预测框的坐标在0和1之间进行了归一化。

def draw_boxes(boxes, figsize, nrows, ncols, grid=(0,0)):

    fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=figsize) 

    for ax, box in zip(axes.flat, boxes):
        ymin, xmin, ymax, xmax = box
        ax.add_patch(patches.Rectangle((xmin, ymin), xmax-xmin, ymax-ymin, 
                                fill=False, edgecolor='red', lw=2))

        # add gridlines to represent feature map cells
        ax.set_xticks(np.linspace(0, 1, grid[0] + 1), minor=True)
        ax.set_yticks(np.linspace(0, 1, grid[1] + 1), minor=True)
        ax.grid(True, which='minor', axis='both')

    fig.tight_layout()

    return fig
Run Code Online (Sandbox Code Playgroud)

如果我们以具有3x3特征图的第四层为例

draw_boxes(feature_map_boxes[(3,3)], figsize=(12,16), nrows=9, ncols=6, grid=(3,3))

3x3功能图的锚框

在上面的图像中,每一行代表3x3特征图中的不同单元格,而每一列代表特定的宽高比。

您最初的假设是正确的,例如在最高层(具有最低分辨率的特征图)中具有宽高比1.0的锚点框的高度/宽度将等于输入图像大小的0.9,而在最低层中的锚点框的高度/宽度将等于输入图像大小的高度/宽度。 / width等于输入图像大小的0.2。在这些限制之间线性内插中间层的锚点大小。

但是,关于TensorFlow锚点生成的微妙之处值得我们注意:

  1. 请注意,在图像示例中,每个网格单元有6个锚点,但是我们仅指定5个宽高比。这是因为为每层添加了一个附加锚,其大小介于当前层的锚大小和下一层的锚大小之间。可以使用interpolated_scale_aspect_ratio上面的anchor_kwargs中的参数或在您的配置中同样地修改(或删除)此参数。
  2. 默认情况下,在对象检测功能图的最低层(具有最高分辨率)中,将忽略预先指定的纵横比列表,而仅用3个纵横比替换。可以使用reduce_boxes_in_lowest_layerboolean参数覆盖它。
  3. 正如您正确指出的那样,默认情况下base_anchor_height = base_anchor_width = 1。但是,如果您输入的图像不是正方形,并且在预处理过程中进行了整形,则实际上不会优化纵横比为1.0的“正方形”锚点来锚定原始图像中正方形的对象(尽管当然可以学习预测这些对象训练期间的形状)。

完整的要点可以在这里找到。

  • 8732应该是SSD论文中提到的先验数。对象检测tensorflow框架仅提供7308 https://github.com/tensorflow/models/blob/master/research/object_detection/anchor_generators/multiple_grid_anchor_generator_test.py#L271 (2认同)