尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Edge AI Kit性能调优实战:i.MX8M+Myriad X+8MP摄像头从8FPS到30FPS

Edge AI Kit性能调优实战:i.MX8M+Myriad X+8MP摄像头从8FPS到30FPS 拿到这块Edge AI Kit的时候我本来以为也就是普通的开发板套件接上电源、插上摄像头、跑个demo就完事了。结果折腾了两天差点把桌子掀了。默认的示例工程在4K分辨率下推理只有8FPS画面卡得像幻灯片Myriad X还时不时掉线。后来仔细把i.MX8M、Myriad X和8MP摄像头这三者之间的数据通路捋清楚从软件栈到模型推理一步步调优才把这套边缘AI套件的真实性能榨出来。这篇文章就是那两天踩坑记录的浓缩版适合刚拿到类似硬件组合、准备在边缘端做视觉AI项目的朋友参考。1. 为什么边缘AI套件会选这三件套i.MX8M、Myriad X与8MP摄像头的匹配逻辑很多人拿到套件的第一反应是为什么不直接用手机SoC为什么不用树莓派加USB摄像头这个问题其实恰恰是理解整套硬件设计的关键。1.1 i.MX8M在套件中扮演的角色i.MX8M系列是NXP推出的应用处理器最常见的是i.MX8M Quad四个Cortex-A53核心加一个Cortex-M4F协处理核心主频在1.5GHz左右。它不像手机SoC那样堆大核、堆GPU但它有一个非常突出的特点工业级稳定性、接口丰富、供货周期长。对边缘AI设备来说部署环境往往不是舒适的桌面可能是工厂车间、农业大棚、电力机房这些场景下设备稳定性比峰值算力重要得多。在整套系统里i.MX8M负责的是“大脑”里的调度工作跑Linux操作系统、处理网络协议栈、管理摄像头驱动、调度Myriad X的推理任务、把结果通过MQTT/HTTP送出去。它不负责重活但所有轻量级但必须存在的任务都由它兜底。1.2 Myriad X弥补了i.MX8M最大的短板i.MX8M的短板很明显它没有足够强的神经网络加速单元i.MX8M Plus这颗芯片例外它带了2.3 TOPS的NPU但i.MX8M标准版是不带的。如果只用CPU来跑YOLO级别的目标检测模型四核A53根本扛不住——我在板子上实测过跑MobileNet SSD差不多2到3 FPS完全没有实用价值。Myriad X是Intel收购Movidius之后推出的视觉处理单元VPU官方标称深度神经网络推理算力超过1 TOPS有16个SHAVE矢量处理核心还带一个硬件神经网络加速引擎。它最厉害的地方不是绝对算力而是能效比一整块Myriad X的功耗大概只有1到2瓦但能在这么低的功耗下跑出一个能用的检测帧率。这对电池供电或者工业现场供电功率有限的设备来说是决定性的优势。1.3 8MP摄像头选择的前瞻性8MP摄像头对应的就是3280x2464分辨率也就是常见意义上的4K级别传感器典型型号如Sony IMX219系列。很多人问做目标检测为什么不用1080P甚至720P帧率还能更高这个问题的答案分两层。第一层高分辨率意味着更远的检测距离。使用同一颗镜头4K传感器在同样视场角下的像素密度远高于1080P相当于变相放大了远处目标这在安防监控、人员计数、车辆识别等场景里能直接延伸有效检测范围。第二层高分辨率原图可以离线保存在本地后续做模型迭代、数据集扩充时原始素材的可用性远高于低分辨率图像。我实际项目中就有过这样的经历一个模型在4K原图上能检出的目标在1080P压缩图上就会漏检因为小目标在缩放过程中直接丢了。这三者的组合逻辑是i.MX8M提供稳定的主控平台Myriad X补齐神经网络推理能力8MP摄像头提供高信息密度的视觉输入。短板互补没有明显的性能短板。2. 硬件规格不会告诉你的事数据通路与系统瓶颈分析看规格书的时候每一项参数都很漂亮但组装起来性能却上不去问题几乎都出在数据通路上。这套系统里有一条关键的链路摄像头 → i.MX8M内存 → Myriad X内存 → 推理结果返回i.MX8M。2.1 像素数据量到底有多大先算一笔基础账。8MP摄像头的原始输出是Bayer格式RAW每像素10位IMX219是10-bit折算成字节大约是每像素1.25字节。一张3280x2464的RAW图大小是3280 x 2464 x 1.25 ≈ 10.1MB。如果按30FPS算每秒摄像头产生的RAW数据量是303MB。但实际处理中ISP图像信号处理器会把Bayer数据转换成YUV420或者RGB888。以YUV420为例每像素1.5字节一张4K图的YUV420数据大约是4.73MB。30FPS下每秒约142MB。这个数据量看起来不大但问题在于它要经过MIPI-CSI接口进入i.MX8M的内存再从内存搬运到Myriad X侧中间任何一环带宽不足都会拖慢整个流水线。2.2 MIPI-CSI接口和USB/PCIe通道的限制i.MX8M的MIPI-CSI接口通常支持2-lane或4-lane配置。IMX219摄像头是2-lane输出每lane带宽大约1Gbps理论总带宽2Gbps即250MB/s。考虑到协议开销实际可用带宽大约在200MB/s左右。这个带宽在4K30FPS YUV420输出时已经用了70%以上如果摄像头输出的是RGB888格式每像素3字节4K30FPS需要约295MB/s直接超过接口带宽这时候要么降低帧率要么换用YUV420输出。Myriad X和主控之间的连接方式也很关键。有些套件用USB 3.0有些用PCIe。USB 3.0理论带宽5Gbps即625MB/s但USB协议栈大量依赖CPU参与中断处理i.MX8M的A53核心在高速USB传输时会有明显的CPU占用。PCIe通道更干净数据绕过USB协议栈延迟更低但i.MX8M标准版的PCIe是2.0 x1理论带宽500MB/s实际可用大约400MB/s。2.3 整条流水线的瓶颈表在我实际测试中各个环节的带宽占用量和瓶颈分布如下表所示流水线环节数据量/带宽需求实际可用带宽瓶颈程度摄像头输出RAW 4K30约303MB/sMIPI-CSI 2-lane约200MB/s严重ISP转换后YUV420 4K30约142MB/s内存写入约60%占用中等YUV420送Myriad X推理约142MB/sUSB 3.0约400MB/s轻推理结果回传小数据每帧几KB到几十KB不构成瓶颈无表格的结论很直白最大的瓶颈在摄像头到ISP这一段。实际调优时最省事且有效的做法是在摄像头端就降低输出分辨率比如直接用1080P输出或者让ISP直接输出NV12格式并通过硬件转码减轻CPU负担而不是在i.MX8M上做耗时的高分辨率软件转换。3. 环境搭建与软件栈选择从交叉编译到OpenVINO运行时的完整链路硬件分析得再透彻最终还是要落到软件能跑起来。这一节是我实际搭建环境的过程记录包括不少容易踩坑的细节。3.1 基础系统的选择套件自带的BSP通常是Yocto Linux内核版本4.14或4.19左右。我的建议是如果你的目标只是验证AI推理直接用Ubuntu-based的rootfs会更省心。Yocto强项是定制化裁剪但它的包管理工具不完整装个OpenVINO的依赖库能把你逼疯。我做的是在Ubuntu 18.04 LTS rootfs上完成整套搭建内核使用Yocto编译出的内核镜像用户空间完全替换为Ubuntu。具体的操作链路是下载Ubuntu base rootfs我用的是ubuntu-base-18.04.5-base-arm64用chroot方式安装必要工具sudo、net-tools、udev、libusb等把rootfs打包成ext4镜像写入SD卡内核和设备树沿用BSP自带文件只替换rootfs分区# 在宿主机上将rootfs写入SD卡的用户分区 sudo tar -xzf ubuntu-base-18.04.5-base-arm64.tar.gz -C /mnt/sd sudo cp -a /usr/bin/qemu-aarch64-static /mnt/sd/usr/bin/ sudo chroot /mnt/sd /bin/bash # 在chroot环境中安装基础工具 apt update apt install -y sudo net-tools udev libusb-1.0-03.2 OpenVINO安装的关键细节Myriad X的推理依赖OpenVINO Toolkit版本选择非常重要。早期OpenVINO版本对ARM的支持不完整直到R5才正式支持树莓派ARM平台我推荐直接装2021.4 LTS版本这是最后一个对Myriad X支持最稳定的版本后面的版本虽然还兼容但在老VPU上的性能没有明显提升。安装方式不要用pip装openvino那是给x86用的ARM平台要用预编译的deb包wget https://storage.openvinotoolkit.org/repositories/openvino/packages/2021.4.2/l_openvino_toolkit_runtime_raspbian_p_2021.4.2.tgz tar -xzf l_openvino_toolkit_runtime_raspbian_p_2021.4.2.tgz cd l_openvino_toolkit_runtime_raspbian_p_2021.4.2 sudo ./install_dependencies/install_NCS_udev_rules.sh source /opt/intel/openvino_2021/bin/setupvars.sh装完以后必须验证USB设备枚举状态。Myriad X在Linux下会注册为USB设备VID是03e7检查一下lsusb | grep 03e7如果看不到输出大概率是udev规则没生效或者USB口供电不足。这一步没走通后面OpenVINO必然报“device not found”。3.3 摄像头驱动的验证方法8MP摄像头通过MIPI-CSI接口连接到i.MX8MLinux下用V4L2框架驱动。先确认设备节点存在v4l2-ctl --list-devices正常输出会显示OV5647或IMX219设备对应/dev/video0。然后测试单帧抓取v4l2-ctl --set-fmt-videowidth1920,height1080,pixelformatYUYV --stream-mmap --stream-count1 --stream-to/tmp/test.raw注意i.MX8M的ISP对传感器输出的RAW数据做处理后通过V4L2子设备接口上报格式。如果设置的像素格式和设备驱动支持的不一致会直接报错。IMX219原生输出RAW10但驱动通常会注册为YUYV或UYVY输出。遇到花屏时先检查格式是否匹配不要一上来就怀疑硬件。3.4 模型转换从TensorFlow到IRMyriad X不直接吃TensorFlow或PyTorch模型必须通过OpenVINO的Model Optimizer转换成中间表示IR格式包含一个.xml文件和一个.bin文件。以TensorFlow的SSD MobileNet V2为例python3 /opt/intel/openvino_2021/deployment_tools/model_optimizer/mo_tf.py \ --input_model frozen_inference_graph.pb \ --tensorflow_use_custom_operations_config /opt/intel/openvino_2021/deployment_tools/model_optimizer/extensions/front/tf/ssd_support.json \ --reverse_input_channels \ --output_dir ./ir_model转换完成后检查.xml文件里的输入尺寸Myriad X对输入尺寸有对齐要求通常最好是16或32的整数倍。如果你的模型输入是300x300直接能用如果是608x608要注意内存占用会直线上升同时推理延迟也会变大。这一步在我的实际项目里反复出现过很多人模型转换成功但在板子上跑不起来多半就是输入尺寸没对齐。4. 端到端AI视觉流水线的实现路线采集、预处理、推理、输出环境搞定后进入核心开发环节。我把整套流水线分成四个模块逐个说明实现逻辑和注意事项。4.1 视频采集模块V4L2的内存映射机制采集端如果不使用GStreamer这类框架直接用V4L2 API关键是用内存映射mmap方式而不是read方式。mmap方式把设备驱动的缓冲区直接映射到用户空间省去了一次内核空间到用户空间的拷贝对4K高分辨率帧的CPU占用差别非常大。// V4L2 mmap模式核心流程 struct v4l2_requestbuffers req; req.count 4; req.type V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory V4L2_MEMORY_MMAP; ioctl(fd, VIDIOC_REQBUFS, req); struct v4l2_buffer buf; buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory V4L2_MEMORY_MMAP; buf.index i; ioctl(fd, VIDIOC_QUERYBUF, buf); // 通过mmap将buf.m.offset映射到用户空间缓冲区队列多申请几块4到6块可以在采集和推理之间形成流水线避免一帧处理慢导致下一帧丢失。4.2 预处理尽量让格式对齐VPU胃口Myriad X通过OpenVINO的输入接口接收图像默认输入是BGR平面格式NCHW。但实际工程里直接从摄像头拿到的是NV12或YUV420格式这时候最错误的做法是把NV12转成BGR CPU数据再塞给Myriad X因为这会白白消耗大量CPU带宽。OpenVINO在2021.4版本支持了NV12输入宏可以直接把NV12数据作为输入张量内部硬件辅助完成颜色转换。实现方式在Python/C里只需设置输入布局为NV12即可// C侧设置NV12输入 InferenceEngine::NHWC_layout? // 更准确的写法是通过InputInfo::setPrecision和setLayout配置 auto inputInfo network.getInputsInfo(); inputInfo.begin()-second-setLayout(Layout::NCHW); inputInfo.begin()-second-setPrecision(Precision::U8);如果摄像头输出1080P NV12而模型输入是300x300还需要做一次缩放。Myriad X内部有图像缩放单元但实际测试中让CPU用OpenCV的resize做缩放在边缘端反而更快。原因在于Myriad X的主要算力应该留给CNN计算缩放这类简单操作CPU做起来性价比更高。4.3 推理执行同步与异步的抉择这是整个流水线里最影响体验的一个决策点。同步模式就是采集一帧、推理一帧、等待结果、再采集下一帧逻辑简单但每一帧都浪费了等待时间实测差不多少了一半性能。异步模式则是采集完一帧立即送入推理队列不等结果出来就继续采集下一帧让采集和推理并行运行。在OpenVINO C API中异步模式用AsyncInferRequest实现auto inferRequest executableNetwork.CreateInferRequest(); // 核心循环 while (running) { // 从摄像头读取帧 frame capture.read(); // 将帧数据放入输入张量 inferRequest.SetBlob(inputName, inputBlob); // 开始异步推理不阻塞 inferRequest.StartAsync(); // 等待上一帧推理结果返回 if (prevRequest) { prevRequest.Wait(IInferRequest::WaitMode::RESULT_READY); // 处理结果并画框 processOutput(prevRequest); } prevRequest inferRequest; }这里有个关键点上一帧的结果要在提交下一帧推理之前取走否则框架会因为缓冲区被覆盖而报错。我最初的实现里少了这一步导致程序跑几十帧后直接崩溃。4.4 后处理与结果输出Myriad X输出的检测结果是若干组数组框坐标、置信度、类别ID。OpenVINO的DetectionOutput层已经做了NMS非极大值抑制省去了手动实现NMS的麻烦。但要注意输出张量的解析方式典型输出形状是[1, 1, N, 7]其中第7个维度包含batch_id、class_id、confidence、x_min、y_min、x_max、y_max。x_min/y_min这些坐标是归一化的[0,1]浮点数需要乘回原始图像的宽高。后处理阶段的经验是画框这个操作看起来轻量但在4K分辨率下每帧绘制几十个框同样会消耗不小CPU。建议先把检测框坐标缩放到一个固定分辨率比如640x480上绘制把画框后的小图叠加在原始流上输出或者只在需要保存证据帧时才绘制全分辨率。5. 我把推理性能从8FPS提到30FPS的调优过程说回文章开头提到的8FPS问题。这个性能数字刚测出来时我一度怀疑是硬件组合搭配不合理。但经过逐步排查和调优最后稳定跑到30FPS以上。整个过程大概经历了四个阶段。5.1 第一阶段确认问题出在同步流水线最初demo是Python写的推理过程如下读取一帧4K图转成RGBresize到300x300送入Myriad X等待结果绘制显示。用top命令一看CPU占用率大约90%Myriad X负载却很低明显是CPU在做预处理和等待时拖沓了。这个阶段我把代码从Python换成了C消除了Python解释器开销并改用V4L2 mmap直接采集CPU占用率从90%降到40%帧率从8FPS提升到14FPS。这一步的收获是在边缘设备上语言选型带来的性能差异远比想象中大。5.2 第二阶段切到异步推理紧接着把推理改为异步模式帧率从14FPS提升到19FPS。这个提升幅度不算大原因是我在代码里等上一帧结果后才开始下一帧采集本质上还是个伪异步。正确的做法是维护两个InferRequest轮流使用一个负责当前帧推理一个接收新帧并允许采集线程独立于推理线程运行。5.3 第三阶段降低摄像头输出分辨率这个阶段是性能突飞猛进的转折点。我把摄像头输出从3280x2464降到了1920x1080模型输入保持300x300不变。这一步带来两个收益第一ISP输出数据量大幅减少MIPI-CSI带宽压力明显缓解。第二CPU侧从NV12到RGB的转换、resize的耗时从大约18ms降到了5ms。合成FPS直接跳到26FPS。很多人担心降低分辨率会影响检测精度。实测下来300x300的模型输入本来就吞不下4K原图的细节用1080P输入和4K输入对检测结果的差异微乎其微。真正会影响精度的不是输入源分辨率而是模型本身的输入尺寸。如果一定要保留4K采集可以让ISP直接输出裁剪后的感兴趣区域ROI而不是全幅输出效果一样但带宽占用更低。5.4 第四阶段模型精度FP32到FP16最后一步是把模型从FP32精度转换为FP16。Myriad X的硬件加速引擎对FP16有原生支持转换后推理延迟下降约20%。再加上模型输入尺寸从300x300降到256x256适配我的检测任务后精度损失可以接受最终帧率稳定在30到32FPS。调优过程的数据汇总优化项帧率延迟单帧推理CPU占用初始Python4K同步8FPS约120ms90%C重构mmap采集14FPS约70ms40%异步推理19FPS约52ms35%摄像头降为1080P26FPS约38ms25%FP16输入尺寸调整32FPS约30ms22%5.5 调优过程中学到的核心经验回头总结最优先级的调优顺序应当是先确保采集端不成为瓶颈再把推理切异步然后增加批处理或降低模型复杂度最后才考虑模型精度转换。很多人在FP32转FP16上死磕结果采集环节CPU已经满载模型转成什么精度都无济于事。另外一个容易被忽略的点Myriad X对单帧推理任务有一个固定的调度开销大约5到8毫秒无论模型多小都省不掉。如果你的模型推理耗时本身只有10毫秒那调度开销占比非常高这时候考虑批处理batch反而能摊薄调度成本。用OpenVINO的SetBatchSize可以指定批大小同时把多帧图像拼成一个批次输入牺牲一点延迟换取整体吞吐量的提升。在多人脸检测、多路视频流场景下这个优化效果非常显著。6. 实测中的典型故障与排查思路整个项目过程中遇到的坑不少挑几个对后续使用者最有参考价值的故障记录下来排查思路比最终答案更重要。6.1 Myriad X掉线报device not found这是出现频率最高的故障。现象是跑着跑着推理突然中断重新执行OpenVINO程序能恢复但在高负载下很快又崩。用dmesg查看内核日志发现USB设备报错usb 1-1.2: reset high-speed USB device number 7 using ci_hdrc排查链路首先检查供电。Myriad X的典型功耗虽然只有一两瓦但瞬态峰值电流可以达到800mA到1A左右。i.MX8M开发板上的USB口如果直接供电很容易在推理高负载时触发过流保护。解决办法是使用带独立供电的USB Hub或者确认板卡USB口能稳定提供1A以上电流。其次检查USB线材质量。Myriad X要求至少是USB 3.0线缆劣质线材会让USB链路的信号完整性变差。我用一根普通Type-C线替换原装线之后掉线频率从每10分钟一次降到几乎没有。最后检查散热。Myriad X在高负载时表面温度可以到70℃以上温度过高会触发内部的过热保护机制表现为USB设备直接断开。这时候给它贴一个散热片问题立竿见影。6.2 摄像头花屏或只有半屏图像花屏通常出现在MIPI-CSI链路配置上常见原因是CSI接口的lane数设置与硬件实际连接不一致。IMX219默认是2-lane输出但有些套件在设计时把MIPI CSI接口做成了4-lane连接或者通过切换板子上的电阻来配置lane数。如果驱动和设备树中设置的lane数和实际不匹配就会导致信号错位图像花掉。排查方法是在设备树里检查csi节点csi1 { status okay; /* lane数在这里配置 */ port { csi1_ep: endpoint { remote-endpoint ov5647_ep; >def letterbox(img, size(300,300), fill128): h, w img.shape[:2] scale min(size[0]/h, size[1]/w) nh, nw int(h*scale), int(w*scale) resized cv2.resize(img, (nw, nh)) canvas np.full((size[0], size[1], 3), fill, dtypenp.uint8) y0 (size[0]-nh)//2 x0 (size[1]-nw)//2 canvas[y0:y0nh, x0:x0nw] resized return canvas检测结果回传的坐标是基于300x300画布归一化的在映射回原始图像时要先减去填充偏移量(x0, y0)再除以缩放比例scale才能得到正确的原始坐标。这一步在我早期项目中反复出错后来统一封装了一个坐标转换函数才彻底解决。6.5 存储卡损坏导致系统频繁卡死最后分享一个不太显眼但影响巨大的问题。在边缘设备上如果SD卡质量不好或者供电不稳ext4文件系统在掉电后容易出现静默损坏表现为系统运行一段时间后IO错误、进程卡死、甚至启动失败。我的排查方法是用smartctl查看SD卡健康状态但大多数嵌入式板卡上的SD卡不支持smart监控。替代方案是尽量使用符合A2标准的工业级SD卡或者直接改用eMMC启动。另外在软件层面把系统挂载为只读是一个很强的缓解手段根文件系统挂载为ro只有数据分区可写同时引入overlayfs来解决临时文件写入问题。这个方案虽然不能完全避免故障但可以把因文件系统损坏导致的系统崩溃概率降低一个数量级。最后再分享一点个人体会这套Edge AI Kit的硬件组合定位本身就是原型验证和中小规模部署i.MX8M它给你的是稳定可靠的平台Myriad X负责把模型推理做了8MP摄像头提供足够的输入质量。真正的开发难点从来不在单个模块而在于怎样让三者在同一套数据流里高速协同。如果你也准备在类似的异构边缘平台上做AI项目建议拿到板子的第一天就先画出完整的带宽和数据通路图把所有可能成为瓶颈的环节标记出来再决定每一段用什么样的实现策略。这样调优的时候你会比我一上来就乱试少走很多弯路。
返回列表