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

资讯详情

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

嵌入式AI实战:YOLOv5在海思Hi3559A上的完整部署指南

嵌入式AI实战:YOLOv5在海思Hi3559A上的完整部署指南 简介本资源是面向嵌入式AI开发者与边缘计算工程师的YOLOv5模型移植工程聚焦于海思HiSilicon Hi3559A芯片平台的目标检测部署实践。资源解决了深度学习模型在国产AI处理器上高效落地的关键问题适用于安防监控、工业视觉、无人机巡检等低延迟、低功耗边缘场景。压缩包共836个文件43.34MB涵盖358个hpp与248个h头文件含NNIE加速接口与OpenCV DNN模块适配层、42个静态库.a与16个动态库.so如libopencv_dnn.so.4.1等核心依赖、17个CMake构建脚本及配套编译工具链完整支持模型量化、ONNX转换、NPU推理封装与交叉编译全流程。目前已有129人下载学习提供从源码结构、硬件抽象层封装到可执行bin生成的全路径工程支撑显著降低Hi3559A平台YOLOv5部署门槛。 干嵌入式AI这行的人对pt - onnx - caffe - om这条模型转换流水线应该都不陌生。我手上这个YOLOv5_Sisi3559A-YOLOv5基于hisi3559a.zip是一份把YOLOv5检测模型完整搬到海思Hi3559A平台上的移植包。很多人拿到这类包第一反应就是解压、翻README、跑Demo但实际走下来会发现从zip里那一堆文件变成板子上稳定的目标检测服务中间隔着交叉编译、算子转换、量化校准、NNIE配置好几道坎。这篇就顺着一个嵌入式开发者的视角把YOLOv5在Hi3559A上落地的完整路径和踩坑记录写清楚。如果你手头正好有类似的包或者打算把YOLOv5搬到海思、瑞芯微这类带NPU的芯片上这篇能帮你省掉不少时间。1. 为什么YOLOv5和海思3559A会被装进同一个压缩包先看包名YOLOv5_Sisi3559A。Sisi3559A大概率是个人或团队的项目代号hisi3559a才是核心。海思Hi3559A是安防、智能相机领域非常经典的SoC内部集成了双核A73双核A53还有一颗官方标称在INT8下约1.7 TOPS算力的NNIENeural Network Inference Engine加速单元。这颗芯片在它活跃的那个时期是端侧跑检测网络的性价比之选所以有大量IPC、边缘盒子、智能摄像头设备跑在它上面。YOLOv5能跟它凑到一起逻辑很清楚模型够轻。YOLOv5s权重文件只有十几MBINT8量化后还能再压一半适合端侧部署。精度够用。在COCO上mAP漂亮直接拿来做业务场景检测人、车、人脸、安全帽之类完全够。导出链路成熟。官方提供了export.pyPyTorch转ONNX几乎一键社区又补上了ONNX转Caffe、Caffe转NNIE这条路。部署资料多。YOLOv5的预选框解码、NMS逻辑都是公开的嵌入式平台移植时只需要把网络计算交给NNIE前后处理在CPU上补齐可操作性很强。换句话说这颗包不是某个人的自嗨它代表了那个阶段端侧AI落地的一个典型组合。适合谁来参考两类人一类是要在海思3559A上从头部署YOLOv5的另一类是想了解嵌入式NPU部署通用流程、但手上暂时只有CPU平台的开发者。1.1 3559A这类芯片在边缘AI里的真实位置现在很多人一上来就聊RK3588、Jetson Orin但真实项目里大量存量设备和在用方案还是基于海思、瑞芯微旧平台。3559A的定位是省电、稳定、成本可控它能跑YOLOv5s跑不了太大模型所以部署时你会看到很多压缩手段输入尺寸砍到640甚至416、INT8量化、只跑检测头不跑分类头。理解了这层约束再看包里的配置和脚本就不会觉得为什么这么麻烦。1.2 YOLOv5在嵌入式部署的优势与代价YOLOv5整个网络结构是标准CNNFPN检测头没有特别冷门的算子大部分都能在NNIE上找到映射。代价是你要手动处理Focus层、SiLU激活和SPP结构——这些在海思的工具链里没有原生算子。后面第四章细说。1.3 包里到底可能装了什么目录与文件推演结合命名习惯和这类项目的常见组织方式合理的包内结构一般是这样的YOLOv5_Sisi3559A/ ├── README.md ├── sdk/ # 海思SDK或依赖库 ├── caffe_model/ # 转换后的caffemodel、prototxt ├── nnie_cfg/ # NNIE配置文件sample_config.json之类 ├── sample/ # 推理示例代码 │ ├── build.sh │ ├── yolo5_detect.cpp │ └── Makefile ├── scripts/ # 模型转换、校准集生成脚本 └── tools/ # onnx2caffe、量化工具等不一定每个包都长这样但八九不离十。拿到手先别急着改代码把目录结构、README、转换脚本理一遍比什么攻略都有用。2. 动手解压前先别急zip校验与三类解压报错排查我见过太多人卡在加压这一步。热搜词里反复出现file is not a zip file、invalid zip archive: could not find EOCD这两个错误我几乎每周都能在群里看到一次。先说结论这两个报错大概率不是解压软件有问题而是文件本身不完整、格式不对或者改错了扩展名。2.1 先校验文件完整性别让坏包浪费一晚上Linux下解压前先看文件类型file YOLOv5_Sisi3559A-YOLOv5基于hisi3559a.zip正常会输出Zip archive data, at least v2.0 to extract。如果输出显示data或者gzip compressed data说明这个文件不是标准zip可能是传输过程中被截断也可能它压根是7z/rar被改名成了zip。用unzip -t做完整性测试unzip -t YOLOv5_Sisi3559A-YOLOv5基于hisi3559a.zip这条命令会逐个entry校验CRC末尾输出No errors detected in compressed data of this archive才算干净。-t是test不是解压跑完不会破坏原文件。Windows端可以先校验文件哈希再解压。下载页面通常会给出SHA256计算一下能提前发现80%的问题。2.2 file is not a zip file和could not find EOCD到底在说什么EOCD是End Of Central Directoryzip文件末尾的一条记录相当于zip的目录索引。解压程序要靠它找到所有文件的位置。如果报could not find EOCD意思是文件末尾缺少这条索引常见原因网络下载中断文件只下了一半。通过QQ、微信、网盘等渠道传输文件被处理工具改写或截断。复制/移动过程中磁盘空间不足文件没写全。文件本身是伪装成zip的其他格式。解决思路是按顺序排查先用ls -lh看文件体积是否和源头一致再file确认真实格式最后再用工具修复。2.3 用Linux命令把包从崩溃边缘救回来如果是轻微损坏可以用zip自带的修复能力zip -FF damaged.zip --out fixed.zip-FF会尝试从原包里恢复可以读取的entry。不过它只对结构稍有破损的zip有效如果EOCD完全丢了可以用7z强行解压7z x damaged.zip7z的解析器比unzip更宽容有时能直接解出内容。实在不行再检查网盘、传输工具是不是对文件做了二次处理比如某些聊天工具会把zip包改成.zip_重命名之类的格式。还有一个实用技巧如果目标包很大只想解压其中某个子目录不用全量解压unzip package.zip caffe_model/* -d output_dir2.4 关于zip密码与加密包的一个提醒热搜里有zip密码移除、zip密码恢复、超人zip解密助手这类词。密码恢复只适用于一个合法场景自己加密过的历史压缩包、忘记密码且能证明归属权。常用的手段是zip2john配合john跑字典或掩码攻击zip2john encrypted.zip hash.txt john --wordlistrockyou.txt hash.txt这个流程在技术上是成熟方案但我建议只在自己有明确权限的包上使用别拿去做任何可能涉及侵权的尝试。如果包是项目方分享的先找对方要密码比自己跑字典快得多。3. 交叉编译环境搭建从SDK到能跑通的hello_world解压只是开始真正的坑在编译环境。Hi3559A是ARM架构板子上自带Linux系统但一般不在板子上直接编译——交叉编译是标准做法。也就是在x86 PC上用海思提供的工具链生成能在ARM板子上跑的可执行文件。3.1 为什么必须在PC上交叉编译而不是板子上直接编板子资源有限编译YOLOv5推理工程动辄需要几个GB的临时空间和较长CPU时间加上SDK依赖库、宏定义、头文件路径都按PC端工具链配置好了在板子上编译反而容易踩到缺依赖、路径错、版本老这三座大山。所以在PC上把静态链接、动态库路径都处理好再通过scp或nfs把可执行文件送到板子上是效率最高的做法。3.2 工具链与SDK版本的不兼容是最早遇到的坑海思官方SDK通常会带一个osdrv目录里面有交叉编译工具链的安装脚本例如arm-himix100-linux或aarch64-himix100-linux。安装后记得把工具链路径加入PATHexport PATH/opt/hisi-linux/x86-arm/aarch64-himix100-linux/bin:$PATH这里最容易出的问题老SDK基于Ubuntu 14.04/16.04编写直接在Ubuntu 18.04/20.04上安装会报libncurses.so.5 not found之类的依赖错误。解决办法是安装兼容库sudo apt install libncurses5 libncurses5-dev更老的SDK还可能在make阶段使用一些已经不兼容的gcc参数此时我会先看SDK自带的文档说明确认支持的操作系统版本。不要为了用新系统硬扛我实测过Ubuntu 16.04虚拟机配合老SDK反而最省心。还有一个容易忽略的点检查工具的位数。老SDK工具链可能是32位版本64位Linux上需要先安装lib32z1、lib32stdc6等运行库否则执行工具链时直接cannot execute binary file。3.3 最小验证先编译一个sample再谈YOLOv5不要一上来就编译完整YOLOv5工程。先用SDK附带的hello_world或sample编译一遍确认工具链正常。比如海思MPP的samplecd sdk/mpp/sample make SENSOR0xxx能跑通之后用file确认生成的可执行文件是ARM格式file sample_vdec # 输出中应该包含 ARM aarch64这一步通过说明交叉编译环境没问题。接下来才进入YOLOv5模型落地的正题。环境变量也是一坑。海思SDK的Makefile通常依赖SDK_PATH、MPP_PATH这类全局变量很多人忘了export导致编译时找不到头文件。我都会在~/.bashrc里显式写清楚export SDK_PATH/opt/hisi_sdk export MPP_PATH$SDK_PATH/mpp export NNIE_PATH$SDK_PATH/mpp/component/nnie4. YOLOv5模型全链路转换pt到ONNX到Caffe再到NNIE这是整条链路里技术含量最高、也最容易劝退的一步。海思NNIE工具链不支持直接吃PyTorch模型官方路线是Caffe。而YOLOv5官方只导出PyTorch和ONNX所以必须走pt - onnx - caffe - NNIE这条四段式路线。4.1 算子在3559A上的生存法则Focus、SiLU、SPP怎么处理YOLOv5有几个结构在NNIE上不能直接跑Focus层本质是切片通道拼接操作NNIE不支持。解决办法是在转换之前把Focus展开成ConvConcat。常见落地方式是用nn操作把它写成显式的slice和concat或者干脆在导出ONNX时用torch.onnx.export的算子优化。SiLU激活YOLOv5默认使用SiLU也叫SwishCaffe/NNIE不直接支持。解决方法是替换成Sigmoid Mul的组合表达式。SPPSpatial Pyramid PoolingYOLOv5s的SPP模块包含多个不同size的MaxPool分支NNIE的MaxPool支持受限尤其是kernel size大于16的情况要特别小心。通常做法是保持小kernel的MaxPool大kernel分支用多个小池化堆叠近似。处理完这些建议先用onnxsim做一遍简化把冗余节点清掉python3 -m onnxsim yolov5s.onnx yolov5s_sim.onnx结构确认无误后再进入Caffe转换。这一步有人用jameslahm/onnx2caffe也有人用TNT我没法说哪个绝对好但原则是转换后必须对比Caffe模型和ONNX模型的逐层输出确保数值误差极小否则后面NNIE上的所有问题都会变得无法定位。4.2 用RuyiStudio做NNIE模型转换与量化校准海思的工具链里有个图形工具叫RuyiStudio支持把Caffe模型转换成NNIE可执行的.wkweight文件。核心配置项包括input_typeYOLOv5一般是RGB图片设置bgr或rgb时要注意和实际预处理保持一致。norm_type均值/方差需要和训练时一致YOLOv5训练时通常做的是归一化到0~1这里不要搞错。data_type量化位宽选择INT8配合校准集。一个典型配置片段{ input_type: bgr, mean: [0, 0, 0], norm: [0.003921569, 0.003921569, 0.003921569], quantize: int8, calibration_image_dir: ./calib_images }这里有个常见坑YOLOv5训练的预处理是把像素除以255转化为0~1区间如果NNIE在推理阶段自动归一化那代码里就别再除以一次。两者重复精度会明显劣化。所以每次转换时都务必核对一遍预处理链路。4.3 校准集选多少张、量化失败怎么定位量化不是凭空做需要准备校准图片。建议从真实业务场景里抽500~1000张而不是随便从ImageNet拉图片。实测下来校准集如果和业务场景差异太大INT8量化后的mAP会掉3~5个点这个损失在端侧项目里非常明显。如果量化后精度掉得离谱排查顺序是确认ONNX转Caffe时算子数值一致。确认预处理归一化、通道顺序、letterbox一致。确认校准集和推理场景分布一致。尝试混精度把敏感层改成FP16其他层保持INT8。4.4 训练侧的配合超参数、数据集格式与单通道模型转换走到一半很多人会回头发现训练侧就有问题。比如热搜里的yolov5训练自己的数据集、yolov5超参数、yolov5训练单通道。这里集中说一下数据集YOLOv5用images和labels两个目录每张图对应一个同名txt每行是class x_center y_center width height归一化坐标。类别从0开始data.yaml里定义nc。格式不对训练出来的模型在部署端做anchor解码时坐标全是乱的这一点在转换和移植时极难排查所以训练前就要确认格式。超参数data/hyps/hyp.scratch.yaml里最影响部署的是anchors。如果关掉自动anchorautoanchorFalse模型输出层的anchor尺寸必须和实际数据匹配迁移到3559A时检测输出解析要按这个模型的anchor来写不要照抄别的模型。单通道有些工业检测场景是灰度图。YOLOv5官方模型输入是三通道RGB训练单通道需要改模型第一层把model里第一个Conv的输入通道由3改成1。对应在NNIE端输入类型也要同步改否则模型尺寸对不上转换直接报维度错误。训练侧还有一个容易忽略的点YOLOv5的检测头输出包括xywh和objectness、class_prob它们在NNIE上是以三个feature map输出的每个输出对应不同的stride8、16、32。部署时解析输出需要先把xywh解码到原图坐标再做NMS。如果你在3559A上跑出来的框位置整体偏移先检查解码逻辑里的stride和anchor是否和模型训练时一致。5. 板端推理代码的组织方式与性能瓶颈模型转换完成后生成.wk文件接下来是在板端调用NNIE API把它跑起来。常用的流程HI_MPI_SYS_Init初始化系统、NNIE_CREATE加载模型、NNIE_RUN执行推理、最后做后处理。说起来简单但实际跑起来会踩到几个和内存、排队有关的坑。5.1 NNIE的调用流程与内存管理要点NNIE推理通常需要先申请连续物理内存和MMZ内存然后用IOMMU映射到用户空间。海思SDK里提供了示例HI_MPI_SYS_Init(); SAMPLE_COMM_SYS_Init(); HI_MPI_NNIE_CREATE(...);关键点只有一个内存对齐。NNIE对tensor的起始地址、宽度、步长有严格对齐要求一般是16字节或64字节不满足时推理结果会错乱甚至直接段错误。我印象最深的一次就是把输入图片宽度设为608 * 2 1结果NNIE跑出来前两个类别的置信度全是乱码直到看SDK文档才发现需要把宽度向上对齐到16的倍数。推理过程中模型输入是一块、输出是三块。建议把输入输出tensor都预先分配好避免每帧重新malloc否则内存碎片会越来越严重嵌入式设备跑一晚上就可能崩。5.2 预处理细节决定了最终精度YOLOv5推理时图片要先做letterbox保持宽高比补灰色边缩放再把BGR通道送入NNIE。很多人在PC上跑YOLOv5时习惯了cv2.dnn.blobFromImage到了板子上以为也是同样逻辑结果忘了letterbox长宽比被拉伸检测框全偏。正确的流程读取原图计算缩放比例min(w_ratio, h_ratio)。缩放图片使得长边匹配输入尺寸。在短边方向填充灰边比如114或128灰值铺满输入尺寸。BGR顺序、归一化方式要和sample_config.json里配置一致。后处理时检测框坐标要按(x - pad) / scale映射回原图这一步漏了框的位置就会整体错位。5.3 实测性能瓶颈IO、NMS、多路并发3559A的NNIE只负责卷积和全连接等网络计算前后处理、解码、NMS都靠CPU。实测瓶颈往往不在算子上而在图片解码和缩放cv::resize在ARM上不如hi_mpp硬件缩放快用VDECVPSS能省一大截CPU。框的后处理YOLOv5输出的候选框数量通常几千个如果纯用openCV的NMS在ARM CPU上跑一帧可能要十几ms。改用std::sort按类别分组快速NMS后能降到几ms。多路视频流如果同时跑多路NNIE是分时复用的主要优化点是把各路的预处理和后处理分配到不同线程让NNIE在推理的同时CPU在做下一帧的预处理形成流水线。性能调优时我会先在板上打印每阶段耗时preprocess_ms、nnie_ms、postprocess_ms。哪一段高就优化哪一段不要凭感觉改。6. 从3559A到RV1106、RK3568一次移植处处通用热搜词里还有rv1106搭建yolov5模型、yolov5在rk3568上。这说明很多人其实是在不同NPU平台之间反复横跳。我自己的经验是一旦在海思上走通了YOLOv5部署全流程再去瑞芯微的RKNN工具、算丰的BMNNSDK思路基本是通的。6.1 三家NPU工具链的本质是同一件事不管是海思NNIE、瑞芯微RKNN还是算丰BMNNSDK核心都是四步把训练好的模型PyTorch/ONNX/TensorFlow转换成各自平台的模型格式.wk / .rknn / .bmodel。做量化校准选择校准集。编译生成目标平台的推理文件。在板端用各自的推理API加载模型跑前向并做后处理。所以遇到新平台先别慌找四个东西模型转换工具、量化校准脚本、推理API示例、文档里的算子支持列表。有这四样YOLOv5就能跑起来。6.2 跨平台移植时最值得先读的三个文件我的习惯是拿到一个平台SDK先读官方YOLO/检测模型示例sample代码它能告诉你预处理、输入输出格式、解码逻辑。算子支持文档确认Focus、SiLU、SPP是否需要自己绕路。量化参数文档确认归一化、均值、量化方式如何配置。读完后先把官方示例跑通再替换成自己的模型。很多移植失败都是因为一上来就想把自己训练的模型塞进去而对平台工具链的约束一无所知。6.3 训练侧配合部署的几个小习惯最后说几个我踩过坑之后养成的习惯训练时就在项目里固定输入尺寸比如640x640部署时不要随意换分辨率否则模型mAP白瞎。训练完立刻导出ONNX并做数值对比确认PyTorch和ONNX输出一致尽早暴露算子兼容问题。保存训练时的anchor和stride配置和.wk文件放一起部署代码里要用。记录预处理流水线letterbox、均值方差、通道顺序写进README。很多时候模型没变、代码没变就是板子上换了个人按旧的预处理习惯写结果把精度搞崩了。我在实际项目里每次拿到一个嵌入式YOLOv5包都会先按这套流程走一遍校验文件、理目录、搭环境、转模型、跑sample、做预处理对齐。这套流程少则半天多则一两天但比盲目改代码省太多时间。这次基于Hi3559A的zip包也让我把YOLOv5从训练到部署的链路又完整过了一遍。如果你手头的包也来自某个开源分享或内部交接里面文件换来换去很正常关键是掌握模型和部署之间的那几条硬约束这才是真正通用的东西。本文还有配套的精品资源点击获取
返回列表