Tensorflowのtfrecord形式で可変数のバイナリインスタンスマスクをシリアル化する

Nov 27 2020

MS Coco 2014データセットの場合、各画像には可変数のバウンディングボックスと、注釈ファイルで指定されたインスタンスポリゴンから取得できる対応するバイナリインスタンスマスクがあります。私はpycocotools(特にcoco.pyファイル)を使用してこれを実現します。ここで、Tensorflowのtfrecords形式を使用して画像情報をシリアル化したいと思います。各画像IDでインデックス付けされた、Python dictの注釈を読み取った後、次のような可変数のバウンディングボックスをシリアル化することができました。

x_min_values = []
x_max_values = []
y_min_values = []
y_max_values = []
for bb in bounding_boxes:
    x_min_values.append(int(bb[0]))
    y_min_values.append(int(bb[1]))
    x_max_values.append(int(bb[2]))
    y_max_values.append(int(bb[3]))

そして、で使用するtf.train.Example機能辞書のために、各リストを次のようにint64機能リストに変換しました。

def _int64_feature_list(value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=value)) 

しかし、問題は、インスタンスマスクが2次元であるため、それらをシリアル化するためにどの戦略を使用すべきかわからないことです。セグメンテーションマスクのようにマスクが1つしかない場合は、配列をフラット化し、64ビットのフィーチャリストを記述してから、逆シリアル化時に画像の高さと幅を使用して配列の形状を変更できますが、これはできません。可変数のマスク用。どんな洞察もありがたいです。

回答

vijaym Dec 08 2020 at 03:24

以下で説明するように、FixedLenSequenceFeatureを使用する必要があります。


それぞれ3つと2つのバウンディングボックスを持つ2つの画像の例

bounding_boxes = []
bounding_boxes.append(np.random.randint(low=0, high=2000,size=(3, 4)))  
bounding_boxes.append(np.random.randint(low=0, high=2000,size=(2, 4)))  
for i, box in enumerate(bounding_boxes):
    print({i},box)

出力:

{0} [[1806 1172 1919 1547]
[1478 1654 498 1689]
[131515 1654 1586]]

{1} [[601 1473 1670 756]
[1791 993 1049 1793]]

#Write tfrecord
def _int64_feature(list_of_ints):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

out_path = './test.tfrec'
with tf.io.TFRecordWriter(out_path) as out:
    for box in bounding_boxes:            
        
        example = tf.train.Example(features=tf.train.Features(feature={
            'boxes': _int64_feature(np.array(box).flatten().tolist()),
            }))
        out.write(example.SerializeToString())

書き込まれたtfrecordを確認します。

ds = tf.data.TFRecordDataset(out_path)

for i, data in enumerate(ds):
    process_each = {
        'boxes': tf.io.FixedLenSequenceFeature([], dtype=tf.int64, allow_missing=True),            
    }
    samples = tf.io.parse_example(data, process_each)
    print(i, samples['boxes'].numpy().reshape(-1, 4))
    

出力:

0 [[1806 1172 1919 1547]
[1478 1654 498 1689]
[131515 1654 1586]]
1 [[601 1473 1670 756]
[1791 993 1049 1793]]