aifollow.news 搜索
返回 AWS 机器学习博客
AWS 机器学习博客· · 原发布时间

AWS 更新 SageMaker SDK v3 边缘视觉模型管理示例

自动核验发布 · 本文由系统生成并完成证据核验,未经人工审稿。

AI 辅助摘要

AWS 更新了按摄像头训练和管理视觉模型的参考示例:流水线分别训练异常检测器和缺陷分类器,评估导出的 ONNX 模型,通过质量门槛后再编译并登记。示例用 Step Functions 控制并发;合成数据完整运行约需 15 分钟,计算费用约 0.07 美元。

正文 · AI 翻译

当质量检测概念验证取得成功时,全设备群的计算机视觉模型生命周期管理问题就会显现。一台摄像头配一个模型运行良好。随后,工厂要求在 40 条产线上取得相同效果,每条产线都有数台摄像头,而每台摄像头看到的情况都不同。它们的拍摄角度不同,同一不锈钢表面的反光不同,环境光也会随哪个车间门打开而变化。在我们参与的生产部署中,使用汇集影像训练的单一模型在相当一部分摄像头上的表现不够好,最终每台摄像头都需要各自微调的模型。此时,真正的问题不再是如何训练好一个模型,而是如何在不针对每个模型安排人工介入的情况下,训练、评估、版本管理并交付数千个模型。本文针对当前的 Amazon SageMaker Python SDK v3,更新了 2023 年系列文章《Build an end-to-end MLOps pipeline for visual quality inspection at the edge》中介绍的模式,并以 Amazon SageMaker Neo 进行边缘优化,取代已弃用的 Amazon SageMaker Edge Manager。我将介绍一条双分支 Amazon SageMaker Pipeline,它为每台摄像头训练一个异常检测器和一个缺陷分类器,并通过质量关卡阻止表现不达标的模型。流水线内的 SageMaker Neo 编译步骤确保每个注册的模型都附带针对设备优化的产物,而 AWS Step Functions 编排层控制整个设备群的训练节奏。你可以使用 AWS Cloud Development Kit(AWS CDK)部署所有组件;使用合成数据完整运行一次流水线,计算成本约为 0.07 美元。完整示例可在 aws-samples GitHub 仓库中获取。解决方案概览 下图展示了该示例的全设备群模型生命周期。编排层将重新训练请求排队,并限制并发任务数量。按摄像头运行的训练流水线准备数据、训练和评估异常检测器与分类器,并为边缘设备生成带版本的模型产物。图 1:解决方案架构 训练部分是一条按摄像头参数化的 SageMaker Pipeline,每次执行包含 13 个步骤。3 个入口步骤并行运行:Preprocess、Fetch Latest Anomaly 和 Fetch Latest Classifier。流水线预处理该摄像头的图像,并分别获取该摄像头两个分支中最近获批的模型,然后训练 2 个模型。第一个是小型卷积自编码器,它学习正常产品的外观,并根据重建误差标记异常。第二个是经过微调、用于确认缺陷的 ResNet18 分类器。每个分支都将模型导出为 ONNX,使用留出数据评估导出的产物,并通过质量关卡。通过关卡后,模型会使用 SageMaker Neo 针对配置的边缘目标进行编译,然后才注册到 SageMaker Model Registry。因此,每个获批的模型包都包含可供设备使用的编译产物。模型包以摄像头 ID 作为元数据,每个分支在获取用于热启动的模型时都会据此筛选,因此重新训练始终从该摄像头自身的历史模型继续。编排部分控制整个设备群的节奏。重新训练请求进入 Amazon Simple Queue Service(Amazon SQS)FIFO 队列,AWS Lambda 函数为每个请求启动一次 Step Functions 执行。每次执行在启动流水线前,都要通过 DynamoDB 信号量获取一个名额,因此突发请求会以稳定的速率逐步处理,而不是同时全部启动。完成事件发布到 Amazon Simple Notification Service(Amazon SNS);运行故障则通过 Amazon EventBridge 规则发送到同一主题,并保留原始错误。系统的输出是按摄像头生成、带版本且通过质量关卡的模型产物。Model Registry 保存可移植的 ONNX 模型,S3 保存该模型经 Neo 编译的版本;后者是由 DLR 运行时加载的针对设备优化的共享库,而不是 ONNX 模型。两者都可供工厂采用的任何交付机制使用。 先决条件 部署该示例需要具备以下条件:一个有权创建 AWS Identity and Access Management(IAM)角色的 AWS 账户。一个 Amazon Simple Storage Service(Amazon S3)存储桶。一个 Amazon Elastic Container Registry(Amazon ECR)存储库。堆栈中的 SageMaker AI、AWS Step Functions、AWS Lambda、Amazon Simple Queue Service(Amazon SQS)、Amazon Simple Notification Service(Amazon SNS)、Amazon EventBridge 和 Amazon DynamoDB 资源。Python 3.10、3.11 或 3.12,以及 Docker。AWS CDK CLI 版本 2.1131.0 或更高版本。较早的 CLI 版本会因云程序集架构与较新版本的 aws-cdk-lib 不匹配而失败。无需提高服务配额。默认情况下,编排层一次最多允许 5 个管道执行,这使并发的 SageMaker 训练作业数量保持在标准账户配额以内。如果部署目标 AWS 区域与 CLI 默认区域不同,请在部署命令本身设置 AWS_REGION、AWS_DEFAULT_REGION 和 CDK_DEFAULT_REGION 这 3 个变量,而不是在 shell 配置文件中设置。例如:AWS_REGION=us-east-2 AWS_DEFAULT_REGION=us-east-2 CDK_DEFAULT_REGION=us-east-2 cdk deploy --all。CDK CLI、Boto3 和 AWS Command Line Interface(AWS CLI)用于确定区域的变量集合有重叠,但并不完全相同;变量不一致会造成令人困惑的部分部署。将这些变量放在命令前面,只会对该次调用设置全部 3 个变量,因此您自己的默认区域不会改变。使用 SDK v3 定义训练管道 本节代码摘自存储库中的 CDK 应用程序,并非独立脚本;它会在 cdk deploy 期间,即堆栈合成管道定义时运行。环境设置和部署命令将在后文的“部署并运行示例”部分介绍。SDK v3 将 SageMaker Python SDK 重组为模块化软件包,以下导入语句展示了该库的新结构:from sagemaker.train import ModelTrainer from sagemaker.train.configs import InputData, Compute, OutputDataConfig from sagemaker.core.training.configs import MetricDefinition from sagemaker.serve.model_builder import ModelBuilder from sagemaker.mlops.workflow.pipeline import Pipeline from sagemaker.mlops.workflow.steps import ProcessingStep, TrainingStep from sagemaker.mlops.workflow.model_step import ModelStep from sagemaker.mlops.workflow.condition_step import ConditionStep from sagemaker.core.workflow.conditions import ConditionGreaterThanOrEqualTo from sagemaker.core.workflow.functions import JsonGet 安装 sagemaker>=3.0.0,<4 时,会分别安装 sagemaker-core、sagemaker-train、sagemaker-serve 和 sagemaker-mlops 软件包。v2 中分散在 Estimator 构造函数参数中的训练配置,如今放在传递给 ModelTrainer 的类型化配置对象中。下面是示例中的异常检测分支训练器,原样摘录:anomalib_trainer = ModelTrainer( training_image=custom_training_image_uri, compute=Compute( instance_type=training_instance_type.to_string(), instance_count=1, ), base_job_name="cv-pipeline-anomalib-train", sagemaker_session=pipeline_session, role=role_arn, hyperparameters={ "program": "train_anomalib.py", "model_name": "autoencoder", "image_size": "256", "num_epochs": "3", "batch_size": "16", "learning_rate": "0.001", }, input_data_config=anomalib_input_data, output_data_config=OutputDataConfig( s3_output_path=run_prefix("anomalib-training") ), ).with_metric_definitions( [ MetricDefinition( name="image_auroc", regex=r"validation:image_auroc=([0-9]*\.?[0-9]+)", ), ] ) anomalib_input_data 从上游步骤属性连接 4 个通道(train、validation、test、pretrained_model),而 run_prefix 将每个 S3 路径限定在管道执行 ID 的范围内,避免并发的 fleet 运行发生冲突。两者都位于存储库中。当管道位于 CDK 应用程序内时,需要注意 v3 的 2 个行为;这两项均未在更新日志中列为破坏性变更。 首先,SDK v3 在构建管道定义时,会根据实时 IAM 信息验证管道的执行角色。此验证发生在合成时,而非执行时。CDK 应用无法在一次部署中同时创建该角色和管道,因为 SDK 验证角色时,该角色尚不存在。这与 cdk bootstrap 不同:后者为每个账户和区域配置一次 CDK 工具包资源,可能已在你的账户中完成。示例自身的两阶段部署由一个碰巧同名的上下文标志驱动。第一轮使用 -c bootstrap=true 创建角色、存储桶和 ECR 存储库;第二轮则针对现已存在的角色合成管道。嵌入管道定义中的角色亚马逊资源名称(ARN)也必须是具体的字符串,不能是尚未解析的 CDK 令牌。其次,v3 角色验证器在模拟 ECR 拉取权限时不使用资源 ARN,因此,即使将执行角色的权限限定于单个 ECR 存储库在运行时能够正常工作,也会验证失败。为此,示例中的角色获得了范围更广的 ECR 授权。最后,示例还采用了一个 v3 的常见做法:使用 PipelineSession(default_bucket=your_bucket) 构建管道,将 SDK 管理的上传内容(例如步骤代码)导入管道自己的存储桶,使所有工件都存放在一处,执行角色的权限也只需覆盖一个存储桶。(授予该角色访问 SDK 默认存储桶的权限也可行。这种做法更简洁。)与缺陷数据特性相符的质量门槛 每个训练完成的模型都会在注册前接受评估,评估针对导出的 ONNX 工件,而不是内存中的 PyTorch 模型。这一区别很重要:接受质量门槛检验的工件就是最终交付的工件,因此,即使训练运行看起来正常,导出问题也不可能让损坏的模型通过门槛。异常检测分支要求 AUROC 至少达到 0.8。分类器分支同时检查两个指标,指标的选择取决于缺陷数据的一个主要特性:类别严重不平衡。在这个示例中,约 90% 的图像属于良品,这符合生产线的实际情况。面对这种分布,普通准确率毫无意义,因为对每张图像都预测“良品”的模型能取得约 0.9 的准确率,却一个缺陷也检测不到。平衡准确率是各类别召回率的平均值,可以纠正这一问题,但它也有盲点。一个对良品的召回率为 100%、对缺陷的召回率仅为 20% 的模型,仍能得到 (1.0 + 0.2) / 2 = 0.6 的分数。因此,门槛要求平衡准确率至少达到 0.6,同时缺陷召回率至少达到 0.5:step_check_classifier = ConditionStep( name="CheckClassifierQuality", conditions=[ ConditionGreaterThanOrEqualTo( left=JsonGet( step_name=step_eval_classifier.name, property_file="evaluation", json_path="balanced_accuracy", ), right=min_accuracy, ), ConditionGreaterThanOrEqualTo( left=JsonGet( step_name=step_eval_classifier.name, property_file="evaluation", json_path="defect_recall", ), right=min_defect_recall, ), ], if_steps=[step_compile_classifier, step_register_classifier], else_steps=[step_fail_classifier], depends_on=[step_eval_classifier], ) ConditionStep 对各条件执行逻辑与运算,因此两个条件都必须通过。阈值是管道参数,可以在每次执行时调整,无需重新部署。如果未达到门槛,FailStep 会将此次执行标记为失败,该分支的模型也不会进入注册表(两个分支各自独立检查,因此另一个分支的模型仍可能注册)。设备群会继续为该摄像头提供先前获批模型的服务。训练代码也从另一侧处理同样的类别不平衡问题。分类器是使用 ImageNet 权重进行微调、带有双类别输出头的 resnet18。对于每个摄像头对应的数据集规模,微调预训练权重是避免模型退化为只预测多数类的关键。训练代码使用 WeightedRandomSampler,按类别频率的倒数对训练批次进行平衡,而损失函数不加权。 将加权损失与加权采样结合使用,会对少数类过度校正。在流水线中使用 SageMaker Neo 为边缘设备编译。请注意前述代码中门控步骤的 if_steps:通过门控后,先执行编译,注册则依赖编译完成。两个训练脚本都以动态批次轴导出 ONNX 模型。质量门控使用 ONNX Runtime 对这些导出的产物评分,随后 CompileAnomalibNeo 或 CompileClassifierNeo 步骤将通过门控的产物交给 SageMaker Neo。固定的顺序是先门控、再编译、最后注册。模型只有在针对设备群的边缘目标完成编译后,才会成为状态为 Approved 的模型包,因此注册表绝不会展示设备无法运行的模型。编译步骤封装了三个容易出错的细节。Neo 要求输入 tar 包只包含模型文件,但训练作业生成的 model.tar.gz 除 ONNX 模型外,还包含检查点和指标。因此,该步骤首先重新打包一个只包含 ONNX 模型的 tar 包。Neo 还要求具体的输入形状,而导出的模型声明了动态批次轴,所以编译请求将批次大小固定为 1。此外,由于流水线步骤可能重试,编译作业名称由执行 ID 确定性生成,使重试能够继续轮询已启动的作业,而不会遗留无人管理的作业。目标是一个流水线参数:NeoTargetDevice 可选择 jetson_xavier 或 rasp4b 等具名设备;默认情况下,它针对 NeoTargetOs/NeoTargetArch 平台进行编译,默认平台为 LINUX/X86_64。编译后的包包含经过优化的 compiled.so,以及用于加载它的 DLR 运行时。默认输出可在任何 x86_64 Linux 主机上运行,因此你可以先验证,再决定是否采用针对特定设备的目标。编译本身不收费。你需要支付驱动编译的处理实例和输出文件的 S3 存储费用。为了以后在不重新训练的情况下将已注册模型编译到其他设备类型,代码仓库提供了一个临时运行的脚本,对模型注册表中的模型执行相同流程。模型注册表中的每摄像头模型:每个分支都注册到各自的模型包组,每个模型包都带有摄像头 ID 及其评估指标。示例中省略了指标的连接代码:classifier_model_builder = ModelBuilder( s3_model_data_url=classifier_model_data, image_uri=custom_training_image_uri, sagemaker_session=pipeline_session, role_arn=role_arn, ) step_register_classifier = ModelStep( name="RegisterClassifierModel", depends_on=[step_compile_classifier], step_args=classifier_model_builder.register( model_package_group_name="sm1k-classifier-model-group", approval_status="Approved", model_metrics=classifier_metrics, customer_metadata_properties={"CameraId": camera_id}, ), ) customer_metadata_properties 中的摄像头身份信息,使两个共享的模型包组成为设备群目录。所有摄像头的模型包都存放在相同的组中,通过按元数据筛选可找回每个摄像头的历史记录。每个分支都有一个获取步骤:它按从新到旧的顺序分页遍历已获批的模型包,直到找到发起请求的摄像头的最新模型,因为 ListModelPackages 无法在服务器端按客户元数据筛选。摄像头首次运行时,获取步骤找不到模型,训练便回退到冷启动初始化(分类器使用 ImageNet 权重,自动编码器随机初始化)。此后每次运行都从该摄像头先前的模型继续训练,这使得在整个设备群中频繁、低成本地进行增量再训练成为可能。请注意这些注册表条目是什么、又不是什么:它们收录的是经过版本管理和质量门控的产物,但其容器引用指向训练镜像,而该镜像不提供推理端点。这些条目用于下游系统拉取产物并将其部署到设备的设备群工作流,而不是用于 CreateEndpoint。 协调设备群训练请求。每个 AWS 账户的并发 SageMaker 训练作业都有服务配额,而这里每次运行管道都会启动多个作业,因此设备群的重新训练需要控制节奏。必须防止突发的 500 个请求变成同时启动的 500 次管道运行。该示例使用信号量,即可用名额的计数器,作用类似一个有 5 个车位的停车场。在 Step Functions 状态机启动管道之前,它会在 DynamoDB 中以原子方式递增计数器来占用一个名额,并通过条件在达到上限时拒绝递增:acquire_semaphore = tasks.DynamoUpdateItem( self, "AcquireSemaphore", table=semaphore_table, key={"LockName": tasks.DynamoAttributeValue.from_string("pipeline-concurrency")}, update_expression="SET ActiveCount = if_not_exists(ActiveCount, :zero) + :one", condition_expression="attribute_not_exists(ActiveCount) OR ActiveCount < :limit", ) 如果所有名额均已占用,运行就会等待并重试。管道完成后,它会递减计数器,释放该名额。有一个细节值得借鉴到你自己的设计中。DynamoDB 条件表达式在单次原子操作中强制执行上限;如果由状态机读取计数器后再作决定,读取与写入之间就会留下竞态窗口。该存储库还实现了其余的运行加固措施,包括在每条失败路径上释放名额,以及通过 Amazon EventBridge 将失败的运行转发到 Amazon SNS。其 README 说明了如何确定等待时限。上限 5 是一个堆栈参数,设置得较低,以便该示例无需申请提高配额,就能在任何标准账户中部署和运行。请根据你账户的训练作业配额调整它。超出单个账户的配额后,如何扩展设备群训练是另一个话题。常见手段包括提高服务配额、将训练分散到不同实例类型或区域,以及将设备群分布到多个账户。你也可以将待处理任务保留在 SQS 中,只在容量释放时允许新任务进入。这些选择取决于设备群的规模和构成。该示例提供了可供扩展的工作框架。部署和运行示例。存储库 README 中的操作指南是权威版本。下面的简要步骤从全新检出的代码开始,在首次部署前设置环境:git clone https://github.com/aws-samples/sample-sagemaker-fleet-cv-pipeline cd sample-sagemaker-fleet-cv-pipeline && python3 -m venv .venv && source .venv/bin/activate pip install -r requirements.txt cdk bootstrap # 每个账户/区域执行一次 cdk deploy SageMakerCVPipelineStack -c bootstrap=true # 角色、存储桶、ECR cdk deploy --all # 管道和编排 ./scripts/push_ecr_image.sh # 构建并推送训练镜像。默认情况下,管道会生成合成的生产线图像,因此无需数据集,也无需数据审批,就能端到端验证整个系统。一次完整运行会执行全部 13 个步骤,包括 2 次 Neo 编译,耗时约 15 分钟,计费的 ml.m5.xlarge 使用时间费用约为 0.07 美元(美国东部〔俄亥俄〕区域〔us-east-2〕,2026 年 7 月,按需计费)。在示例规模下,编排资源合计每月费用远低于 0.10 美元。为了用真实图像运行管道,该存储库提供了 BCCD 数据集下载程序。该数据集包含 364 张带标注的血涂片显微图像,最初在 GitHub 上开源,后来按 MIT 许可证重新整理为 Pascal VOC 格式。Roboflow 也以公有领域资料的形式分发同一数据集。该脚本将血小板的存在映射为缺陷类别,可选择按摄像头拆分图像以模拟设备群,并将训练数据压缩包上传到管道存储桶。配套笔记本会使用真实数据运行完整管道,并对正常样本和异常样本并排执行 ONNX 推理。 将血小板视为缺陷,只是为了示意制造业中的缺陷分布,并非临床主张。清理:模型包是在流水线运行时创建的,因此 AWS CloudFormation 无法删除它们。请先用 AWS CLI 删除模型包,然后运行 cdk destroy --all -c bootstrap=true --force 销毁堆栈。README 列出了具体命令。结语:在本文中,我展示了一个可运行的 SageMaker SDK v3 参考架构,用于车队规模的计算机视觉全生命周期管理。该架构包含一条双分支训练流水线:每个模型都要针对其导出的 ONNX 构件通过质量门控,再由 SageMaker Neo 编译,之后才会注册。Model Registry 的组织方式利用摄像头元数据,将共享的模型包组转化为各摄像头可用于热启动的历史记录;Step Functions 编排层则在账户配额范围内控制车队训练的节奏。对于需求可由 Amazon Lookout for Vision 等托管方案满足的团队,采用托管方案更简单。此模式面向托管方案未覆盖的逐摄像头、车队规模约束。这些设计原则也适用于计算机视觉以外的领域:应根据平衡准确率和少数类召回率,而非准确率,设置门控;应评估并编译实际交付的构件;应让运行故障发出通知,而不是悄无声息地终止。示例只需几分钟即可部署,完整验证运行的计算成本约为 7 美分,因此一个低成本的后续步骤是克隆代码仓库并运行示例。之后,可以让 BCCD 下载器指向真实的存储桶,为你的硬件设置 NeoTargetDevice,或根据车队规模调整编排的边界参数。对于 SDK v3 迁移本身,我始终参考的是 SageMaker Python SDK 文档以及宣布推出新版 SDK 的两篇系列文章。如果你希望获得帮助,将此模式适配到你的生产环境,请联系你的 AWS 客户团队。关于作者:Kiowa Jackson。Kiowa 是 AWS ProServe 的高级机器学习工程师。他专注于将计算机视觉与代理式 AI 相结合的视觉智能系统,并将这些系统投入企业工业领域的生产环境。

发现内容有误?提交纠错