news 2026/9/26 14:40:07

YOLOv5手势识别入门:2000张标注数据训练到部署全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv5手势识别入门:2000张标注数据训练到部署全流程解析

简介:这套YOLOv5手势识别资料包面向目标检测与深度学习实践者,聚焦人机交互场景中10种常见手势(如数字、字母、比心等)的识别,适合用于算法学习、毕业设计或小型手势控制系统开发。包内数据为2000张已标注图像,标签采用YOLO标准txt格式,并预置3组训练好的pt权重模型、6个yaml配置文件和图形化界面代码,下载后即可直接推理或继续训练。资源共71个文件,以jpg/png图像作为数据集、pt模型权重和yaml配置作为推理与训练核心,csv记录与txt说明辅助使用,压缩包总大小约276.93MB,结构清晰、易于按需取用。配套的B站视频教程从环境搭建到模型调用逐步讲解,能显著降低入门门槛。目前已有21410人学习下载,是兼顾完整数据、现成模型与教程的实用型手势识别资源。

1. 2000 张标注数据做 YOLOv5 手势识别:这套方案到底值不值得上车

先泼一盆冷水:手势识别不是什么高不可攀的算法题,用 YOLOv5 训练自己的数据集,2000 张标注好的图片完全够起步,比很多人以为的“至少上万张”要现实得多。这套方案的价值在于把数据、代码、模型三样东西凑齐了,你不用从零去爬图、打标签、调环境,拿到手就能把 training 跑起来,适合三类人:一是要做毕业设计或课程项目,需要一个能演示、能讲清楚原理的完整闭环;二是产线上要做“手势控制设备”之类的小需求,先验证可行性再决定要不要上更重的模型;三是刚接触目标检测,想用 YOLOv5 练手但被环境配置和数据集格式劝退过的初学者。

但这里有个关键前提——2000 张标注数据并不意味着你一定能训出好模型。数据集的标注质量、类别分布、拍摄场景和你的应用场景是否一致,直接决定最终效果。接下来的内容,我会从数据体检、环境搭建、训练参数到踩坑排查,把这套方案拆到能照着复现的程度。

2. 手势数据集到手先别急着训:目录结构、标注格式与质量体检

2.1 数据集的标准布局:images、labels 与 train/val 划分

我拿到数据集的第一件事不是打开图片看,而是看目录结构。YOLOv5 训练自己的数据集,目录布局有硬性要求,不满足的话 train.py 第一步就会报错。标准布局是 images 和 labels 两个大目录下各自分出 train 和 val 子目录,对应图片和标注文件必须在子目录里一一对应:

gesture_dataset/ ├── images/ │ ├── train/ # 约 1600 张 │ └── val/ # 约 400 张 ├── labels/ │ ├── train/ # 与 images/train 同名的 txt │ └── val/ # 与 images/val 同名的 txt └── gesture.yaml # 数据集配置文件

每一张图片对应一个同名 txt 文件。比如hand_001.jpg对应hand_001.txt,这个 txt 里每一行代表一个标注框,格式是五列:class_id x_center y_center width height,其中 x_center、y_center、width、height 都是相对图片宽高的归一化数值,范围 0~1。class_id是整数,从 0 开始,对应 yaml 文件里 names 列表的下标。

常见的 2000 张手势数据集一般标注 5 类左右,比如拳头、手掌、拇指、比心、OK 这些基础手势。gesture.yaml 内容大致长这样:

train: gesture_dataset/images/train val: gesture_dataset/images/val nc: 5 names: ['fist', 'palm', 'thumb', 'love', 'ok']

这段配置的含义很直接:train 和 val 指向图片目录的绝对路径或相对路径,nc 告诉 YOLOv5 你要分几类,names 是类别名称列表。注意 names 的顺序必须和 txt 标注里的 class_id 一一对应,否则训练过程不报错,但推理出来的类别名全是乱的。我就见过有人把['palm', 'fist']写反,mAP 看起来很高,实际每个框都张冠李戴。

