YOLOv5 训练找不到标签, No labels found in /path/train.cache 问题的解决方法(亲测可用)
❤️ 网上绝大部分教程所述解决方法都不靠谱,也没有分析问题发生的原因,本文彻底解决了YOLOv5训练时找不到标签,出现 No labels found in /path/train.cache 的问题!希望通过本文,在配置环境的过程中,为各位解决一些不必要的麻烦。——©️ Sylvan Ding
版本 | 系统 |
---|---|
YOLOv5 v6.1 | Linux |
出现 No labels found
的原因主要有两点,一方面是因为网上下载的数据集只提供了其专属的标签格式,需要转换成YOLOv5格式的标签;另一方面则是因为项目目录的组织问题。本文重点探讨后者,即由项目目录的组织问题而引起的找不到标签的问题,这类问题网上的解答较少。
标签格式有误
网上下载的数据集大多数只提供 VOC
格式的 .xml
标记文件,存放于 annotations
文件夹中,或是其他格式的标记文件。此时,就应当先编写程序,将标签转换成YOLOv5所需格式。
YOLOv5标签格式说明
After using a tool like Roboflow Annotate to label your images, export your labels to YOLO format, with one
*.txt
file per image (if no objects in image, no*.txt
file is required). The*.txt
file specifications are:
- One row per object
- Each row is
class x_center y_center width height
format.- Box coordinates must be in normalized xywh format (from 0 - 1). If your boxes are in pixels, divide
x_center
andwidth
by image width, andy_center
andheight
by image height.- Class numbers are zero-indexed (start from 0).
convert VOC to YOLOv5
VOC到YOLOv5格式转换,可以参考yolov5/data/VOC.yaml
中,36行convert_label()
,其中convert_box()
提供了坐标转换功能。
def convert_label(path, lb_path, year, image_id):def convert_box(size, box):dw, dh = 1. / size[0], 1. / size[1]x, y, w, h = (box[0] + box[1]) / 2.0 - 1, (box[2] + box[3]) / 2.0 - 1, box[1] - box[0], box[3] - box[2]return x * dw, y * dh, w * dw, h * dhin_file = open(path / f'VOC{year}/Annotations/{image_id}.xml')out_file = open(lb_path, 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):cls = obj.find('name').textif cls in yaml['names'] and not int(obj.find('difficult').text) == 1:xmlbox = obj.find('bndbox')bb = convert_box((w, h), [float(xmlbox.find(x).text) for x in ('xmin', 'xmax', 'ymin', 'ymax')])cls_id = yaml['names'].index(cls) # class idout_file.write(" ".join([str(a) for a in (cls_id, *bb)]) + '\n')
注:
convert_box(size, box)
,bb = convert_box((w, h), [float(xmlbox.find(x).text) for x in ('xmin', 'xmax', 'ymin', 'ymax')])
❤️ 具体实现细节可以参考其他博主的文章,这类文章比较多。
其他格式转换成YOLOv5
对其他不同格式的标记文件,需要手动编写程序以转换成YOLOv5格式标记。
yolov5/utils/general.py
中的一些函数也许能给您提供一些启发,如xyxy2xywh()
, xywh2xyxy()
… 他们负责坐标格式的转换。
项目目录的结构有误
在得到正确的标签格式后,仍出现No labels found
错误,这时考虑项目目录组织结构出现错误。
正确的目录结构
coco
⭐️ 先放结论,以COCO为例,正确的目录结构应当为:
# path example
../datasets/coco128/images/im0.jpg # image
../datasets/coco128/labels/im0.txt # label
# yolov5/data/coco.yaml
path: ../datasets/coco # dataset root dir
train: train2017.txt # train images (relative to 'path')
val: val2017.txt # val images
test: test-dev2017.txt
-
datasets
文件夹和yolov5
文件夹同级,datasets
下建立各个数据集文件。以coco
为例,images
文件夹直接存放所有图片数据,labels
文件夹直接存放图片对应的*.txt
标记文件。. ├── images │ ├── 20151127_114556.jpg │ ├── 20151127_114946.jpg │ └── 20151127_115133.jpg ├── labels │ ├── 20151127_114556.txt │ ├── 20151127_114946.txt │ └── 20151127_115133.txt
-
注意,
images
和labels
文件夹的命名均不能改成别的!原因稍后再说。 -
train2017.txt
,val2017.txt
,test-dev2017.txt
中存放训练集、验证集、测试集的图片文件路径,其内容如下所示:./images/20151127_114556.jpg ./images/20151127_114946.jpg ./images/20151127_115133.jpg
coco128
如果你想用coco128的文件组织形式:
# yolov5/data/coco128.yaml
path: ../datasets/coco128 # dataset root dir
train: images/train2017 # train images (relative to 'path') 128 images
val: images/train2017 # val images (relative to 'path') 128 images
test: # test images (optional)
则datasets
目录结构应当为:
coco128
├── images
│ ├── test
│ │ └── 20151127_115133.jpg
│ └── train2017
│ └── 20151127_114556.jpg
└── labels├── test│ └── 20151127_115133.txt└── train2017└── 20151127_114556.txt
- 注意,
images
和labels
文件夹的命名均不能改成别的! images
和labels
文件夹内,创建相互对应的文件夹用来存放训练集、验证集、测试集,文件夹名字要一致,没有要求,但需要在coco128.yaml
中设置。
错误原因探究
yolov5/utils/datasets.py
391行 img2label_paths(img_paths)
定义了图片路径到标签路径的映射,447行 self.label_files = img2label_paths(self.im_files) # labels
调用 img2label_paths()
以生成 label_files
.
def img2label_paths(img_paths):# Define label paths as a function of image pathssa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep # /images/, /labels/ substringsreturn [sb.join(x.rsplit(sa, 1)).rsplit('.', 1)[0] + '.txt' for x in img_paths]
YOLOv5 locates labels automatically for each image by replacing the last instance of
/images/
in each image path with/labels/
.
即YOLOv5会自动将图片路径../datasets/coco128/images/*.jpg
更改为../datasets/coco128/labels/*.txt
,以寻找labels路径!
如何解决问题?
在上述 label_files
赋值后,打印 label_files
,我们就能得到标记的路径,再根据打印出的路径修改自己项目的文件路径,方能解决一切问题!
参考文献
Cannot find labels in train.cache custom dataset COCO #6158