生成数据智能

使用 Amazon SageMaker 通过生成式 AI 构建个性化头像 | 亚马逊网络服务

日期:

生成式人工智能已成为增强和加速各个行业(包括娱乐、广告和平面设计)创意过程的常用工具。 它为观众提供了更加个性化的体验,并提高了最终产品的整体质量。

生成式人工智能的一项显着优势是为用户创造独特且个性化的体验。 例如,流媒体服务使用生成式人工智能来生成个性化的电影标题和视觉效果,以提高观众的参与度,并根据用户的观看历史和偏好构建标题的视觉效果。 然后,系统会生成数千种游戏插图版本,并对它们进行测试以确定哪个版本最吸引用户的注意力。 在某些情况下,与没有个性化艺术作品的节目相比,电视剧的个性化艺术作品显着提高了点击率和观看率。

在这篇文章中,我们将演示如何使用稳定扩散等生成式人工智能模型来构建个性化化身解决方案 亚马逊SageMaker 同时节省多模型端点(MME)的推理成本。 该解决方案演示了如何通过上传 10-12 张自己的图像来微调个性化模型,然后该模型可以根据任何文本提示生成头像,如以下屏幕截图所示。 尽管此示例生成个性化头像,但您可以通过对特定对象或样式进行微调来将该技术应用于任何创意艺术生成。

解决方案概述

以下架构图概述了我们的头像生成器的端到端解决方案。

本文的范围和示例 GitHub代码 我们仅关注模型训练和推理编排(上图中的绿色部分)。 您可以参考完整的解决方案架构并在我们提供的示例之上进行构建。

模型训练和推理可以分为四个步骤:

  1. 将图像上传至 亚马逊简单存储服务 (亚马逊 S3)。 在此步骤中,我们要求您提供至少 10 张您自己的高分辨率图像。 图像越多,结果越好,但训练时间也越长。
  2. 使用 SageMaker 异步推理微调 Stable Diffusion 2.1 基本模型。 我们将在本文后面解释使用推理端点进行训练的基本原理。 微调过程从准备图像开始,包括面部裁剪、背景变化和模型大小调整。 然后我们使用低秩适应(LoRA),一种用于大型语言模型(LLM)的参数高效微调技术,来微调模型。 最后,在后处理中,我们将微调后的 LoRA 权重与推理脚本和配置文件 (tar.gz) 一起打包,并将其上传到 SageMaker MME 的 S3 存储桶位置。
  3. 使用带有 GPU 的 SageMaker MME 托管微调模型。 SageMaker 将根据每个模型的推理流量从 Amazon S3 位置动态加载和缓存模型。
  4. 使用微调模型进行推理。 之后 亚马逊简单通知服务 (Amazon SNS) 指示微调已发送的通知,您可以通过提供立即使用该模型 target_model 调用MME创建头像时的参数。

我们将在以下部分中更详细地解释每个步骤,并演练一些示例代码片段。

准备图像

为了通过微调稳定扩散来生成自己的图像来获得最佳效果,您通常需要提供大量不同角度、不同表情、不同背景的自己的照片。 然而,通过我们的实施,您现在只需 10 个输入图像即可获得高质量的结果。 我们还添加了自动预处理,以从每张照片中提取您的脸部。 您所需要的只是从多个角度清晰地捕捉您的外观本质。 包括正面照片、两侧的侧面照片以及中间角度的照片。 您还应该添加具有不同面部表情的照片,例如微笑、皱眉和中性表情。 混合表情将使模型更好地再现您独特的面部特征。 输入图像决定了您可以生成的头像的质量。 为了确保正确完成此操作,我们建议采用直观的前端 UI 体验来指导用户完成图像捕获和上传过程。

以下是不同角度、不同面部表情的自拍照示例。

微调稳定扩散模型

将图像上传到 Amazon S3 后,我们可以调用 SageMaker 异步推理 端点来开始我们的训练过程。 异步端点适用于具有大负载(最多 1 GB)和长处理时间(最多 1 小时)的推理用例。 除了 SageMaker 托管的其他本机功能(例如自动扩展)之外,它还提供用于对请求进行排队的内置排队机制,以及通过 Amazon SNS 的任务完成通知机制。

