использование интерфейса Оценщика для вывода с предварительно обученной моделью обнаружения объектов тензорного потока

Я пытаюсь загрузить предварительно обученную модель обнаружения объекта тензорного потока из объекта Tensorflow Обнаружение репо как tf.estimator.Estimator и использование его для прогнозирования.

Я могу загрузить модель и выполнить логический вывод с помощью Estimator.predict(), однако результат будет мусором. Другие методы загрузки модели, например как Predictor, и вывод работает нормально.

Мы будем очень благодарны за любую помощь в правильной загрузке модели в качестве Estimator вызова predict(). Мой текущий код:

Загрузите и подготовьте изображение

def load_image_into_numpy_array(image):
    (im_width, im_height) = image.size
    return np.array(list(image.getdata())).reshape((im_height, im_width, 3)).astype(np.uint8)

image_url = 'https://i.imgur.com/rRHusZq.jpg'

# Load image
response = requests.get(image_url)
image = Image.open(BytesIO(response.content))

# Format original image size
im_size_orig = np.array(list(image.size) + [1])
im_size_orig = np.expand_dims(im_size_orig, axis=0)
im_size_orig = np.int32(im_size_orig)

# Resize image
image = image.resize((np.array(image.size) / 4).astype(int))

# Format image
image_np = load_image_into_numpy_array(image)
image_np_expanded = np.expand_dims(image_np, axis=0)
image_np_expanded = np.float32(image_np_expanded)

# Stick into feature dict
x = {'image': image_np_expanded, 'true_image_shape': im_size_orig}

# Stick into input function
predict_input_fn = tf.estimator.inputs.numpy_input_fn(
    x=x,
    y=None,
    shuffle=False,
    batch_size=128,
    queue_capacity=1000,
    num_epochs=1,
    num_threads=1,
)

Примечание:

train_and_eval_dict также, кажется, содержит input_fn для предсказания

train_and_eval_dict['predict_input_fn']

Однако на самом деле это возвращает tf.estimator.export.ServingInputReceiver, с которым я не уверен, что делать. Это потенциально может быть источником моих проблем, поскольку требуется предварительная обработка, прежде чем модель действительно увидит изображение.

Загрузить модель как Estimator

Модель загружена из зоопарка TF Model Zoo здесь, код для загрузки модели адаптирован из здесь.

model_dir = './pretrained_models/tensorflow/ssd_mobilenet_v1_coco_2018_01_28/'
pipeline_config_path = os.path.join(model_dir, 'pipeline.config')

config = tf.estimator.RunConfig(model_dir=model_dir)

train_and_eval_dict = model_lib.create_estimator_and_inputs(
    run_config=config,
    hparams=model_hparams.create_hparams(None),
    pipeline_config_path=pipeline_config_path,
    train_steps=None,
    sample_1_of_n_eval_examples=1,
    sample_1_of_n_eval_on_train_examples=(5))

estimator = train_and_eval_dict['estimator']

Выполнить вывод

output_dict1 = estimator.predict(predict_input_fn)

Это распечатает некоторые сообщения журнала, одно из которых:

INFO:tensorflow:Restoring parameters from ./pretrained_models/tensorflow/ssd_mobilenet_v1_coco_2018_01_28/model.ckpt

Так что похоже, что предварительно натренированные веса набирают обороты. Однако результаты выглядят так:

Изображение с ошибками обнаружения

Загрузить ту же модель, что и Predictor

from tensorflow.contrib import predictor

model_dir = './pretrained_models/tensorflow/ssd_mobilenet_v1_coco_2018_01_28'
saved_model_dir = os.path.join(model_dir, 'saved_model')
predict_fn = predictor.from_saved_model(saved_model_dir)

Выполнить вывод

output_dict2 = predict_fn({'inputs': image_np_expanded})

Результаты выглядят неплохо:

введите здесь описание изображения


person DavidS    schedule 30.04.2019    source источник
comment
Удалось ли вам заставить его работать в качестве оценщика?   -  person Mat    schedule 26.09.2019
comment
Нет, сдался и просто использовал predictor.   -  person DavidS    schedule 27.09.2019


Ответы (1)


Когда вы загружаете модель в качестве оценщика и из файла контрольной точки, вот функция восстановления, связанная с ssd моделями. Из ssd_meta_arch.py

