亚马逊AWS官方博客
在 Amazon SageMaker 上托管 Libcom 图片融合服务
图像融合技术广泛应用于多个行业,如电商营销素材和广告创意等领域。其目标是将前景插入到背景图像中,通过解决外观、几何和语义上的不一致性,实现逼真和谐的合成图像。生成式人工智能技术在为商品生成背景时,常常会对商品整体进行修改,导致出现“货不对版”的问题。为控制这一问题,我们推荐一款卓越的图片融合工具库 Libcom(the library of image composition)。该工具库提供了各种图片融合场景所需的模型,这些预训练模型开箱即用,用户还可以利用自有风格的数据进行进一步训练,以满足特定效果。Amazon SageMaker 是一个云机器学习平台,可用于为几乎任何使用场景构建、训练和部署模型。Notebook 实例为构建机器学习模型提供了灵活的环境,省去了用户在管理底层计算基础设施上花费的时间和精力。本文介绍了如何在 Amazon SageMaker 上部署 Libcom 图片融合模型。
方案总览
上图是在 Amazon SageMaker 上搭建和使用 Libcom 模型的整体架构。本文采用 BYOC(Bring Your Own Container)的方式,也就是将现有代码构建成自定义 Docker 镜像的方式迁移到 Amazon SageMaker,适合于现有代码与依赖库的关系比较复杂的情况。
首先我们使用一个亚马逊云科技海外账号,具有访问 Amazon CloudFormation 和 Amazon SageMaker 的权限。登陆亚马逊云科技 Console 后,以 us-east-1 区为例,选择打开 CloudFormation 服务,点击 Create Stack(with new resource),上传模版文件,通过自动化的方式部署本次实验所需要的环境和代码。
点击下一步,输入Stack Name
确认创建 IAM Resource 后提交
等待几分钟 CloudFormation Stack 创建完成后,会提供一个 Notebook 实例,实例上已包含克隆好的初始化代码
在亚马逊云科技的 Console 里选择 SageMaker 服务,在左边导航栏打开 Notebook Instance,找到创建好的 Notebook Instance: libcom-sm-notebook,点击 Open JupyterLab 打开 Notebook 实例,进到 host-libcom-on-sagemaker-endpoint 目录后,看到两个 Notebook:
- deploy.ipynb:负责下载模型、打包推理代码、构建镜像、创建在线推理端点和实验结束后的资源清理
- predict.ipynb:提供了样图的测试步骤和结果展示
创建 SageMaker Libcom Endpoint
按照 deploy.ipynb 中的步骤顺序执行即可。本文使用 Libcom 提供的两种模型:
- FOPAHeatMapModel 基于一对前景-背景图,预测所有位置的合理性分数,输出最佳位置的合成图像
- ImageHarmonizationModel 调整前景照明,使其与背景相匹配
为节约推理时间,我们提前将模型下载到本地,和推理代码一起打包到镜像中
# download models
!chmod +x download_pretrained_model.sh && bash download_pretrained_model.sh
下载完成后,把模型和推理代码打包成镜像,推送到 Amazon ECR
# build containers used by sageMaker
!chmod +x build_and_push.sh && bash build_and_push.sh $region_name
因为是 BYOC 模式,需要遵循 SageMaker Hosting 定义的一套镜像构建范式,重点说明如下,细节请参考代码文件。
- 容器启动命令,参考代码中的 serve 文件
docker run image serve
- 容器应用的心跳检测服务
@app.route('/ping', methods=['GET']) def ping(): #Determine if the container is working and healthy. In this sample container # Declare it healthy if we can load the model successfully.""" # health = ScoringService.get_model() is not None status = 200 #if health else 404 return flask.Response(response='\n', status=status, mimetype='application/json')
- 容器应用的推理服务
import flask . . . app = flask.Flask(__name__) . . . @app.route('/invocations', methods=["POST"]) def invoke(request): # model() is a hypothetical function that gets the inference output: resp_body = model(request) return flask.Response(resp_body, mimetype='text/plain')
详细的推理服务参考 libcom/libcom/predictor.py 中的定义,本次推理代码允许用户输入 4 种方法,将在下一章测试环节详细展开说明。
Libcom/libcom/predictor.py 部分内容:
@app.route('/invocations', methods=['POST'])
def transformation():
data = json.loads(flask.request.data)
function_name = data.get("function",None)
if function_name == "heatmap_compose":
result = heatmap_compose(data)
elif function_name == "simple_compose":
result = simple_compose(data)
elif function_name == "pct_mode":
result = pctnet(data)
elif function_name == "cdt_mode":
result = cdtnet(data)
部署成功后,在 SageMaker→Endpoints 观测到 Endpoint 处于 InService 状态
测试 SageMaker Libcom Endpoint
打开 predict.ipynb 根据提供的步骤顺序执行即可。
在图片融合场景中,我们需要向模型提供前景物体的信息,以便进行图片的合成和和谐化处理。为了实现这一目标,我们使用蒙版来标记前景物体。蒙版的获取方法有很多种,其中最常见的是使用 SAM(Segment Anything Model),本文不再详述。
1. 热力图与最佳放置位置
将准备的前景图模特,模特蒙版和背景图卧室组成请求体发送给推理端点。推理服务会根据前景图和背景图包含的信息,生成一张热力图,热力图中高亮的位置表示背景图的最佳放置位置。基于热力图的生成结果,定制推理代码取了热力图最亮的点,作为背景图中最适合放置前景的位置,执行图片合成。
## Generate FOPA image and placement suggestion
background_path = "uploads/bg.png"
foreground_path = "uploads/fg.jpg"
foreground_mask_path = "uploads/fg_mask.png"
bg=encode_image(background_path)
fg=encode_image(foreground_path)
fg_mask=encode_image(foreground_mask_path)
function = "heatmap_compose"
payload = {
"function":function,
"background":bg,
"foreground":fg,
"foreground_mask":fg_mask,
"scale_x":0.8
}
# Prepare the request body as a JSON object
request_body = json.dumps(payload)
# Send the inference request to the endpoint
response = client.invoke_endpoint(
EndpointName=endpoint_name,
Body=request_body,
ContentType="application/json"
)
# Parse the response
response_body = response["Body"].read().decode("utf-8")
fopa_result = json.loads(response_body)
bbox=fopa_result['bboxes']
print(bbox)
heatmap=save_image_from_base64(fopa_result['heatmap_image'],'results','heatmap')
comp_img=save_image_from_base64(fopa_result['comp_image'],'results','comp_img')
comp_mask=save_image_from_base64(fopa_result['comp_mask'],'results','comp_mask')
grid_img = make_image_grid([heatmap, comp_img, comp_mask])
from IPython.display import display,Image
cv2.imwrite(heatmap, grid_img)
display(Image(filename=heatmap))
根据热力图放置效果:
测试阶段用户可能会调整合并的位置,推理代码中提供用户自定义位置 bbox 放置前景图片。
# prepare images
background_path = "uploads/bg.png"
foreground_path = "uploads/fg.jpg"
foreground_mask_path = "uploads/fg_mask.png"
bg=encode_image(background_path)
fg=encode_image(foreground_path)
fg_mask=encode_image(foreground_mask_path)
function = "simple_compose"
bbox = [376, 187, 550, 791]
print(bbox)
payload = {
"function":function,
"background":bg,
"foreground":fg,
"foreground_mask":fg_mask,
"bbox":bbox
}
# Prepare the request body as a JSON object
request_body = json.dumps(payload)
# Send Image Compose inference request to the endpoint
response = client.invoke_endpoint(
EndpointName=endpoint_name,
Body=request_body,
ContentType="application/json"
)
# Parse the response
response_body = response["Body"].read().decode("utf-8")
compose_result = json.loads(response_body)
# Process the result
#decode_image(compose_result['comp_image'])
#decode_image(compose_result['comp_mask'])
comp_image=save_image_from_base64(compose_result['comp_image'],'results','comp_image')
comp_mask=save_image_from_base64(compose_result['comp_mask'],'results','comp_mask')
grid_img = make_image_grid([comp_image, comp_mask])
from IPython.display import display,Image
cv2.imwrite(comp_image, grid_img)
display(Image(filename=comp_image))
根据指定坐标放置效果:
大家会注意到,每次合成图片后,服务端还会返回一张合成图的前景位置蒙版,这是用于给合成图片做后续光影和谐处理的输入使用。
2. 图片合成后的和谐化
Libcom 提供了两种和谐化算法,PCTNet(像素预测变换)和 CDTNet(像素和谐变换),供不同的场景和实际效果选用。
使用 CDTNet:
# choose cdt mode
comp_image_path = "uploads/comp_image.png"
comp_mask_path = "uploads/comp_mask.png"
comp_image=encode_image(comp_image_path)
comp_mask=encode_image(comp_mask_path)
function = "cdt_mode"
payload = {
"function":function,
"comp_image":comp_image,
"comp_mask":comp_mask
}
#payload
# Prepare the request body as a JSON object
request_body = json.dumps(payload)
# Send the inference request to the endpoint
response = client.invoke_endpoint(
EndpointName=endpoint_name,
Body=request_body,
ContentType="application/json"
)
# Parse the response
response_body = response["Body"].read().decode("utf-8")
harmony_result = json.loads(response_body)
harmony_image=save_image_from_base64(harmony_result['cdt_result'],'results','harmony')
grid_img = make_image_grid([comp_image_path, harmony_image])
from IPython.display import display,Image
cv2.imwrite(harmony_image, grid_img)
display(Image(filename=harmony_image))
使用 CDTNet 的效果(左侧模特原图,右侧 CDTNet 效果图):
使用 PCTNet 的效果(左侧模特原图,右侧 PCTNet 效果图):
在 PCTNet 预训练模型中,我们注意到在预测室内光源后,人物的暗色调被过度强调,不太符合人物和谐化的场景。然而,在下面的商品处理示例中表现的就更自然。
(左侧香水合成到背景的原图,右侧对香水瓶做 PCTNet 和谐化效果图)
资源清理
实验结束后,执行 deploy.ipynb 中的代码,清理资源,避免浪费
# delete endpoint for cost saving
endpoint_name = 'libcom'
model_name='libcom'
import boto3
sagemaker_client = boto3.client("sagemaker")
# Delete the endpoint
sagemaker_client.delete_endpoint(EndpointName=endpoint_name)
# Delete the endpoint configuration
sagemaker_client.delete_endpoint_config(EndpointConfigName=endpoint_name)
# Delete the model
sagemaker_client.delete_model(ModelName=model_name)
总结
生成式 AI 的出现极大地提高了我们创造创意、尝试新风格的效率。然而,在商品展示等场景中,真实性仍然是一个不可或缺且至关重要的需求。本文演示了如何在 Amazon SageMaker 上部署 libcom 图片融合服务,借助 Amazon SageMaker 提供的完全托管、可扩展的基础设施,轻松满足各种规模的生产负载需求。