尽管微调不是推理用例,但我们选择在这里使用它来代替 SageMaker 训练作业,因为它具有内置的排队和通知机制,并且 托管自动缩放,包括在服务不使用时缩减至 0 个实例的能力。 这使我们能够轻松地将微调服务扩展到大量并发用户,并且无需实现和管理额外的组件。 然而,它确实存在 1 GB 有效负载和 1 小时最大处理时间的缺点。 在我们的测试中,我们发现 20 分钟足以在 ml.g10xlarge 实例上使用大约 5.2 个输入图像获得相当好的结果。 然而,SageMaker 培训将是大规模微调工作的推荐方法。

要托管异步端点,我们必须完成几个步骤。 首先是定义我们的模型服务器。 对于这篇文章,我们使用 大型模型推理容器 (LMI)。 LMI 由 DJL Serving 提供支持,DJL Serving 是一种高性能、与编程语言无关的模型服务解决方案。 我们选择此选项是因为 SageMaker 托管推理容器已经拥有我们需要的许多训练库,例如 Hugging Face 扩散器加快。 这大大减少了为我们的微调工作定制容器所需的工作量。

以下代码片段显示了我们在示例中使用的 LMI 容器的版本:

inference_image_uri = ( f"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0.21.0-deepspeed0.8.3-cu117"
)
print(f"Image going to be used is ---- > {inference_image_uri}")

除此之外,我们还需要有一个 serving.properties 配置服务属性的文件,包括要使用的推理引擎、模型工件的位置和动态批处理。 最后,我们必须有一个 model.py 将模型加载到推理引擎并准备模型的数据输入和输出的文件。 在我们的示例中,我们使用 model.py 文件来启动微调工作,我们将在后面的部分中更详细地解释这一点。 这俩 serving.propertiesmodel.py 文件提供于 training_service 文件夹中。

定义模型服务器后的下一步是创建一个端点配置,该配置定义如何提供异步推理服务。 对于我们的示例,我们只是定义最大并发调用限制和输出 S3 位置。 随着 ml.g5.2xlarge 例如,我们发现我们能够同时微调最多两个模型,而不会遇到内存不足(OOM)异常,因此我们设置 max_concurrent_invocations_per_instance 到 2。如果我们使用不同的调整参数集或较小的实例类型,则可能需要调整此数字。 我们建议最初将其设置为 1 并监控 GPU 内存利用率 亚马逊CloudWatch.

# create async endpoint configuration
async_config = AsyncInferenceConfig( output_path=f"s3://{bucket}/{s3_prefix}/async_inference/output" , # Where our results will be stored max_concurrent_invocations_per_instance=2, notification_config={   "SuccessTopic": "...",   "ErrorTopic": "...", }, #  Notification configuration
)

最后,我们创建一个SageMaker模型,将容器信息、模型文件和 AWS身份和访问管理 (IAM) 角色转换为单个对象。 该模型是使用我们之前定义的端点配置来部署的:

model = Model( image_uri=image_uri, model_data=model_data, role=role, env=env
) model.deploy( initial_instance_count=1, instance_type=instance_type, endpoint_name=endpoint_name, async_inference_config=async_inference_config
) predictor = sagemaker.Predictor( endpoint_name=endpoint_name, sagemaker_session=sagemaker_session
)

当端点准备就绪时,我们使用以下示例代码来调用异步端点并开始微调过程:

sm_runtime = boto3.client("sagemaker-runtime") input_s3_loc = sess.upload_data("data/jw.tar.gz", bucket, s3_prefix) response = sm_runtime.invoke_endpoint_async( EndpointName=sd_tuning.endpoint_name, InputLocation=input_s3_loc)

有关 SageMaker 上 LMI 的更多详细信息,请参阅 使用 DJLServing 和 DeepSpeed 模型并行推理在 Amazon SageMaker 上部署大型模型.

调用后,异步端点开始对我们的微调作业进行排队。 每个作业都经过以下步骤:准备图像、执行 Dreambooth 和 LoRA 微调以及准备模型工件。 让我们更深入地了解微调过程。

准备图像

