mirror of
				https://github.com/THU-MIG/yolov10.git
				synced 2025-11-04 08:56:11 +08:00 
			
		
		
		
	Fix HUBDatasetStats for no-label edge cases (#4583)
This commit is contained in:
		
							parent
							
								
									2db35afad5
								
							
						
					
					
						commit
						f755ba88c3
					
				@ -93,11 +93,15 @@ If you have your own dataset and would like to use it for training detection mod
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
You can easily convert labels from the popular COCO dataset format to the YOLO format using the following code snippet:
 | 
					You can easily convert labels from the popular COCO dataset format to the YOLO format using the following code snippet:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					!!! example ""
 | 
				
			||||||
from ultralytics.data.converter import convert_coco
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
convert_coco(labels_dir='../coco/annotations/')
 | 
					    === "Python"
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					        ```python
 | 
				
			||||||
 | 
					        from ultralytics.data.converter import convert_coco
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        convert_coco(labels_dir='path/to/coco/annotations/')
 | 
				
			||||||
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format.
 | 
					This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -69,11 +69,15 @@ For those looking to introduce their own datasets with oriented bounding boxes,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Transitioning labels from the DOTA dataset format to the YOLO OBB format can be achieved with this script:
 | 
					Transitioning labels from the DOTA dataset format to the YOLO OBB format can be achieved with this script:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					!!! example ""
 | 
				
			||||||
from ultralytics.data.converter import convert_dota_to_yolo_obb
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
convert_dota_to_yolo_obb('path/to/DOTA')
 | 
					    === "Python"
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					        ```python
 | 
				
			||||||
 | 
					        from ultralytics.data.converter import convert_dota_to_yolo_obb
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        convert_dota_to_yolo_obb('path/to/DOTA')
 | 
				
			||||||
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This conversion mechanism is instrumental for datasets in the DOTA format, ensuring alignment with the Ultralytics YOLO OBB format.
 | 
					This conversion mechanism is instrumental for datasets in the DOTA format, ensuring alignment with the Ultralytics YOLO OBB format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,9 +10,7 @@ keywords: Ultralytics, YOLO, pose estimation, datasets, training, YAML, keypoint
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Ultralytics YOLO format
 | 
					### Ultralytics YOLO format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
** Label Format **
 | 
					The dataset label format used for training YOLO pose models is as follows:
 | 
				
			||||||
 | 
					 | 
				
			||||||
The dataset format used for training YOLO pose models is as follows:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. One text file per image: Each image in the dataset has a corresponding text file with the same name as the image file and the ".txt" extension.
 | 
					1. One text file per image: Each image in the dataset has a corresponding text file with the same name as the image file and the ".txt" extension.
 | 
				
			||||||
2. One row per object: Each row in the text file corresponds to one object instance in the image.
 | 
					2. One row per object: Each row in the text file corresponds to one object instance in the image.
 | 
				
			||||||
@ -119,10 +117,14 @@ If you have your own dataset and would like to use it for training pose estimati
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Ultralytics provides a convenient conversion tool to convert labels from the popular COCO dataset format to YOLO format:
 | 
					Ultralytics provides a convenient conversion tool to convert labels from the popular COCO dataset format to YOLO format:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					!!! example ""
 | 
				
			||||||
from ultralytics.data.converter import convert_coco
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
convert_coco(labels_dir='../coco/annotations/', use_keypoints=True)
 | 
					    === "Python"
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					        ```python
 | 
				
			||||||
 | 
					        from ultralytics.data.converter import convert_coco
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        convert_coco(labels_dir='path/to/coco/annotations/', use_keypoints=True)
 | 
				
			||||||
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format. The `use_keypoints` parameter specifies whether to include keypoints (for pose estimation) in the converted labels.
 | 
					This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format. The `use_keypoints` parameter specifies whether to include keypoints (for pose estimation) in the converted labels.
 | 
				
			||||||
 | 
				
			|||||||
@ -10,9 +10,7 @@ keywords: Ultralytics, YOLO, Instance Segmentation, Dataset, YAML, COCO, Auto-An
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Ultralytics YOLO format
 | 
					### Ultralytics YOLO format
 | 
				
			||||||
 | 
					
 | 
				
			||||||
** Label Format **
 | 
					The dataset label format used for training YOLO segmentation models is as follows:
 | 
				
			||||||
 | 
					 | 
				
			||||||
The dataset format used for training YOLO segmentation models is as follows:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. One text file per image: Each image in the dataset has a corresponding text file with the same name as the image file and the ".txt" extension.
 | 
					1. One text file per image: Each image in the dataset has a corresponding text file with the same name as the image file and the ".txt" extension.
 | 
				
			||||||
2. One row per object: Each row in the text file corresponds to one object instance in the image.
 | 
					2. One row per object: Each row in the text file corresponds to one object instance in the image.
 | 
				
			||||||
@ -28,16 +26,16 @@ The format for a single row in the segmentation dataset file is as follows:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
In this format, `<class-index>` is the index of the class for the object, and `<x1> <y1> <x2> <y2> ... <xn> <yn>` are the bounding coordinates of the object's segmentation mask. The coordinates are separated by spaces.
 | 
					In this format, `<class-index>` is the index of the class for the object, and `<x1> <y1> <x2> <y2> ... <xn> <yn>` are the bounding coordinates of the object's segmentation mask. The coordinates are separated by spaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Here is an example of the YOLO dataset format for a single image with two object instances:
 | 
					Here is an example of the YOLO dataset format for a single image with two objects made up of a 3-point segment and a 5-point segment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
0 0.6812 0.48541 0.67 0.4875 0.67656 0.487 0.675 0.489 0.66
 | 
					0 0.681 0.485 0.670 0.487 0.676 0.487
 | 
				
			||||||
1 0.5046 0.0 0.5015 0.004 0.4984 0.00416 0.4937 0.010 0.492 0.0104
 | 
					1 0.504 0.000 0.501 0.004 0.498 0.004 0.493 0.010 0.492 0.0104
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
!!! tip "Tip"
 | 
					!!! tip "Tip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - The length of each row does not have to be equal.
 | 
					      - The length of each row does **not** have to be equal.
 | 
				
			||||||
      - Each segmentation label must have a **minimum of 3 xy points**: `<class-index> <x1> <y1> <x2> <y2> <x3> <y3>`
 | 
					      - Each segmentation label must have a **minimum of 3 xy points**: `<class-index> <x1> <y1> <x2> <y2> <x3> <y3>`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Dataset YAML format
 | 
					### Dataset YAML format
 | 
				
			||||||
@ -103,11 +101,15 @@ If you have your own dataset and would like to use it for training segmentation
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
You can easily convert labels from the popular COCO dataset format to the YOLO format using the following code snippet:
 | 
					You can easily convert labels from the popular COCO dataset format to the YOLO format using the following code snippet:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					!!! example ""
 | 
				
			||||||
from ultralytics.data.converter import convert_coco
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
convert_coco(labels_dir='../coco/annotations/', use_segments=True)
 | 
					    === "Python"
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					        ```python
 | 
				
			||||||
 | 
					        from ultralytics.data.converter import convert_coco
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        convert_coco(labels_dir='path/to/coco/annotations/', use_segments=True)
 | 
				
			||||||
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format.
 | 
					This conversion tool can be used to convert the COCO dataset or any dataset in the COCO format to the Ultralytics YOLO format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,11 +123,15 @@ Auto-annotation is an essential feature that allows you to generate a segmentati
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
To auto-annotate your dataset using the Ultralytics framework, you can use the `auto_annotate` function as shown below:
 | 
					To auto-annotate your dataset using the Ultralytics framework, you can use the `auto_annotate` function as shown below:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```python
 | 
					!!! example ""
 | 
				
			||||||
from ultralytics.data.annotator import auto_annotate
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto_annotate(data="path/to/images", det_model="yolov8x.pt", sam_model='sam_b.pt')
 | 
					    === "Python"
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					        ```python
 | 
				
			||||||
 | 
					        from ultralytics.data.annotator import auto_annotate
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					        auto_annotate(data="path/to/images", det_model="yolov8x.pt", sam_model='sam_b.pt')
 | 
				
			||||||
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Argument   | Type                | Description                                                                                             | Default      |
 | 
					| Argument   | Type                | Description                                                                                             | Default      |
 | 
				
			||||||
|------------|---------------------|---------------------------------------------------------------------------------------------------------|--------------|
 | 
					|------------|---------------------|---------------------------------------------------------------------------------------------------------|--------------|
 | 
				
			||||||
 | 
				
			|||||||
@ -264,7 +264,7 @@ Below are code examples for using each source type:
 | 
				
			|||||||
        ```
 | 
					        ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    === "Streams"
 | 
					    === "Streams"
 | 
				
			||||||
        Run inference on remote streaming sources using RTSP, RTMP, and IP address protocols. If mutliple streams are provided in a `*.streams` text file then batched inference will run, i.e. 8 streams will run at batch-size 8, otherwise single streams will run at batch-size 1.
 | 
					        Run inference on remote streaming sources using RTSP, RTMP, and IP address protocols. If multiple streams are provided in a `*.streams` text file then batched inference will run, i.e. 8 streams will run at batch-size 8, otherwise single streams will run at batch-size 1.
 | 
				
			||||||
        ```python
 | 
					        ```python
 | 
				
			||||||
        from ultralytics import YOLO
 | 
					        from ultralytics import YOLO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,7 @@ Ultralytics provides various installation methods including pip, conda, and Dock
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        !!! note
 | 
					        !!! note
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
            If you are installing in a CUDA environment best practice is to install `ultralytics`, `pytorch` and `pytorch-cuda` in the same command to allow the conda package manager to resolve any conflicts, or else to install `pytorch-cuda` last to allow it override the CPU-specific `pytorch` package if necesary.
 | 
					            If you are installing in a CUDA environment best practice is to install `ultralytics`, `pytorch` and `pytorch-cuda` in the same command to allow the conda package manager to resolve any conflicts, or else to install `pytorch-cuda` last to allow it override the CPU-specific `pytorch` package if necessary.
 | 
				
			||||||
            ```bash
 | 
					            ```bash
 | 
				
			||||||
            # Install all packages together using conda
 | 
					            # Install all packages together using conda
 | 
				
			||||||
            conda install -c conda-forge -c pytorch -c nvidia ultralytics pytorch torchvision pytorch-cuda=11.8 
 | 
					            conda install -c conda-forge -c pytorch -c nvidia ultralytics pytorch torchvision pytorch-cuda=11.8 
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							@ -47,7 +47,7 @@ setup(
 | 
				
			|||||||
            'mkdocs-material',
 | 
					            'mkdocs-material',
 | 
				
			||||||
            'mkdocstrings[python]',
 | 
					            'mkdocstrings[python]',
 | 
				
			||||||
            'mkdocs-redirects',  # for 301 redirects
 | 
					            'mkdocs-redirects',  # for 301 redirects
 | 
				
			||||||
            'mkdocs-ultralytics-plugin>=0.0.25',  # for meta descriptions and images, dates and authors
 | 
					            'mkdocs-ultralytics-plugin>=0.0.26',  # for meta descriptions and images, dates and authors
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        'export': [
 | 
					        'export': [
 | 
				
			||||||
            'coremltools>=7.0.b1',
 | 
					            'coremltools>=7.0.b1',
 | 
				
			||||||
 | 
				
			|||||||
@ -115,7 +115,7 @@ class BaseDataset(Dataset):
 | 
				
			|||||||
                    raise FileNotFoundError(f'{self.prefix}{p} does not exist')
 | 
					                    raise FileNotFoundError(f'{self.prefix}{p} does not exist')
 | 
				
			||||||
            im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS)
 | 
					            im_files = sorted(x.replace('/', os.sep) for x in f if x.split('.')[-1].lower() in IMG_FORMATS)
 | 
				
			||||||
            # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS])  # pathlib
 | 
					            # self.img_files = sorted([x for x in f if x.suffix[1:].lower() in IMG_FORMATS])  # pathlib
 | 
				
			||||||
            assert im_files, f'{self.prefix}No images found'
 | 
					            assert im_files, f'{self.prefix}No images found in {img_path}'
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
            raise FileNotFoundError(f'{self.prefix}Error loading data from {img_path}\n{HELP_URL}') from e
 | 
					            raise FileNotFoundError(f'{self.prefix}Error loading data from {img_path}\n{HELP_URL}') from e
 | 
				
			||||||
        if self.fraction < 1:
 | 
					        if self.fraction < 1:
 | 
				
			||||||
 | 
				
			|||||||
@ -110,13 +110,12 @@ class YOLODataset(BaseDataset):
 | 
				
			|||||||
            tqdm(None, desc=self.prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT)  # display results
 | 
					            tqdm(None, desc=self.prefix + d, total=n, initial=n, bar_format=TQDM_BAR_FORMAT)  # display results
 | 
				
			||||||
            if cache['msgs']:
 | 
					            if cache['msgs']:
 | 
				
			||||||
                LOGGER.info('\n'.join(cache['msgs']))  # display warnings
 | 
					                LOGGER.info('\n'.join(cache['msgs']))  # display warnings
 | 
				
			||||||
        if nf == 0:  # number of labels found
 | 
					 | 
				
			||||||
            raise FileNotFoundError(f'{self.prefix}No labels found in {cache_path}, can not start training. {HELP_URL}')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Read cache
 | 
					        # Read cache
 | 
				
			||||||
        [cache.pop(k) for k in ('hash', 'version', 'msgs')]  # remove items
 | 
					        [cache.pop(k) for k in ('hash', 'version', 'msgs')]  # remove items
 | 
				
			||||||
        labels = cache['labels']
 | 
					        labels = cache['labels']
 | 
				
			||||||
        assert len(labels), f'No valid labels found, please check your dataset. {HELP_URL}'
 | 
					        if not labels:
 | 
				
			||||||
 | 
					            LOGGER.warning(f'WARNING ⚠️ No images found in {cache_path}, training may not work correctly. {HELP_URL}')
 | 
				
			||||||
        self.im_files = [lb['im_file'] for lb in labels]  # update im_files
 | 
					        self.im_files = [lb['im_file'] for lb in labels]  # update im_files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Check if the dataset is all boxes or all segments
 | 
					        # Check if the dataset is all boxes or all segments
 | 
				
			||||||
@ -130,10 +129,9 @@ class YOLODataset(BaseDataset):
 | 
				
			|||||||
            for lb in labels:
 | 
					            for lb in labels:
 | 
				
			||||||
                lb['segments'] = []
 | 
					                lb['segments'] = []
 | 
				
			||||||
        if len_cls == 0:
 | 
					        if len_cls == 0:
 | 
				
			||||||
            raise ValueError(f'All labels empty in {cache_path}, can not start training without labels. {HELP_URL}')
 | 
					            LOGGER.warning(f'WARNING ⚠️ No labels found in {cache_path}, training may not work correctly. {HELP_URL}')
 | 
				
			||||||
        return labels
 | 
					        return labels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # TODO: use hyp config to set all these augmentations
 | 
					 | 
				
			||||||
    def build_transforms(self, hyp=None):
 | 
					    def build_transforms(self, hyp=None):
 | 
				
			||||||
        """Builds and appends transforms to the list."""
 | 
					        """Builds and appends transforms to the list."""
 | 
				
			||||||
        if self.augment:
 | 
					        if self.augment:
 | 
				
			||||||
 | 
				
			|||||||
@ -447,10 +447,17 @@ class HUBDatasetStats:
 | 
				
			|||||||
            return [[int(c[0]), *(round(float(x), 4) for x in points)] for c, points in zipped]
 | 
					            return [[int(c[0]), *(round(float(x), 4) for x in points)] for c, points in zipped]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for split in 'train', 'val', 'test':
 | 
					        for split in 'train', 'val', 'test':
 | 
				
			||||||
            if self.data.get(split) is None:
 | 
					            self.stats[split] = None  # predefine
 | 
				
			||||||
                self.stats[split] = None  # i.e. no test set
 | 
					            path = self.data.get(split)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Check split
 | 
				
			||||||
 | 
					            if path is None:  # no split
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            files = [f for f in Path(path).rglob('*.*') if f.suffix[1:].lower() in IMG_FORMATS]  # image files in split
 | 
				
			||||||
 | 
					            if not files:  # no images
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Get dataset statistics
 | 
				
			||||||
            dataset = YOLODataset(img_path=self.data[split],
 | 
					            dataset = YOLODataset(img_path=self.data[split],
 | 
				
			||||||
                                  data=self.data,
 | 
					                                  data=self.data,
 | 
				
			||||||
                                  use_segments=self.task == 'segment',
 | 
					                                  use_segments=self.task == 'segment',
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user