自定义和构建微服务(1)——集成自定义 AI 模型

  1. 选择适当的芯片组来筛选可用的型号
  • 高通龙翼™ RB3 Gen 2:QCS6490
  • 高通 IQ-9075:QCS9075
  1. 从筛选的视图中选择一个模型以转到模型页面
  2. 在型号页面上,从下拉列表中选择 EVK 的芯片组,然后选择 TorchScript > TFLite
  3. 可使用APULX提供的模型,也可以自定自定义编译适配模型
    在这里插入图片描述

确保前/后处理支持

验证 Qualcomm 智能多媒体 SDK (IM SDK) 兼容性

  1. 选择Qualcomm IM SDK 支持的模型
  • 标记为 IM SDK 支持的模型可以直接用于 IM SDK 插件
  • 如果选择任何未标记 IM SDK 支持的模型,则需要确保添加预处理/后处理支持
  1. 通过参考插件的模块部分来验证后处理模型和张量布局支持
    例如,以下源代码显示了 qtimlvdetection 插件支持的模型和张量格式
    gst-plugin-mlvdetection/modules · imsdk.lnx.2.0.0.r2-rel · CodeLinaro / le / platform / vendor / qcom-opensource / gst-plugins-qti-oss · GitLab

量化模型的常数值

  1. 从APLUX平台下载模型

需要量化模型才能利用 Snapdragon 平台上的 NPU 加速。