正如我们前面提到的,输入图像的质量直接影响微调模型的质量。 对于头像用例,我们希望模型专注于面部特征。 我们不要求用户提供精心策划的精确尺寸和内容的图像,而是使用计算机视觉技术实施预处理步骤来减轻这种负担。 在预处理步骤中,我们首先使用人脸检测模型来隔离每张图像中最大的人脸。 然后,我们将图像裁剪并填充到模型所需的 512 x 512 像素大小。 最后,我们从背景中分割脸部并添加随机背景变化。 这有助于突出面部特征,使我们的模型能够从面部本身而不是背景中学习。 下图说明了此过程中的三个步骤。

步骤1: 使用计算机视觉进行人脸检测 步骤2: 将图像裁剪并填充为 512 x 512 像素 步骤3(可选): 分割并添加背景变化

Dreambooth 和 LoRA 微调

为了进行微调,我们结合了 Dreambooth 和 LoRA 的技术。 Dreambooth 允许您个性化您的稳定扩散模型,使用唯一标识符将主题嵌入到模型的输出域中,并扩展模型的语言视觉词典。 它使用一种称为 事先保存 保留模型对主题类别(在本例中为人)的语义知识,并使用该类别中的其他对象来改进最终图像输出。 这就是 Dreambooth 只需输入几张主题图像即可获得高质量结果的原因。

以下代码片段显示了我们的输入 trainer.py 我们的头像解决方案的类。 注意我们选择了 <<TOK>> 作为唯一标识符。 这样做的目的是为了避免选择模型字典中可能已经存在的名称。 如果名称已经存在,模型必须先忘记然后重新学习该主题,这可能会导致微调结果不佳。 学科类别设置为 “a photo of person”,它通过首先生成人物照片作为微调过程中的附加输入来实现预先保存。 这将有助于减少过度拟合,因为模型试图使用先前的保存方法来保存一个人的先前知识。

status = trn.run(base_model="stabilityai/stable-diffusion-2-1-base", resolution=512, n_steps=1000, concept_prompt="photo of <<TOK>>", # << unique identifier of the subject learning_rate=1e-4, gradient_accumulation=1, fp16=True, use_8bit_adam=True, gradient_checkpointing=True, train_text_encoder=True, with_prior_preservation=True, prior_loss_weight=1.0, class_prompt="a photo of person", # << subject class num_class_images=50, class_data_dir=class_data_dir, lora_r=128, lora_alpha=1, lora_bias="none", lora_dropout=0.05, lora_text_encoder_r=64, lora_text_encoder_alpha=1, lora_text_encoder_bias="none", lora_text_encoder_dropout=0.05
)

配置中启用了许多内存节省选项,包括 fp16, use_8bit_adam,以及梯度累积。 这将内存占用量减少到 12 GB 以下,从而允许在一个计算机上同时微调最多两个模型 ml.g5.2xlarge 实例。

LoRA 是一种针对 LLM 的高效微调技术,可冻结大部分权重,并将小型适配器网络附加到预训练的 LLM 的特定层,从而实现更快的训练和优化存储。 对于稳定扩散,适配器连接到推理管道的文本编码器和 U-Net 组件。 文本编码器将输入提示转换为U-Net模型可以理解的潜在空间,U-Net模型在后续的扩散过程中使用潜在含义生成图像。 微调的输出只是 text_encoder 和 U-Net 适配器重量。 在推理时,这些权重可以重新附加到基本稳定扩散模型以重现微调结果。

下图是原作者提供的LoRA微调细节图: Cheng-Han Jiang、Yung-Sung Chuang、Hung-yi Lee,“AACL_2022_tutorial_PLM”,2022 年

通过结合这两种方法,我们能够生成个性化模型,同时调整数量级的参数。 这导致训练时间更快并降低了 GPU 利用率。 此外,存储经过优化,适配器重量仅为 70 MB,而完整稳定扩散模型的重量为 6 GB,尺寸减少了 99%。

准备模型工件

微调完成后,后处理步骤将 TAR LoRA 权重与模型的其余部分一起为 NVIDIA Triton 提供文件。 我们使用Python后端,这意味着需要Triton配置文件和用于推理的Python脚本。 请注意,Python 脚本必须命名 model.py。 最终模型 TAR 文件应具有以下文件结构:

|--sd_lora |--config.pbtxt |--1 |--model.py |--output #LoRA weights |--text_encoder |--unet |--train.sh

使用带有 GPU 的 SageMaker MME 托管微调模型

