发布于: Oct 18, 2022
先决条件
在本演练中,我们需要一个拥有适当 Amazon Web Services 身份与访问管理(IAM)权限的 Amazon Web Services 账户,用以启动 Amazon Web Services CloudFormation 模板。
这里,我们使用 CloudFormation 栈以部署解决方案。此栈将创建所有必要资源,具体包括:
- 一个 Amazon SageMaker notebook 实例,用于在 Jupyter notebook 中运行 Python 代码。
- 与 notebook 实例相关联的 IAM 角色。
- 一个 Amazon ES 域,用于将句子嵌入向量存储在 KNN 索引内以供检索。
- 两个 S3 存储桶:一个用于存储源服饰图像,另一个用于托管静态网站。
在此步骤中,我们应该在notebook的开头使用 NLU based Item Search 标题。请遵循 notebook 中的步骤并按顺序运行各个单元。
您可以使用 sentence-transformers 句子转换器中的预训练BERT模型(distilbert-base-nli-stsb-mean-tokens),并将其托管在 Amazon SageMaker PyTorch 模型服务器端点之上,借此生成定长的句子嵌入。嵌入内容将被保存在 CloudFormation 栈所创建的 Amazon ES 域内。关于更多详细信息,请参阅 notebook 中的各 markdown 单元。
按 notebook 一步操作,直至 Deploying a full-stack NLU search application 单元。
此 notebook 中包含多个重要的单元,我们将引导您完成其中所对应的操作。
首先从 Feidegger 处下载多模语料库数据集,其中包含时尚图片与德语描述。具体参见以下代码:
## 数据准备 import os import shutil import json import tqdm import urllib.request from tqdm import notebook from multiprocessing import cpu_count from tqdm.contrib.concurrent import process_map images_path = 'data/feidegger/fashion' filename = 'metadata.json' my_bucket = s3_resource.Bucket(bucket) if not os.path.isdir(images_path): os.makedirs(images_path) def download_metadata(url): if not os.path.exists(filename): urllib.request.urlretrieve(url, filename) #将metadata.json下载至本地notebook download_metadata('https://raw.githubusercontent.com/zalandoresearch/feidegger/master/data/FEIDEGGER_release_1.1.json') def generate_image_list(filename): metadata = open(filename,'r') data = json.load(metadata) url_lst = [] for i in range(len(data)): url_lst.append(data[i]['url']) return url_lst def download_image(url): urllib.request.urlretrieve(url, images_path + '/' + url.split("/")[-1]) #生成图片列表 url_lst = generate_image_list(filename) workers = 2 * cpu_count() #将图片下载至本地磁盘 process_map(download_image, url_lst, max_workers=workers) Upload the dataset to Amazon S3: #将数据集上传至S3 files_to_upload = [] dirName = 'data' for path, subdirs, files in os.walk('./' + dirName): path = path.replace("\\","/") directory_name = path.replace('./',"") for file in files: files_to_upload.append({ "filename": os.path.join(path, file), "key": directory_name+'/'+file }) def upload_to_s3(file): my_bucket.upload_file(file['filename'], file['key']) #将图片上传至s3 process_map(upload_to_s3, files_to_upload, max_workers=workers)
此数据集中包含德语产品描述,因此我们需要使用 Amazon Translate 将各德语句子翻译为英语:
with open(filename) as json_file: data = json.load(json_file) #定义翻译器函数 def translate_txt(data): results = {} results['filename'] = f's3://{bucket}/data/feidegger/fashion/' + data['url'].split("/")[-1] results['descriptions'] = [] translate = boto3.client(service_name='translate', use_ssl=True) for i in data['descriptions']: result = translate.translate_text(Text=str(i), SourceLanguageCode="de", TargetLanguageCode="en") results['descriptions'].append(result['TranslatedText']) return results
将句子转换器模型保存至 notebook 实例:
!pip install sentence-transformers #将模型保存至由sagemaker托管的磁盘当中 from sentence_transformers import models, SentenceTransformer saved_model_dir = 'transformer' if not os.path.isdir(saved_model_dir): os.makedirs(saved_model_dir) model = SentenceTransformer('distilbert-base-nli-stsb-mean-tokens') model.save(saved_model_dir)
使用以下代码,将模型工件(model.tar.gz)上传至 Amazon S3:
#将模型压缩为.gz格式 import tarfile export_dir = 'transformer' with tarfile.open('model.tar.gz', mode='w:gz') as archive: archive.add(export_dir, recursive=True) #将模型上传至S3 inputs = sagemaker_session.upload_data(path='model.tar.gz', key_prefix='model') inputs
使用 Amazon SageMaker Python SDK 将模型部署至 Amazon SageMaker PyTorch 模型服务器当中。具体参见以下代码:
from sagemaker.pytorch import PyTorch, PyTorchModel from sagemaker.predictor import RealTimePredictor from sagemaker import get_execution_role class StringPredictor(RealTimePredictor): def __init__(self, endpoint_name, sagemaker_session): super(StringPredictor, self).__init__(endpoint_name, sagemaker_session, content_type='text/plain') pytorch_model = PyTorchModel(model_data = inputs, role=role, entry_point ='inference.py', source_dir = './code', framework_version = '1.3.1', predictor_cls=StringPredictor) predictor = pytorch_model.deploy(instance_type='ml.m5.large', initial_instance_count=3)
使用以下代码定义余弦相似度 Amazon ES KNN索引映射(要定义余弦相似度 KNN 索引映射,您需要使用 Amazon ES 7.7 或者更高版本):
#KNN索引映射 knn_index = { "settings": { "index.knn": True, "index.knn.space_type": "cosinesimil", "analysis": { "analyzer": { "default": { "type": "standard", "stopwords": "_english_" } } } }, "mappings": { "properties": { "zalando_nlu_vector": { "type": "knn_vector", "dimension": 768 } } } }
每种产品都对应 5 条视觉描述,我们需要将5条描述结合起来以获得一个固定长度的句子嵌入。具体请参见以下代码:
def concat_desc(results): obj = { 'filename': results['filename'], } obj['descriptions'] = ' '.join(results['descriptions']) return obj concat_results = map(concat_desc, results) concat_results = list(concat_results) concat_results[0]
使用以下代码,将句子嵌入与关联的 Amazon S3 图像 URI 导入至 Amazon ES KNN 索引当中。您还可以全文翻译描述内容,以便之后在 Elasticsearch 当中比较 KNN 搜索与标准匹配文本查询之间的差异。
# 定义一项函数,将对应于各S3 URI的特征向量导入至Elasticsearch KNN索引 # 此过程大约需要10分钟。 def es_import(concat_result): vector = json.loads(predictor.predict(concat_result['descriptions'])) es.index(index='idx_zalando', body={"zalando_nlu_vector": vector, "image": concat_result['filename'], "description": concat_result['descriptions']} ) workers = 8 * cpu_count() process_map(es_import, concat_results, max_workers=workers)
在拥有一个能够正常工作的 Amazon Sagemaker 端点之后,我们可以在 Amazon ES 上提取文本特征与 KNN 索引,接下来即可构建一款真实的全栈机器学习驱动型 Web 应用程序。这里我们使用 Amazon Web Services SAM 模板通过 API Gateway 与 Lambda 部署无服务器 REST API。REST API 接受新的搜索字符串、生成嵌入,并将相似的相关项返回至客户端。接下来,您可以将与 REST API 交互的前端网站上传至 Amazon S3。前端代码使用Amplify 与您的 REST API 相集成。
- 在以下单元中,预填充一个 CloudFormation 模板,此模板将为全栈应用程序创建必要的资源,例如 Lambda 与 API Gateway:
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' # 生成CloudFormation快速创建链接 print("Click the URL below to create the backend API for NLU search:\n") print(( 'https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create/review' f'?templateURL={sam_template_url}' '&stackName=nlu-search-api' f'¶m_BucketName={outputs["s3BucketTraining"]}' f'¶m_DomainName={outputs["esDomainName"]}' f'¶m_ElasticSearchURL={outputs["esHostName"]}' f'¶m_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 输出。
- 选择此链接。
您将跳转至应用程序页面,可以在这里提供您自己的搜索文本,以使用 KNN 方法及常规的全文本搜索方法查找产品。
- 完成 KNN 搜索应用程序的测试与实验之后,请运行 notebook 末尾的最后两个单元:
# 删除端点 predictor.delete_endpoint() # 清空S3内容 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 Web Services 资源,请前往 Amazon Web Services CloudFormation 控制台并删除 nlu-search-api 与 nlu-search 栈。
在本文中,我们共同了解了如何使用 Amazon SageMaker 与Amazon ES KNN索引功能创建基于KNN的搜索应用程序。我们使用了句子转换器Python库内的预训练BERT模型。您也可以使用自己的数据集对BERT模型进行调优。关于更多详细信息,请参阅使用 Amazon Elastic Inference 在 Amazon SageMaker 上微调并部署 PyTOrch BERT 模型。
本文建议您使用GPU实例处理大多数深度学习项目。在大部分情况下,在 GPU 实例上训练新模型的速度要比 CPU 实例快。如果使用多个 GPU 实例,或者在多个 GPU 实例之间使用分布式训练,则可实现亚线性资源扩展。但是,我们在此用例中使用了 CPU 实例,因此您可以在 Amazon Web Services Free Tier 下完成演练。
相关文章