
简介这份咖啡叶片检测数据集专为YOLO系列目标检测算法设计适用于YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10以及YOLO11等常见版本面向需要真实农业场景图像来训练叶片检测模型的开发者和研究人员。整个压缩包共有两千个文件其中包含九百九十九张JPG格式原图、一千个TXT格式标注文件以及一个YAML配置文件整体大小约为二十四点五三兆字节数据已经按照训练、验证和测试划分完毕下载后可以直接用于模型训练和效果验证。每个标签都采用标准的YOLO格式即「类别、中心点横坐标、中心点纵坐标、目标框宽度、目标框高度」所有坐标均被归一化到零到一之间加载方便同时也可以根据需求转换成VOC格式便于切换到其他目标检测框架。目前已有五十七人学习下载对于刚接触YOLO或者需要快速获得带标注农业数据集的学习者来说能够省去自行采集和人工标注的大量时间可以直接专注于算法调参与精度对比。1. 咖啡叶片检测为什么离不开 YOLO 算法这份带标签数据集先解决什么问题用 yolo 算法做咖啡叶片检测本质上要解决一个问题给模型一张叶片照片让它把所有叶片或病斑区域用矩形框标出来。咖啡叶片检测数据集-1000张图像带标签-叶子testing-detection-zsmzd.zip 这份 zip 包恰好提供了训练一个最小可用模型所需的全部原料图像、标签和明确的检测目标。你不需要自己去网上爬图、手工画框解压之后就能跑通一整套目标检测流程。对谁有用如果你是刚接触目标检测的开发者这份 1000 张图的小数据集是第一个能让你完整走一遍 YOLO 流程的练习场如果你做植物病理研究或农场巡检它能验证“用框定位病斑”这条路是否可行再决定要不要投入大规模标注如果你在评估边缘设备的机器视觉方案它也能快速帮你判断 YOLO 算法在当前硬件上的表现边界。这套流程不只能用在咖啡叶片上轴承缺陷检测、鸟类目标检测等单类目标检测场景基本是同一套做法换数据集就能迁移。2. 解剖这份 1000 张带标签数据集目录结构、标签格式与训练前检查2.1 先解压看目录这类 zip 包的常见命脉拿到类似“叶子testing-detection-zsmzd.zip”的包第一步永远是先解压看目录结构不要直接拿去训练。这是我反复强调的习惯数据集目录一旦理解错后面所有路径、脚本、训练命令都会跟着错。我一般这样操作unzip yolo算法-咖啡叶片检测数据集-1000张图像带标签-叶子testing-detection-zsmzd.zip -d coffee_leaf cd coffee_leaf tree -L 2参数说明unzip -d指定解压目标目录避免在下载目录里摊开几百个文件tree -L 2只显示两层目录足够看清顶层结构。如果系统没有 tree用ls -R也能代替。常见的目录结构有两种。一种是顶层直接放images/和labels/两个目录下各有 train、val、test 子目录另一种是顶层按 train/val 分每个子目录内再放 images 和 labels。这份数据集名字里有“testing-detection”很可能在压缩包里还夹带一个说明文件或类别映射文件。解压后第一时间打开classes.txt或label_map.txt看一眼确认类别编号从 0 开始还是从 1 开始——这地方出错不会报错只会让你训练出来的模型所有框都偏一个类别属于比较隐蔽的坑。另外要注意图片和标签文件的命名一致性。图片叫IMG_0001.jpg、标签叫0001.txt的错位情况并不少见。如果文件名对不上YOLO 训练时会直接跳过这些图数据量本来就只有 1000 张再少几十张对结果影响不小。2.2 YOLO 标签格式解读每行是一个归一化坐标这类数据集的标签通常是.txt纯文本和 YOLO 系列算法的要求一致。每个 txt 文件对应一张 jpg 图片每一行描述一个目标框格式固定为五个数字0 0.5234375 0.3819444 0.04375 0.0708333 0 0.61875 0.4333333 0.03125 0.0527778这五个数字的含义如下表字段含义取值范围class_id类别编号从 0 开始0 ~ nc-1x_center目标框中心点 x 坐标已除以图像宽0 ~ 1y_center目标框中心点 y 坐标已除以图像高0 ~ 1width目标框宽度已除以图像宽0 ~ 1height目标框高度已除以图像高0 ~ 1所有数值都在 0 到 1 之间这是 YOLO 标签区别于 VOC 格式 xml 的关键特征。如果这份数据集的任务是检测叶片本身那么类别编号只有 0如果同时标注了“健康叶片”“锈病叶片”“虫眼叶片”等多个类别txt 里就会混着多个 class_id。拿到数据后先弄清楚标注粒度后面训练才知道自己的模型到底在学什么。和 COCO 那种 json 标注不同YOLO 的 txt 标签是纯文本、一个文件对一张图不需要额外解析库。如果某个数据集给的是 VOC 的 xml 标注需要先用脚本转成 txt但带“testing-detection”这类标识的包通常直接给 YOLO 格式省了转换这一步。万一你手上的包是 xml转换时注意两点一是类别要从 0 重新编号二是标注框的坐标要除以图片宽高做归一化缺一不可。2.3 训练前用脚本检查标签统计类别、框尺寸和缺漏拿到标签后不要急着训练先写个脚本做一次“体检”。我通常会统计总框数、类别分布、异常标注和缺图情况import os from collections import Counter label_dir labels/train image_dir images/train total_boxes 0 class_counter Counter() issues [] for f in os.listdir(label_dir): if not f.endswith(.txt): continue img_file f.replace(.txt, .jpg) if not os.path.exists(os.path.join(image_dir, img_file)): issues.append(f缺图: {f}) with open(os.path.join(label_dir, f)) as fh: for line in fh: parts line.strip().split() if len(parts) ! 5: issues.append(f列数不对: {f} - {line}) continue cls int(parts[0]) x, y, w, h map(float, parts[1:]) if w 1 or h 1: issues.append(f坐标未归一化: {f} - {line}) if x 0 or y 0 or x 1 or y 1: issues.append(f中心点越界: {f} - {line}) class_counter[cls] 1 total_boxes 1 print(总框数:, total_boxes) print(类别分布:, class_counter) print(问题记录:) for item in issues: print( , item)这段脚本做四件事检查标签和图片是否一一对应检查每行是否正好 5 列检查框宽高是否在 0 到 1 之间检查中心点坐标是否越界。跑完一遍数据集里比较明显的错误都能暴露出来。对缺图的文件宁可删掉对应标签也不要硬凑文件名否则训练读取时会触发边界异常。除了“缺图”还有一种更隐蔽的情况是“缺标签”图片存在但没有任何 txt 文件对应。ultralytics 训练时会静默跳过这类图片不会报错所以需要单独对比两个目录的文件名集合把缺标签的图找出来。数据只有 1000 张多找回几十张有效图比调任何训练参数都实在。3. 把数据集跑进 YOLOv8环境准备、目录重排与最小训练命令3.1 环境搭建和依赖版本CUDA、PyTorch、ultralytics 的组合跑 YOLO 算法目前最省心的方式是使用 ultralytics 这个 Python 包它把 YOLOv8 的训练、验证、推理、导出都封装成了命令行工具。环境搭建我建议用 conda 隔离避免把系统 Python 搞乱conda create -n yolo python3.10 conda activate yolo pip install ultralytics8.2.0 torch2.2.0 torchvision0.17.0这里选 torch 2.2.0 是相对稳定的组合和 ultralytics 8.2.0 配合没有已知的算子兼容问题。如果你装的是 torch 2.0 以下新版 ultralytics 在导出模型时可能会报某些算子在 CUDA 上找不到实现反过来 torch 版本太新也可能遇到 CUDA 运行时版本不匹配的警告。如果机器没有 NVIDIA 显卡CPU 也能跑只是训练一个 epoch 的时间会长 5 到 10 倍建议先用 yolov8n 最小模型验证流程。装完先跑一条最简单的推理命令确认环境通yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg这条命令会自动下载 yolov8n 预训练权重然后对示例图片做一次推理。如果这里能正常输出结果图说明 PyTorch、ultralytics、CUDA 的链路是通的。如果报错多半是 CUDA 版本和 PyTorch 不匹配可以用python -c import torch; print(torch.cuda.is_available())先确认 GPU 是否真的被识别。3.2 按 YOLO 规范重排目录train、val、test 怎么分无论原始 zip 的结构是什么样的ultralytics 最终需要的是“图像路径 标签路径 数据集 YAML”。最稳妥的方式是把数据统一重排成下面的结构datasets/coffee_leaf/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── coffee_leaf.yaml用下面的脚本把原始图片和标签按 8:2 划分到训练集和验证集import os import shutil import random random.seed(42) image_dir images label_dir labels train_ratio 0.8 all_images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(all_images) split_idx int(len(all_images) * train_ratio) os.makedirs(datasets/coffee_leaf/images/train, exist_okTrue) os.makedirs(datasets/coffee_leaf/images/val, exist_okTrue) os.makedirs(datasets/coffee_leaf/labels/train, exist_okTrue) os.makedirs(datasets/coffee_leaf/labels/val, exist_okTrue) for f in all_images[:split_idx]: shutil.copy(os.path.join(image_dir, f), datasets/coffee_leaf/images/train/) shutil.copy(os.path.join(label_dir, f.replace(.jpg, .txt)), datasets/coffee_leaf/labels/train/) for f in all_images[split_idx:]: shutil.copy(os.path.join(image_dir, f), datasets/coffee_leaf/images/val/) shutil.copy(os.path.join(label_dir, f.replace(.jpg, .txt)), datasets/coffee_leaf/labels/val/) print(训练集:, split_idx, 验证集:, len(all_images) - split_idx)说明这里用shutil.copy而不是os.rename是给自己留后悔药——即使后面发现划分有问题原始文件还在可以重新划分。随机种子固定为 42保证每次跑出来的划分结果一致方便复现实验。如果你的原始目录已经是 train/val 分开的这段脚本要改成遍历两个子目录后分别复制不要照搬。有一点需要特别注意如果你是按文件名随机划分同一株咖啡树的连续照片很可能同时落在训练集和验证集里导致验证分数虚高。正确的做法是先把文件名按拍摄对象的前缀分组再按组划分。这个细节我在第 5 章专门展开讲这里先埋个伏笔。3.3 最小训练命令从零开始跑通第一个 epoch目录重排好之后在datasets/coffee_leaf/下新建coffee_leaf.yamlpath: /绝对路径/datasets/coffee_leaf # 改成你自己的实际路径 train: images/train val: images/val nc: 1 names: 0: coffee_leaf然后执行训练命令yolo train datacoffee_leaf.yaml modelyolov8n.pt epochs100 imgsz640 batch16第一次训练的目标是验证数据链路是通的不是追求精度。yolov8n.pt是最小的预训练权重下载大约 6 MB失败会提示网络问题。训练时终端会打印每个 epoch 的 box_loss、cls_loss、dfl_loss结束时在runs/detect/train/下生成best.pt和last.pt。如果这一步报错常见的几种情况yaml 里的 path 写成了相对路径但当前工作目录不在数据集根目录图片和标签没有放在对应的 train/val 子目录里某个标签文件为空。逐个排查就行。训练完看一眼runs/detect/train/results.png里面有 loss 曲线和 mAP 曲线能直观判断训练是否正常收敛。4. 训练过程中的参数调整与效果验证从 mAP 到叶片边界4.1 关键训练参数imgsz、batch、epochs、patience 怎么设跑通最小命令之后可以针对咖啡叶片这个任务开始调参数。先看imgsz默认 640 对大多数目标都适用。咖啡叶片图像如果是近景拍摄叶片占画面比例很大640 够用如果图像里叶片很小、密集或者要检测的是叶片上更小的病斑可以提到 960 或 1280但训练时间会显著增加。我一般先用 640 跑通再看验证集里小目标的表现决定要不要升。batch大小取决于显存。16G 显存跑 yolov8n 用 batch16 没问题但如果换 yolov8m 或 imgsz1280显存不够就会报 CUDA out of memory。epochs不要一开始设太多先设 100 配合patience20做早停即验证集 mAP 连续 20 个 epoch 没有提升就自动停止省时间也避免过拟合。我常用的一组起步参数是yolo train datacoffee_leaf.yaml modelyolov8n.pt \ epochs200 patience30 imgsz640 batch16 \ lr00.005 lrf0.01 optimizerAdamW参数说明lr0是初始学习率YOLO 默认 0.01但 1000 张小数据集建议降到 0.005 或 0.001否则前几个 epoch 的 loss 波动很大甚至发散。lrf是最终学习率与初始学习率的比值0.01 表示训练结束时学习率降到初始值的 1%。optimizerAdamW对小数据集比默认的 SGD 更稳收敛曲线更平滑缺点是每轮训练时间略长。如果数据量充足、追求更高精度把modelyolov8n.pt换成yolov8s.pt或yolov8m.pt。模型越大backbone 提取的特征越丰富但训练时间和显存开销成倍增加。对咖啡叶片这种纹理特征明显、目标不算太小的任务yolov8n 到 yolov8s 之间的提升最明显再往上收益就边际递减了。4.2 验证指标怎么看mAP50、mAP50-95、precision、recall训练结束或早停后runs 目录下会生成混淆矩阵、PR 曲线和各类指标曲线。对叶片检测任务我按下面的表格判断模型好坏指标含义叶片场景参考值mAP50IoU 阈值为 0.5 时的平均精度评估“框大概在不在目标附近”0.85 以上算能落地mAP50-95IoU 从 0.5 到 0.95 的平均精度评估框边界的贴合度0.6 以上说明边界预测较准precision预测框中真正包含目标的比例越高误检越少建议 0.85 以上recall真实目标中被检出的比例越低漏检越多建议 0.85 以上如果 mAP50 高但 mAP50-95 明显低说明模型虽然找到了叶片的大致位置但框的边缘不够准。这在叶片互相重叠、病斑和健康组织边界模糊时很常见。解决思路要么提升 imgsz要么换更大模型要么检查标签框本身是否画得随意。precision 和 recall 的取舍要看实际应用场景。在病虫害巡检场景里我宁可接受低一点 precision也要保住 recall。原因是漏检一片带锈病的叶子比多框一片健康叶子代价大得多——前者会导致病害蔓延后者顶多是人工筛一下。反过来如果做的是自动采摘机器人precision 低会导致机械臂抓错目标这时候就要把置信度阈值调高、优先保证 precision。4.3 过拟合与欠拟合的干预手段早停、数据增强、冻结权重1000 张图的数据集在深度学习里算小的过拟合是大概率事件。现象是训练集 loss 持续下降验证集 mAP 停滞甚至倒退。除了早停还有几个手段比较好用。数据增强是成本最低的解法。ultralytics 默认已开启 HSV 色域变换、随机翻转、平移、缩放但这些对叶片这种纹理敏感的目标还不够。可以在 yaml 里追加mosaic: 1.0 mixup: 0.2 copy_paste: 0.2mosaic 把四张图拼成一张训练mixup 按比例混合两张图copy_paste 把某个目标复制到另一张图上。这三个增强对防止过拟合有显著效果但要留意mosaic 的拼接会让单个目标变小如果数据集里本来就有不少小目标建议把 mosaic 降到 0.5mixup 超过 0.3 会让叶片纹理变得模糊导致验证集上病斑检测变差。这些都算 yolo 损失函数之外的“软技巧”不在训练日志里直接体现但效果很实在。冻结权重是另一个思路。如果数据集和 ImageNet 里的自然图像差异不算太极端可以先冻结 backbone只训练 headyolo train datacoffee_leaf.yaml modelyolov8n.pt freeze10freeze10 表示冻结前 10 层保留预训练模型提取的基础特征防止小数据集把 backbone 带偏。如果训练到一半发现 loss 下降很慢可以取消冻结用已经收敛的 head 作为初始化继续全量微调。这个“先冻结、后解冻”的操作比从头训练更稳也是我在小数据集上习惯用的保底方案。5. 咖啡叶片检测的常见坑与排查我在跑这类数据集时踩过的雷5.1 标签坐标归一化出错叶片框全偏到左上角现象训练时 loss 能正常下降但推理时所有框都挤在图像左上角或者框的尺寸明显不对。 原因标签文件里的坐标没有除以图像宽高做归一化而是像素坐标直接进了模型或者除以了一个固定值比如 1000导致中心点和宽高数值全部偏小。YOLO 要求标签坐标必须归一化到 0 到 1 之间否则模型学到的框位置就是错的。 解决用 2.3 的脚本遍历所有标签找出 w 或 h 大于 1 的文件。如果确认没有归一化批量修正from PIL import Image def normalize_labels(img_path, label_path, out_path): with Image.open(img_path) as im: w_real, h_real im.size with open(label_path) as f: lines f.readlines() with open(out_path, w) as f: for line in lines: parts line.strip().split() cls, x_pix, y_pix, w_pix, h_pix parts x_norm float(x_pix) / w_real y_norm float(y_pix) / h_real w_norm float(w_pix) / w_real h_norm float(h_pix) / h_real f.write(f{cls} {x_norm:.6f} {y_norm:.6f} {w_norm:.6f} {h_norm:.6f}\n)这个脚本假设原始标签存的是像素坐标而且中心点坐标和宽高都是像素值。修正后再跑一遍体检脚本确认所有数值都落在 0 到 1 区间内。5.2 类别不平衡健康叶片多、病斑叶片太少怎么办现象训练结束后模型在健康叶片上 recall 很高但病斑类别的 recall 几乎为 0输出的框全部落在健康叶子上。 原因如果这份数据集按叶片状态标注很可能健康叶片占了 80% 以上病斑样本只占少数。模型在类别不平衡下学会了“全都预测为健康叶片”因为这样整体 loss 最低但它根本没有学到病斑的特征。 解决先看类别分布。确认不平衡后最直接的做法是对少数类别做过采样——把病斑样本复制几份和多数类数量接近再训练。另一种做法是给少数类更高的 loss 权重ultralytics 里设置类别权重的方法不是特别直观我一般优先做数据层过采样。如果过采样之后训练时病斑的 loss 还是被淹没再考虑换用带 focal loss 的配置。5.3 光照与背景干扰大棚环境下漏检和误检现象在实验室或统一背景下拍摄的数据集上 mAP 很高一到真实大棚或野外模型就把泥土、杂草、反光水珠当成了叶片或者把阴影里的叶片漏掉。 原因训练集里的图像大多是固定角度、固定光照测试环境的光照和背景差异大。这是目标检测迁移失败的典型问题也常见于轴承缺陷检测这类工业场景——训练时是在恒定的流水线打光下拍的部署到现场光照一变效果就崩。 解决训练时把数据增强里的曝光度、对比度、模糊强度加大模拟不同光照条件。ultralytics 的 hsv_h、hsv_s、hsv_v 三个增强参数控制色相、饱和度、亮度你可以在 yaml 里把 hsv_v 从默认的 0.4 提到 0.6。但这和图像超分辨率重建是两码事——超分是放大图像细节你要的是颜色和亮度的抖动让模型学会忽略光照差异。如果增强之后还是不行就在部署现场重新采一批图像做半自动标注后加入训练集。5.4 数据集泄露同一株咖啡树的图像同时出现在训练集和验证集现象训练时 mAP 冲到 0.95验证时 mAP 也很漂亮但把模型拿到新环境、新植株上一测成绩立即明显下滑。 原因拍照时通常会对同一株树连续拍多张这些图像背景、角度、叶片状态高度相似。如果按文件名随机切分训练集和验证集同一株的相似图像会同时出现在两边验证集过乐观。这个现象在遥感图像标注和作物病害数据里尤其普遍因为采集员习惯对着一块区域连拍。 解决正确做法是按拍摄对象分组划分。把文件名前缀相同的图像视为一个组按组打乱后划分 train/val而不是按单张图划分。比如文件名是tree_01_001.jpg、tree_01_002.jpg就把tree_01开头的所有图放进同一个集合。代码上先提取前缀、对前缀集合做 split再展开到图像列表。这一步虽然麻烦但出来的验证指标才真正有参考价值。5.5 目标框太小导致缩样后信息丢失现象病斑区域在整张图中只占很小面积imgsz640 训练能收敛但推理时小病斑一直漏检导致召回率上不去。 原因病斑可能只有 20×20 像素缩放到 640×640 后在特征图上只占几个像素点backbone 下采样之后信息基本丢失。yolov8n 的颈部网络对微小目标本来就偏弱。 解决把 imgsz 提高到 960 或 1280让病斑在缩放后保留更多像素。YOLO 训练时本身会做多尺度随机缩放但如果输入分辨率不够多尺度也救不回来。这是小目标检测的通用痛点换用专门的小目标改进版本或提高输入分辨率是两条最直接的路。6. 用训练好的权重做推理与部署验证模型在真实叶片图像上的最后一步训练结束后真正让人踏实的是把 best.pt 用在一张没见过的图像上。先整一个带标注的测试目录跑一次推理看效果yolo predict modelruns/detect/train/weights/best.pt \ sourcetest_images/ \ conf0.25 iou0.45conf 是置信度阈值iou 是 NMS 的 IoU 阈值。放在咖啡叶片场景里如果漏检严重就把 conf 降到 0.15如果误检太多就提到 0.4。我会先用 0.2 跑一遍看结果图里多检和漏检的比例再决定往哪个方向调。确认效果可接受后顺手导出 ONNX 格式为后续边缘部署做准备yolo export modelbest.pt formatonnx imgsz640导出后在 Python 里可以用 onnxruntime 推理读取输出层的[1, 84, 8400]张量解析出每个候选框的类别、置信度和坐标。到这里整个流程才算闭环——从一份 zip 数据集到能跑在本地的一颗模型再到能转移到其他运行时环境的部署文件。我用这套流程处理过好几类农业检测数据从咖啡叶片到其他作物叶片过程大同小异。最深的感受是数据集的质量决定训练结果的上限YOLO 算法只是把这份上限兑现出来。拿到任何一份标注数据先花半小时做标签体检、按场景分组划分训练集比多调十次学习率都值。这纯属血泪经验希望帮到你。本文还有配套的精品资源点击获取