OTA 更新部署与 AWS Greengrass, 和 Triton 推理服务
Deepstream 应用搭配 Triton 推理服务器
计算机视觉应用在整个生命周期中通常需要定期更新。这些可能包括为了适应不断变化的业务需求而修改代码,或更新权重以提高模型的精度。对高效交付代码工具的需求催生了快速发展的MLops领域,该领域借鉴了传统软件工程中的持续集成和持续交付(CI/CD)理念。
边缘设备为部署流程增加了额外的复杂性。首先,需要一个可靠的传输协议来确保代码成功传输到目标设备。其次,这些设备可能具有不同的硬件规格,从而可能导致兼容性问题。
在本教程中,我们将探讨中立ML系统的概念。随后,我们将使用ONNX、Nvidia Triton和AWS GreengrassV2将交通检测模型部署到Jetson设备上。
不可知论的机器学习
一个中立的机器学习平台旨在兼容。兼容性可能体现在以下几个方面:
- 硬件无关性 — 设计为可以在移动、嵌入式和云端等不同硬件类型上运行。硬件无关的机器学习系统应该能够最小程度地修改就能利用目标设备上可用的加速器(例如GPU、TPU、FPGA)。
- 模型无关性 — 支持各种机器学习模型类型(如LLMs、对象检测器和场景分类器)。此外,它们应该与不同的实现框架(例如PyTorch、Tensorflow、MXnet等)相容。
- 应用无关性 — 支持从低到高的推断负载、多个并发模型以及对延迟的需求等各种应用场景和要求。
在机器学习中,互操作性问题尤其具有挑战性,因为绝大多数神经网络模型需要专门的硬件或软件优化才能在合理的时间内运行这些模型。
为了满足互操作性需求,同时保持性能不受影响,业内相关方共同开发了以下工具:
- ONNX — 代表开放神经网络交换(Open Neural Network Exchange),ONNX 是一个开源的模型框架,支持多种硬件平台。其他框架如 PyTorch 中的模型可以在训练后转换并通过 ONNX Runtime 部署,从而加速推理。
- Nvidia Triton 推理服务器 — 提供独立的容器化微服务来进行推理,Triton 更进一步优化了这一点,通过为 ONNX 和 Tensorflow 模型提供 Nvidia 芯片特定的优化。Triton 包含内置工具,如并行推理和模型实例的复制,用于扩展 ML 系统的功能。
配置 Triton 模型
我们教程的第一步是使用一个RT-DETR目标检测模型。在本教程中,我们将使用一个经过微调的模型,该模型是在一个包含500张交通图像的数据集上训练的。不过,你也可以直接使用该官方仓库中的原始权重。该仓库还提供了一个转换脚本来将PyTorch权重导出为ONNX格式。但在本教程中,我们使用的是这个链接提供的转换脚本。
NVIDIA Triton 推理服务器需要按照如下文件结构设置模型仓库:
models_repo/
|
+-- 模型名
|
+-- config.pbtxt
+-- 1
|
+-- model.onnx
目录名 [1] 表示模型的版本号,每次更新都会递增这个数字。该文件夹包含模型的权重文件,本例中为一个 .onnx 文件。用户还需要在 config.pbtxt 文件中定义模型的配置信息。以下是一个用于 RT-DETR 模型的示例。
name: "rtdetr"
platform: "onnxruntime_onnx"
max_batch_size: 4
default_model_filename: "model.onnx"
input [
{
name: "input"
data_type: TYPE_FP32 /* 单精度浮点数 (single-precision floating-point) */
format: FORMAT_NCHW
dims: [ 3, 640, 640 ]
}
]
output [
{
name: "output"
data_type: TYPE_FP32 /* 单精度浮点数 (single-precision floating-point) */
dims: [ 300, 6 ]
}
]
instance_group [
{
kind: GPU 类型 /* KIND_GPU */
count: 1 /* 计数 */
gpus: 0 /* GPU 设备 */
}
]
我们来看看这个文件里面写了什么。
第一个部分包含基本信息,包括模型名称和权重文件,。可以通过调整max_batch_size参数来启用动态批处理技术,这在处理多个视频源的推理任务时非常有用。
name: "rtdetr"
platform: "onnxruntime_onnx"
max_batch_size: 1
default_model_filename: "model.onnx"
请注意“platform”字段,该字段需要一个包含所需执行环境和模型文件格式的字符串。这在每种模型类型中都是不同的。例如,TensorRT模型将使用以下平台配置:
以下是一个配置文件示例:
name: "rtdetr"
platform: "tensorrt_plan"
max_batch_size: 1 # (最大批处理尺寸)
default_model_filename: "model_b1_gpu0_fp16.engine" # (默认模型文件名)
下面我们会定义输入张量的形状。模型期望输入是一张640x640像素的RGB图像,颜色通道在前,接着是高度和宽度。
输入配置如下:
输入 [
{
名称: "输入"
数据类型: TYPE_FP32
格式: FORMAT_NCHW
维度: [3, 640, 640]
}
]
ONNX 后端支持动态批处理大小,不过,并非所有情况都支持动态批处理大小。对于固定批处理大小,必须在“dims”字段中定义批处理大小。
输入:
{
name: "inputs"
data_type: TYPE_FP32
# 该模型的维度顺序为高度、宽度、通道
dims: [1, 640, 640, 3]
}
输出形状也需要定义。RT-DETR 预测前 300 个对象的类别、置信度和四个边界框参数,输出一个 300 x 6 的张量。
输出 [
{
name: "output"
数据类型: TYPE_FP32
维度: [ 300, 6 ]
}
]
改为:
输出 {
name: "output"
数据类型: TYPE_FP32
维度: [ 300, 6 ]
}
如果你对自己的模型的输入和输出不太确定,可以考虑使用模型可视化工具,例如比如 Netron。
最后一部分表示 Triton 是否应该在设备的 GPU 或 CPU 上运行模型。用户还可以指定要使用哪个 GPU,如果有多个 GPU 的话。
实例组配置 [
{
类型: GPU
数量: 1个
GPU数量: 0
}
]
兼容的 ONNX 和 TensorFlow 模型可以可选地在运行时编译为 Nvidia 的专有 TensorRT 格式,以获得进一步的性能增益。模型还可以量化为较低的精度,从而实现更快的推理速度,不过,对于较大的模型来说,这一过程通常需要约 45 分钟,可能会比较漫长。
## 可选
优化配置 { 执行加速器配置 {
GPU执行加速器: [ {
名称: "tensorrt"
参数: { key: "precision_mode" value: "FP16" } # 量化模式
}]
}}
**物联网,智慧的**
随着2010年代智能设备的普及,带来了设备管理平台的一波浪潮。除了支持空中更新(OTA更新)外,这些平台还提供了角色访问控制、设备监控和故障检测等额外工具,使其适合在边缘环境中安全地部署小型视觉模型。
对于本教程,我们将使用 AWS Greengrass,因为它支持大多数 Windows 和 Linux 设备,包括我们的目标 Jetson AGX Xavier 设备。Greengrass 的部署包,也称为 _组件_ ,包含以下内容:
* _工件 —_ 源文件包括应用程序代码、模型权重、媒体文件等。可以使用 AWS Lambda 函数将 Docker 容器作为工件部署,从托管的容器仓库中拉取镜像。
* _配置文件 —_ 包含运行应用程序生命周期活动的指令的配置文件。用户指定 shell 命令来安装、运行和关闭包含在工件中的应用程序。
请先在 AWS 控制台创建一个新的 IAM 用户账号并附加以下权限策略文件。
* _AWSGreengrassFullAccess — 授予访问 AWS Greengrass 部署服务的完整访问权限。_
* _AmazonS3FullAccess — 授予访问存储在 AWS S3 存储桶中的对象的完整访问权限。_
在此之后,我们创建一个新的 S3 存储桶,并附加以下 GetObject 策略权限,以让 Greengrass 用户从其中提取对象。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "允许访问",
"Principal": {
"AWS": "arn:aws:iam::您的ACCOUNT_ID:user/用户名称"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::您的BUCKET_NAME/*"
}
]
}
完成这些步骤后,我们可以继续进行在目标Jetson设备上安装[Greengrass物联网核心](https://docs.aws.amazon.com/greengrass/v2/developerguide/install-greengrass-v2.html)软件。这样做会将我们的Jetson设备注册为属于Thing组的核心设备,然后我们就可以在这个设备上部署Greengrass组件了。
**再看看推理流程**
在我的[之前的教程](https://medium.com/@jjn62/accelerating-real-time-vision-applications-f38ba34e8d78)中,我们探讨了使用Nvidia Deepstream SDK来实现加速的视觉应用程序。我们将基于Python示例,并在该推理管道中添加以下插件:
1. _Nvtracker_ — 跟踪对象在帧之间,通过为每个检测分配一个唯一的ID实现。持久对象跟踪允许对车辆进行更复杂的分析,例如计算交通流量。
2. _Nvdsanalytics_ — 提供感兴趣区域的过滤。我们只关注一个方向上的交通流量,因此,这个插件将用于排除不必要的检测。
3. _Nvmsgconv_ 和 _Nvmsgbroker_ — 检测的元数据将被发布为Kafka消息主题,以便进行进一步的下游处理。这可能涉及时间序列数据的存储和分析、警报触发或其他基于云的操作。
此外,我们将修改我们的sink元素,使其将边界框可视化输出到RTSP流,而不是显示在屏幕上。这一点非常重要,因为部署在Greengrass上的Deepstream Python应用程序无法在屏幕上显示窗口,并将退出并显示错误信息。完整的应用程序代码可以在该链接中找到:[here](https://github.com/jastinjn/deepstream-greengrass-app)。
克隆仓库之后,将源文件夹的内容压缩成归档文件,并将这个压缩文件上传到上一节创建的 S3 存储桶中。
**大展厨艺**
为了构建我们的部署包,在AWS控制台中创建一个新的Greengrass组件。这将引导用户提供一个JSON或YAML格式的组件配置文件。请使用以下配置文件:
{
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "nvds-awsgg-deployment",
"ComponentVersion": "1.0.xx",
"ComponentType": "aws.greengrass.generic",
"ComponentDescription": "这是我第一个deepstream应用",
"ComponentPublisher": "Amazon",
"ComponentConfiguration": {
"DefaultConfiguration": {
"ConnString": "localhost;9092;quickstart-events"
}
},
"Manifests": [
{
"Platform": {
"os": "linux"
},
"Name": "Linux",
"Lifecycle": {
"Run": {
"Script": "#!/bin/bash\ncd {artifacts:decompressedPath}/nvds-aws-gg\npython3 deepstream_app.py -g nvinferserver -c config_infer_primary_rtdetr_triton.yml -i file://$(pwd)/awsgg-example.mp4 --conn-str='{configuration:/ConnString}' --silent -d rtsp",
"RequiresPrivilege": true
}
},
"Artifacts": [
{
"Uri": "s3://your/s3/uri/package.zip",
"Unarchive": "解压缩",
"Permission": {
"Read": "ALL",
"Execute": "ALL"
}
}
]
}
],
"Lifecycle": {}
}
我们来把这个配方拆开看看。顶部部分包含了组件的通用信息,包括它的名称和版本号。值得注意的是,版本号**必须增加**以便触发未来的部署或重新部署。我们还定义了一个配置变量,包含了Kafka服务器的连接字符串。
"RecipeFormatVersion": "2020-01-25",
"ComponentName": "nvds-awsgg-deployment",
"ComponentVersion": "1.0.xx",
"ComponentType": "aws.greengrass.generic",
"ComponentDescription": "我的第一个DeepStream应用程序",
"ComponentPublisher": "Amazon (亚马逊)",
"ComponentConfiguration": {
"DefaultConfiguration": {
"ConnString": "localhost;9092;quickstart-events" // 连接字符串
}
},
在 manifest 文件中,我们配置 Greengrass 将我们 S3 存储桶中的归档文件设置为工件,通过提供其唯一资源标识符(URI)。我们设置该资源在设备接收后自动解压。
资源列表:
"Artifacts": [
{
"Uri": "s3://your/s3/uri/package.zip", // S3对象的URI,例如s3://your/s3/uri/package.zip
"Unarchive": "解压格式",
"Permission": {
"权限设置:"
"Read": "读取权限: ALL (表示所有权限)",
"Execute": "执行权限: ALL (表示所有权限)"
}
}
]
解压后的工件位置可以随后用作组件生命周期事件中的变量。本例中的脚本启动了一个 bash 环境,切换到解压工件所在的目录,并最终使用所需的命令行参数运行 Deepstream 应用。请注意,命令之间使用 \n 字符分隔。
"生命周期:": {
"运行脚本": {
"脚本": "#!/bin/bash\n
cd {artifacts:decompressedPath}/nvds-aws-gg\n
python3 deepstream_app.py -g nvinferserver -c config_infer_primary_rtdetr_triton.yml -i file://$(pwd)/awsgg-example.mp4 --conn-str='{configuration:/ConnString}' --silent -d rtsp",
"需要特权": true
}
},
如果在运行该应用程序之前需要先安装依赖项,可以按照以下方式来安装。
"生命周期:": {
"安装": {
"脚本内容": "#!/bin/bash\n
cd {artifacts:decompressedPath}/nvds-aws-gg\n
pip3 install -qr requirements.txt",
"需要管理员权限": true
}
},
在检查完食谱详情之后,选择目标设备或设备组,然后点击“部署”。恭喜你!如果一切顺利,您将在几分钟内看到消息开始发布到您的Kafka主题。如果有错误发生,日志文件可以在目标Jetson设备的/opt/greengrass/v2/目录中找到。
该项目的完整代码可以在这里查看 此处。
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章