SageMaker Batch Transform多图像mini-batch>1推理异常排查
问题根源
你的配置和代码存在两个核心错配,直接导致拿到的字节是混乱的:
split_type='Line'仅适用于按换行分隔的文本类输入(如CSV、JSON Lines),JPEG是二进制格式,不存在按行拆分的逻辑,SageMaker会粗暴按字节中的换行符切割二进制内容,直接把图片切碎。- 开启
strategy='MultiRecord'后,SageMaker不会直接裸拼多张图片的字节发给容器——二进制格式没有天然分隔符,无法直接拆分单张边界,SageMaker会用带长度标记的RecordIO格式封装批量记录,你当前直接把整个请求体当单张JPEG读取,自然会读到混合了格式头、多图内容的异常字节。
修正方案
第一步:调整批量转换配置
首先要保证输入路径下每张图片单独存储为一个独立S3对象,不要把多张图片打包成单个大文件上传,二进制图片无法被自动切分。
配置修改如下:
transformer = sagemaker.transformer.Transformer( model_name=model_name, instance_count=instance_count, instance_type=instance_type, max_concurrent_transforms=16, max_payload=5, # 单批次请求最大体积,单位MB,根据单张图大小调整即可控制单批次包含的图片数量 output_path=inference_output_data, strategy='MultiRecord', assemble_with='RecordIO' # 指定用RecordIO格式封装批量记录 ) transformer.transform( data=batch_input, content_type='image/jpeg', job_name=job_name, split_type=None, # 关闭行切分,每个S3独立对象即为单个样本 wait=False, logs=False )
第二步:修改容器端推理逻辑,解析批量请求
你需要在接口中解析RecordIO格式的请求体,按长度标记拆分出每张图片的原始字节,再做批量预处理,示例代码如下:
import struct import io from PIL import Image import flask @app.route('/invocations', methods=['POST']) def transformation(): request_bytes = flask.request.data preprocessed_imgs = [] offset = 0 total_len = len(request_bytes) while offset < total_len: # 校验RecordIO魔数 magic_num, = struct.unpack('<I', request_bytes[offset:offset+4]) if magic_num != 0xced7230a: flask.abort(400, description="Invalid request format") offset += 4 # 读取当前记录长度 img_len, = struct.unpack('<I', request_bytes[offset:offset+4]) offset +=4 # 读取单张图片字节并做预处理 single_img_bytes = request_bytes[offset:offset+img_len] offset += img_len img = Image.open(io.BytesIO(single_img_bytes)) preprocessed_imgs.append(preprocess_image(img)) # 按下游Triton服务要求的格式封装批量预处理结果并返回 return build_response_for_triton(preprocessed_imgs)
备选方案(无需解析RecordIO)
如果不需要mini-batch带来的吞吐提升,可以直接把strategy设为SingleRecord,保持split_type=None,此时每个POST请求仅携带单张图片,你之前batch size=1的代码可以直接运行,不需要修改解析逻辑。
内容的提问来源于stack exchange,提问作者Harel Farkash
相关产品推荐
相关产品推荐

