ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

端侧AI开发板实战:从YOLOv5部署到硬件调试与软件开发

端侧AI开发板实战:从YOLOv5部署到硬件调试与软件开发 Microduck-HD1910这块板子我断断续续折腾了大半年。最开始拿到手的时候连“点个灯”都折腾了半天后来一步步把训练好的YOLOv5模型跑到板载NPU上再后来接上摄像头做实时检测、把检测结果通过HTTP接口和RTSP推流输出整套链路才算真正打通。这篇教程就是我这大半年踩坑记录的完整版核心就是标题里的三件事模型部署、硬件调试、软件开发。这三个词看起来是三条独立的技术路线实际在端侧AI开发里是咬合在一起的。适合刚拿到类似开发板不知道从哪下手的初学者也适合算法工程师想把自己训练的模型真正跑在嵌入式设备上的场景。我尽量不写“你只需要照着敲命令”这种话。每一步我都会讲清楚为什么要这么做、参数为什么这么选、出了问题怎么排查。文中的命令和代码都是从我自己实际调试过程中整理出来的你可以直接抄但更建议先理解再动手。1. 项目拆解HD1910能干什么先盘一盘板子1.1 核心规格拆解这板子到底“硬”在哪Microduck-HD1910是一块典型的端侧AI开发板主控芯片是一颗四核Cortex-A55处理器主频1.8GHz板载NPU算力标称6 TOPSINT8。内存是2GB LPDDR4x存储是8GB eMMC。外设接口给的比较全一路MIPI-CSI摄像头接口、一个千兆网口、一个USB 3.0、一组调试串口还有若干GPIO和I2C/SPI总线。先说说这几项配置意味着什么。四核A55的CPU性能不算强但跑Linux系统和应用调度足够6 TOPS的NPU算力才是这块板子的核心价值它决定了你能在上面跑什么量级的模型。以我实测的情况看YOLOv5s在640×640输入下NPU单次推理大约在20到30毫秒之间也就是每秒钟能处理30到50帧这个水平做实时视频分析完全够用。如果换成YOLOv8s或者带Transformer结构的模型帧率会明显掉下来不是NPU不行是预处理、内存带宽和CPU搬运的开销会变成瓶颈。ISP和硬件编解码单元也值得一提。板子上的ISP模块负责处理摄像头RAW数据输出RGB/YUV图像质量比CPU软处理的要好得多H.264/H.265硬件编解码单元则能让你把推理结果直接编码成视频流推出去。这些硬件模块和NPU配合起来才构成了一台完整的边缘视频分析设备而不仅仅是一块能跑模型的开发板。1.2 树莓派5、通用IPC模组和HD1910怎么选很多朋友问我为什么不用树莓派5树莓派5的CPU性能确实比HD1910强不少但它的AI能力很尴尬没有内置NPU要么用CPU硬跑模型要么外接USB加速棒。CPU跑YOLOv5s640×640输入下大概要200到300毫秒一帧做实时视频分析压力很大外接加速棒虽然能提升推理速度但成本和功耗都上去了而且边缘设备的形态就变了。通用IPC模组比如市面常见的Hi3516系列又是另一个极端。这类芯片出货量大、成本低但开发资料的开放程度参差不齐模型转换工具链往往要签NDA才能拿到出了问题连社区求助都难。对于个人开发者和小团队来说上手门槛太高。HD1910走的是中间路线有NPU算力兜底模型部署链路相对完整配套的SDK、示例程序和文档在国内技术社区能找到不少讨论。它不适合拿来当纯计算平台跑科学计算也不适合做超低成本的量产IPC方案它最适合的场景就是“我要做一套端侧视觉AI原型并且希望尽快跑通”。当成打样验证平台用价值最大。我先把这个定位说清楚后面所有内容都是围绕这个定位展开的。1.3 这篇教程的完整路径整个开发链路其实就四步环境准备 → 模型部署 → 硬件调试 → 软件开发。环境准备解决的是“用什么工具编译、怎么连上板子”模型部署解决的是“训练好的权重怎么变成NPU能跑的格式”硬件调试解决的是“板子上的电源、时钟、外设是否正常工作”软件开发解决的是“推理能力怎么组织成一个稳定运行的应用”。这四个环节不是线性关系实际开发中经常要来回跳。比如模型部署好了推理结果不对排查半天发现是摄像头输出的图像格式不对这就从模型问题跳到了硬件调试问题。所以在动手之前先在脑子里把整条链路想一遍后面遇到问题会少很多焦虑。2. 环境准备3步搞定交叉编译工具链与串口通路2.1 主机环境与硬件连接串口是生命线开发这台板子建议准备一台Ubuntu 20.04的主机虚拟机也行但USB设备透传和串口映射在虚拟机里偶尔会有兼容性问题能原生跑就原生跑。硬件上需要Microduck-HD1910开发板一块、12V/2A电源适配器一个、USB转串口模块一个推荐CP2102或CH340方案、网线一根、MicroSD卡用来烧写系统镜像虽然板载eMMC有系统但SD卡启动调试起来更方便。接线的时候串口模块的RX接板子的TXTX接板子的RXGND必须接GND。很多新手第一次接串口没反应十有八九是TX和RX接反了或者只接了两根信号线没共地。板子的调试串口通常标注为UART0或者DEBUG波特率一般是1152008N1。为什么要强制你用串口而不是SSH因为串口是板子的最后一条退路。系统还没完全起来的时候、内核崩溃的时候、U-Boot需要中断的时候只有串口能看到输出、能交互。SSH是在系统正常运行之后才有的东西。我自己的习惯是调试串口永远插着网线也插着串口看日志、网口传文件各干各的活。2.2 安装交叉编译工具链与SDK三步完成拿到SDK压缩包后习惯上放到~/workspace/hd1910_sdk目录下。SDK里的交叉编译工具链是ARM架构的gcc版本一般是8.3或者9.2。安装过程其实就是解压、配置环境变量、验证版本三个动作mkdir -p ~/workspace/hd1910_sdk # 将SDK压缩包拷贝到该目录后解压 tar -xzf hd1910_sdk_v1.2.tar.gz cd hd1910_sdk_v1.2 # 安装交叉编译工具链以arm-linux-gnueabihf 8.3为例 tar -xJf toolchain/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz -C /opt/ export PATH/opt/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin:$PATH # 验证 arm-linux-gnueabihf-gcc --version如果看到gcc版本信息正常打印交叉编译环境就绪了。接着把SDK里的工具链路径和库路径写进~/.bashrc不然每次开终端都要重新export。为什么要用交叉编译而不是直接在板子上编译两个原因首先是板端CPU能力有限在板子上编译一个大工程可能要半小时主机上只要几十秒更重要的是SDK提供的工具链针对这颗芯片做了优化链接库和启动文件都是配套好的你用通用的arm gcc去编译很可能会因为库版本不匹配遇到各种诡异问题。在端侧开发中交叉编译是标配技能。2.3 第一次编译运行串口打印Hello HD1910环境准备好以后第一个实验建议做最小验证写一个Hello World程序交叉编译放到板子上跑确认整条编译-传输-运行链路是通的。#include stdio.h int main(void) { printf(Hello Microduck-HD1910!\n); printf(NPU Dev Board Ready.\n); return 0; }编译命令很简单arm-linux-gnueabihf-gcc hello.c -o hello然后用scp通过网口传到板子上scp hello root192.168.1.110:/root/板子的IP地址怎么确定最简单的方式是板子和主机用网线直连板子默认开启DHCP的时候会给一个169.254.x.x的地址或者你手动把主机配置成和板子同一网段在串口里用ifconfig查看板子当前的IP。传上去之后执行chmod x hello ./hello如果串口终端里打印出了Hello输出说明主机-网络-板子-串口-交叉编译这套基础链路全部打通。这一步看着简单但它是后面所有工作的地基。我见过不少同学的板子在这种基础环节卡住反而是后面模型部署走得很顺。提示如果板子系统里缺少glibc动态库编译的时候可以加上-static参数编一个静态链接版本避免依赖问题。嵌入式环境里这是很常见的处理手段。3. 模型部署链路从训练好的YOLOv5到板端NPU推理3.1 模型导出ONNX你需要关心的三个参数模型部署的第一步是把PyTorch训练好的best.pt权重导出为ONNX格式。YOLOv5官方仓库里提供了现成的导出脚本命令大致如下cd yolov5 python export.py \ --weights best.pt \ --include onnx \ --imgsz 640 \ --batch 1 \ --opset 11 \ --simplify这几个参数里最有讲究的是batch、opset和simplify。batch我强烈建议固定为1。端侧推理一次处理的通常就是一张图固定batch可以让模型的输入输出的shape在转换时写死避免动态shape导致的麻烦。NPU对动态shape的支持普遍比GPU差一旦输入尺寸有变化很可能触发重新编译或者直接报错。opset一般选11。ONNX算子集版本太高NPU的转换工具不一定认识选太低又可能缺少一些新算子。以当前主流端侧NPU工具链的兼容性来看opset 11是适用范围最广、踩坑最少的选择。--simplify会调用onnx-simplifier工具把模型里的冗余算子、恒等映射、多余的Transpose折叠掉。这一步对NPU部署尤其重要因为GPU和CPU运行时不介意的算子NPU可能不支持简化后的模型结构更干净转换成功率更高。导出之后建议先用Netron打开看一眼计算图确认输入节点是images、输出节点是output0shape是[1, 25200, 85]这种典型的目标检测头结构。这一步能让你直观了解模型结构是否符合预期也能减少后面转换报错后的排查时间。3.2 模型转换与INT8量化精度掉点的根源和补偿ONNX还不是NPU能直接执行的格式。你需要用HD1910配套的模型转换工具把ONNX转换成NPU专用的模型格式。转换工具的名字不同厂商叫法不同有的是rknn-toolkit有的是自研的convert工具但核心流程是一致的加载ONNX模型、配置量化数据集、设置输入格式、生成可部署的模型文件。以我用的转换工具为例关键脚本结构如下from convert_tool import HD1910Converter converter HD1910Converter( onnx_pathbest.onnx, output_pathbest_hd1910.duck, input_size[1, 3, 640, 640], quantizeTrue, quant_datasetcalibration_images/, target_platformhd1910_npu ) converter.convert() converter.export()这里最容易翻车的是量化环节。NPU的INT8推理算力是6 TOPS但如果用FP16推理算力大概会掉一半以上所以我建议默认开启INT8量化。量化之后模型体积缩小到原来的四分之一左右推理速度提升但精度可能会下降。量化掉点的原因说起来很直白网络里的权重和激活值原本在FP32里可以表示成非常精细的小数变成INT8后只能表达256个离散整数相当于把一条平滑的曲线强行改成了阶梯状。偏差一定会存在问题是怎么把它控制在小范围内。我的经验是量化校准数据集的选择比什么都重要。不要直接用训练集的图片去做校准最好准备100到200张覆盖真实应用场景的图片。比如你做的是工厂质检采集的应该是工厂流水线上的真实图像你做的是道路监控就用实际摄像头拍的道路图像。校准集和真实场景的分布差异越大量化后的精度损失越严重。如果量化后mAP从0.93掉到0.8以下尝试下面几个手段第一检查预处理中和训练时是否一致包括归一化系数、RGB/BGR顺序、letterbox的比例第二把模型中某些对精度影响大的层比如Detect头的前几层设置为不量化保留FP16甚至FP32计算这种混合精度策略在工程中用得非常多第三增加量化校准集的图片数量我从50张增加到200张后部分模型的精度能回升3到5个点。3.3 板端推理Python快速验证到C正式接入模型转换文件有了接下来就是在板子上跑推理。先用Python做快速验证因为Python侧调试方便、出问题能看到明显的异常堆栈适合确认模型是否真的被NPU正确加载。在板端Python环境中推理代码大致如下import hd1910_runtime as rt import numpy as np from PIL import Image model rt.load_model(best_hd1910.duck) input_tensor np.zeros((1, 3, 640, 640), dtypenp.float32) # 模拟读入一张图片并做预处理 img Image.open(test.jpg).resize((640, 640)) input_tensor[0] np.asarray(img).transpose(2, 0, 1).astype(np.float32) / 255.0 outputs model.inference(input_tensor) print(outputs.shape) print(outputs)如果你只是验证精度上面的代码勉强够用。但注意一点这里直接transpose会把HWC转成CHW然后除以255归一化你必须确认这和训练时的预处理完全一致。YOLOv5训练时用的是RGB、归一化到0到1、letterbox处理你部署时也得这么做。我见过太多人在这翻了跟头模型转换全对最后输出全是乱码怎么查都查不出来其实只是图像通道顺序和归一化范围不一致。Python验证没问题后正式产品里还是得用C。原因很简单Python解释器在嵌入式平台上占用资源多、启动慢而且依赖库的部署这件事本身就容易把人逼疯。C推理的骨架如下#include hd1910_runtime.h #include vector #include cstring int main() { auto model hd1910_load_model(best_hd1910.duck); if (!model) return -1; // 模型输入: 1x3x640x640, 输出: 1x25200x85 std::vectorfloat input(1 * 3 * 640 * 640, 0.0f); std::vectorfloat output(1 * 25200 * 85, 0.0f); // 假设 input 已经填充好预处理后的图像数据 hd1910_set_input(model, input.data(), input.size()); hd1910_run(model); hd1910_get_output(model, output.data(), output.size()); // 后处理: NMS、过滤低置信度框 post_process(output); hd1910_release(model); return 0; }这里再强调一个容易踩坑的地方NPU的输入输出通常要求内存对齐有的芯片要求64字节对齐有的要求128字节对齐。你用std::vector分配的内存不一定满足对齐要求保险的做法是使用SDK提供的内存分配API或者直接用posix_memalign申请对齐内存。搞不定这个推理时大概率会报内存访问错误或者输出结果错乱。4. 硬件调试实战上电、启动、摄像头三大关4.1 上电时序与供电最容易忽视的第一道坎你可能觉得硬件调试离算法很远但模型在板子上跑不动的时候你才会意识到硬件是底层约束。我先从上电说起。Microduck-HD1910的上电时序是芯片厂商设计好的各电源域之间有先后顺序。你手里的开发板已经把DC-DC电路做完了自己不需要太关心时序细节但有两个点必须注意供电电流和电源质量。这块板子加上摄像头模组、NPU满载运行时电流可以到2A左右。如果电源适配器标称12V/1A轻载的时候看起来一切正常一旦NPU开始大量计算电压就会被拉垮板子会瞬间重启或者NPU推理报错。我自己就遇到过这类问题跑Python小模型一切正常一上YOLOv5推理就崩溃查了很久才发现是电源功率余量不足。排查办法很简单用万用表测板子上12V输入端的电压空载时如果低于11.5V或者推理时电压波动超过0.5V这个电源就不合格换一个12V/2A以上的再试。有示波器的话看纹波几百毫伏的纹波在NPU高速开关时是致命的。4.2 启动日志分析串口输出里的藏宝图板子上电后串口里会滚动输出一大段启动信息。这些信息在初看时可能是一堆天书但它是排查启动问题的关键线索。正常的启动日志大致分三个阶段U-Boot、内核、文件系统。先看U-Boot阶段。日志里会出现芯片型号、内存大小、启动介质信息。当看到Hit any key to stop autoboot时按下回车可以进入U-Boot命令行这是修改启动参数、切换启动介质的重要入口。如果日志停在这一行之前不动多半是DDR初始化失败或者时钟配置错误这种情况用户基本无能为力大概率是板子硬件问题。内核阶段看Starting kernel ...之后的输出。如果卡在某一行没有继续推进优先怀疑设备树dtb和外设驱动。我遇到过启动卡在Waiting for root device /dev/mmcblk0p2的情况这说明内核找不到根文件系统排查方向是SD卡分区表是否正确、根分区是否存在、U-Boot传给内核的root参数是否指向了正确的分区。最后是文件系统阶段。看到Welcome to ...或者登录提示符系统启动就完成了。整个过程如果有任何一步报错或者卡死先把卡住时最后几行日志完整截下来发到社区求助或者对照厂商文档信息足够别人才能帮你定位。注意排查启动问题截图不如复制文字。串口终端里最好开启日志保存功能minicom可以用-C参数指定日志文件别等出了问题才后悔没留日志。4.3 摄像头调试让NPU有料可算部署在HD1910上的视觉应用图像来源多半是MIPI-CSI接口的摄像头模组。先把摄像头物理接好然后在板端确认设备节点是否存在v4l2-ctl --list-devices正常情况下你应该看到类似microduck-camera的设备节点通常是/dev/video0。接着测试单帧采集v4l2-ctl --device/dev/video0 --set-fmt-videowidth1920,height1080,pixelformatNV12 \ --stream-mmap --stream-count1 --stream-toframe.raw执行完如果生成了frame.raw文件说明视频通路已经通了一半。接下来把这个文件拷回主机用YUV播放工具打开看内容。如果画面是绿色或者花屏大概率是MIPI通道配置错误或者ISP初始化失败如果是全黑的检查摄像头模组电源和时钟是否正常。帧率和分辨率的问题也很常见。sensor驱动对时钟频率很敏感配置不对会导致帧率减半或者图像撕裂。这块板子的ISP可以输出1080p30fps我实际测试时如果sensor驱动配置正确v4l2-ctl --stream-mmap --stream-count100采集100帧应该是不到四秒钟就完成。摄像头调试是整个硬件环节里最磨人的部分因为它涉及的链条最长sensor上电 → MIPI时钟 → ISP初始化 → V4L2驱动 → 应用层读取任何一环出问题都表现为“没有图像”或“图像不对”。推荐的做法是用厂商SDK里自带的摄像头测试程序先跑通确认硬件没问题再切换到自己的代码不要一上来就用自己写的采集程序去调试硬件。4.4 NPU性能监测怎么看推理有没有跑满模型跑起来之后很多人关心一个实际的问题NPU到底被利用了多高总感觉推理速度慢又说不清瓶颈在哪。HD1910的Linux内核里暴露了一些sysfs节点可以查看NPU频率、温度、使用率等信息。例如cat /sys/class/misc/hd1910_npu/device/freq cat /sys/class/misc/hd1910_npu/device/utilization cat /sys/class/misc/hd1910_npu/device/temp如果不是root用户记得加sudo。另外SDK通常还会提供一个hd1910_perf命令行工具可以统计单次推理的耗时和NPU占用率。我实测的结论是很多项目里NPU利用率只有30到50%CPU反而长期处于高负载。这是因为模型输入的前处理图像缩放、格式转换、归一化都在CPU上跑如果缩放算法效率低或者做了多余的拷贝CPU就成了瓶颈。不要一觉得卡就去优化模型网络结构先用perf工具定位瓶颈到底在NPU还是CPU再对症下药。5. 软件开发落地把推理能力封装成可用的应用5.1 架构设计一个可扩展的AI视频流水线模型跑通、硬件稳定之后接下来就是把这套能力变成真正能用的产品功能。最忌讳的做法是把采集、推理、显示全部塞进一个while(1)循环里。这样写demo可以但一旦要加功能、改逻辑、做性能优化就会牵一发动全身。推荐的做法是流水线架构四个模块——图像采集、预处理、模型推理、后处理输出模块之间用队列解耦。采集线程只负责把摄像头帧放进队列就返回推理线程从队列取帧、做预处理、调用NPU推理、后处理把结果放到输出队列输出线程负责叠加画面、推流、上报HTTP或MQTT。用队列解耦最大的好处是每一级都能独立调优。采集速度慢不会卡住推理推理速度跟不上也不会丢了后面的输出。你可以在推理线程里做丢弃策略队列满就丢最旧的帧保证实时性优先。5.2 C多线程实现代码骨架与内存管理下面给一个简化但能在HD1910上跑起来的C多线程骨架核心思路是用三个线程和两个队列#include thread #include mutex #include condition_variable #include queue #include memory struct Frame { std::vectoruint8_t data; // 图像原始数据 uint64_t timestamp; }; std::queueFrame input_queue; std::queueFrame output_queue; std::mutex in_mtx, out_mtx; std::condition_variable in_cv, out_cv; void capture_thread() { while (running) { Frame f; // 从V4L2读取摄像头数据到 f.data { std::lock_guardstd::mutex lock(in_mtx); if (input_queue.size() 5) { input_queue.push(std::move(f)); in_cv.notify_one(); } // 队列满则丢弃当前帧 } } } void inference_thread() { Frame f; while (running) { { std::unique_lockstd::mutex lock(in_mtx); in_cv.wait(lock, [] { return !input_queue.empty(); }); f std::move(input_queue.front()); input_queue.pop(); } // 预处理 NPU推理 后处理 std::vectorDetection dets run_inference(f.data); Frame out overlay_and_encode(f, dets); { std::lock_guardstd::mutex lock(out_mtx); output_queue.push(std::move(out)); out_cv.notify_one(); } } } void output_thread() { while (running) { Frame f; { std::unique_lockstd::mutex lock(out_mtx); out_cv.wait(lock, [] { return !output_queue.empty(); }); f std::move(output_queue.front()); output_queue.pop(); } // 推流或通过网络上报 } }这个骨架看起来简单但已经足够在真实项目里跑起来。有两个细节要提醒第一如果要做极致性能std::queue的锁竞争会成为瓶颈可以考虑用环形缓冲区的无锁队列替代第二图像的拷贝开销非常大尽量用移动语义或者共享指针传递Frame对象不要在队列里反复复制整帧数据。我实际调过的项目里仅仅消除图像深拷贝端到端延迟就能降低30%。5.3 结果输出叠加画面、HTTP接口与消息推送推理结果怎么给出去至少有三种方式视频流叠加画面、HTTP JSON接口、MQTT消息推送。具体用哪种取决于业务场景。视频流叠加适用于需要人眼查看监控画面的场景。做法很简单拿到检测框坐标后用CPU在RGB图像上画框和标签然后把图像送给硬件编码器编码通过RTSP推流。HD1910的硬件编码器可以处理1080p30编码基本不影响NPU推理性能。HTTP接口适合对接平台。比如在板子上跑一个小型HTTP服务提供一个/detect接口接收图像或加载指定通道的最新帧返回JSON格式的检测结果。这个方案的好处是调试简单用浏览器或者Postman就能看结果。// 伪代码HTTP回调中返回检测结果 void on_http_request() { Frame f get_latest_frame(); auto dets run_inference(f); json result to_json(dets); send_response(result); }MQTT则适合IoT场景。检测到异常事件时通过MQTT发布消息到云端或服务端比如火灾检测、人员闯入这类事件型应用。这种模式下板子不需要维护长连接资源占用低更适合电池供电或弱网环境。开发软件的时候一定时刻牢记一个原则成品要看的是稳定性和可维护性。功能做到位只是第一步长期运行不内存泄漏、断电重启能自恢复、日志清晰可排查这些才决定项目能不能真正从开发台走向机房和现场。6. 高频问题排查与经验价值提炼6.1 模型部署期的高发问题问题一量化后精度严重掉点。前面说过校准集的重要性。如果你校准集没问题但精度还是掉得离谱可以考虑混合精度量化把Detect输出层之前的几个卷积层保留为FP16代价是推理速度略微下降但精度回升明显。我的经验是精确找出敏感层的方法很笨但有效逐个把某个层改成不量化跑一遍测试集看精度变化虽然耗时但定位准确。问题二算子不支持导致转换失败。比如模型里用了GridSample或者自定义的SiLU实现不当NPU工具链会报“unsupported operator”。解决办法有两种一种是替换成等价的算子组合比如把某些上采样操作改用转置卷积另一种是回退到CPU执行这个算子NPU上只跑主干网络。这两种做法各有利弊替换算子的方式能保性能但工作量不定CPU回退方式实现快但会拖慢整体速度。问题三模型转换成功但推理输出全零或乱码。首先确认输入tensor的内存布局是不是和转换时一致。其次打印一下原始ONNX模型的输出和NPU模型输出的对比如果FP32参考推理的结果和NPU结果的差距很大多半是输入预处理不一致。最后看内存对齐用SDK分配的内存接口重新申请输入缓冲区这个坑我至少踩了三次。6.2 硬件与系统的典型故障速查表现象可能原因排查动作解决方案上电后没有任何输出电源灯不亮电源未接、电源损坏、板级短路万用表量电源输出和板端电压测试点更换12V/2A电源串口无输出串口线接反、未共地、波特率不对、串口模块驱动未装检查TX/RX/GND接线与波特率设置lsusb查看模块是否识别调整接线安装CH340等驱动启动卡在ubootDDR初始化失败、启动介质异常检查日志最后的输出点尝试进入uboot命令行重新烧写uboot联系厂商确认硬件摄像头画面花屏MIPI时钟配置错误、ISP未初始化完成检查dmesg中的mipi/isp日志对比sensor驱动配置重新加载sensor驱动检查设备树参数NPU推理时板子重启供电电流不足、过热保护万用表测电压cat /sys/class/misc/hd1910_npu/device/temp查温度换大功率电源加装散热片或风扇推理速度远低于预期CPU预处理瓶颈、NPU未跑满用perf工具统计CPU/NPU耗时占比优化预处理算法使用硬件缩放模块6.3 几条带血的个人经验第一先把全流程最短路径跑通再优化性能。拿到板子的第一周不要想着把模型精度调多高、帧率跑到多快而是要确保“摄像头画面 → 推理输出 → 结果可视化”这条路能闭环。一条从零到一的链路上会遇到无数意想不到的问题链路通了之后再谈优化才有抓手。第二不要迷信官方demo。官方示例程序通常只负责展示最理想的状态真实场景里的光照条件、输入尺寸、目标形态都更复杂。把官方demo当作参考手册而不是答案出现问题时要敢于自己动手改代码来验证猜测。第三版本管理要严格。SDK版本、模型转换工具版本、板载固件版本、甚至摄像头sensor驱动的版本这些东西每次升级都可能带来行为变化。我习惯在每个项目目录里放一个VERSIONS.md文件记录所有关键组件的版本号和日期排查问题时先看它能省下大量时间。第四不要在板子上折腾编译。板端容量小编译大项目会频繁报“No space left on device”而且长时间高负载运行对散热也是考验。主机交叉编译虽然初期配置麻烦点但长期来看效率最高这也是为什么第2章花了那么大篇幅讲环境搭建。第五别急着在这块板子上跑大语言模型。2GB内存和6 TOPS算力摆在那里硬上量化后的Llama或Qwen速度会很感人。这块板子的正确用法是把视觉推理做好做透搞定实时的目标检测、分类、分割任务这已经是端侧AI里最实用的方向了。大半年玩下来我最深的体会是端侧AI开发项目最后比拼的是系统工程能力。模型部署只是把算法从一个平台搬到另一个平台硬件调试要求你懂电源、时钟和总线软件开发则要有产品思维和代码洁癖。每一块都是单独的学问但它们最终会汇聚到“让一台边缘设备稳定、持续地产生价值”这同一个目标上。如果你现在刚拿到Microduck-HD1910别被这篇长文吓住。按着第2章把环境搭好第3章用官方示例模型跑通一次推理你就会有感觉了。剩下的都是在一条已经走得通的路上把路修得更好。
返回列表