对模型进行微调后,我们使用 SageMaker MME 托管个性化的稳定扩散模型。 SageMaker MME 是一项强大的部署功能,允许在单个端点后面的单个容器中托管多个模型。 它自动管理模型的流量和路由,以优化资源利用率、节省成本并最大限度地减少管理数千个端点的运营负担。 在我们的示例中,我们在 GPU 实例上运行,SageMaker MME 使用 Triton Server 支持 GPU。 这允许您在单个 GPU 设备上运行多个模型并利用加速计算。 有关如何在 SageMaker MME 上托管 Stable Diffusion 的更多详细信息,请参阅 使用 Stable Diffusion 模型创建高质量图像,并使用 Amazon SageMaker 经济高效地部署它们.

对于我们的示例,我们进行了额外的优化,以便在冷启动情况下更快地加载微调模型。 这是可能的,因为 LoRA 的适配器设计。 由于所有微调模型的基本模型权重和 Conda 环境都是相同的,因此我们可以通过将这些公共资源预加载到托管容器来共享这些公共资源。 只剩下 Triton 配置文件、Python 后端(model.py),并在首次调用后从 Amazon S3 动态加载 LoRA 适配器权重。 下图提供了并排比较。

这将模型 TAR 文件从大约 6 GB 显着减少到 70 MB,因此加载和解压速度更快。 为了在我们的示例中进行预加载,我们创建了一个实用程序 Python 后端模型 models/model_setup。 该脚本只是将基本稳定扩散模型和 Conda 环境从 Amazon S3 复制到一个公共位置,以便在所有微调模型之间共享。 以下是执行该任务的代码片段:

def initialize(self, args): #conda env setup self.conda_pack_path = Path(args['model_repository']) / "sd_env.tar.gz" self.conda_target_path = Path("/tmp/conda") self.conda_env_path = self.conda_target_path / "sd_env.tar.gz" if not self.conda_env_path.exists(): self.conda_env_path.parent.mkdir(parents=True, exist_ok=True) shutil.copy(self.conda_pack_path, self.conda_env_path) #base diffusion model setup self.base_model_path = Path(args['model_repository']) / "stable_diff.tar.gz" try: with tarfile.open(self.base_model_path) as tar: tar.extractall('/tmp') self.response_message = "Model env setup successful." except Exception as e: # print the exception message print(f"Caught an exception: {e}") self.response_message = f"Caught an exception: {e}"

然后每个微调的模型将指向容器上的共享位置。 Conda环境被引用于 config.pbtxt.

name: "pipeline_0"
backend: "python"
max_batch_size: 1 ... parameters: { key: "EXECUTION_ENV_PATH", value: {string_value: "/tmp/conda/sd_env.tar.gz"}
}

稳定扩散基础模型是从 initialize() 每个的功能 model.py 文件。 然后,我们将个性化的 LoRA 权重应用于 unet 和 text_encoder 模型来重现每个微调模型:

... class TritonPythonModel: def initialize(self, args): self.output_dtype = pb_utils.triton_string_to_numpy( pb_utils.get_output_config_by_name(json.loads(args["model_config"]), "generated_image")["data_type"]) self.model_dir = args['model_repository'] device='cuda' self.pipe = StableDiffusionPipeline.from_pretrained('/tmp/stable_diff', torch_dtype=torch.float16, revision="fp16").to(device) # Load the LoRA weights self.pipe.unet = PeftModel.from_pretrained(self.pipe.unet, unet_sub_dir) if os.path.exists(text_encoder_sub_dir): self.pipe.text_encoder = PeftModel.from_pretrained(self.pipe.text_encoder, text_encoder_sub_dir)

使用微调模型进行推理

现在我们可以通过调用 MME 端点来尝试我们的微调模型。 我们在示例中公开的输入参数包括 prompt, negative_promptgen_args,如下面的代码片段所示。 我们设置字典中每个输入项的数据类型和形状,并将它们转换为 JSON 字符串。 最后,字符串有效负载和 TargetModel 被传递到生成您的头像图片的请求中。

