Files
security-ai-edge/docs/edge-inference-optimization.md

4.5 KiB

Edge 推理结构优化说明

目标

本次优化只调整 security-ai-edge 内部实时推理链路,目标是:

  • 保持现有功能不变
  • 保持与其他项目的现有对接方式不变
  • 提升单卡场景下的实时稳定性
  • 降低解码线程被 CPU 预处理拖慢的风险
  • 在高并发下优先处理最新帧,避免旧帧堆积

本次未修改以下外部行为:

  • WVP 下发摄像头与 ROI 配置的方式
  • Redis / MQTT / HTTP 对接协议
  • 告警生成、告警去重、截图回调、心跳上报的外部接口
  • TensorRT engine 文件加载方式

改动概览

1. 解耦读帧线程与推理预处理

优化前:

  • RTSPStreamReader 读到帧后,直接通过回调进入 _process_frame
  • _process_frame 内部会做 ROI 遍历、裁剪、预处理、入推理队列
  • 当 ROI 多、CPU 紧张时,读帧线程容易被预处理阻塞

优化后:

  • RTSPStreamReader 只负责读帧和保存“最新帧”
  • 新增中心调度线程 FrameScheduler
  • 调度线程从每路流提取最新帧,再统一调用 _process_frame

收益:

  • 解码线程不再承担重 CPU 预处理
  • 拉流稳定性更高
  • 更符合实时视频系统“最新帧优先”的处理模型

2. 每路流改为“最新帧消费”

优化前:

  • get_latest_frame() 通过清空队列获取最后一帧
  • 在高并发下,队列遍历和频繁出队会增加额外开销

优化后:

  • 流对象内部维护 _latest_frame
  • 调度线程直接消费这份最新帧引用
  • 中间帧天然被覆盖,不再积压到后面阶段

收益:

  • 获取最新帧成本更低
  • 更适合实时系统而非离线批处理

3. ROI 预处理结果复用

优化前:

  • 同一 ROI 下如果绑定多个算法,会重复执行 preprocess_single

优化后:

  • 先筛出启用的 bind
  • 对每个 ROI 只执行一次预处理
  • 多个 bind 复用同一份裁剪图和缩放信息

收益:

  • 降低 CPU crop / resize / normalize 开销
  • ROI 绑定越多,收益越明显

4. 推理队列增加拥塞保护

优化前:

  • ROI 任务持续追加到 _batch_roi_queue
  • 在输入高于推理吞吐时,可能出现旧任务堆积

优化后:

  • _batch_roi_queue 增加最大挂起量限制
  • 超限时丢弃最旧 ROI 任务

收益:

  • 控制排队长度
  • 避免系统在高压时持续处理过期画面

说明:

  • 这是实时系统常见策略,目标是“宁可丢旧帧,不处理过期帧”

5. TensorRT 设备选择修正

优化前:

  • TensorRT 初始化时固定使用 cuda.Device(0)
  • 即使配置里指定了 device_id,实际也不会生效

优化后:

  • 改为使用 self.config.device_id

收益:

  • 保留现有单卡行为
  • 为后续指定 GPU 设备提供正确基础

当前结构

优化后的主链路为:

  1. RTSPStreamReader 拉流并保存最新帧
  2. FrameScheduler 周期性轮询所有流
  3. _process_frame 生成 ROI 推理任务
  4. _batch_roi_queue 聚合任务并做拥塞保护
  5. InferenceWorker 做小批量 TensorRT 推理
  6. PostProcessor + AlgorithmManager 输出业务告警
  7. ResultReporter / AlarmUploadWorker 继续负责上报

兼容性说明

本次优化没有改变这些关键约束:

  • 摄像头仍然按 ROI 配置启动和停用
  • 算法处理入口 _handle_detections 不变
  • 现有告警冷却、ROI 去重、resolve 机制不变
  • 现有外部平台无需修改配置或接口

因此它属于“内部调度优化”,而不是“系统集成改造”。

新增运行指标

get_status() 新增了以下统计项:

  • dropped_frames
  • dropped_roi_tasks
  • inference_batches
  • scheduler_cycles

这些指标用于判断:

  • 是否存在旧帧丢弃
  • 是否出现 ROI 队列拥塞
  • 推理批次是否稳定
  • 调度线程是否持续运行

仍可继续优化的方向

本次改造重点是“在当前架构下提升实时性和稳定性”,后续还可以继续做:

  • 将 OpenCV/FFmpeg CPU 解码切换到 GPU 硬解
  • 将调度参数做成配置项,例如最大帧年龄、调度周期、最大挂起 ROI 数
  • 为不同摄像头增加优先级调度
  • 为高频 ROI 增加更细粒度缓存和复用
  • 为推理链路补充阶段耗时统计:调度、预处理、推理、后处理

适用场景

这版结构更适合:

  • 单卡部署
  • 多路 RTSP 并发
  • 小 batch 实时推理
  • 需要低延迟而非离线全量处理的场景

如果后续要切到 GPU 解码,当前这版调度结构也更容易继续演进,因为“读帧”和“处理帧”已经拆开了。