1. 手掌纹检测数据集的核心价值与选型逻辑
1.1 为什么手掌纹检测值得单独做一个数据集
手掌纹识别在生物特征识别领域里算是一个比较特殊的分支。跟人脸、指纹比起来,手掌纹的数据采集条件更可控,但公开可用的标注数据集却少得多。我最初接触这个方向是因为一个非接触式身份核验的需求,当时翻遍了公开渠道,发现要么是纯图像分类数据集,要么是采集设备封闭、格式不公开的私有库,真正能直接拿来做目标检测训练的资源非常有限。
这个数据集的出现恰好填补了这个缺口。2011张图像、VOC和YOLO双格式标注、单类别(手掌纹区域),这三个特征组合在一起,意味着你可以直接把它丢进YOLO系列模型里跑训练,不需要再做格式转换的二次加工。对于想快速验证手掌纹检测方案可行性的开发者来说,省掉的这部分预处理时间可能就是一两天的工作量。
从应用场景来看,手掌纹检测模型可以服务于几个方向:非接触式门禁系统的感兴趣区域定位、掌纹识别流水线中的预处理环节、以及手部姿态分析中的关键区域提取。这些场景的共同点是,你不需要一步到位做完整的身份识别,而是先把手掌纹区域从复杂背景中框出来,后续再交给特征提取或匹配模块处理。目标检测在这里扮演的是“粗定位”角色,它的精度直接影响下游任务的输入质量。
1.2 VOC与YOLO双格式的实际意义
很多人拿到数据集第一反应是看图片数量和类别数,但格式这件事其实更值得关注。VOC格式用XML文件存储标注信息,每个目标对应一个<object>节点,包含类别名和边界框的四个坐标值。YOLO格式则是每张图对应一个txt文件,每行表示一个目标,格式是类别索引 中心x 中心y 宽度 高度,所有坐标都归一化到0到1之间。
这两种格式同时提供,解决的是不同训练框架的兼容问题。VOC格式是Pascal VOC时代的遗产,但至今仍被很多评估脚本和可视化工具支持,比如你想用voc_eval计算mAP,或者用LabelImg做标注复核,VOC格式更顺手。YOLO格式则是Ultralytics系列框架的标准输入,从YOLOv5到YOLOv8再到最新的YOLO11,数据加载器默认读的就是这种归一化txt。
我实际用下来,这个数据集的双格式一致性做得不错。所谓一致性,是指同一张图的XML和txt标注指向的是同一个边界框,没有出现坐标偏移或类别错位的情况。这一点听起来是基本要求,但我在其他数据集上确实遇到过转换脚本写错导致标注框整体偏移几个像素的问题,训练时loss降不下去,排查半天才发现是数据的问题。
1.3 单类别设计的取舍分析
单类别意味着所有标注框的类别标签都是同一个,通常是“palm”或“palmprint”。这种设计有明确的适用边界:如果你的任务只是检测手掌纹区域是否存在、在哪里,单类别完全够用;但如果你想区分左手右手、或者区分不同的手掌纹类型,这个数据集就不适合直接使用。
从训练角度看,单类别有个容易被忽视的好处:正负样本的定义更清晰。多类别检测中,一个框可能被误判为其他类别,损失函数的分类分支会引入额外噪声。单类别时分类分支的优化目标非常集中,模型更容易收敛。我在小规模数据集上做过对比,同样的网络结构,单类别训练到稳定状态需要的epoch数通常比多类别少20%到30%。
当然,单类别也意味着你不能直接用这个数据集训练一个多任务模型。如果后续要扩展,比较务实的做法是先用这个数据集预训练一个手掌纹检测的骨干网络,然后在自己标注的多类别数据上做微调。预训练阶段学到的特征提取能力是可以迁移的,尤其是手掌纹的纹理和边缘特征,在不同类别间有共性。
2. 数据集结构与标注细节深度拆解
2.1 目录组织与文件命名规范
一个结构清晰的数据集目录能省掉大量排查时间。按照VOC和YOLO双格式的常见组织方式,这个数据集的目录结构大概率是这样的:
dataset/ ├── images/ # 所有原始图像 │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── annotations/ # VOC格式XML标注 │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── labels/ # YOLO格式txt标注 │ ├── 000001.txt │ ├── 000002.txt │ └── ... └── ImageSets/ └── Main/ ├── train.txt ├── val.txt └── test.txt这里有个细节值得注意:图像文件名和标注文件名必须严格对应,只是扩展名不同。我在处理其他数据集时遇到过图像是IMG_001.jpg但标注是001.xml的情况,写数据加载器时得额外做名称映射,很容易出错。这个数据集如果命名规范统一,直接按文件名匹配就行。
ImageSets/Main/下的划分文件是VOC格式的标准做法,每行一个文件名(不含扩展名)。YOLO训练时通常不直接读这个文件,而是用train.txt和val.txt指定图像路径列表。如果你要用YOLO格式训练,需要自己生成这两个列表文件,或者用Ultralytics框架的data.yaml配置指向图像目录,让框架自动划分。
2.2 VOC标注文件的关键字段解读
打开一个VOC格式的XML文件,核心结构如下:
<annotation> <folder>images</folder> <filename>000001.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>palm</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>120</xmin> <ymin>85</ymin> <xmax>520</xmax> <ymax>410</ymax> </bndbox> </object> </annotation>size字段记录图像宽高和通道数,这个信息在训练时用于验证标注坐标是否越界。bndbox的四个值是绝对像素坐标,原点在左上角。truncated表示目标是否被截断,difficult表示是否难以识别,这两个标志在计算mAP时会影响样本的纳入或排除。
我建议在正式训练前写个脚本扫一遍所有XML,检查三件事:xmin < xmax且ymin < ymax是否成立、坐标是否在图像尺寸范围内、name字段是否统一。这三个检查能过滤掉大部分标注错误。曾经有个数据集里混了几张xmin和xmax写反的标注,训练时这些框的宽高变成负数,损失函数直接出NaN,排查起来很费时间。
2.3 YOLO标注的归一化计算与验证
YOLO格式的每行标注长这样:
0 0.500000 0.515625 0.625000 0.677083第一个0是类别索引,后面四个是归一化后的中心坐标和宽高。归一化的计算方式是:
center_x = (xmin + xmax) / 2 / image_widthcenter_y = (ymin + ymax) / 2 / image_heightwidth = (xmax - xmin) / image_widthheight = (ymax - ymin) / image_height
以刚才的XML为例,图像宽640高480,边界框是(120, 85, 520, 410):
center_x = (120 + 520) / 2 / 640 = 320 / 640 = 0.5center_y = (85 + 410) / 2 / 480 = 247.5 / 480 ≈ 0.5156width = (520 - 120) / 640 = 400 / 640 = 0.625height = (410 - 85) / 480 = 325 / 480 ≈ 0.6771
验证YOLO标注是否正确,可以反向计算回像素坐标,跟VOC的bndbox对比。如果误差在1到2个像素以内,说明转换没问题。我习惯在训练前随机抽20张图做这个反向验证,比单纯看文件数量靠谱得多。
注意:YOLO格式的坐标是归一化值,如果图像尺寸在训练时被resize,标注不需要重新计算,因为归一化坐标是尺度无关的。但如果你做了裁剪或padding,就需要同步调整标注。
2.4 2011张图像的数据分布评估
2011张对于目标检测任务来说属于小规模数据集。作为参考,COCO有超过20万张,VOC2007也有近1万张。小数据集训练的关键是控制过拟合,具体策略后面会展开讲。
先看数据分布。如果这2011张图像来自不同的采集条件(光照、背景、手掌姿态),那数据的多样性可能比数量更重要。我通常会做几个统计:图像分辨率分布、边界框尺寸分布、边界框在图像中的位置分布。这些统计能帮你判断数据集是否存在偏置。
比如,如果80%的边界框都集中在图像中央区域,模型可能会学到“手掌纹总在中间”这个先验,遇到手掌偏左或偏右的图像就检测不好。解决办法是在数据增强时加入随机裁剪和随机平移,打破这种位置偏置。
另一个要看的指标是每张图的目标数量。单类别数据集里,如果大部分图像只有1个手掌纹,少数图像有2个或更多,那模型可能会偏向于每张图只预测一个框。训练时可以通过调整max_det参数或后处理逻辑来适配实际需求。
3. 从零搭建YOLO训练环境的完整流程
3.1 环境准备与依赖安装
训练环境我推荐用Python 3.8到3.10之间的版本,太新的版本有时会遇到某些库的兼容问题。PyTorch的版本跟CUDA驱动相关,如果你有NVIDIA显卡,先确认驱动版本,再选对应的PyTorch安装命令。
用conda创建独立环境是个好习惯,避免跟系统Python或其他项目的依赖冲突:
conda create -n palm_det python=3.9 conda activate palm_det安装PyTorch,以CUDA 11.8为例:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118然后安装Ultralytics框架:
pip install ultralytics验证安装是否成功:
import torch print(torch.cuda.is_available()) # 应该输出True from ultralytics import YOLO print(YOLO.__version__)如果torch.cuda.is_available()返回False,说明CUDA没配好,训练会退到CPU上,速度慢几十倍。这种情况先检查显卡驱动和CUDA版本是否匹配,不要急着往下走。
3.2 数据集配置文件编写
Ultralytics框架用YAML文件描述数据集路径和类别信息。在项目根目录新建palm_dataset.yaml:
path: /absolute/path/to/dataset train: images/train val: images/val test: images/test nc: 1 names: 0: palmpath是数据集根目录的绝对路径,train、val、test是相对于path的图像目录。这里假设你已经把2011张图像按比例划分到了三个子目录中。常见的划分比例是7:2:1或8:1:1,小数据集建议验证集不少于200张,否则评估指标的波动会很大。
如果原始数据集没有划分,可以用脚本随机拆分:
import os import random import shutil image_dir = "dataset/images" train_dir = "dataset/images/train" val_dir = "dataset/images/val" test_dir = "dataset/images/test" os.makedirs(train_dir, exist_ok=True) os.makedirs(val_dir, exist_ok=True) os.makedirs(test_dir, exist_ok=True) images = [f for f in os.listdir(image_dir) if f.endswith(('.jpg', '.png'))] random.seed(42) random.shuffle(images) n = len(images) train_end = int(n * 0.7) val_end = int(n * 0.9) for i, img in enumerate(images): src = os.path.join(image_dir, img) if i < train_end: dst = os.path.join(train_dir, img) elif i < val_end: dst = os.path.join(val_dir, img) else: dst = os.path.join(test_dir, img) shutil.copy(src, dst)注意标注文件也要跟着图像一起移动,YOLO格式的txt文件放在跟图像同级的labels目录下,目录结构要跟images保持一致。
3.3 训练参数配置与启动
Ultralytics的训练入口很简洁,但参数配置决定了训练效果。以下是一个针对小数据集的配置示例:
from ultralytics import YOLO model = YOLO("yolov8n.pt") # 从预训练权重开始 results = model.train( data="palm_dataset.yaml", epochs=150, imgsz=640, batch=16, lr0=0.001, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3, patience=30, augment=True, mosaic=1.0, mixup=0.1, copy_paste=0.1, degrees=10.0, translate=0.1, scale=0.5, fliplr=0.5, flipud=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, device=0, workers=4, project="palm_runs", name="exp1" )几个关键参数的解释:
epochs=150:小数据集容易过拟合,但训练轮次太少又学不充分。150轮配合patience=30的早停机制,是个比较稳妥的起点。lr0=0.001:初始学习率。YOLOv8默认是0.01,但小数据集上我倾向于调低一个数量级,避免初期震荡太大。mosaic=1.0:Mosaic增强把四张图拼成一张,能显著增加单张图的上下文多样性,对小数据集特别有效。mixup=0.1:Mixup把两张图按透明度混合,进一步增加样本多样性,但比例不宜过高,否则图像语义会变得模糊。fliplr=0.5:水平翻转。手掌纹检测中,左右手翻转后语义不变,这个增强可以放心开。flipud=0.0:垂直翻转。手掌纹上下翻转后不符合真实场景,关掉。
启动训练后,控制台会输出每轮的损失值和评估指标。重点关注box_loss和cls_loss是否稳定下降,以及mAP50是否在验证集上持续提升。如果box_loss下降但mAP50不升反降,大概率是过拟合了,需要加强正则化或减少模型参数量。
3.4 训练过程监控与日志解读
Ultralytics默认会在project/name目录下生成训练日志和权重文件。results.csv记录了每轮的详细指标,可以用pandas读取后画图:
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("palm_runs/exp1/results.csv") df.columns = df.columns.str.strip() fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(df["epoch"], df["train/box_loss"], label="train box loss") axes[0].plot(df["epoch"], df["val/box_loss"], label="val box loss") axes[0].legend() axes[1].plot(df["epoch"], df["metrics/mAP50(B)"], label="mAP50") axes[1].legend() plt.savefig("training_curve.png")我一般会看三条曲线:训练损失、验证损失、mAP50。理想情况下,训练损失和验证损失同步下降,mAP50稳步上升。如果验证损失在某个epoch后开始上升,而训练损失还在降,那就是过拟合的信号,早停机制应该在这个时候触发。
实操心得:小数据集训练时,我习惯把
save_period设为10,每10轮存一个权重文件。这样即使训练后期过拟合了,还能回退到中间某个效果更好的checkpoint。
4. 小数据集训练的策略与调优经验
4.1 迁移学习与骨干网络选择
2011张图从头训练一个检测模型,效果通常不会太好。迁移学习是必选项。YOLOv8提供了n、s、m、l、x五个尺度的预训练权重,参数量从300万到6800万不等。小数据集上,我强烈建议从yolov8n.pt或yolov8s.pt开始。
原因很简单:模型参数量越大,拟合小数据集的能力越强,但过拟合的风险也越高。nano版本只有300万参数,在2011张图上训练,过拟合风险相对可控。如果nano版本的效果不达标,再考虑升级到small版本,同时加强数据增强和正则化。
冻结骨干网络的前几层是另一种控制过拟合的手段。YOLOv8的freeze参数可以指定冻结的层数:
model.train(..., freeze=10)冻结前10层意味着这些层的权重在训练中不更新,只训练后面的检测头。这样做的好处是保留了预训练模型在通用图像上学到的底层特征(边缘、纹理),同时让检测头专注于手掌纹这个特定任务。缺点是如果手掌纹的底层特征跟通用图像差异很大,冻结反而会限制模型的学习能力。我的经验是,先不冻结跑一轮,看看效果,如果过拟合明显再尝试冻结。
4.2 数据增强的组合策略
小数据集训练的核心矛盾是:模型需要足够的样本多样性来学习泛化能力,但实际可用的样本又很少。数据增强就是在这个矛盾中找平衡。
对于手掌纹检测,我推荐的增强组合是:
| 增强类型 | 参数值 | 作用 | 注意事项 |
|---|---|---|---|
| Mosaic | 1.0 | 四图拼接,增加上下文 | 训练后期可降低到0.5 |
| Mixup | 0.1 | 两图混合,增加多样性 | 过高会导致语义模糊 |
| 水平翻转 | 0.5 | 左右手互换 | 手掌纹语义不变,安全 |
| 随机平移 | 0.1 | 位置偏移 | 模拟手掌不在中央的情况 |
| 随机缩放 | 0.5 | 尺度变化 | 模拟不同距离拍摄 |
| HSV色调 | 0.015 | 颜色扰动 | 模拟不同光照 |
| HSV饱和度 | 0.7 | 饱和度扰动 | 模拟不同采集设备 |
| HSV亮度 | 0.4 | 亮度扰动 | 模拟不同曝光 |
Mosaic增强在训练前期效果很好,但到了训练后期,四图拼接可能导致边界框的上下文不自然。我通常会在最后20%的epoch里把mosaic降到0.5或关闭,让模型在更接近真实分布的图像上做微调。Ultralytics支持通过close_mosaic参数指定在第几个epoch关闭:
model.train(..., mosaic=1.0, close_mosaic=30)这表示前120轮用Mosaic,最后30轮关闭。
4.3 学习率调度与早停机制
学习率调度对训练稳定性影响很大。YOLOv8默认用余弦退火,从lr0线性warmup到设定值,然后按余弦曲线衰减到lrf * lr0。小数据集上,我建议把warmup_epochs设到3到5,让模型在初期慢慢适应数据分布,避免一开始就大步更新导致震荡。
早停机制通过patience参数控制。如果验证集指标连续patience轮没有提升,训练自动停止。小数据集上我通常设patience=30,给模型足够的探索空间,同时避免在过拟合区域浪费太多时间。
有个细节容易被忽略:早停的监控指标默认是mAP50-95,但小数据集上这个指标波动很大,有时mAP50在涨但mAP50-95没动。可以通过save_best和save_last参数控制保存策略,我一般两个都开,训练结束后对比两个权重的实际表现再决定用哪个。
4.4 过拟合的识别与应对
过拟合的典型表现是:训练损失持续下降,验证损失在某个点后开始上升,mAP50在验证集上停滞或下降。识别过拟合最直接的方法是看损失曲线,但更可靠的是看验证集上的实际检测效果。
我习惯在训练中期用验证集跑一次推理,把预测框和真实框画在同一张图上对比。如果模型在训练集上框得很准,但在验证集上漏检或误检明显,那就是过拟合了。
应对过拟合的手段按优先级排序:
- 增加数据增强强度:提高
mixup、copy_paste的比例,或者加入新的增强方式如随机遮挡。 - 降低模型复杂度:从
yolov8s换回yolov8n,或者冻结更多层。 - 增加正则化:提高
weight_decay,或者在检测头加入Dropout。 - 减少训练轮次:配合早停,在验证指标最好的checkpoint处停止。
踩过的坑:有一次我在一个小数据集上训练,mAP50到了0.85就上不去了,以为是模型容量不够,换了大模型反而降到0.78。后来发现是验证集的划分有问题,验证集里的图像跟训练集有重叠,导致评估指标虚高。重新按图像来源划分后,真实mAP50只有0.72,但模型泛化能力反而更好了。
5. 模型评估、推理与部署实操
5.1 评估指标解读与验证集测试
训练完成后,用验证集跑一次评估:
model = YOLO("palm_runs/exp1/weights/best.pt") metrics = model.val(data="palm_dataset.yaml", split="val") print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.box.map75) # mAP75 print(metrics.box.maps) # 每个类别的mAP对于单类别检测,map50是最直观的指标。0.9以上说明模型在验证集上表现很好,0.7到0.9之间属于可用但还有优化空间,低于0.7就需要检查数据质量或调整训练策略了。
但指标只是参考,实际效果还得看可视化。用验证集图像跑推理并保存结果:
results = model.predict( source="dataset/images/val", conf=0.25, iou=0.45, save=True, project="palm_runs", name="val_predictions" )conf=0.25是置信度阈值,低于这个值的预测框会被过滤掉。iou=0.45是NMS的IoU阈值,控制重叠框的合并程度。这两个参数需要根据实际场景调整:如果漏检多,降低conf;如果误检多,提高conf。
5.2 推理速度优化与模型导出
如果要把模型部署到边缘设备或移动端,推理速度是关键。YOLOv8支持导出为ONNX、TensorRT、OpenVINO等格式:
model.export(format="onnx", imgsz=640, half=True)half=True表示用FP16精度导出,模型体积减半,推理速度提升,精度损失通常在可接受范围内。导出ONNX后可以用ONNX Runtime做推理:
import onnxruntime as ort import numpy as np import cv2 session = ort.InferenceSession("best.onnx") input_name = session.get_inputs()[0].name img = cv2.imread("test.jpg") img = cv2.resize(img, (640, 640)) img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, HWC to CHW img = np.expand_dims(img, axis=0).astype(np.float32) / 255.0 outputs = session.run(None, {input_name: img})ONNX Runtime在CPU上的推理速度比PyTorch快不少,如果设备有GPU,可以装onnxruntime-gpu进一步加速。
5.3 实际场景中的后处理技巧
模型输出的原始预测框通常需要后处理才能用于实际业务。常见的后处理包括:
- 置信度过滤:去掉低置信度的框,减少误检。
- NMS:合并重叠框,避免同一目标被多次检测。
- 边界框裁剪:把超出图像边界的框裁剪到图像范围内。
- 宽高比过滤:手掌纹的宽高比通常在0.5到2.0之间,超出这个范围的框可能是误检。
我习惯在推理脚本里加一个宽高比过滤:
def filter_boxes(boxes, min_ratio=0.3, max_ratio=3.0): filtered = [] for box in boxes: x1, y1, x2, y2 = box[:4] w = x2 - x1 h = y2 - y1 ratio = w / h if h > 0 else 0 if min_ratio <= ratio <= max_ratio: filtered.append(box) return filtered这个过滤在手掌纹检测中特别有用,因为手掌纹区域的形状相对固定,长条形或极扁的框大概率是误检。
5.4 常见问题速查与排查思路
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 训练loss不下降 | 学习率过大或数据标注错误 | 检查标注文件坐标是否越界 | 降低lr0,重新检查标注 |
| mAP50波动大 | 验证集太小或分布不均 | 统计验证集样本数量和类别分布 | 增加验证集比例,重新划分 |
| 推理速度慢 | 模型太大或未用GPU | 检查推理设备 | 换yolov8n,导出ONNX |
| 漏检严重 | 置信度阈值过高 | 降低conf看召回率变化 | 调低conf,增加训练数据 |
| 误检多 | 背景干扰或过拟合 | 可视化误检样本 | 增加负样本,加强增强 |
| 框位置偏移 | 标注格式转换错误 | 反向验证YOLO坐标 | 重新转换标注 |
独家避坑:如果训练时
box_loss正常下降但cls_loss一直是0,检查数据集的nc和names配置。单类别时nc=1,names里只有一个类别名。如果nc设成了0或者names为空,分类分支的损失计算会出问题。
6. 数据集扩展与模型迭代的实用建议
6.1 从单类别到多类别的扩展路径
如果后续业务需要区分左手右手,或者区分不同的手掌纹类型,扩展路径是:先用手掌纹检测模型做预训练,然后在新的多类别数据上微调。微调时把nc改成新的类别数,names更新为对应的类别名,加载预训练权重时用model = YOLO("best.pt")然后model.train(data="new_dataset.yaml")。
微调的学习率要比从头训练低,通常设lr0=0.0001到0.0005,让模型在保留原有特征的基础上适应新类别。训练轮次也可以减少,50到100轮通常够用。
6.2 数据采集与标注的实操建议
如果现有2011张不够用,需要自己补充数据,几个实操建议:
- 采集设备多样化:不同手机、不同摄像头拍出来的手掌纹在分辨率、色彩、噪点上都有差异,多样化的数据能提升模型泛化能力。
- 光照条件覆盖:强光、弱光、侧光、逆光都要有,避免模型只在特定光照下有效。
- 背景多样性:纯色背景、复杂背景、纹理背景都要采集,让模型学会区分手掌纹和背景。
- 标注一致性:多人标注时先统一标准,边界框是紧贴手掌纹边缘还是留一点余量,要提前约定好。
标注工具推荐LabelImg或CVAT,前者轻量适合小规模,后者支持多人协作和视频标注。标注完成后用脚本做一次一致性检查,确保没有漏标、错标、坐标越界。
6.3 模型版本管理与实验记录
小数据集训练往往需要多次实验才能找到最优配置。我习惯用以下方式管理实验:
- 每次实验建一个独立目录,命名格式
exp_日期_配置简述,比如exp_20250115_lr0.001_mosaic1.0。 - 训练配置保存为YAML文件放在实验目录下,方便复现。
- 关键指标记录在表格里,包括mAP50、mAP50-95、训练时长、模型大小。
这样做的目的是,当某个实验效果特别好时,能快速定位到当时的配置,而不是靠记忆去猜。我吃过这个亏,有一次调出一个效果很好的模型,但忘了当时的学习率和增强参数,重新试了好几次才复现出来。
6.4 持续迭代的节奏把控
手掌纹检测模型的迭代不是一蹴而就的。我的经验是分三个阶段:
第一阶段,用现有2011张数据快速跑通流程,验证方案可行性,目标是把mAP50做到0.8以上。
第二阶段,针对第一阶段暴露的问题补充数据。比如漏检多就补充手掌纹不完整的样本,误检多就补充复杂背景的负样本。
第三阶段,优化推理速度和部署方案。如果目标设备是边缘设备,可能需要量化或剪枝;如果是服务器端,可以保持FP32精度追求最高准确率。
每个阶段之间留出足够的评估时间,不要急着往下走。我见过太多项目因为跳过评估直接部署,结果在实际场景中效果大打折扣,回头返工的成本比当初认真评估高得多。
最后分享一个我在实际项目中总结的小技巧:手掌纹检测的边界框不需要特别精确,因为下游的特征提取模块通常会对框内区域做归一化处理。所以训练时可以把box_loss的权重适当调低,让模型更关注“有没有检测到”而不是“框得准不准”。这个策略在召回率优先的场景下特别有效,能减少漏检,代价是框的位置精度略有下降,但对整体流程影响不大。