API обнаружения объектов TF - извлекать вектор признаков для каждого bbox обнаружения

Я использую API обнаружения объектов Tensorflow и работаю над предварительно обученной моделью ssd-mobilenet. Есть ли способ использовать последний глобальный пул мобильной сети для каждого bbox в качестве вектора функций? Я не могу найти название операции, содержащей эту информацию.

Мне удалось извлечь метки обнаружения и bboxes на основе примера на github:

 image_tensor = detection_graph.get_tensor_by_name( 'image_tensor:0' )
 # Each box represents a part of the image where a particular object was detected.
 detection_boxes = detection_graph.get_tensor_by_name( 'detection_boxes:0' )
 # Each score represent how level of confidence for each of the objects.
 # Score is shown on the result image, together with the class label.
 detection_scores = detection_graph.get_tensor_by_name( 'detection_scores:0' )
 detection_classes = detection_graph.get_tensor_by_name( 'detection_classes:0' )
 num_detections = detection_graph.get_tensor_by_name( 'num_detections:0' )
 #TODO: add also the feature vector output

 # Actual detection.
 (boxes, scores, classes, num) = sess.run(
                [detection_boxes, detection_scores, detection_classes, num_detections],
                feed_dict={image_tensor: image_np_expanded} )

2 ответа

Как сказал Стив, векторы функций в Faster RCNN в API обнаружения объектов, похоже, сбрасываются после SecondStageBoxPredictor. Я смог проделать их через сеть, изменив core/box_predictor.py и meta_architectures / fast_rcnn_meta_arch.py.

Суть в том, что код подавления не-max на самом деле имеет параметр для Additional_fields (см. Core/post_processing.py:176 на master). Вы можете передать набор тензоров, имеющих одинаковую форму в первых двух измерениях с блоками и счетами, и функция вернет их отфильтрованные так же, как и поля и оценки. Вот отличия от мастера изменений, которые я сделал:

https://gist.github.com/donniet/c95d19e00ff9abeb786415b3a9348e62

