Как выполнить вывод на модели классификации изображений одновременно для нескольких изображений в MXNet и Python 2.7 - PullRequest
0 голосов
/ 08 апреля 2019

Я выполняю логический вывод с использованием Python 2.7, среды MXNet V1.3.0 ML на модели классификации изображений в формате ONNX (V1.2.1 с opset 7), где я передаю изображение логическому выводу за раз. Что мне нужно сделать, чтобы выполнить асинхронный вывод для нескольких изображений, но также дождаться завершения всех из них?

Я извлекаю кадры в виде изображений .jpeg из видео со скоростью 30 кадров в секунду. Так, например, когда я запускаю процесс на видео длительностью 20 с, он генерирует 600 изображений JPEG. Сейчас я перебираю список этих изображений и передаю относительный путь каждому из них в следующую функцию, которая затем выводит из целевого изображения.

def infer(self, target_image_path):
        target_image_path = self.__output_directory + '/' + target_image_path

        image_data = self.__get_image_data(target_image_path)  # Get pixel data

        '''Define the model's input'''
        model_metadata = onnx_mxnet.get_model_metadata(self.__model)
        data_names = [inputs[0]
                      for inputs in model_metadata.get('input_tensor_data')]
        Batch = namedtuple('Batch', 'data')

        ctx = mx.eia()  # Set the context to elastic inference

        '''Load the model'''
        sym, arg, aux = onnx_mxnet.import_model(self.__model)
        mod = mx.mod.Module(symbol=sym, data_names=data_names,
                            context=ctx, label_names=None)
        mod.bind(data_shapes=[(data_names[0], image_data.shape)],
                 label_shapes=None, for_training=False)

        mod.set_params(arg_params=arg, aux_params=aux,
                       allow_missing=True, allow_extra=True)

        '''Run inference on the image'''
        mod.forward(Batch([mx.nd.array(image_data)]))
        predictions = mod.get_outputs()[0].asnumpy()
        predictions = predictions[0].tolist()

        '''Apply emotion labels'''
        zipb_object = zip(self.__emotion_labels, predictions)
        prediction_dictionary = dict(zipb_object)

        return prediction_dictionary

Ожидаемое поведение: асинхронный запуск логического вывода для каждого изображения, а также ожидание завершения процесса для всего пакета.

1 Ответ

2 голосов
/ 11 апреля 2019

Одна вещь, которую вы не должны делать, это загружать модель для каждого изображения. Нужно загрузить модель один раз, а затем выполнить вывод на всех ваших 600 изображениях.

Например, вы можете изменить свой код следующим образом:

def load_model(self):
        '''Load the model'''
        model_metadata = onnx_mxnet.get_model_metadata(self.__model)
        data_names = [inputs[0]
                      for inputs in model_metadata.get('input_tensor_data')]
        Batch = namedtuple('Batch', 'data')

        ctx = mx.eia()  # Set the context to elastic inference

        '''Load the model'''
        sym, arg, aux = onnx_mxnet.import_model(self.__model)
        mod = mx.mod.Module(symbol=sym, data_names=data_names,
                            context=ctx, label_names=None)
        mod.bind(data_shapes=[(data_names[0], image_data.shape)],
                 label_shapes=None, for_training=False)

        mod.set_params(arg_params=arg, aux_params=aux,
                       allow_missing=True, allow_extra=True)

        return mod


def infer(self, mod, target_image_path):
        target_image_path = self.__output_directory + '/' + target_image_path

        image_data = self.__get_image_data(target_image_path)  # Get pixel data

        '''Run inference on the image'''
        mod.forward(Batch([mx.nd.array(image_data)]))
        predictions = mod.get_outputs()[0].asnumpy()
        predictions = predictions[0].tolist()

        '''Apply emotion labels'''
        zipb_object = zip(self.__emotion_labels, predictions)
        prediction_dictionary = dict(zipb_object)

        return prediction_dictionary

MXNet работает на асинхронном движке, вам не нужно ждать окончания обработки изображения, чтобы поставить в очередь новое.

Некоторые вызовы в MXNet являются асинхронными, например, когда вы вызываете mod.forward(), эти вызовы немедленно возвращаются и не ожидают вычисления результата. Другие вызовы являются синхронными, например mod.get_outputs()[0].asnumpy(), при этом данные копируются в ЦП, поэтому они должны быть синхронными. Синхронный вызов между каждой итерацией немного замедляет обработку.

Предполагая, что у вас есть доступ к списку image_paths, вы можете обрабатывать их следующим образом, чтобы минимизировать время ожидания и иметь точку синхронизации только в конце:

    results = []
    for target_image_path in image_paths:
        image_data = self.__get_image_data(target_image_path)  # Get pixel data

        '''Run inference on the image'''
        mod.forward(Batch([mx.nd.array(image_data)]))
        results.append(mod.get_outputs()[0])
    predictions = [result.asnumpy()[0].tolist() for result in results]

Подробнее об асинхронном программировании в MXNet вы можете прочитать здесь: http://d2l.ai/chapter_computational-performance/async-computation.html

Еще лучше, если вы знаете, что у вас есть N изображений для обработки, вы можете объединить их в пакеты, например, по 16, чтобы увеличить параллельность обработки. Однако это увеличит потребление памяти. Поскольку вы, похоже, используете контекст упругого вывода, ваша общая память будет ограничена, и я бы посоветовал придерживаться меньшего размера пакета, чтобы не рисковать исчерпать память.

...