def restore_map(self,
                  fine_tune_checkpoint_type='detection',
                  load_all_detection_checkpoint_vars=False):
    """Returns a map of variables to load from a foreign checkpoint.
    See parent class for details.
    Args:
      fine_tune_checkpoint_type: whether to restore from a full detection
        checkpoint (with compatible variable names) or to restore from a
        classification checkpoint for initialization prior to training.
        Valid values: `detection`, `classification`. Default 'detection'.
      load_all_detection_checkpoint_vars: whether to load all variables (when
         `fine_tune_checkpoint_type='detection'`). If False, only variables
         within the appropriate scopes are included. Default False.
    Returns:
      A dict mapping variable names (to load from a checkpoint) to variables in
      the model graph.
    Raises:
      ValueError: if fine_tune_checkpoint_type is neither `classification`
        nor `detection`.
    """
    if fine_tune_checkpoint_type not in ['detection', 'classification']:
      raise ValueError('Not supported fine_tune_checkpoint_type: {}'.format(
          fine_tune_checkpoint_type))

    if fine_tune_checkpoint_type == 'classification':
      return self._feature_extractor.restore_from_classification_checkpoint_fn(
          self._extract_features_scope)

    if fine_tune_checkpoint_type == 'detection':
      variables_to_restore = {}
      for variable in tf.global_variables():
        var_name = variable.op.name
        if load_all_detection_checkpoint_vars:
          variables_to_restore[var_name] = variable
        else:
          if var_name.startswith(self._extract_features_scope):
            variables_to_restore[var_name] = variable

    return variables_to_restore

Как вы можете видеть, даже если в файле конфигурации задано from_detection_checkpoint: True, будут восстановлены только переменные в области экстрактора функций. Чтобы восстановить все переменные, вам нужно будет установить

load_all_detection_checkpoint_vars: True

в файле конфигурации.

Итак, описанная выше ситуация вполне понятна. При загрузке модели как Estimator будут восстановлены только переменные из области действия средства извлечения признаков, а веса области действия предикторов не будут восстановлены, оценщик, очевидно, даст случайные прогнозы.

При загрузке модели в качестве предиктора загружаются все веса, поэтому прогнозы являются разумными.

person danyfang    schedule 01.05.2019
comment
Спасибо за ответ! Похоже, этого поля нет в предоставленных файлах конфигурации, я попытаюсь выяснить, где я могу его установить. - person DavidS; 01.05.2019
comment
вы можете просто добавить прямо под from_detection_checkpoint: True - person danyfang; 01.05.2019
comment
Хм, просто попробовал, вроде ничего не сделал. from_detection_checkpoint: True (под которым я вставил load_all_detection_checkpoint_vars: True) есть в конфиге поезда. Поскольку я не тренируюсь, а просто делаю прогнозы, не думаю, что это имело какое-то влияние. - person DavidS; 01.05.2019
comment
Затем вы можете попробовать удалить строку фильтрации в функции выше. Как вручную установить переменные для восстановления? - person danyfang; 01.05.2019
comment
Изменено значение arg по умолчанию с False на True, но безрезультатно. Не похоже, что этот метод вызывается, когда модель загружается для прогнозирования. - person DavidS; 01.05.2019
comment
Если это только для прогнозирования, то конфигурационный файл не понадобится. Но поскольку вы создавали Estimator, вызывая model_lib.create_estimator_and_inputs, он вызовет model_fn, а затем вызовет restore_map. Вы можете распечатать несколько знаков внутри функции, чтобы узнать, действительно ли она вызывается. - person danyfang; 01.05.2019
comment
Да, я добавил к методу оператор печати, он не вызывается. Кстати, я открыт для любых других способов загрузки модели как Estimator, я не забочусь об использовании model_lib.create_estimator_and_inputs. Если вы посмотрите в model_lib.create_model_fn(), вы увидите, что detection_model.restore_map() вызывается только когда mode == tf.estimator.ModeKeys.TRAIN. - person DavidS; 01.05.2019
comment
Да вы правы. Так что, возможно, в этом и заключается проблема. Я имею в виду, что при создании Estimator без использования режима поезда веса не будут правильно инициализированы. Так, может быть, сначала попробуйте режим поезда, а затем режим прогнозирования? - person danyfang; 01.05.2019
comment
Может быть, если бы я мог каким-то образом вызвать Estimator.train() с input_fn, работающим в течение 0 эпох, это сработало бы? Потому что на самом деле я не хочу менять веса. - person DavidS; 01.05.2019
comment
Да, я бы тоже попробовал. Я думал о добавлении restore_map в режим прогнозирования, но не уверен, будет ли он вызывать restore_map каждый раз, когда делает прогноз. - person danyfang; 01.05.2019
comment
Пока не повезло, на самом деле не думаю, что это сработает, так как вызов Estimator.predict() перезагружает веса из контрольной точки. Очень обидно, что это так сложно. - person DavidS; 01.05.2019