- 选择适当的芯片组来筛选可用的型号
- 高通龙翼™ RB3 Gen 2:QCS6490
- 高通 IQ-9075:QCS9075
- 从筛选的视图中选择一个模型以转到模型页面
- 在型号页面上,从下拉列表中选择 EVK 的芯片组,然后选择 TorchScript > TFLite
- 可使用APULX提供的模型,也可以自定自定义编译适配模型
确保前/后处理支持
验证 Qualcomm 智能多媒体 SDK (IM SDK) 兼容性
- 选择Qualcomm IM SDK 支持的模型
- 标记为 IM SDK 支持的模型可以直接用于 IM SDK 插件
- 如果选择任何未标记 IM SDK 支持的模型,则需要确保添加预处理/后处理支持
- 通过参考插件的模块部分来验证后处理模型和张量布局支持
例如,以下源代码显示了 qtimlvdetection 插件支持的模型和张量格式
gst-plugin-mlvdetection/modules · imsdk.lnx.2.0.0.r2-rel · CodeLinaro / le / platform / vendor / qcom-opensource / gst-plugins-qti-oss · GitLab
量化模型的常数值
- 从APLUX平台下载模型
需要量化模型才能利用 Snapdragon 平台上的 NPU 加速。
-
在图形查看器工具中打开模型文件(例如:https://netron.app/)。
-
选择模型的输入节点以查看模型属性
-
从模型的输出节点复制值
在上面的示例中,q_scale 是 quantization:linear 中提到的值,输出时 q_offset 为 -59。您需要根据插件的实现从模型图中更改 q_offset 的符号。
本部分将指导您在 Qualcomm IM SDK 插件中添加模型后处理支持,尤其是在当前 Qualcomm IM SDK 插件不支持模型后处理的情况下
本指南以 qtimlvdetection 插件为例,解释添加自定义模型后处理的步骤
准备工作 qtimlvconverter 支持模型的预处理。
示例:将 YoloV8 模块支持添加到 qtimlvdetection
- 在 qtimlvdetection 插件中编写一个新模块以启用后处理支持。
请参阅 gst-plugin-mlvdetection/modules/ml-vdetection-yolov8.c 示例代码。
-
为自定义模型编写一个新文件。在模型后处理模块中,gst_ml_module_process 函数负责执行所有后处理作
-
重新编译插件。按照中提供的说明进行作 编译并安装 Qualcomm IM SDK 插件 。
-
在 Cmakelists.txt 中添加新文件
请参阅 gst-plugin-mlvdetection/modules/CMakeLists.txt 例。 -
通过运行推理插件和后处理插件的 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);
- 更新元数据解析并验证 后处理模块(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);
}
}
- 使用来自 后处理模块结构(第 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);
}
}
- 更新后的 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;
}
- 更新 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 插件创建自定义管道