发布于: Jan 7, 2022

在本次提升视觉搜索能力的演练中,您需要准备一个具有适当 IAM 权限的亚马逊云科技账户,用于启动 CloudFormation 模板。

部署您的解决方案

在解决方案的部署方面,我们需要使用 CloudFormation 栈。请准备栈创建所涉及的一切必要资源,具体包括:

一个 Amazon SageMaker notebook 实例,用于在 Jupyter notebook 中运行 Python 代码。

  • 一个与该 notebook 实例相关联的 IAM 角色。
  • 一个 Amazon ES 域,用于将图像嵌入向量存储在 KNN 索引内并进行检索。
  • 两个 S3存储桶:其一用于存储源时尚图像,其二用于托管静态网站。

Jupyter notebook 中,我们还需要部署以下几项:

Amazon SageMaker 端点,用于实时获取图像特征向量与嵌入。

  • 一套 Amazon Web Services SAM 模板,用于通过 API Gateway Lambda 建立一套无服务器后端。
  • 一个托管在 S3 存储桶上的静态前端网站,用于呈现端到端机器学习应用程序的使用界面。前端代码使用 ReactJS Amplify JavaScript 库。

首先,请完成以下操作步骤:

  • 使用您的 IAM 用户名与密码登录至 Amazon 管理控制台。 
  • 选择 Launch Stack 并在新选项卡中将其打开:
  • Quick create stack 页面中,勾选复选框以确认创建 IAM 资源。
  • 选择 Create stack
  • 等待栈执行完成。

大家可以在 Events 选项卡中的栈创建进度中查看各种事件。栈创建完成之后,您将看到状态转为 CREATE_COMPLETE

CloudFormation 模板创建完成后,您可以在 Resources 选项卡中看到所有资源。

  • Outputs 选项卡中,选择 SageMaker Notebook URL 值。

此超链接将在您的 Amazon SageMaker notebook 实例上打开 Jupyter notebook,供您用于完成选项卡中的其余部分。

这时,您应该已经处于 Jupyter notebook 的登录页面中。
 
  • 选择 visual-image-search.ipynb

在 Amazon ES 上构建 KNN 索引

在此步骤中,我们应该在 notebook 开头的 Visual image search 标题位置。遵循 notebook中 的步骤并按次序运行各单元。

这里,我们使用托管在 Amazon SageMaker 端点上的预训练 Resnet50 模型生成图像特征向量(嵌入)。嵌入将被保存在 CloudFormation 栈所创建的 Amazon ES 域中。关于更多详细信息,请参阅 notebook 中的 markdown 单元。

找到 notebook 当中的 Deploying a full-stack visual search application单元。

notebook 中包含多个重要单元。

要加载预训练 ResNet50 模型,同时剔除最终 CNN 分类器层,请使用以下代码(此模型仅作为图像特征提取器使用):

#Import Resnet50 model
model = tf.keras.applications.ResNet50(weights='imagenet',include_top=False,input_shape=(3, 224, 224),pooling='avg')

我们将模型另存为TensorFlow SavedModel格式,其中包含完整的TensorFlow程序,包括权重与计算。详见以下代码:

#Save the model in SavedModel format
model.save('./export/Servo/1/', save_format='tf')

将模型工件(model.tar.gz)上传至Amazon S3,具体代码如下: 

#Upload the model to S3
sagemaker_session = sagemaker.Session()
inputs = sagemaker_session.upload_data(path='model.tar.gz', key_prefix='model')
inputs

您可以使用Amazon SageMaker Python SDK将模型部署至基于 Amazon SageMaker TensorFlow Serving 的服务器当中。此服务器负责提供 TensorFlow Serving REST API 中的一套超集,详见以下代码:

# define a function to extract image featuresfrom time import sleep

sm_client = boto3.client('sagemaker-runtime')
ENDPOINT_NAME = predictor.endpoint
def get_predictions(payload):
    return sm_client.invoke_endpoint(EndpointName=ENDPOINT_NAME,
                                           ContentType='application/x-image',
                                           Body=payload)
def extract_features(s3_uri):
    key = s3_uri.replace(f's3://{bucket}/', '')
    payload = s3.get_object(Bucket=bucket,Key=key)['Body'].read()
    try:
        response = get_predictions(payload)
    except:
        sleep(0.1)
        response = get_predictions(payload)

    del payload
    response_body = json.loads((response['Body'].read()))
    feature_lst = response_body['predictions'][0]
    
    return s3_uri, feature_lst

predictor = sagemaker_model.deploy(initial_instance_count=3, instance_type='ml.m5.xlarge')

使用以下代码从 Amazon SageMaker 端点处提取参考图像特征:

# define a function to extract image featuresfrom time import sleep

sm_client = boto3.client('sagemaker-runtime')
ENDPOINT_NAME = predictor.endpoint
def get_predictions(payload):
    return sm_client.invoke_endpoint(EndpointName=ENDPOINT_NAME,
                                           ContentType='application/x-image',
                                           Body=payload)
