SageMaker TensorFlow对象检测模型

磐创AI

    这篇文章描述了如何在Amazon SageMaker中使用TensorFlow对象检测模型API来实现这一点。
    首先,基于AWS示例笔记本,将解释如何使用SageMaker端点在单个图像上运行模型。对于较小的图像,这种方法可行,但对于较大的图像,我们会遇到问题。
    为了解决这些问题,改用批处理转换作业。
    
    起点:使用SageMaker TensorFLow对象检测API进行模型推断
    AWS提供了一些关于GitHub如何使用SageMaker的好例子。
    使用此示例使用TensorFlow对象检测API对对象检测模型进行预测:
    
    将模型部署为端点时,可以通过调用端点,使用该模型一次推断一个图像。此代码取自示例笔记本,显示了如何定义TensorFlowModel并将其部署为模型端点:
    import cv2
    import sagemaker
    from sagemaker.utils import name_from_base
    from sagemaker.tensorflow import TensorFlowModel
    role = sagemaker.get_execution_role()
    model_artefact = '<your-model-s3-path>'
    model_endpoint = TensorFlowModel(
       name=name_from_base('tf2-object-detection'),
       model_data=model_artefact,
       role=role,
       framework_version='2.2',
    )
    predictor = model_endpoint.deploy(initial_instance_count=1, instance_type='ml.m5.large')
    然后,将图像加载为NumPy数组,并将其解析为列表,以便将其传递给端点:
    def image_file_to_tensor(path):
       cv_img = cv2.imread(path,1).astype('uint8')
       cv_img = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
       return cv_img
    img = image_file_to_tensor('test_images/22673445.jpg')
    input = {
     'instances': [img.tolist()]
    }
    最后,调用端点:
    detections = predictor.predict(input)['predictions'][0]
    问题:端点请求负载大小太大
    这在使用小图像时很好,因为API调用的请求负载足够小。然而,当使用较大的图片时,API返回413错误。这意味着有效负载超过了允许的大小,即6 MB。
    当然,我们可以在调用端点之前调整图像的大小,但我想使用批处理转换作业。
    解决方案:改用批处理转换作业
    使用SageMaker批量转换作业,你可以定义自己的最大负载大小,这样我们就不会遇到413个错误。其次,这些作业可用于一次性处理全套图像。
    图像需要存储在S3存储桶中。所有图像都以批处理模式(名称中的内容)进行处理,预测也存储在S3上。
    为了使用批处理转换作业,我们再次定义了TensorFlowModel,但这次我们还定义了入口点和源目录:
    model_batch = TensorFlowModel(
       name=name_from_base('tf2-object-detection'),
       model_data=model_artifact,
       role=role,
       framework_version='2.2',
       entry_point='inference.py',
       source_dir='.',
    )
    inference.py代码转换模型的输入和输出数据,如文档中所述。此代码需要将请求负载(图像)更改为NumPy数组,并将其解析为列表对象。
    从这个示例开始,我更改了代码,使其加载图像并将其转换为NumPy数组。inference.py中input_handler函数更改为以下内容:
    import io
    import json
    import numpy as np
    from PIL import Image
    def input_handler(data, context):
       """ Pre-process request input before it is sent to TensorFlow Serving REST API
       Args:
           data (obj): the request data, in format of dict or string
           context (Context): an object containing request and configuration details
       Returns:
          (dict): a JSON-serializable dict that contains request body and headers
      """
       if context.request_content_type == "application/x-image":
           payload = data.read()              
            image = Image.open(io.BytesIO(payload))        
            array = np.asarray(image)
            return json.dumps({'instances': [array.tolist()]})
        raise ValueError('{{"error": "unsupported content type {}"}}'.format(
            context.request_content_type or "unknown"))
    注意,在上面的代码中排除了output_handler函数。
    此函数需要Python包NumPy和Pillow,它们未安装在运行批处理推断作业的机器上。
    我们可以创建自己的镜像并使用该镜像(在TensorFlowModel对象初始化时使用image_uri关键字)。
    也可以提供requirements.txt并将其存储在笔记本所在的文件夹中(称为source_dir=“.”)。该文件在镜像引导期间用于使用pip安装所需的包。内容为:
    numpy
    pillow
    首先,想使用OpenCV(就像在endpoint示例中一样),但该软件包不太容易安装。
    我们现在使用模型创建transformer对象,而不是将模型部署为模型端点:
    input_path = "s3://bucket/input"
    output_path = "s3://bucket/output"
    tensorflow_serving_transformer = model_batch.transformer(
       instance_count=1,
       instance_type="ml.m5.large",
       max_concurrent_transforms=1,
       max_payload=5,
       output_path=output_path,
    )
    最后,使用transform:
    tensorflow_serving_transformer.transform(
       input_path,
       content_type="application/x-image",
    )
    图像由模型处理,结果将作为JSON文件最终在output_path bucket中。命名等于输入文件名,后跟.out扩展名。你还可以调整和优化实例类型、最大负载等。
    最后
    这很可能不是最具成本效益的方法,因为我们将图像作为NumPy数组传递给转换器。
    此外,我们还可以在inference.py中调整output_handler函数压缩并存储在S3上的JSON,或仅返回相关检测。