在这里插入图片描述

  1. 在图形查看器工具中打开模型文件(例如:https://netron.app/)。

  2. 选择模型的输入节点以查看模型属性

  3. 从模型的输出节点复制值

在这里插入图片描述

在上面的示例中,q_scale 是 quantization:linear 中提到的值,输出时 q_offset 为 -59。您需要根据插件的实现从模型图中更改 q_offset 的符号。

添加预处理/后处理支持

本部分将指导您在 Qualcomm IM SDK 插件中添加模型后处理支持,尤其是在当前 Qualcomm IM SDK 插件不支持模型后处理的情况下
本指南以 qtimlvdetection 插件为例,解释添加自定义模型后处理的步骤

准备工作 qtimlvconverter 支持模型的预处理。

示例:将 YoloV8 模块支持添加到 qtimlvdetection

  1. 在 qtimlvdetection 插件中编写一个新模块以启用后处理支持。

请参阅 gst-plugin-mlvdetection/modules/ml-vdetection-yolov8.c 示例代码。

  1. 为自定义模型编写一个新文件。在模型后处理模块中,gst_ml_module_process 函数负责执行所有后处理作

  2. 重新编译插件。按照中提供的说明进行作 编译并安装 Qualcomm IM SDK 插件 。

  3. 在 Cmakelists.txt 中添加新文件
    请参阅 gst-plugin-mlvdetection/modules/CMakeLists.txt 例。

  4. 通过运行推理插件和后处理插件的 GStreamer 管道来验证对新模型的后处理支持。

修改 AI 元数据

先决条件 该模型具有预处理/后处理支持

元数据在 gst-plugin-mlvdetection/modules/ml-vdetection-yolov8.c(第 312 行) 后处理模块的结构。

static void
gst_ml_module_parse_tripleblock_frame (GstMLSubModule * submodule,
    GArray * predictions, GstMLFrame * mlframe)
{
  GstProtectionMeta *pmeta = NULL;
  GstMLBoxPrediction *prediction = NULL;
  GstMLLabel *label = NULL;
  gpointer bboxes = NULL, scores = NULL, classes = NULL;
  GstVideoRectangle region = { 0, };
  GstMLType mltype = GST_ML_TYPE_UNKNOWN;
  guint n_paxels = 0, idx = 0, class_idx = 0;
  gfloat confidence = 0;
  gint nms = -1;

  pmeta = gst_buffer_get_protection_meta_id (mlframe->buffer,
      gst_batch_channel_name (0));

  prediction = &(g_array_index (predictions, GstMLBoxPrediction, 0));
  prediction->info = pmeta->info;

  // Extract the source tensor region with actual data.
  gst_ml_structure_get_source_region (pmeta->info, ®ion);

  1. 更新元数据解析并验证 后处理模块(849 行) 用于检测用例。
if (has_object_detection) {
  json_builder_set_member_name (json_builder, "object_detection");
  json_builder_begin_array (json_builder);

  for (idx = 0; idx < gst_value_list_get_size (&list); idx++) {
    GQuark id = 0;
    structure = GST_STRUCTURE (
        g_value_get_boxed (gst_value_list_get_value (&list, idx)));

    id = gst_structure_get_name_id (structure);

    if (IS_OBJECT_DETECTION (id)) {
      gst_detection_text_metadata_to_json_append (json_builder, structure);
    }
  }

  1. 使用来自 后处理模块结构(第 404 行), 例如边界框、颜色和标签。
if (has_object_detection) {
  json_builder_set_member_name (json_builder, "object_detection");
  json_builder_begin_array (json_builder);

  for (idx = 0; idx < gst_value_list_get_size (&list); idx++) {
    GQuark id = 0;
    structure = GST_STRUCTURE (
        g_value_get_boxed (gst_value_list_get_value (&list, idx)));

    id = gst_structure_get_name_id (structure);

    if (IS_OBJECT_DETECTION (id)) {
      gst_detection_text_metadata_to_json_append (json_builder, structure);
    }
  }

  1. 更新后的 JSON 配置由 Redis 发布(第 404 行)
static gboolean
gst_redis_sink_publish (GstBaseSink * bsink, const gchar *string, gchar *channel)
{
  redisReply *reply = NULL;
  GstRedisSink *sink = GST_REDIS_SINK (bsink);

  g_return_val_if_fail (string != NULL, FALSE);
  g_return_val_if_fail (channel != NULL, FALSE);

  GST_DEBUG_OBJECT (sink, "REDIS: PUBLISH %s %s", channel, string);

  reply = redisCommand (sink->redis, "PUBLISH %s %b",
      channel, string, strlen (string));
  freeReplyObject(reply);
  return TRUE;
}

  1. 更新 gst-launch 命令中的模型路径、标签和常量值。

根据模型格式(DLC、BIN、TFLite),需要在以下命令中更改推理插件
应添加与新命令相关的模型路径、标签和常量文件,以便新模型正常工作。
尝试使用更新的参数执行 gst-launch 命令,并确保输出符合预期,然后再继续作。

export XDG_RUNTIME_DIR=/dev/socket/weston && export WAYLAND_DISPLAY=wayland-1 && ulimit -n 4096 && gst-launch-1.0 -e \
qtimltflite name=tflite_yolov5 delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/data/yolov5m-320x320-int8.tflite qtimltflite name=tflite_Mobilenet_1 delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/data/mobilenet_v3_large_quantized.tflite qtimltflite name=tflite_Mobilenet_2 delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/data/mobilenet_v3_large_quantized.tflite qtimltflite name=tflite_Mobilenet_3 delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/data/mobilenet_v3_large_quantized.tflite qtimltflite name=tflite_Mobilenet_4 delegate=external external-delegate-path=libQnnTFLiteDelegate.so external-delegate-options="QNNExternalDelegate,backend_type=htp;" model=/opt/data/mobilenet_v3_large_quantized.tflite qtimlvconverter name=ml_convert_0 ! queue ! tflite_yolov5. tflite_yolov5. ! queue ! tee name=t_split_1 qtivcomposer name=mixer sink_0::position="<0, 0>" sink_0::dimensions="<1280, 720>" sink_1::position="<0, 0>" sink_1::dimensions="<1280, 720>" sink_2::position="<0, 0>" sink_2::dimensions="<384, 216>" sink_3::position="<896, 0>" sink_3::dimensions="<384, 216>" sink_4::position="<0, 504>" sink_4::dimensions="<384, 216>" sink_5::position="<896, 504>" sink_5::dimensions="<384, 216>" sink_6::position="<0, 0>" sink_6::dimensions="<384, 40>" sink_7::position="<896, 0>" sink_7::dimensions="<384, 40>" sink_8::position="<0, 504>" sink_8::dimensions="<384, 40>" sink_9::position="<896, 504>" sink_9::dimensions="<384, 40>" mixer. ! waylandsink sync=true fullscreen=true filesrc location=/opt/data/Animals_000_720p_180s_30FPS.mp4 ! qtdemux ! queue ! h264parse ! v4l2h264dec capture-io-mode=5 output-io-mode=5 ! queue ! tee name=v_split_1 ! queue ! metamux1. v_split_1. ! queue ! ml_convert_0. t_split_1. ! queue ! qtimlvdetection threshold=75.0 results=4 module=yolov5 labels=/opt/data/yolov5m.labels constants="YoloV5,q-offsets=<3.0>,q-scales=<0.005047998391091824>;" ! text/x-raw ! queue ! qtimetamux name=metamux1 ! queue ! tee name=t_split_2 ! queue ! mixer. t_split_1. ! queue ! qtimlvdetection threshold=75.0 results=5 module=yolov5 labels=/opt/data/yolov5m.labels constants="YoloV5,q-offsets=<3.0>,q-scales=<0.005047998391091824>;" ! video/x-raw,width=512,height=288 ! queue ! mixer. t_split_2. ! queue ! qtivsplit name=vsplit1 src_0::mode=single-roi-meta src_1::mode=single-roi-meta src_2::mode=single-roi-meta src_3::mode=single-roi-meta vsplit1. ! queue ! tee name=split_1 ! queue ! ml_convert_1. split_1. ! queue ! mixer. vsplit1. ! queue ! tee name=split_2 ! queue ! ml_convert_2. split_2. ! queue ! mixer. vsplit1. ! queue ! tee name=split_3 ! queue ! ml_convert_3. split_3. ! queue ! mixer. vsplit1. ! queue ! tee name=split_4 ! queue ! ml_convert_4. split_4. ! queue ! mixer. qtimlvconverter name=ml_convert_1 ! queue ! tflite_Mobilenet_1. tflite_Mobilenet_1. ! queue ! mlclass_1. qtimlvconverter name=ml_convert_2 ! queue ! tflite_Mobilenet_2. tflite_Mobilenet_2. ! queue ! mlclass_2. qtimlvconverter name=ml_convert_3 ! queue ! tflite_Mobilenet_3. tflite_Mobilenet_3. ! queue ! mlclass_3. qtimlvconverter name=ml_convert_4 ! queue ! tflite_Mobilenet_4. tflite_Mobilenet_4. ! queue ! mlclass_4. qtimlvclassification name=mlclass_1 threshold=51.0 results=2 module=mobilenet labels=/opt/data/mobilenet.labels extra-operation=softmax constants="Mobilenet,q-offsets=<-29.0>,q-scales=<0.18705224990844727>;" ! video/x-raw,width=384,height=40 ! queue ! mixer. qtimlvclassification name=mlclass_2 threshold=51.0 results=2 module=mobilenet labels=/opt/data/mobilenet.labels extra-operation=softmax constants="Mobilenet,q-offsets=<-29.0>,q-scales=<0.18705224990844727>;" ! video/x-raw,width=384,height=40 ! queue ! mixer. qtimlvclassification name=mlclass_3 threshold=51.0 results=2 module=mobilenet labels=/opt/data/mobilenet.labels extra-operation=softmax constants="Mobilenet,q-offsets=<-29.0>,q-scales=<0.18705224990844727>;" ! video/x-raw,width=384,height=40 ! queue ! mixer. qtimlvclassification name=mlclass_4 threshold=51.0 results=2 module=mobilenet labels=/opt/data/mobilenet.labels extra-operation=softmax constants="Mobilenet,q-offsets=<-29.0>,q-scales=<0.18705224990844727>;" ! video/x-raw,width=384,height=40 ! queue ! mixer.

Results 结果

  • 已成功添加新模型后处理
  • 新 AI 模型的自定义 AI 元数据具有 JSON 架构,并通过 Redis 传输
  • 使用 Qualcomm IM SDK 的 Redis 插件创建自定义管道
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值