Затем вместо загрузки замороженного графика мне пришлось перестроить сеть и загрузить переменные из контрольной точки следующим образом (примечание: я загрузил контрольную точку для более быстрого rcnn отсюда: http://download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_coco_2018_01_28.tar.gz)

import sys
import os
import numpy as np

from object_detection.builders import model_builder
from object_detection.protos import pipeline_pb2

from google.protobuf import text_format
import tensorflow as tf

# load the pipeline structure from the config file
with open('object_detection/samples/configs/faster_rcnn_resnet101_coco.config', 'r') as content_file:
    content = content_file.read()

# build the model with model_builder
pipeline_proto = pipeline_pb2.TrainEvalPipelineConfig()
text_format.Merge(content, pipeline_proto)
model = model_builder.build(pipeline_proto.model, is_training=False)

# construct a network using the model
image_placeholder = tf.placeholder(shape=(None,None,3), dtype=tf.uint8, name='input')
original_image = tf.expand_dims(image_placeholder, 0)
preprocessed_image, true_image_shapes = model.preprocess(tf.to_float(original_image))
prediction_dict = model.predict(preprocessed_image, true_image_shapes)
detections = model.postprocess(prediction_dict, true_image_shapes)

# create an input network to read a file
filename_placeholder = tf.placeholder(name='file_name', dtype=tf.string)
image_file = tf.read_file(filename_placeholder)
image_data = tf.image.decode_image(image_file)

# load the variables from a checkpoint
init_saver = tf.train.Saver()
sess = tf.Session()
init_saver.restore(sess, 'object_detection/faster_rcnn_resnet101_coco_11_06_2017/model.ckpt')

# get the image data
blob = sess.run(image_data, feed_dict={filename_placeholder:'image.jpeg'})
# process the inference
output = sess.run(detections, feed_dict={image_placeholder:blob})

# get the shape of the image_features
print(output['image_features'].shape)

Предостережение: я не запускал модульные тесты tenorflow против внесенных мною изменений, поэтому рассмотрите их только для демонстрационных целей, и необходимо провести дополнительное тестирование, чтобы убедиться, что они не нарушают что-либо еще в API обнаружения объектов.

Поддержка извлечения функций была добавлена ​​в недавнем PR: (https://github.com/tensorflow/models/pull/7208). Чтобы использовать эту функцию, вы можете повторно экспортировать предварительно обученные модели с помощью инструмента экспорта.

Для справки, это был сценарий, который я использовал:

#!/bin/bash
# NOTE: run this from tf/models/research directory

# Ensure that the necessary modules are on the PYTHONPATH
PYTHONPATH=".:./slim:$PYTHONPATH"

# Modify this to ensure that Tensorflow is accessible to your environment
conda activate tf37

# pick a model from the model zoo
ORIG_MODEL="faster_rcnn_inception_resnet_v2_atrous_oid_v4_2018_12_12"

# point at wherever you have downloaded the pretrained model
ORIG_MODEL_DIR="object_detection/pretrained/${ORIG_MODEL}"

# choose a destination where the updated model will be stored
DEST_DIR="${ORIG_MODEL_DIR}_with_feats"
echo "Re-exporting model from $ORIG_MODEL_DIR"

python3 object_detection/export_inference_graph.py \
     --input_type image_tensor \
     --pipeline_config_path "${ORIG_MODEL_DIR}/pipeline.config" \
     --trained_checkpoint_prefix "${ORIG_MODEL_DIR}/model.ckpt" \
     --output_directory "${DEST_DIR}"

Чтобы использовать реэкспортированную модель, вы можете обновить run_inference_for_single_image в примере записной книжки включить detection_features как выход:

def run_inference_for_single_image(image, graph):
    with graph.as_default():
        with tf.Session() as sess:
            # Get handles to input and output tensors
            ops = tf.get_default_graph().get_operations()
            all_tensor_names = {output.name for op in ops for output in op.outputs}
            tensor_dict = {}
            for key in ['num_detections', 'detection_boxes', 'detection_scores', 'detection_classes',
                        'detection_masks', 'detection_features']:
                tensor_name = key + ':0'
                if tensor_name in all_tensor_names:
                    tensor_dict[key] = tf.get_default_graph().get_tensor_by_name( tensor_name)
            if 'detection_masks' in tensor_dict:
                # The following processing is only for single image
                detection_boxes = tf.squeeze(tensor_dict['detection_boxes'], [0])
                detection_masks = tf.squeeze(tensor_dict['detection_masks'], [0])
                # Reframe is required to translate mask from box coordinates to image coordinates and fit the image size.
                real_num_detection = tf.cast(tensor_dict['num_detections'][0], tf.int32)
                detection_boxes = tf.slice(detection_boxes, [0, 0], [real_num_detection, -1])
                detection_masks = tf.slice(detection_masks, [0, 0, 0], [real_num_detection, -1, -1])
                detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks( detection_masks, detection_boxes, image.shape[1], image.shape[2])
                detection_masks_reframed = tf.cast( tf.greater(detection_masks_reframed, 0.5), tf.uint8)
                # Follow the convention by adding back the batch dimension
                tensor_dict['detection_masks'] = tf.expand_dims( detection_masks_reframed, 0)
            image_tensor = tf.get_default_graph().get_tensor_by_name('image_tensor:0')

            # Run inference
            output_dict = sess.run(tensor_dict, feed_dict={image_tensor: image})

            # all outputs are float32 numpy arrays, so convert types as appropriate
            output_dict['num_detections'] = int(output_dict['num_detections'][0])
            output_dict['detection_classes'] = output_dict[ 'detection_classes'][0].astype(np.int64)
            output_dict['detection_boxes'] = output_dict['detection_boxes'][0]
            output_dict['detection_scores'] = output_dict['detection_scores'][0]
            output_dict['detection_features'] = output_dict['detection_features'][0]
            if 'detection_masks' in output_dict:
                output_dict['detection_masks'] = output_dict['detection_masks'][0]
    return output_dict

По общему признанию, это не идеальный ответ, но я много покопался в Faster-RCNN с TF-OD API и добился некоторого прогресса в этой проблеме. Я объясню, что я понял, изучив версию Faster-RCNN, и, надеюсь, вы сможете перевести ее на SSD. Лучше всего, если вы покопаетесь в графике на TensorBoard и просмотрите имена тензоров на графике обнаружения.

Во-первых, не всегда простое однозначное соответствие между характеристиками и рамками / баллами. То есть не существует простого тензора, который вы можете извлечь из сети, который обеспечит это, по крайней мере, по умолчанию.

Вот код для получения функций из сети Faster-RCNN:

https://gist.github.com/markdtw/02ece6b90e75832bd44787c03a664e8d

Хотя это обеспечивает нечто похожее на векторы функций, вы можете видеть, что есть несколько других людей, которые столкнулись с проблемами с этим решением. Принципиальная проблема заключается в том, что вектор объектов передается в процессор SecondStagePost, который выполняет несколько операций перед detection_boxes тензор, и подобные тензоры, создаются.

Перед обработчиком SecondStagePost создаются оценки и блоки классов, а вектор объектов остается позади, и его больше никогда не будет видно. В постпроцессоре есть мультиклассовая стадия NMS и стадия сортировки. Конечным результатом является MaxProposalsFromSecondStage, тогда как вектор объектов заполняется для [MaxProposalsFromFirstStage, NumberOfFeatureVectors]. Таким образом, существует децимация и операция сортировки, которая затрудняет сопряжение конечного результата с индексами векторов объектов.

Мое текущее решение состоит в том, чтобы вытащить вектор объектов и поля из перед вторым этапом и сделать все остальное вручную. Несомненно, есть лучшее решение, чем это, но трудно проследить график и найти правильные тензоры для операции сортировки.

Я надеюсь, что это помогает вам! Sorry that I couldn't offer you an end-to-end solution but I hope this gets you over your current road block.

Другие вопросы по тегам