VOC与YOLO数据集转换及YOLO训练全流程实战指南

发布时间:2026/9/15 6:23:12
VOC与YOLO数据集转换及YOLO训练全流程实战指南 简介面向药品检测与目标检测模型训练场景这份感冒药品分类检测数据集提供960张标注图片覆盖999感冒灵、板蓝根、布洛芬、drugs四个类别累计1365个矩形标注框可用于药品识别、零售货架巡检、药品包装检测等实际任务。数据集同时提供Pascal VOC和YOLO两种格式标注xml与txt文件按图片命名对应适配LabelImg标注工具可直接接入YOLO系列、Faster R-CNN等主流检测框架省去格式转换环节。压缩包共2000个文件以txt标签文件、xml标注文件和jpg图像文件为主整体大小44.17MB文件结构规整便于批量读取和训练。目前已有394人学习/下载适合目标检测初学者或药品行业开发者作为标注数据补充既能用于教学实践也可为医疗、零售场景的检测模型提供高质量的标注样本节省人工采集与标注时间提升项目迭代效率。1. 目标检测数据集到手先别急着训练拿到「感冒药品分类检测数据集 959 张 3 类别 VOCYOLO 格式的 zip 压缩包」这一类的目标检测数据集多数人第一反应是解压出来直接丢进 YOLO 训练脚本里。然后踩坑loss 异常、mAP 上不去、类别全丢。问题不在模型在于你还没弄清这批数据到底长什么样、标注是不是干净、VOC 和 YOLO 两种格式之间到底能不能直接互相替代。这类小规模医学/药品类目标检测数据集通常只有几百到一千张图3 个类别意味着每个类别的正样本数量非常有限任何标注错位、类别映射错误都会在训练和评估时被无限放大。这篇文章就是把目标检测数据集的完整处理链路讲清楚从解压 zip 开始到目录识别、格式校验、可视化再到用 YOLO 流程完成训练和验证最后给出让这个小数据集发挥最大效用的几个实用建议。2. 从 zip 里看清 VOC 与 YOLO 数据集的标准布局2.1 解压结构里藏着两套标注体系压缩包叫「感冒药品分类检测数据集 959 张 3 类别 VOCYOLO 格式.zip」绝大多数此类数据集解压后都是这样的目录骨架unzip 感冒药品分类检测数据集959张3类别VOCYOLO格式.zip -d ./medicine_dataset cd ./medicine_dataset find . -maxdepth 3 -type d | sort常见的目录布局要么是VOCdevkit风格要么是images labels的 YOLO 风格有些打包者会把两种格式平铺成两个根目录比如VOC/和YOLO/。如果是前者里面通常是JPEGImages、Annotations、ImageSets/Main三分天下如果是后者images/train、labels/train一一对应。这是阅读数据的第一个关键点目标检测数据集的可用性并不在于图片数量而在于标注与图片的文件名是否完全咬合一旦错位模型读到的是错配的框训练效率直接归零。我一般会先做一个全量文件清单确认图片数量和 xml/txt 数量是否对齐echo 图片文件数: $(find . -name *.jpg -o -name *.jpeg -o -name *.png | wc -l) echo VOC标注数: $(find . -name *.xml | wc -l) echo YOLO标注数: $(find . -name *.txt | wc -l)配合数量检查还需要看每个类别下的正样本图片数。3 类别通常对应「感冒颗粒 / 胶囊 / 口服液」或「颗粒 / 片剂 / 胶囊」一类划分具体类别名需要看 labels 目录的.txt文件与配置文件obj.names或data.yaml来确认。常见坑是txt 里的类别编号从 0 开始而 xml 里的类别名是字符串二者如果靠人工去写对应关系漏一个就全乱。2.2 VOC 的 XML 字段与 YOLO 的 TXT 字段到底差在哪VOC 格式全称 PASCAL VOC标注以 XML 描述图片中每个目标的object节点annotation folderJPEGImages/folder filenameIMG_0001.jpg/filename size width640/width height480/height depth3/depth /size object namecapsule/name bndbox xmin100/xmin ymin120/ymin xmax260/xmax ymax300/ymax /bndbox /object /annotationYOLO 格式则完全不同每个 txt 文件与图片同名每一行表示一个目标五个字段依次是class x_center y_center width height全部是相对图片宽高的归一化小数0 0.500000 0.466667 0.240625 0.325000VOC 保存的是左上角和右下角的绝对像素坐标YOLO 保存的是中心点加宽高的相对坐标。理解这个差异是后续所有脚本和训练排错的地基常见的「坐标全跑到图外、loss 不收敛」都源于换算公式用反。对比维度VOCXMLYOLOTXT坐标形式绝对值像素归一化小数0~1框的表示xmin, ymin, xmax, ymaxx_center, y_center, width, height类别表示字符串标签名数字编号需配合 names 文件每图文件数1 个 xml 标注整张图1 个 txt 标注整张图常见配套目录JPEGImages Annotationsimages labels从实际使用角度说YOLO 系列训练脚本默认只吃 txtVOC 格式一般用于学术对比、检测模型迁移和部分老工具链。拿到数据集以后我建议以「原始格式识别 统一转换到 YOLO」为第一优先级因为 YOLO 系的目标检测流程无论 v5、v8 还是其他全部围绕 images/labels 结构展开统一后能免去几乎所有的格式兼容性问题。3. 用脚本把感冒药品检测数据集从 VOC 转到 YOLO 并完成校验3.1 数据集格式转换的最小实现常见做法是写一个 Python 脚本遍历Annotations下的 xml用xml.etree.ElementTree解析出每个目标的类别和坐标再做归一化映射。以感冒药品 3 类别数据集为例先建立类别映射表再用一个循环把所有标注转成 YOLO txt。这里给出一个可以直接复制的实现import os import xml.etree.ElementTree as ET # 类别映射以数据集中真实类别名为准这里仅示例 class_mapping { capsule: 0, granule: 1, oral_liquid: 2, } voc_ann_dir VOC/Annotations yolo_label_dir YOLO/labels os.makedirs(yolo_label_dir, exist_okTrue) for xml_file in os.listdir(voc_ann_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_ann_dir, xml_file)) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) txt_name xml_file.replace(.xml, .txt) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_mapping: print(f警告未知类别 {name} 出现在 {xml_file}) continue class_id class_mapping[name] bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 关键确保边界坐标不越界 xmin max(0, min(xmin, img_w - 1)) xmax max(0, min(xmax, img_w - 1)) ymin max(0, min(ymin, img_h - 1)) ymax max(0, min(ymax, img_h - 1)) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 过滤掉无效小框或全零框 if w 0 or h 0: print(f跳过无效框{xml_file} 中 {name}) continue lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(os.path.join(yolo_label_dir, txt_name), w) as f: f.write(\n.join(lines))脚本逻辑并不复杂但有三处细节值得单独强调。第一是坐标裁剪XML 里偶尔会有手工标注越界的点比如 xmax 超过图片宽度 2 个像素这类边界数据在训练时会导致 anchor 匹配异常最好在转换阶段统一处理掉。第二是归一化的顺序必须先算中心点再除以宽高如果用原始宽高表达式(xmax - xmin) / 2 xmin再归一化同样结果没问题但要避免把两个端点直接当成中心点用。第三是过滤w 0的退化框这种框在 VOC 工具链里能存在在 YOLO 输入管线里则会成为 NaN loss 的来源。3.2 转换后必须做的标注完整性检查转换完成不等于数据可用还要做一轮自动校验。这一步是新手最容易跳过但老手绝不省略的环节。主要检查三件事txt 文件与图片文件是否同名存在、txt 里每行的类别编号是否存在于 0~2 之间、归一化坐标是否都落在 0~1 区间内。import os image_dir YOLO/images label_dir YOLO/labels valid_classes {0, 1, 2} image_names {os.path.splitext(f)[0] for f in os.listdir(image_dir)} label_names {os.path.splitext(f)[0] for f in os.listdir(label_dir)} missing_labels image_names - label_names missing_images label_names - image_names print(f缺标注的图片数量: {len(missing_labels)}) print(f缺图片的标注数量: {len(missing_images)}) for f in sorted(os.listdir(label_dir)): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f)) as fh: for line in fh: parts line.strip().split() if len(parts) ! 5: print(f字段数错误: {f}) continue cls int(parts[0]) coords list(map(float, parts[1:])) if cls not in valid_classes: print(f类别编号越界: {f}) if any(c 0 or c 1 for c in coords): print(f坐标越界: {f})像感冒药品这种小目标检测场景图像里一个胶囊或一袋颗粒只占画面的百分之几坐标转换差一点点就可能导致目标框偏移到背景上。因此校验脚本建议在每次处理数据集后都跑一遍不要只跑一次就对自己说「没问题」。我也习惯顺手统计每个类别的目标框数量确认三个类别是否均衡。类别不均衡严重时即便训练 mAP 数值看起来还行实际推理对少数类别的召回率会非常难看这种情况在自带小样本特性的药品分类数据上尤其常见。4. 用拆分后的照片跑通 YOLO 目标检测流程并调参4.1 构建训练集与验证集的数据集 YAMLYOLO 系训练框架统一通过 YAML 描述数据集路径与类别数。把 959 张感冒药品图片按 8:1:1 或 8:2 拆成训练集和验证集之后配置文件长这样path: /home/user/medicine_dataset/YOLO train: images/train val: images/val test: images/test nc: 3 names: 0: capsule 1: granule 2: oral_liquid如果你的数据集没有预拆分用一行 Python 按比例随机划分即可import os import random import shutil src_images YOLO/images src_labels YOLO/labels out_base YOLO random.seed(42) for split in [train, val, test]: os.makedirs(f{out_base}/images/{split}, exist_okTrue) os.makedirs(f{out_base}/labels/{split}, exist_okTrue) all_files [f for f in os.listdir(src_images) if f.endswith(.jpg)] random.shuffle(all_files) n len(all_files) n_train int(n * 0.8) n_val int(n * 0.1) splits { train: all_files[:n_train], val: all_files[n_train:n_train n_val], test: all_files[n_train n_val:], } for split, files in splits.items(): for f in files: shutil.move(os.path.join(src_images, f), f{out_base}/images/{split}/{f}) label_file f.replace(.jpg, .txt) shutil.move(os.path.join(src_labels, label_file), f{out_base}/labels/{split}/{label_file})YAML 里的path建议写成绝对路径避免不同系统相对路径歧义nc必须与类别映射表的数量保持一致否则训练进程直接报错。拆分的随机种子固定住保证每次实验结果可复现这一点在反复调参时尤其有用。接下来就是真正把数据送进 YOLO 目标检测流程里跑起来。4.2 用预训练权重训练感冒药品检测模型训练命令要能直接看出输入输出的位置以 YOLOv8 为例最直接的训练命令是cd /home/user/medicine_dataset yolo detect train \ datamedicine.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/detect \ namegansmao_exp如果你的环境里是 YOLOv5对应的训练命令稍有不同python train.py \ --data medicine.yaml \ --weights yolov5s.pt \ --img 640 \ --epochs 100 \ --batch 16 \ --project runs/train \ --name gansmao_exp959 张的规模决定了模型不应从随机权重从头训练预训练权重提供的底层特征边缘、纹理、局部形状对药品这类小物体极其宝贵。常见参数配置逻辑是yolov8s或yolov5s足够没必要上l或x因为数据量只有千张级别大模型在这个规模上更容易过拟合imgsz640是速度和精度之间的常见默认值batch大小根据显存调整显存不足就降到 8 或 4patience做早停小数据集训练很容易在 60~80 轮后开始震荡早停可以帮你保住最佳权重。参数名推荐值说明modelyolov8s.pt小模型在千级数据集上泛化性更好imgsz640标准输入分辨率兼顾速度与精度batch4~16由显存决定越稳定越好lr00.005~0.01小数据集可适当降低初始学习率patience20~30验证集分数停滞时提前终止cacheTrue小数据集可缓存到内存显著提速AMD 显卡用户需要注意原生 YOLO 环境大多面向 NVIDIA CUDA换到 AMD 平台需要配好对应推理环境或改用 CPU 训练。这类环境问题不是模型问题尽可能先用云 GPU 或本地 NVIDIA 卡跑通一小轮比如 10 个 epoch确认数据链路没问题再开完整训练。第一个 epoch 的 loss 曲线如果迅速下降然后趋于平缓说明数据和模型整体健康如果 loss 直接跳动甚至出现 NaN优先排查标注文件而不是瞎调学习率。5. 验证检测效果时重点看每类别的各项指标而不是总体精度5.1 用 confusion matrix 和 per-class AP 定位类别混淆训练结束后YOLO 输出目录里会有confusion_matrix.png和results.csv。先别急着看 mAP把三个类别的 precision、recall 和 AP 分别列出来看哪个类别拖后腿。感冒药品的三个类别在视觉上极易混淆胶囊壳有半透明反光颗粒冲剂形态不规则口服液玻璃瓶反光强烈这些都会让检测模型把背景纹理误判为目标边缘。下边这个命令直接读取训练输出中的验证结果逐类汇报检测效果cat runs/detect/gansmao_exp/results.csv | column -t -s,重点看指标为metrics/precision(B)、metrics/recall(B)、metrics/mAP50(B)和metrics/mAP50-95(B)的行。如果你的识别任务中口服液类别 recall 偏低后续改进方向是针对小目标检测调整 anchor 或增大输入分辨率或者在数据增强中增加 HSV 扰动强度来模拟不同光照下的玻璃反光。如果 confusion matrix 显示颗粒经常被误判为胶囊就该回看训练图片里这两类的朝向和尺度分布而不是盲目增加训练轮数。5.2 用推理图检查感冒药品解的框是否贴合目标轮廓跑一轮真实推理把预测结果画回原图是比任何数值都直观的验证方式。YOLO 提供了直接推理并输出标注图的命令yolo predict \ modelruns/detect/gansmao_exp/weights/best.pt \ sourceYOLO/images/val \ saveTrue \ conf0.25 \ iou0.45 \ projectruns/val_predict \ namevisual_check检查推理图时看三个细节目标框边缘是否明显大于或小于药品实体边界说明标注不精准、同一目标是否出现多个重叠框NMS 阈值偏低、小目标是否被漏检。如果推理结果里框总是偏大说明验证集标注本身存在误差需要回炉修正如果偏小通常不是标注问题而是模型把药品局部纹理当成完整物体这时需要检查训练集中的标注是否遗漏了部分目标。5.3 小数据集上让检测精度再上一个台阶的实践技巧959 张图做 3 类别检测模型很快就能达到「能看但不稳」的水平。要继续提升常见的方向是按顺序做这几件事第一把图片分辨率从 640 提到 960对感冒药品这类小目标检测数据集来说分辨率提升的收益往往比换模型架构更大代价是训练显存和推理耗时增加第二用 YOLO 自带的数据增强参数比如hsv_h0.015、hsv_s0.7、hsv_v0.4、degrees10让药品在不同光照和轻微旋转下依然能被检出注意幅度不能太大否则颗粒类目标会形变到不可识别的程度第三用已经训练好的权重做第二轮微调把epochs降到 50、学习率降到 0.001让模型在专用数据上精修而不是从头学一遍。再进阶一点的做法是用mosaic0.5替代默认的 1.0。mosaic 增强在这个规模的数据集中容易制造大量包含多个药品目标但不含标注信息的小块过强的 mosaic 反而干扰小目标学习。另外可以尝试训练时开启cos_lrTrue让学习率余弦衰减通常能比固定衰减多稳定最后一小段训练。最后一个建议是如果这种药品分类检测的标注质量一般优先用置信度阈值 0.35 而不是 0.25 做推理避免把药品包装上的文字区域也框成目标。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询