def extract_features(s3_uri):
    key = s3_uri.replace(f's3://{bucket}/', '')
    payload = s3.get_object(Bucket=bucket,Key=key)['Body'].read()
    try:
        response = get_predictions(payload)
    except:
        sleep(0.1)
        response = get_predictions(payload)

    del payload
    response_body = json.loads((response['Body'].read()))
    feature_lst = response_body['predictions'][0]
    
    return s3_uri, feature_lst

使用以下代码定义 Amazon ES KNN 索引映射:

#Define KNN Elasticsearch index mapping
knn_index = {
    "settings": {
        "index.knn": True
    },
    "mappings": {
        "properties": {
            "zalando_img_vector": {
                "type": "knn_vector",
                "dimension": 2048
            }
        }
    }}

使用以下代码将图像特征向量与关联的 Amazon S3 图像 URI 导入至 Amazon ES KNN 索引:

# defining a function to import the feature vectors corrosponds to each S3 URI into Elasticsearch KNN index# This process will take around ~3 min.

def es_import(i):
    es.index(index='idx_zalando',
             body={"zalando_img_vector": i[1], 
                   "image": i[0]}
            )
    
process_map(es_import, result, max_workers=workers)

构建一款全栈视觉搜索应用程序

现在,我们已经拥有了一个能够正常工作的 Amazon SageMaker 端点,并可以在 Amazon ES 上提取图像特征与KNN索引,接下来应该构建一款实际可用的全栈ML支持型Web应用程序了。我们使用 Amazon SAM 模板通过 API GatewayLambda 部署无服务器 REST API 。该REST API负责接收新图像、生成嵌入,并将得到的相似图像返回至客户端。接下来,我们将与新 REST API 交互的前端网站上传至 Amazon S3 。前端代码使用 Amplify 与我们的 REST API 相集成。 

  • 在以下单元中,预填充一套 CloudFormation 模板。此模板负责为全栈应用程序创建 API Gateway Lambda 等必要资源:
s3_resource.Object(bucket, 'backend/template.yaml').upload_file('./backend/template.yaml', ExtraArgs={'ACL':'public-read'})


sam_template_url = f'https://{bucket}.s3.amazonaws.com/backend/template.yaml'
# Generate the CloudFormation Quick Create Link
print("Click the URL below to create the backend API for visual search:\n")print((
    'https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review'
    f'?templateURL={sam_template_url}'
    '&stackName=vis-search-api'
    f'&param_BucketName={outputs["s3BucketTraining"]}'
    f'&param_DomainName={outputs["esDomainName"]}'
    f'&param_ElasticSearchURL={outputs["esHostName"]}'
    f'&param_SagemakerEndpoint={predictor.endpoint}'))
  • 以下截屏所示,为预生成的CloudFormation模板链接。
  • 择该链接。

这时我们会跳转至 Quick create stack 页面。

  • 选择复选框以确认创建 IAM 资源、各 IAM 资源自定义名称以及 CAPABILITY_AUTO_EXPAND
选择 Create stack

栈创建完成之后,我们会看到状态转为CREATE_COMPLETE。您可以在 Resources 选项卡中查看 CloudFormation 模板创建完成的全部资源。

  • 在栈创建完成之后,继续按后续单元执行。

以下单元显示,我们的全栈应用程序(包括前端与后端代码)已经成功部署:

print('Click the URL below:\n')print(outputs['S3BucketSecureURL'] + '/index.html')
以下截屏所示,为 URL 的输出结果。
  • 选择该链接。
这时我们将跳转至应用程序页面,并可以在这里上传服饰图像服饰 URL 链接,借此获取相似服饰推荐。
  • 在完成对视觉搜索应用程序的测试与试验之后,请运行 notebook 下方的最后两个单元:
# Delete the endpoint
predictor.delete_endpoint()
# Empty S3 Contents
training_bucket_resource = s3_resource.Bucket(bucket)
training_bucket_resource.objects.all().delete()

hosting_bucket_resource = s3_resource.Bucket(outputs['s3BucketHostingBucketName'])
hosting_bucket_resource.objects.all().delete()
  • 这些单元会终止您的 Amazon SageMaker 端点并清空S3存储桶,为资源清理步骤做好准备。

资源清理

要删除其余亚马逊云科技资源,请转至 Amazon CloudFormation 控制台并删除其中的vis-search-apivis-search栈。

总结 

在本文中,我们介绍了如何使用 Amazon SageMakerAmazon ES KNN 索引创建基于机器学习的视觉搜索应用程序。我们还使用到在ImageNet 数据集上经过预训练的 ResNet50 模型。当然,大家也可以使用其他预训练模型,例如 VGGInception 以及 MobileNet 等,并使用自己的数据集进行调优。

对于大部分深度学习类用例,我们建议您使用 GPU 实例。在 GPU 实例上训练新模型,将带来远超 CPU 实例的训练速度。如果您拥有多个 GPU 实例,或者需要在多个 GPU 实例之间使用分布式训练,则可以进行次线性扩展。本用例中仅使用 CPU 实例,因此您可以在 Amazon Free Tier 中通过免费资源完成演练。

相关文章