如何在MXNet和Python 2.7中针对多个图像同时在图像分类模型上运行推理

时间:2019-04-08 11:40:17

标签: python-2.7 mxnet

我在ONNX格式(分类号为V1.2.1的V1.2.1)的图像分类模型上使用Python 2.7,MXNet V1.3.0 ML框架运行推理,在该模型中我一次将图像馈入推理器。我该怎么办才能异步运行多个图像的推理,但还要等待所有图像完成?

我正在从30 FPS的视频中提取帧作为.jpeg图像。例如,当我在长度为20s的视频上运行该过程时,它将生成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 个答案:

答案 0 :(得分:2)

您不应该做的一件事就是为每个图像加载模型。应该加载一次模型,然后对所有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()会将数据复制到CPU,因此它必须是同步的。在每个迭代之间进行同步调用会减慢处理速度。

假设您有权访问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张)以提高处理的并行性。但是,这样做会增加内存消耗。由于您似乎使用的是弹性推断上下文,因此您的整体内存将受到限制,我建议坚持使用较小的批处理大小,以免出现内存不足的风险。