import random prompt = """<<TOK>> epic portrait, zoomed out, blurred background cityscape, bokeh, perfect symmetry, by artgem, artstation ,concept art,cinematic lighting, highly detailed, octane, concept art, sharp focus, rockstar games, post processing, picture of the day, ambient lighting, epic composition""" negative_prompt = """
beard, goatee, ugly, tiling, poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, extra limbs, disfigured, deformed, body out of frame, blurry, bad anatomy, blurred, watermark, grainy, signature, cut off, draft, amateur, multiple, gross, weird, uneven, furnishing, decorating, decoration, furniture, text, poor, low, basic, worst, juvenile, unprofessional, failure, crayon, oil, label, thousand hands """ seed = random.randint(1, 1000000000) gen_args = json.dumps(dict(num_inference_steps=50, guidance_scale=7, seed=seed)) inputs = dict(prompt = prompt, negative_prompt = negative_prompt, gen_args = gen_args) payload = { "inputs": [{"name": name, "shape": [1,1], "datatype": "BYTES", "data": [data]} for name, data in inputs.items()]
} response = sm_runtime.invoke_endpoint( EndpointName=endpoint_name, ContentType="application/octet-stream", Body=json.dumps(payload), TargetModel="sd_lora.tar.gz",
)
output = json.loads(response["Body"].read().decode("utf8"))["outputs"]
original_image = decode_image(output[0]["data"][0])
original_image

清理

按照笔记本清理部分中的说明删除本文中配置的资源,以避免不必要的费用。 参考 Amazon SageMaker定价 有关推理实例成本的详细信息。

结论

在这篇文章中,我们演示了如何在 SageMaker 上使用 Stable Diffusion 创建个性化头像解决方案。 通过仅用几张图像对预先训练的模型进行微调,我们就可以生成反映每个用户的个性和个性的头像。 这只是我们如何使用生成式人工智能为用户创建定制且独特的体验的众多示例之一。 可能性是无限的,我们鼓励您尝试这项技术并探索其增强创意过程的潜力。 我们希望这篇文章内容丰富且具有启发性。 我们鼓励您尝试该示例,并在社交平台上使用主题标签#sagemaker #mme #genai 与我们分享您的创作。 我们很想看看你做了什么。

除了稳定扩散之外,还有许多其他生成式 AI 模型 亚马逊SageMaker JumpStart。 参考 开始使用 Amazon SageMaker JumpStart 探索他们的能力。


作者简介

詹姆斯吴 是 AWS 的高级 AI/ML 专家解决方案架构师。 帮助客户设计和构建 AI/ML 解决方案。 James 的工作涵盖了广泛的 ML 用例,主要兴趣在于计算机视觉、深度学习和在整个企业中扩展 ML。 在加入 AWS 之前,James 担任了 10 多年的架构师、开发人员和技术领导者,其中包括 6 年的工程经验和 4 年的营销和广告行业经验。

西蒙·扎马林 是一位AI / ML解决方案架构师,其主要重点是帮助客户从其数据资产中提取价值。 在业余时间,Simon喜欢与家人共度时光,阅读科幻小说,并从事各种DIY房屋项目。

维克拉姆·埃兰戈 是位于美国弗吉尼亚州的 Amazon Web Services 的 AI/ML 专家解决方案架构师。 Vikram 通过设计和思想领导力帮助金融和保险行业客户大规模构建和部署机器学习应用程序。 他目前专注于自然语言处理、负责任的人工智能、推理优化以及在整个企业范围内扩展机器学习。 业余时间,他喜欢与家人一起旅行、徒步旅行、烹饪和露营。

张拉娜 是 AWS WWSO AI 服务团队的高级解决方案架构师,专门研究用于内容审核、计算机视觉和自然语言处理的 AI 和 ML。 凭借其专业知识,她致力于推广 AWS AI/ML 解决方案,并协助客户在不同行业(包括社交媒体、游戏、电子商务以及广告和营销)转变其业务解决方案。

索拉布·特里坎德 是 Amazon SageMaker Inference 的高级产品经理。 他热衷于与客户合作,并以机器学习民主化的目标为动力。 他专注于与部署复杂的 ML 应用程序、多租户 ML 模型、成本优化以及使深度学习模型的部署更易于访问相关的核心挑战。 在业余时间,Saurabh 喜欢徒步旅行、学习创新技术、关注 TechCrunch 以及与家人共度时光。

现货图片

最新情报

现货图片