web-dev-qa-db-ja.com

Tensorflow検出APIのSSDアンカー

N行N列の画像のカスタムデータセットで [〜#〜] ssd [〜#〜] 検出器をトレーニングしたいと思います。そこで、 Tensorflowオブジェクト検出API を掘り下げて、MobileNetv2に基づく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
    }
}

SSDアンカージェネレータプロト を見ると、次のように仮定するのは正しいですか:base_anchor_height=base_anchor_width=1

はいの場合、結果のアンカーは次のようになります マルチグリッドアンカージェネレーター (画像が300x300の正方形の場合)は次のとおりです:0.2 * 300 = 60 * 60ピクセルから0.9 * 300の範囲のサイズ= 270 * 270ピクセル(アスペクト比が異なる)?

したがって、フィールドを修正してNxN画像をトレーニングしたい場合は、次のようにします。

fixed_shape_resizer {
  height: N
  width: N
}

彼は、(0.2 * N、0.2 * N)ピクセルから(0.9 * N、0.9 * N)ピクセル(アスペクト比が異なる)の範囲の同じ構成ファイルアンカーを使用しますか?

コードを把握するのが難しく、まだドキュメントがほとんどないように思われるので、私は多くの仮定をしました。私は正しいですか?モデルをトレーニングせずに使用されるアンカーを視覚化する簡単な方法はありますか?

5
jean

モデルをトレーニングせずにアンカーボックスの座標を生成および視覚化するために使用できるいくつかの関数を次に示します。ここで行っているのは、トレーニング/推論中にグラフで使用される関連する操作を呼び出すことだけです。

まず、特定のサイズの入力画像のオブジェクト検出レイヤーを構成するフィーチャマップの解像度(形状)を知る必要があります。

_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)]
_

これにより、特徴マップの形状のリストが返されます。たとえば、[(19,19), (10,10), (5,5), (3,3), (2,2), (1,1)]は、アンカーボックスの座標を返す2番目の関数に渡すことができます。

_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
_

あなたの例では、次のように呼び出すことができます。

_boxes = get_feature_map_boxes(
    min_scale=0.2,
    max_scale=0.9,
    feature_map_shape_list=get_feature_map_shapes(300, 300)
)
_

構成内のアスペクト比はデフォルトの_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
_

例として3x3の特徴マップを持つ4番目のレイヤーを取り上げる場合

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

Anchor boxes for 3x3 feature map

上の画像では、各行は3x3特徴マップの異なるセルを表し、各列は特定のアスペクト比を表しています。

最初の仮定は正しかった。たとえば、最上層のアスペクト1.0(最低解像度の特徴マップ)のアンカーボックスの高さ/幅は入力画像サイズの0.9に等しいが、最下層のアンカーボックスの高さは/ widthは入力画像サイズの0.2に等しい。中央のレイヤーのアンカーサイズは、これらの制限の間で線形補間されます。

ただし、TensorFlowアンカーの生成に関して、知っておく価値のある微妙な点はほとんどありません。

  1. 画像の例では、グリッドセルごとに6つのアンカーがありますが、指定するアスペクト比は5つだけです。これは、現在のレイヤーのアンカーサイズと次のレイヤーのアンカーサイズの中間のサイズを持つ各レイヤーにアンカーが追加されるためです。これは、上記のanchor_kwargsまたは同様に構成で_interpolated_scale_aspect_ratio_パラメーターを使用して変更(または削除)できます。
  2. デフォルトでは、事前に指定されたアスペクト比のリストは、オブジェクト検出機能マップの最下層(最高の解像度)では無視され、3つのアスペクト比に置き換えられます。これは、_reduce_boxes_in_lowest_layer_ booleanパラメーターでオーバーライドできます。
  3. あなたが正しく指摘したように、デフォルトでは_base_anchor_height = base_anchor_width = 1_。ただし、入力画像が正方形ではなく、前処理中に形状が変更された場合、アスペクト1.0の「正方形」アンカーは、元の画像で正方形であったオブジェクトをアンカーするために実際には最適化されません(もちろん、これらを予測することはできますが)トレーニング中の形状)。

完全な要点は ここ で見つけることができます。

11
macloudy