Serialize o número variável de máscaras de instância binária com o formato tfrecord do Tensorflow
Para o conjunto de dados MS Coco 2014, cada imagem tem um número variável de caixas delimitadoras e máscaras de instância binárias correspondentes que podem ser obtidas do polígono de instância fornecido no arquivo de anotação. Eu consigo isso usando pycocotools (em particular o arquivo coco.py). Agora, desejo serializar as informações da imagem usando o formato tfrecords do Tensorflow. Depois de ler as anotações de um dicionário python, indexado por cada id de imagem, fui capaz de serializar números variáveis de caixas delimitadoras como:
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]))
E então, para meu ditado de recursos ser usado tf.train.Example
, converti cada lista em uma lista de recursos int64 como:
def _int64_feature_list(value):
return tf.train.Feature(int64_list=tf.train.Int64List(value=value))
Mas agora o problema é que, como as máscaras de instância são bidimensionais, não tenho certeza de qual estratégia devo usar para serializá-las. Se houvesse apenas uma máscara, como em uma máscara de segmentação, eu poderia simplesmente nivelar a matriz e escrever uma lista de recursos de 64 bits e, em seguida, usar a altura e largura da imagem para remodelar a matriz ao desserializar, mas não posso fazer isso para números variáveis de máscaras. Todos os insights são apreciados.
Respostas
É necessário usar FixedLenSequenceFeature conforme explicado abaixo:
Um exemplo de 2 imagens com 3 e 2 caixas delimitadoras cada
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)
Resultado:
{0} [[1806 1172 1919 1547]
[1478 1654 498 1689]
[131 515 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())
Verifique o tfrecord escrito:
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))
Resultado:
0 [[1806 1172 1919 1547]
[1478 1654 498 1689]
[131 515 1654 1586]]
1 [[601 1473 1670 756]
[1791 993 1049 1793]]