多路视频推理架构:多摄像头并发方案设计

多路视频推理架构:多摄像头并发方案设计
多路视频推理架构多摄像头并发方案设计单路推理搞定了多路怎么搞售货柜、安防监控、多机位质检都是多路摄像头同时跑。这篇讲多路推理的架构设计多进程还是多线程、NPU 资源怎么分配、流水线怎么组织、怎么保证稳定性。大家好我是黒漂技术佬。单路推理相对简单把模型跑起来就行。但实际项目里经常是多路摄像头——售货柜可能两三个摄像头安防系统十几路这时候架构设计就很重要了。多路不是单路 × N 那么简单资源竞争、稳定性、延迟控制、异常处理都是问题。这篇讲多路视频推理的架构设计基于 RK3588 平台讲我实际项目里踩过的坑。一、多路推理的挑战1. 算力有限NPU 算力就 6 TOPS单路 YOLOv8n 占一部分多路加起来不能超。2. 内存共享RK3588 的 NPU 和 CPU 共享内存多路模型 多路视频帧内存压力不小。3. 调度复杂多任务怎么分配 NPU 资源排队还是并行延迟怎么保证4. 稳定性一路挂了不能影响其他路。某一路异常崩溃整个程序不能跟着挂。5. 延迟控制每一路的推理延迟都要可控不能某路堵了其他路也跟着卡。二、架构选型多进程 vs 多线程方案一多线程单进程多线程一个进程每路一个线程共享同一个地址空间。主进程 ├── 线程摄像头1 拉流预处理推理后处理 ├── 线程摄像头2 拉流预处理推理后处理 └── 线程摄像头3 拉流预处理推理后处理优点共享内存方便数据交换快资源共享模型可以复用看API启动快开销小缺点一个线程崩了整个进程挂调试复杂线程安全问题多内存隔离差一路内存泄漏全进程遭殃方案二多进程每路一个独立进程主进程管理。主进程管理 ├── 子进程1摄像头1 完整流水线 ├── 子进程2摄像头2 完整流水线 └── 子进程3摄像头3 完整流水线优点隔离性好一路挂了不影响其他路内存独立不会互相干扰可以单独重启某一路缺点进程间通信麻烦每个进程都加载模型内存占用 × N进程切换开销略大方案三混合架构拉流解码多进程推理统一调度。进程1摄像头1 拉流解码 → ┐ 进程2摄像头2 拉流解码 → ┼→ 推理服务统一调度NPU→ 各自后处理 进程3摄像头3 拉流解码 → ┘优点推理集中管理资源利用率高拉流解码隔离稳定适合路数多的场景缺点架构复杂开发量大怎么选2-4 路模型相同多线程就行简单高效售货柜场景推荐路数多、稳定性要求高多进程隔离好10 路以上考虑混合架构推理集中调度售货柜一般 2-3 路摄像头我用的是多线程方案简单够用。三、NPU 资源分配RK3588 三核 NPU多路怎么分方案 1联合模式共享默认所有路共用三核联合的 NPU排队推理。路1推理 → 路2推理 → 路3推理 → 路1推理 → ...优点单路推理最快缺点多路串行总延迟 各路相加适合路数少2-3路、单路延迟要求高方案 2独立模式各占一核每路绑定一个 NPU 核心并行推理。NPU0: 路1 → 路1 → 路1 → ... NPU1: 路2 → 路2 → 路2 → ... NPU2: 路3 → 路3 → 路3 → ...优点真正并行总吞吐高各路互不影响缺点单路推理慢一点单核比三核慢适合路数刚好 3 路、追求总吞吐方案 3混合分配重要的路占两核次要的路占一核。根据业务优先级动态调整。我的选择售货柜两路摄像头主摄像头商品识别占两核高优先级副摄像头人流检测占一核低优先级主路推理优先保证延迟注意RKNN 的 context 和核心绑定每个核心要单独的 context。多路独立模式就要创建多个 rknn context分别绑定不同核心。四、流水线设计每一路内部都是流水线多路之间也要考虑调度。单路流水线上篇讲过拉流解码 → 预处理 → NPU推理 → 后处理 → 结果输出每个阶段一个线程队列串起来。多路共享推理线程如果 NPU 推理是瓶颈多路共用一个推理线程排队处理路1 预处理 → ┐ 路2 预处理 → ┼→ 推理队列 → NPU推理 → 分发回各路 → 后处理 路3 预处理 → ┘优点NPU 利用率最高不会闲置统一调度方便控制优先级缺点架构复杂一点排队会增加延迟适合路数多、推理时间长的场景。独立流水线每路完整一套每路各有各的预处理、推理、后处理线程路1: 拉流 → 预处理 → 推理 → 后处理 路2: 拉流 → 预处理 → 推理 → 后处理优点简单各路独立好调试一路有问题不牵连缺点NPU 可能闲置各推理时间错开的话还好线程数多路数少2-4路推荐这个简单可靠。五、帧率控制与降帧策略多路并发算力不够的时候怎么办1. 按需推理不是每帧都推理按业务需要的帧率来。售货柜待机状态每秒 1 帧检测有没有人开门状态全帧率识别商品没人的时候降帧率省算力省电2. 动态降帧NPU 忙不过来的时候自动降帧率if(inference_queue.size()THRESHOLD){// 队列太长了丢一帧降帧率skip_frametrue;}保证延迟不爆炸牺牲帧率保实时性。3. 优先级调度重要的摄像头优先级高先推理主摄像头商品识别高优先级副摄像头环境监控低优先级高优先级的帧插队先处理。4. 分辨率动态调整算力紧张时自动降低输入分辨率正常640×640负载高416×416精度降一点但帧率保住了。六、内存管理多路最容易出内存问题。1. 输入输出缓冲池预分配一批缓冲循环使用不要每帧 new/delete。classBufferPool{std::queueBuffer*free_buffers;std::mutex mtx;public:Buffer*acquire();// 拿一个voidrelease(Buffer*);// 还回来};每路共用缓冲池或者每路自己的池。2. 模型内存共享如果多路跑同一个模型尽量共享权重内存看 RKNN API 支持情况。不能共享的话每个 context 一份权重N 路就是 N 份。模型不大的话还好大模型要注意。3. 监控内存使用定期查进程内存占用异常增长及时告警。// 读取 /proc/self/status 看 VmRSSlongget_memory_usage_kb();七、异常处理与稳定性多路系统稳定性很重要一路挂了不能全挂。1. 每路独立 try-catchC 里每路线程外层包一层异常捕获voidcamera_thread(intid){try{while(running){// 正常逻辑}}catch(conststd::exceptione){LOG_ERROR(摄像头%d异常: %s,id,e.what());// 触发重启逻辑restart_camera(id);}}2. 自动重连RTSP 断流、摄像头掉线自动重连while(running){if(!camera.is_connected()){camera.reconnect();std::this_thread::sleep_for(3s);continue;}// 正常处理}3. 超时检测推理超时、某帧卡住了要有超时机制// 推理加超时autoresultinference_with_timeout(frame,100ms);if(!result){LOG_WARN(推理超时跳过这帧);continue;}4. 看门狗主进程监控各路状态长时间没输出就重启那一路。5. 日志分级每路的日志带上 ID方便排查问题[CAM01] 拉流成功 [CAM02] 推理超时跳过 [CAM01] 检测到商品: 可乐 x2八、售货柜多路架构实例硬件RK3588 2 路 IPC 摄像头主摄像头1080p货架商品识别高优先级副摄像头720p用户操作区域检测低优先级架构多线程 独立流水线主线程管理状态机 ├── 线程主摄像头拉流解码FFmpeg硬解 ├── 线程主摄像头预处理RGA ├── 线程主摄像头推理NPU01两核 ├── 线程主摄像头后处理业务逻辑 │ ├── 线程副摄像头拉流解码 ├── 线程副摄像头预处理 ├── 线程副摄像头推理NPU2一核 └── 线程副摄像头后处理性能数据路数分辨率帧率NPU占用CPU占用主路640×64025fps~60%两核~15%辅路416×41610fps~20%一核~5%合计--~80%~20%还有余量足够跑其他业务逻辑。稳定性连续跑 7×24 小时没有崩溃。偶尔摄像头断流自动重连不影响另一路。九、常见坑坑 1多线程共用一个 RKNN contextRKNN context 不是线程安全的多线程同时调用会崩。解决每个线程一个 context或者推理线程加锁串行化。坑 2内存泄漏多路长时间跑一点点泄漏累积起来很可怕。解决用内存池、预分配、定期检查内存占用。坑 3某路卡住拖慢全局共享队列的话一路处理慢了队列堆积其他路也受影响。解决每路独立队列或者有丢帧机制。坑 4NPU 资源竞争多路同时抢 NPU调度开销大总吞吐反而低。解决独立模式各占一核或者统一排队调度。坑 5初始化顺序乱多路同时初始化 RKNN、打开摄像头资源竞争容易出奇怪的问题。解决串行初始化初始化完再启动各线程。十、本篇小结多路架构少路用多线程简单多路用多进程隔离好NPU 分配联合模式单路快独立模式多路并行吞吐高每路内部用流水线提升单路吞吐量帧率控制按需推理、动态降帧、优先级调度内存缓冲池预分配、监控内存、避免泄漏稳定性异常捕获、自动重连、超时检测、看门狗调试每路日志带ID方便定位问题下一篇讲模型精度评估与 bad case 优化模型上线后怎么评估效果、怎么分析误检漏检、怎么迭代优化。我是黒漂技术佬。