ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv8 Pose姿态识别:ONNX导出、量化与部署完整指南

YOLOv8 Pose姿态识别:ONNX导出、量化与部署完整指南 简介人体姿态估计是计算机视觉中的核心任务旨在从图像中定位人体关键点。YOLOv8 Pose作为单阶段模型将目标检测与关键点回归统一于同一网络一次前向即可输出检测框和关键点显著简化部署流程。ONNX作为跨平台模型中间表示使PyTorch训练的模型能灵活迁移至不同推理后端。在实际工程中INT8量化是边缘设备部署的关键可大幅提升推理速度。无论是健身动作纠正还是安防行为分析姿态识别应用广泛。围绕YOLOv8 Pose从数据准备、模型训练、ONNX导出、量化优化到RK3588等平台部署的完整链路系统总结实际项目中的经验与常见问题排查方法为开发者提供从模型到落地的实践指南。 很多搞姿态识别的朋友都遇到过这个情况从网上下载或者从同事手里拷来一个Onnx Yolov8 Pose.rar解压之后发现里面是一个.onnx模型文件但又不知道怎么在具体项目里用起来或者跑通之后发现效果和预期差很远。这个标题背后其实是一个完整的链路YOLOv8 的姿态识别模型怎么训练、怎么导出 ONNX、怎么优化量化、最后怎么部署到实际平台。这篇内容就围绕这条链路把我实际跑过的方案和踩过的坑都讲清楚。我先把话说在前面姿态识别和普通的目标检测不一样目标检测只需要输出目标的类别和框但姿态识别还要额外输出人身上的关键点坐标和置信度。YOLOv8 Pose 的核心价值在于它把检测和关键点任务统一在一个网络里前向推理一次就能同时拿到检测框、类别和关键点部署起来比两阶段方案省事太多。再加上 ONNX 是跨平台的中转格式从 PyTorch 训练完到边缘设备推理中间基本都靠它衔接。1. 为什么是 ONNX 格式的 YOLOv8 Pose模型结构和部署逻辑1.1 YOLOv8 Pose 输出的不只是一个框先对齐一下基础认知。YOLOv8 的目标检测模型输出是[batch, 84, 8400]这么个张量84 代表 4 个框坐标加 80 个类别得分。但 YOLOv8 Pose 的输出格式不是这样它输出的是[batch, 56, 8400]以 COCO 17 个关键点为例。56 的构成是4 个框坐标 1 个目标得分 17 个关键点 × 2 个坐标 17 个关键点 × 1 个置信度也就是 4 1 34 17 56。这个差异在导出 ONNX 和写后处理代码的时候特别重要。有一个常见的坑把 Pose 模型的输出当成普通目标检测来处理结果后处理完全对不上关键点怎么都绘不出来。所以动手之前先确认自己的模型是哪一种yolov8n-pose.onnx这种文件名里的pose已经说明了它的性质。1.2 从 PyTorch 到 ONNX为什么非要过这一道手有人会问既然 PyTorch 模型也能直接部署为什么还要转化为 ONNX我个人的理由有三个。第一ONNX 是一个中间表示它不绑定 PyTorch 的运行环境目标平台上只要有一个 ONNX Runtime 或者能把它转成其他格式的转换器就可以。第二训练环境和服务端推理环境往往是隔离的很多嵌入式设备上根本没有办法装 PyTorchONNX 相当于一个通用交换格式模型训练好之后转成 ONNX 再分发到不同的推理后端。第三ONNX 本身带有一些计算图优化能力比如算子融合、常量折叠有时候转完之后的推理效率反而比直接用 PyTorch 更高。在模型量化和剪枝的场景下ONNX 也是一个很好的中间形态。比如后续要做 INT8 量化PyTorch 里的量化生态不如 ONNX Runtime 或者专门的转换工具成熟转成 ONNX 之后再做静态量化流程会顺畅很多。所以业界常见的做法就是PyTorch 训练 - 导出 ONNX - 优化/量化 - 部署到不同平台。1.3 核心应用场景姿态识别到底能干什么把姿态识别模型落地常见的场景包括健身动作计数和姿势纠正、舞蹈动作对比打分、人体行为识别跌倒检测、打架检测、安防场景下的异常姿态预警、体育赛事动作分析。如果是做健身或者舞蹈打分COCO 的 17 个关键点定义基本够用。如果是做精度要求更高的手部姿态或者面部关键点那就不能直接用 YOLOv8 Pose需要换专门的关键点模型。我见过一个做健身镜产品的团队他们最初用的就是 YOLOv8 Pose 的输出的 17 个关键点上位机拿到这些点之后计算关节角度和动作幅度然后和标准动作库比对效果非常不错。这类应用对模型的硬件要求不高一个普通的边缘盒子就能跑得很流畅。2. 用 YOLOv8 训练姿态识别数据准备与训练流程2.1 数据标注关键点标注的具体操作如果要训练自己的姿态识别模型第一步是数据标注。推荐的工具是 Labelme 和 CVAT。Labelme 适合小规模数据单机运行即可CVAT 是网页版的适合多人协作标注大批量数据。标注的时候需要注意几个要点关键点的顺序和编号必须和模型定义的骨架连接关系一致不然训练出来的关键点全乱了。被遮挡的关键点不能随便乱标需要标记为不可见visible0而不是硬标一个错误位置。对于密集人群场景每个人都要单独标注不能因为遮挡就跳过。标注完的数据通常是一个 JSON 文件需要转换成 YOLOv8 Pose 训练需要的格式。YOLOv8 的姿态数据格式是每个样本一个 txt 文件每一行内容为class_id, x1, y1, x2, y2, kpt1_x, kpt1_y, kpt1_v, kpt2_x, kpt2_y, kpt2_v, ...。这里x1, y1, x2, y2是人体边界框的归一化坐标kpt_x, kpt_y是归一化后的关键点坐标kpt_v是可见性标志0 表示未标注1 表示标注但被遮挡2 表示可见。我自己写过一个 Python 脚本把 Labelme 的 JSON 转成 YOLO 格式。这里有一个容易忽略的点YOLOv8 的框坐标和关键点坐标都是基于图片宽高归一化的但是关键点的可见性标志不能只取 0 或 1如果在标注时没有区分被遮挡和不存在的点建议统一填 2 或 1不要填 0否则训练时损失函数会忽略这些点导致预测不稳定。2.2 训练配置数据集结构和关键超参训练的时候数据集目录结构建议这样组织datasets/ ├── train/ │ ├── images/ │ └── labels/ ├── val/ │ ├── images/ │ └── labels/ └── data.yamldata.yaml里面要写清楚路径、关键点数量和类别名称。大致内容如下path: ./datasets train: train/images val: val/images kpt_shape: [17, 3] names: 0: personkpt_shape: [17, 3]中的 3 指的是(x, y, visibility)三个值。如果训练的是 17 点 COCO 格式就保持这个配置。训练超参方面我用得比较多的是一组稳妥的默认值epochs100小数据集可以先跑 50 轮看趋势。batch16根据显存调整GTX 1660 Ti 这种 6GB 显存的卡batch 设 8 到 16 基本没问题。imgsz640输入分辨率保持 640后续导出 ONNX 也保持一致。optimizerauto让 YOLOv8 自动选择优化器。device0如果只有 CPU 就写cpu。训练命令很简单yolo pose train datadata.yaml modelyolov8n-pose.pt epochs100 batch16 imgsz640 device0这里有一个很多人新手期会踩的坑训练前一定要先确认测试集和验证集的数据分布一致不要训练集都是白天拍摄的图片验证集都是晚上的不然训练损失很好看验证损失一塌糊涂。2.3 训练过程中的损失曲线怎么看训练完会在runs/pose/train/目录下生成多个结果文件其中results.png里有损失曲线盒图是训练损失验证损失是另外一条曲线。如果训练损失持续下降但验证损失在第 30 轮左右开始上升说明过拟合了这时候要么加数据增强要么减小模型容量要么提前停止训练。还有一个细节YOLOv8 会输出box_loss、pose_loss、cls_loss和dfl_loss多项损失。pose_loss是专门针对关键点的损失如果它下降得很慢多半是数据标注有问题特别是遮挡点的可见性标志没有处理对。3. YOLOv8 Pose 导出 ONNX 的完整步骤与验证3.1 导出命令与核心参数训练完成后导出的方式我现在几乎都用 Ultralytics 自带的命令行yolo export modelruns/pose/train/weights/best.pt formatonnx opset12 simplifyTrue dynamicFalse imgsz640几个参数值得展开说一下。opset12ONNX 算子集的版本。opset 版本太低的 YOLOv8 导出会报算子不支持的错误太高的版本在旧的 ONNX Runtime 上又不兼容。12 是兼容性最好的一个版本实测下来 RKNN 和 NCNN 的转换工具对 opset 12 的支持最稳。simplifyTrue用 onnx-simplifier 对计算图做简化它会把一些冗余节点合并、消除对减少模型大小和提升推理速度都有帮助。dynamicFalse固定输入尺寸。如果要做动态尺寸输入dynamicTrue让模型接受任意尺寸的输入但绝大多数部署场景都会固定输入尺寸做静态尺寸导出之后模型更小、推理更快。导出完成后验证一下生成的文件python -c import onnx; monnx.load(best.onnx); onnx.checker.check_model(m); print(OK)看到打印OK说明模型结构没有问题。3.2 理解导出的 ONNX 模型的输入输出这个环节值得多花几分钟。导出的 ONNX 模型输入是一个张量形状是[1, 3, 640, 640]分别表示 batch、通道数、高、宽。输出是一个[1, 56, 8400]的张量其中 8400 是 YOLOv8 在不同尺度特征图上的预测框总数640 输入下三个检测头分别在 80×80、40×40、20×20 的特征图上输出加起来刚好是 8400。如果在导出时加了dynamicTrue输入输出的维度会出现batch或者height、width的动态维度这个在部署的时候要注意处理。我建议线上部署一律用固定尺寸尺寸变了模型精度和速度都容易出幺蛾子。3.3 用 ONNX Runtime 跑通推理之后就可以写一个简单的推理脚本验证 ONNX 模型的输出是否和 PyTorch 模型输出一致。这里最直接的办法是拿同一张图分别跑 PyTorch 模型和 ONNX 模型对比输出张量的差异。import onnxruntime as ort import numpy as np import cv2 from ultralytics import YOLO # 预处理图片 img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (640, 640)) img img.astype(np.float32) / 255.0 img np.transpose(img, (2, 0, 1))[None] # ONNX Runtime 推理 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name output sess.run(None, {input_name: img})[0] print(onnx output shape:, output.shape)如果 PyTorch 和 ONNX 的输出张量数值差异在1e-3量级以内说明导出没有问题。如果差异很大大概率是预处理不一致比如 RGB/BGR 通道顺序搞反了或者归一化方式不一样。3.4 后处理从 ONNX 原始输出到关键点坐标YOLOv8 Pose 的 ONNX 输出是 8400 个候选框每个候选框有 56 个值后处理要做的事概括下来有这几步解码边界框YOLOv8 的框坐标是相对特征图网格的偏移需要换成输入图像像素坐标。过滤置信度低的候选框。非极大值抑制NMS把重叠的检测框合并。提取关键点坐标只保留最终保留框对应的关键点。按置信度阈值过滤关键点并把坐标从归一化值转换为像素坐标。YOLOv8 的 NMS 默认不会集成在 ONNX 模型里所以这一步要在部署端自己实现。如果用的是onnxruntime-gpu或者专门部署框架如 OpenVINO它们往往自带高效的 NMS 算子可以省去不少事。4. INT8 量化和模型优化让姿态识别在低算力设备上跑起来4.1 为什么必须量化一个性能对比很多人拿到 YOLOv8 Pose 模型第一反应是往手机或者边缘设备上跑。但 FP32 的模型在 GTX 1660 Ti 这种显卡上虽然流畅换上 RK3588 或者手机 NPU 就会有压力。我实测过一个场景同样的yolov8n-pose.onnx在 RK3588 的 NPU 上用 FP16 推理单帧耗时约 35ms而 INT8 量化之后单帧耗时约 18ms差距接近一倍。所以如果你的部署目标是嵌入式和移动端INT8 量化几乎是必经之路。4.2 用 ONNX Runtime 做 INT8 静态量化ONNX Runtime 提供了量化的 API推荐用静态量化动态量化对姿态识别这种任务效果不稳定。静态量化的流程是准备一个校准数据集运行模型统计每层激活值的分布然后根据分布计算缩放因子scale和零点zero point。import onnxruntime as ort from onnxruntime.quantization import quantize_static, CalibrationDataReader, QuantType class PoseCalibrationDataReader(CalibrationDataReader): def __init__(self, images, input_name): self.data [(input_name, img) for img in images] self.iter 0 def get_next(self): if self.iter len(self.data): return None data self.data[self.iter] self.iter 1 return {data[0]: data[1]} # 采集 100 张图片做校准 calib_images [preprocess(img) for img in load_images(calib/)[:100]] quantize_static( model_inputbest.onnx, model_outputbest_int8.onnx, calibration_data_readerPoseCalibrationDataReader(calib_images, images), quant_formatQuantType.QInt8, per_channelTrue )校准图片最好来自真实部署场景的图片不要用训练集或者验证集。比如部署在健身房就采集健身房的实际画面部署在室外监控就采集室外的画面。这样量化后的分布才贴合实际环境。校准数据集数量 100 到 200 张就够了太多了也只是拖慢量化时间。4.3 量化后精度下降的处理办法INT8 量化之后精度掉一点是正常的但掉得太多就需要处理。我常用的几个办法混合精度量化敏感层保持 FP16 或 FP32只有非敏感层用 INT8。ONNX Runtime 支持的MatMulNBits量化方式可以按层控制。换成 per-channel 量化per-channel 比 per-tensor 精度更高ONNX Runtime 默认支持显存和内存开销略大一些。贴靠校准集增加校准集的多样性尤其是边缘场景比如运动模糊、低光照人像让量化时激活值分布有更多覆盖。反复测试用同一组测试集分别跑 FP32 和 INT8把输出差异最大的样本挑出来反推是哪些输入分布没有被校准集覆盖。如果只是做快速验证也可以考虑直接使用onnxruntime-genai或者各家厂商提供的 QDQ 格式模型推理框架内置了优化流程精度通常比自己手搓的量化好一些。4.4 轻量化辅助方案输入尺寸和 NMS 优化除了量化还有一个省算力的利器是降低输入分辨率。如果你的应用场景里人体占比比较大把输入从 640 降到 416 或者 320速度能提升 30% 到 50%某些场景下精度下降在可接受范围内。不过要注意降输入分辨率对关键点精度的伤害比对检测框的伤害更大如果关键点坐标是后续角度计算的核心输入我建议至少保留 512 分辨率。另外可以把 NMS 整合进 ONNX 模型用NonMaxSuppression算子替代外部 NMS这样部署代码更简洁但 ONNX Runtime 的 NMS 在 CPU 上速度不够快GPU 上表现不错。我一般建议在边缘设备上仍然用外部 NMS把多出来的时间用来提升关键点检测精度。5. 部署到 RK3588、手机端和嵌入式设备5.1 RK3588 上的转换与部署RK3588 是现在边缘设备上很主流的一块芯片6 TOPS 的 NPU 算力在姿态识别场景里非常够用。关于标题里提到的 rk3588 部署 YOLOv8我讲一下流程。第一步将 ONNX 模型转换为 RKNN 格式使用 RKNN-Toolkit2。转换核心代码如下from rknn.api import RKNN rknn RKNN() rknn.config(target_platformrk3588, mean_values[[0, 0, 0]], std_values[[255, 255, 255]]) rknn.load_onnx(modelbest_int8.onnx) rknn.build(do_quantizationFalse) rknn.export_rknn(best_rk3588.rknn)这里mean_values和std_values必须和训练时预处理一致否则颜色通道不对检测精度会大幅度下降。如果是导出的 ONNX 模型已经包含了归一化预处理那 RKNN 配置里就不需要再做一遍。第二步编写 RKNN 推理代码。这个内容比较多这里只列关键结构// 伪代码 rknn_input inputs[1]; inputs[0].index 0; inputs[0].type RKNN_TENSOR_UINT8; inputs[0].size 640 * 640 * 3; inputs[0].fmt RKNN_TENSOR_NHWC; inputs[0].buf img_data; rknn_run(ctx, nullptr); rknn_output outputs[1]; rknn_outputs_get(ctx, 1, outputs, nullptr); // outputs[0].buf 就是 [1, 56, 8400] 的原始推理结果后续的后处理和前面用 ONNX Runtime 的一样但是要注意 RKNN 输出的 tensor 布局可能是NHWC或者NCHW取决于 RKNN 的配置。我在 RK3588 上实际卡过的就是因为NCHW和NHWC没有转换结果所有的框都是错位的。第三步性能评估。RKNN-Toolkit 自带一个性能分析工具可以直接跑在开发板上评估每层的耗时方便找到性能瓶颈。实测yolov8n-pose在 RK3588 上 INT8 单帧大约 60 FPS640 输入效果已经很流畅。5.2 手机端部署NCNN 和 MNN手机端部署现在主流是 NCNN 和 MNN。这两个框架都支持 ONNX 转模型格式。NCNN 转换命令onnx2ncnn best.onnx best.param best.binMNN 转换命令MNNConvert -f ONNX --modelFile best.onnx --MNNModel best.mnn --bizCode 1000转换完怎么在手机 App 里调起来核心逻辑和 RKNN 差不多读入模型、设置输入、运行推理、取输出。NCNN 在安卓上跑 YOLOv8 Pose 的示例有很多但注意自己模型的关键点数量和输出张量形状要和示例代码匹配如果是 17 点就直接用官方示例如果是自定义关键点数就要改输出解析的代码。手机端如果要追求极致性能还要注意几个细节使用 GPU 加速NCNN 里可以启用 VulkanMNN 里启用 Metal/OpenCL。输入图片的缩放方式NCNN 用resize的时候最好先letterbox把图片等比缩放到 640×640 的区域内剩余部分填充灰色值为 114而不是直接拉伸。直接拉伸会改变人体长宽比关键点位置会偏移。线程数设置NCNN 设置num_threads为 CPU 物理核心数不要超过否则频繁线程调度反而更慢。5.3 ONNX Runtime 直接部署服务端和桌面端方案如果部署在服务端或者桌面端不追求极致边缘性能ONNX Runtime 是首选。它支持的平台多API 简单而且自带多种执行提供程序CPU、CUDA、TensorRT、OpenVINO。import onnxruntime as ort providers [CUDAExecutionProvider, CPUExecutionProvider] session ort.InferenceSession(best.onnx, providersproviders)如果有 GPU会上自动优先用 CUDAExecutionProvider没有 GPU 就退化到 CPUExecutionProvider。对于 GTX 1660 Ti 这种显卡跑 FP16 或者 INT8 的 YOLOv8 Pose速度能到上百 FPS实时性没有任何问题。ONNX Runtime 还有一个功能值得提一下它支持多个模型同时运行如果同一台服务上既跑检测又跑跟踪可以将多个 session 合并到一个进程里用线程池调度能省去不少重复的框架初始化和显存开销。5.4 模型部署到嵌入式设备的通用流程总结部署到嵌入式设备通常可以分为这几步用训练好的 PyTorch 权重导出 ONNX。在 PC 上用 ONNX Runtime 验证 ONNX 输出正确性。根据目标设备的推理后端将 ONNX 转为对应格式RKNN、NCNN、MNN、OpenVINO IR 等。在目标设备上做一个最小推理测试确认输入输出维度正确。加上后处理和业务逻辑集成到实际应用中。做性能和精度回归测试确认量化或者格式转换没有引入不可接受的精度损失。这套流程我走了很多次每一步都有自己独特的坑但总体的顺序是最稳的不要跳步。6. 理解 YOLOv8 的网络结构对部署和优化的帮助6.1 C2f 模块和 ADown 结构的实际意义YOLOv8 的 backbone 用了 C2f 模块这是对之前 C3 模块的改进。C2f 的核心思路是梯度分流把输入特征在多个分支里传递最后再拼接起来。这种设计让网络每一层都能学到更丰富的特征但同时也意味着在导出 ONNX 后计算图里的 Concatenate 节点数量会比较多。如果有的部署框架对 Concat 算子的实现不友好可能会成为推理瓶颈。用 onnx-simplifier 简化之后这种情况会缓解不少。关于热搜词里提到的 ADown实际上 YOLOv9 及其他版本才使用了ADown它不是 YOLOv8 的标准结构。但很多人会把它作为改进点融合进 YOLOv8目的是用更少的参数做下采样替换掉原来的卷积下采样模块。如果你用改进版 YOLOv8 训练模型并且在导出 ONNX 时遇到算子不支持的问题排序第一的要查是不是自定义模块里的算子。6.2 头部改进不同任务头的差异YOLOv8 Pose 的 detection head 和 YOLOv8 Detect 是分开的Pose head 的回归分支除了输出框坐标以外还会多一组关键点回归分支。改进 head 结构时要始终记得输出向量的排布因为后处理解析依赖这个排布。无论 head 怎么改最终输出的尾部最好保持标准格式[x1, y1, x2, y2, obj_score, kpt1_x, kpt1_y, kpt1_v, ...]这样现有部署代码改动最小。6.3 把注意力机制融入 C2fECA 等模块的实战表现YOLOv8 的生态中很多人会把 EMA、ECA、CA、CBAM 等注意力机制融入 C2f 模块。实际测试下来ECAEfficient Channel Attention是性价比较高的选择它只做全局平均池化再接一个一维卷积几乎不增加额外参数量却能给关键点检测带来 1 到 2 个百分点的 AP 提升。我在自己的模型里试过把 ECA 加进 C2f 模块的 bottleneck 里训练时损失下降速度和原版接近但最终的关键点 AP 高了大概 1.5 个百分点。部署时的代价是 ONNX 模型多了一个GlobalAveragePool和Conv节点对整体推理速度影响很小。如果你也是做姿态识别并且对精度有进一步的要求可以考虑这个改进方向。6.4 损失函数曲线图的绘制与收敛判断既然提到训练就顺便把绘制损失函数曲线图的方法说一下。YOLOv8 训练日志里自带的results.png已经画好了所有损失曲线但如果想把多条训练记录放在同一张图上对比比如对比是否加了注意力机制可以自己读取训练目录下的results.csv用 matplotlib 绘制。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/pose/train/results.csv) plt.plot(df[epoch], df[train/pose_loss], labeltrain/pose_loss) plt.plot(df[epoch], df[val/pose_loss], labelval/pose_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.show()关键看val/pose_loss的走势如果它已经很多轮不降反升说明模型快收敛了加训练轮数没有意义不如回头调数据。7. 实操中遇到的几个高频问题和排查链路7.1 ONNX 导出时算子不支持的排查过程现象执行导出命令之后报错提示某个算子不支持常见的有grid_sampler、aten::index_put等。排查先把opset调高12 或 13大部分情况解决。还不行就把simplifyFalse关掉导出原始计算图看看是不是某个自定义模块导致的。我遇到过一位朋友把torch.stack写在 forward 里导出时死活过不去最后在 forward 里改成torch.cat并调整维度顺序问题就消失了。这类问题的思路很简单查看报错信息里的算子名在 PyTorch 源码里找到对应的前向函数重写成一个 ONNX 支持的等价写法。7.2 ONNX Runtime 推理结果和 PyTorch 不一致现象同一张图PyTorch 检测结果正常ONNX Runtime 输出完全不对。排查这个问题的原因几乎都出在预处理上。先检查归一化PyTorch 模型喂的是(0,1)范围的数据ONNX 模型可能需要喂(0,255)或者先做letterbox。再检查通道顺序PyTorch 训练时用 RGB 还是 BGR推理端对应上。还要注意 YOLOv8 在推理时默认会对图片做letterbox如果 ONNX 模型是从 PyTorch 直接导出的它没有内置letterbox预处理需要在外部完成否则图片比例不对输出肯定不对。7.3 量化后关键点位置漂移现象INT8 量化后检测框还准但关键点位置偏移比较大。排查关键点的回归任务比检测任务对数值精度更敏感。可以尝试把关键点回归分支单独用 FP16 算子保留只对 backbone 做 INT8 量化。ONNX Runtime 的量化配置里支持排除某些节点把关键点头部的卷积层加入排除名单实测精度恢复很多。7.4 手机端 NCNN 转换之后推理结果全乱现象NCNN 转换后模型能加载但输出结果和 ONNX Runtime 差别巨大。排查先在 PC 上用 NCNN 的 Python 接口跑一遍同样图片确认是不是转换的问题。如果 PC 上不对多半是letterbox预处理不一致如果 PC 上对但手机上不对检查输入像素格式RGBA 还是 RGB和内存对齐。NCNN 默认的输入格式是 RGB 且带 padding 的如果上层代码传了 RGBA 数据就会多出一通道数值全错。8. 我个人的经验总结和最终建议做姿态识别这个项目走到最后你会发现真正难的不是跑通一个 demo而是把模型稳定地部署到目标设备上保证它在真实场景里不掉链子。我个人在实际项目里的体会有几条一定要尽早确定部署平台和推理后端再决定训练和导出方案。先定后端再定导出格式和量化方式。我见过太多项目训练端用 FP32 跑得很开心临上线才发现目标设备不支持某些算子或者量化要求严苛结果返工。数据标注是姿态识别最大的成本又是最容易出问题的环节。如果多人协作标注一定要制定严格的关键点标注规范不要把模糊性留给标注员自由发挥。ONNX 模型文件在交付的时候最好附带一份输入输出说明包括张量形状、数据类型、是否需要预处理、后处理逻辑。因为很多接收模型的人不一定会去读源码有说明能避免大量沟通成本。最后再分享一个小技巧如果你需要快速验证一个 ONNX 姿态识别模型有没有坏不需要准备完整的数据集直接下载一张包含人像的测试图片跑一遍推理之后把 17 个关键点用画点连线的方式画在图片上保存。如果输出图像里人的姿态连贯、点位分布合理说明这个模型基本可用如果点位乱飞、画出来像抽象艺术作品那就先查预处理和后处理再考虑是不是模型本身有问题。《Onnx Yolov8 Pose.rar 姿态识别》这个标题背后牵扯的内容远不止解压一个文件那么简单它覆盖了模型训练、数据准备、格式转换、量化优化、边缘部署、后处理适配等一整条知识链。理清每个环节之间的关系再动手做比拿到一个模型文件就急着运行要稳妥得多。本文还有配套的精品资源点击获取
返回列表