2.2 标注质量体检:用脚本筛出漏标、错标和比例失调

很多人拿到数据直接开训,等到 loss 不降才开始怀疑数据有问题。我的习惯是先写一个体检脚本,把标注文件的统计信息打出来,这一步花五分钟,能省后面好几天的排错时间。需要重点检查三件事:类别样本数是否均衡、标注框大小分布、有没有中心坐标越界或宽高为 0 的坏标注。

下面这个脚本可以快速统计类别数量和框尺寸分布:

import os from collections import Counter label_dir = "gesture_dataset/labels/train" class_counter = Counter() box_area_list = [] for file in os.listdir(label_dir): if not file.endswith(".txt"): continue with open(os.path.join(label_dir, file), "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: print(f"bad line in {file}: {line.strip()}") continue cls = int(parts[0]) w = float(parts[3]) h = float(parts[4]) # 归一化后的宽高,面积占比 = w*h class_counter[cls] += 1 box_area_list.append(w * h) print("类别分布:", class_counter) print("框面积占比 均值: {:.3f}, 最小: {:.3f}, 最大: {:.3f}".format( sum(box_area_list)/len(box_area_list), min(box_area_list), max(box_area_list)))

逻辑说明:遍历 labels/train 下所有 txt,解析每一行标注,统计类别 ID 出现次数,同时计算每个框在整张图中的面积占比。这个脚本不依赖任何第三方库,用标准库就能跑。重点看两个输出:类别分布如果某个类只有几十个样本,而其他类有几百个,训练时这个类很容易被模型忽略;框面积占比如果绝大多数都小于 0.05,说明手势在画面中占的比例很小,YOLOv5 的默认锚框对它不友好,后面要重点调。

参数说明:box_area_list里存的是归一化后的面积占比。如果发现大量小框,训练时建议把输入分辨率从 640 提升到 768 或者把 anchors 的尺度调小,不要让模型去学习它根本看不清的小目标。

2.3 用 10 行代码把数据集转成 YOLOv5 要的布局

如果你手上的数据是 Roboflow 导出的 VOC XML 格式,或者 COCO JSON 格式,需要先转成 YOLOv5 的 txt 格式。VOC XML 转 YOLO 的代码不复杂,核心公式就两个:x_center = (xmin + xmax) / 2 / img_width,width = (xmax - xmin) / img_width,y 方向同理。

import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_txt, class_map): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find("size/width").text) img_h = int(root.find("size/height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in class_map: continue cls_id = class_map[name] box = obj.find("bndbox") xmin = float(box.find("xmin").text) ymin = float(box.find("ymin").text) xmax = float(box.find("xmax").text) ymax = float(box.find("ymax").text) x_center = ((xmin + xmax) / 2) / img_w y_center = ((ymin + ymax) / 2) / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n") with open(out_txt, "w") as f: f.writelines(lines) class_map = {"fist": 0, "palm": 1, "thumb": 2, "love": 3, "ok": 4} # 遍历 VOC 目录,逐文件转换 for xml_file in os.listdir("voc_annotations"): if xml_file.endswith(".xml"): voc_to_yolo( os.path.join("voc_annotations", xml_file), os.path.join("labels", xml_file.replace(".xml", ".txt")), class_map, )

逻辑说明:函数 voc_to_yolo 读取一个 XML 文件,从 size 节点拿图片宽高,遍历所有 object 节点,用 class_map 把类别名映射成 ID,再按 VOC 的 bndbox 坐标换算成 YOLO 的归一化中心点坐标和宽高。循环部分批量处理整个目录。

参数说明:class_map里的映射关系必须和后续 gesture.yaml 里的 names 顺序保持一致。还有个常见坑:VOC 坐标可能超出图片边界(标注软件手抖导致),转换后 x_center 或 w 会出现大于 1 的值,训练时 YOLOv5 会把这个框忽略但不是报错,表现为某个类别一直学不好。转换后建议再跑一遍 2.2 的体检脚本,把越界行直接过滤掉。

3. YOLOv5 环境配置与最小训练命令:从空环境到第一次出 loss 曲线

3.1 环境配置:Python、PyTorch 与 CUDA 的版本搭配

YOLOv5 环境配置是新手最容易翻车的环节,翻车点集中在 PyTorch 和 CUDA 版本不匹配。我的建议是:先确定显卡驱动支持的 CUDA 版本,再装对应版本的 PyTorch,最后才装 requirements.txt,顺序不能反。

# 查看显卡驱动支持的 CUDA 版本 nvidia-smi

如果输出显示 CUDA Version 12.1,那就可以放心装 cu121 版本的 PyTorch。我一般用 pip 安装而不是 conda,因为 conda 解依赖太慢而且容易把 Python 版本带偏:

python -m venv yolov5_env source yolov5_env/bin/activate # Windows 下用 yolov5_env\Scripts\activate pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

逻辑说明:先建虚拟环境,再装 PyTorch。用--index-url指定 CUDA 对应版本的下载源,避免 pip 默认装到 CPU 版本的 torch。这一步装完可以用下面命令验证 GPU 是否可用:

python -c "import torch; print(torch.cuda.is_available(), torch.__version__)"

输出True 2.x.0+cu121就说明环境没问题。如果输出 False,大概率是 torch 装成了 CPU 版,或者 CUDA 驱动版本太低。不需要重装系统,退一个 PyTorch 版本通常是有效的,比如把 cu121 换成 cu118。

3.2 拉取代码与预训练权重:目录结构要心里有数

环境就绪后,clone YOLOv5 官方仓库,然后装依赖。这个仓库本身就是一个完整的训练框架,train.py、detect.py、export.py 都在根目录,models 目录下是网络结构定义,data 目录下是内置数据集配置,utils 目录封装了损失计算、增强、日志这些功能。

git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt

依赖装完先别急着训练,去下载 yolov5s.pt 预训练权重放到 yolov5 目录下。用预训练权重做迁移学习是这套方案能「2000 张就够用」的核心原因——COCO 上预训练过的模型已经学会了通用的边缘、纹理、色块特征,我们的手势数据集只需要在这些特征之上微调,而不是从零学。

3.3 最小训练命令:第一次跑通比追求精度更重要

第一次训练的目标是让整个链路跑通,看到 loss 曲线在下降,而不是追求多高的 mAP。所以参数不要开太猛:

python train.py --data gesture_dataset/gesture.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 50 \ --workers 4 \ --project runs/hand_train

参数说明:--data指向数据集 yaml,--weights用 yolov5s.pt,这是速度和精度的平衡点,显存不够可以换 yolov5n.pt;--img 640是输入分辨率,YOLOv5 会按 32 的倍数做 padding;--batch 16是批次大小,8GB 显存跑 yolov5s 用 16 是安全值;--epochs 50是训练轮数,2000 张数据 50 轮大致能看到收敛趋势;--workers 4是数据加载线程数;--project指定训练日志和权重输出目录,不设的话默认写在 runs/train 下。

训练启动后终端会打印每轮的 box_loss、cls_loss、mAP 等指标,同时在runs/hand_train/exp目录下生成 results.png,这个图是整个训练过程最重要的体检报告。第一次跑通后你会发现,真正耗时间的不是写代码,而是等收敛和调参数。

4. YOLOv5 手势识别的 6 个必调参数:mAP 是从这些超参数里省出来的

4.1 超参数是黑匣子?先理解锚框、输入尺寸和学习率的关系

YOLOv5 的超参数像一个黑匣子,很多人只知道抄别人的配置,却不理解为什么这么设。其实核心就三件事:模型看多大图、每个位置能匹配到多大的目标、每次参数更新迈多大的步子。这三件事分别对应--img、--anchors和--lr。

--img决定了输入分辨率。640 是默认值,但如果你 2.2 节体检时发现手势框面积占比偏小,比如大部分框不到画面的 1/20,那么 640 分辨率下每个手势只有几十个像素,特征根本提不出来。这时候把--img 768或--img 896可能是最直接的提升手段。副作用是显存占用和训练时间都会上升,新手容易忽略这个权衡。

锚框是个更隐蔽的变量。YOLOv5 默认会根据你的数据集自动重新计算锚框,开启方式是在 yaml 里写anchors参数或者用--noautoanchor关闭。我一般让 YOLOv5 自动算,它会在训练前先跑一遍 k-means 聚类,统计你所有标注框的尺寸分布,然后生成 9 组锚框尺寸。如果你发现训练日志里有autoanchor: 0.98 anchors/target OK这条信息,说明锚框和数据集匹配得很好;如果数值明显低于 1,就要考虑是不是标注框太极端,比如全部是细长条框。

4.2 六个必调参数:epochs、batch、img、lr 与它们的推荐范围

下面这六组参数是我在多次手势识别训练里反复调过的,直接给出推荐范围和理由:

参数推荐范围说明
--epochs100~2002000 张数据 100 轮以内基本收敛,超过 200 轮大概率过拟合
--batch8~32显存 8GB 用 8~16,batch 太大会让 loss 震荡幅度变大
--img640~768手势占画面小就调大,但 960 以上性价比陡降
--lr00.001~0.01默认 0.01,迁移学习时 0.001 更稳
--cos-lr开启余弦退火能避免后期 loss 平台期
--patience20~50验证集 mAP 不再提升时提前停止,省时间

以 lr0 为例,这个参数是 SGD 的初始学习率。YOLOv5 默认值 0.01 是针对从零训练或大规模数据设计的,我们只有 2000 张,权重还是 COCO 预训练来的,此时学习率保持 0.01 很容易把已经学好的通用特征冲掉。我通常会降到 0.001~0.003,配合余弦退火,收敛曲线会平滑很多。

batch 的设置经验是:显存能塞得下就尽量往 16 以上拉,batch 太小会让 BatchNorm 的统计量不稳定,导致每次验证集 mAP 忽高忽低。但如果显存只有 6GB,硬上 32 会直接 OOM。这时候有两个后悔药:一是把--img从 640 降到 512,二是切换到 yolov5s 的轻量版 yolov5n,而不是死磕 batch 大小。

4.3 训练中断怎么办:断点续训与最优权重选择

训练是个长活,跑一半断电、显存被别的进程抢走、或者你想换一组学习率重新来过,都很常见。YOLOv5 的续训机制很简单,用--resume参数指向上次的权重文件即可:

python train.py --resume runs/hand_train/exp/weights/last.pt

逻辑说明:last.pt保存的是最近一个 epoch 的完整状态,包括优化器状态、学习率调度器位置和当前 epoch 数,所以 resume 后会从断点继续,不会从头开始。很多人不知道的是,--resume只需要给权重路径,训练参数会自动从上次的配置里读取,不需要重新写一遍全部参数。

最后选权重有个小讲究:YOLOv5 训练完会产生best.pt和last.pt。best.pt 是验证集 mAP 最高的那一轮,last.pt 是最后一轮。如果 best 出现在第 83 轮而 last 在第 100 轮,我一般选 best.pt 做推理,除非最后一轮的 mAP 和 best 差不多——因为训练末期的权重往往开始在训练集上过拟合了,泛化能力反而下降。

5. 训练手语模型最容易翻车的 5 个坑:从现象到解决的排查笔记

5.1 现象:一训练就报 CUDA out of memory

现象:train.py 刚跑几个 step 就报RuntimeError: CUDA out of memory。

原因:batch、img、模型大小和显存四者的乘积超过了显存容量。8GB 显存跑 yolov5s + batch 32 + img 640,几乎必炸。

解决:按顺序调整三个参数。先降 batch 到 16,还炸就降 img 到 512,再炸就换 yolov5n.pt。我自己的底线是:宁可小 batch 跑 100 轮,也不为了面子硬撑大 batch 导致中途 OOM 整个训练白干。另外检查一下是不是训练时其他进程占了显存,nvidia-smi看一眼,把不用的进程杀掉。

5.2 现象:loss 一直在高位震荡,不收敛

现象:训练了 30 轮,box_loss 还在 0.08 上下抖,验证集 mAP 一直没有上升趋势。

原因:最常见的是学习率太大或太小,其次是标签和图片有大量错配,最后是类别极度不平衡。

解决:先用学习率的“前后对比法”排查。把 lr0 降一个数量级,从 0.01 改到 0.001,训 10 轮看 loss 是否开始平稳下降。如果还是不行,回到 2.2 节的体检脚本,检查是不是某个类别的 sample 数量过少,模型根本没学到这个类的特征。该类的数量低于 50 张时,考虑补充数据或者把几个相似手势合并成一类。

5.3 现象:训练完在测试图上什么都检测不到

现象:detect.py 跑一张测试图,输出为空,什么框都没有。

原因:三种可能性最大——置信度阈值设太高、测试图片和数据集的拍摄角度/光照差异太大、类别名和 label 错位。

解决:先把--conf-thres降到 0.1 试试,如果 0.1 能出框说明模型学到了东西,只是阈值卡太严。如果降到 0.1 还是空,说明测试图对模型来说完全是陌生场景。这时候检查训练集里手的尺度——如果训练集全是近景特写,给一张全身照,模型当然认不出来。这也是我在 2.2 节强调框面积分布的原因:数据集的尺度分布决定了模型的适用边界。

5.4 现象:训练集 mAP 很高,换批数据就崩

现象:验证集 mAP 到 0.95,模型权重换到另一批同场景图片上检测,框全乱。

原因:这是典型的过拟合,2000 张数据量本身不多,如果拍摄背景单一、人物单一、光照固定,模型学到的是「这个背景下的手」,不是「手」。

解决:开启更强的数据增强,YOLOv5 的 hyp.scratch.yaml 里有hsv_h、hsv_s、degrees、flipud这些增强参数。把degrees从 0 改成 15,hsv_s从 0.7 提到 0.9,让模型见过更多角度和色彩变化。更治本的办法是采集更多不同背景和不同人的数据,至少保证训练集里有多于三个人、两种背景。

5.5 现象:训练时 mAP 正常,推理时一张图要跑好几秒

现象:GPU 上训练正常,部署到 CPU 或者边缘设备上,单帧推理延迟高到没法用。

原因:weights 是 FP32 精度且模型尺寸较大,CPU 推理既吃计算量又吃内存带宽。

解决:用 export.py 导出成 FP16 或 INT8 的 ONNX 模型,推理速度能明显提升。这也是把 YOLOv5 部署到树莓派 5 这类边缘设备前的常见做法——先导出 ONNX,再接 NCNN 或 OpenVINO 做进一步的硬件适配。新手容易忽略的问题是:导出后要检查输出格式变化,ONNX 的输出是(1, 25200, 5+n)的原始预测张量,得自己写 NMS 后处理,不是拿来直接就有框。

6. 用训练好的模型做实时手势识别:推理验证与边缘设备部署技巧

训练完成后第一件事是用训练时没见过的图片或视频验证,别直接上摄像头,否则翻车了都不知道是模型问题还是采集问题。用下面的命令对测试视频做离线推理:

python detect.py --weights runs/hand_train/exp/weights/best.pt \ --source test_video.mp4 \ --conf-thres 0.4 \ --project runs/detect_test

参数说明:--source可以是图片路径、视频路径、摄像头设备号 0,也可以是目录。--conf-thres是置信度阈值,0.4 是个比较稳的起点,低于 0.4 误检变多,高于 0.6 容易漏检。跑完后输出带框的视频或图片,我习惯逐帧扫一遍,重点看连续帧里类别标签是否抖动——如果一会在 fist 一会在 palm,说明模型对中间过渡状态不稳定,需要补一些过渡姿态的样本。

实时摄像头推理可以用--source 0启动,但如果帧率太低,先确认是不是在 CPU 上跑。有一种更实操的做法是,把检测脚本拆成「读帧-推理-画框-显示」四步,把推理部分单独计时,定位时间花在哪一段。我见过很多人以为模型慢,实际上是 OpenCV 的读帧和显示缓存拖了后腿。

边缘设备部署是我的另一个习惯。树莓派 5 上部署自己训练的 YOLOv5 模型,常用路径是先导出 ONNX,再转成 NCNN 格式,避开 PyTorch 推理的高内存占用。导出命令如下:

python export.py --weights runs/hand_train/exp/weights/best.pt \ --include onnx \ --opset 12

导出后用 NCNN 的 onnx2ncnn 工具转换,再到板子上做推理。部署阶段我会把输入分辨率固定到 640,因为 NCNN 对动态分辨率支持不好,运行时再做一次等比缩放填充,这一层适配往往要写不少代码,但做一次后面就能复用。

最后说一个我自己的教训:手势识别这种任务,准确率看着高不如稳定,类别抖动、框跳动在演示场景里比精度低更尴尬。所以我的习惯是——小模型先把全流程跑通,再回头加数据提精度,而不是一开始就上大模型。这套 YOLOV5 手势识别方案,数据、代码、模型都给你配齐了,剩下的是你愿不愿意花一周时间把它吃透。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 14:40:04

LangGraph + PostgreSQL Checkpoint:打造可恢复的Agent运行时架构

开篇:从一个让你抓狂的“断点”说起我现在的日常已经离不开 LangGraph,但真正让我下定决心重构整个 Agent 项目架构的,是一次印象极深的线上事故。当时我用一个最朴素的 while 循环,在代码里让大模型反复调用工具、把结果塞回上下…

作者头像 李华
网站建设 2026/9/26 14:39:51

frp toml配置详解:从语法坑点到生产级实战

1. 为什么现在必须读懂 frp 的 toml 配置文件 frp 这个工具,我从 2018 年第一批内网穿透实践者开始用起,最早是 ini 格式,后来官方在 v0.50.0 版本(2023 年 3 月发布)正式弃用 ini,全面转向 toml。这不是一…

作者头像 李华
网站建设 2026/9/26 14:38:53

从《Madad》出发:民族音乐版本比较的聆听与音频分析之道

洗耳系列:从《Madad》看民族音乐版本比较中的聆听与分析之道 在整理音乐素材时,我常会遇到一个困惑:同一首作品的多个版本,明明旋律骨架相同,给人的感受却截然不同。最近重新听 Sami Yusuf 的《Madad (Nasimi Arabic V…

作者头像 李华
网站建设 2026/9/26 14:37:00

Wi-Fi 6 ax调度全解析:从OFDMA到BSS Coloring的实战指南

如果你最近在翻无线网络相关的资料,大概率会看到“ax”和“ax调度”这两个词绑在一起出现。这不是某个新出的命令行工具,也不是哪家厂商标的硬件型号,而是 IEEE 802.11ax,也就是 Wi-Fi 联盟改名之后的 Wi-Fi 6。前面的“ax调度”&…

作者头像 李华
网站建设 2026/9/26 14:36:58

Claude赋能汽车研发:从数据处理到代码生成的实战指南

前阵子跟一个做底盘标定的朋友提到Claude,他第一反应是“AI写代码的工具吧,跟我测车有什么关系”。我让他别急着下结论,先回答我一个问题:你每天下班后花最多时间在干什么?他想都没想就说——整理测试数据、截图截波形…

作者头像 李华
网站建设 2026/9/26 14:35:37

ROS小车DRL导航实战:从Gazebo仿真到实机部署

简介:本资源是一套面向计算机、电子信息与自动化专业学习者的移动机器人智能导航实践方案,聚焦深度强化学习在ROS框架下的落地应用,涵盖DQN、DDQN等主流算法的避障导航实现。资源包含2000个文件,以652个CMakeLists.txt和585个Make…

作者头像 李华