Skip to content

Reference for ultralytics/models/yolo/detect/val.py

Note

This file is available at https://github.com/ultralytics/ultralytics/blob/main/ultralytics/models/yolo/detect/val.py. If you spot a problem please help fix it by contributing a Pull Request 🛠️. Thank you 🙏!


ultralytics.models.yolo.detect.val.DetectionValidator

DetectionValidator(dataloader=None, save_dir=None, args=None, _callbacks=None)

Bases: BaseValidator

A class extending the BaseValidator class for validation based on a detection model.

This class implements validation functionality specific to object detection tasks, including metrics calculation, prediction processing, and visualization of results.

Attributes:

Name Type Description
is_coco bool

Whether the dataset is COCO.

is_lvis bool

Whether the dataset is LVIS.

class_map List[int]

Mapping from model class indices to dataset class indices.

metrics DetMetrics

Object detection metrics calculator.

iouv Tensor

IoU thresholds for mAP calculation.

niou int

Number of IoU thresholds.

lb List[Any]

List for storing ground truth labels for hybrid saving.

jdict List[Dict[str, Any]]

List for storing JSON detection results.

stats Dict[str, List[Tensor]]

Dictionary for storing statistics during validation.

Examples:

>>> from ultralytics.models.yolo.detect import DetectionValidator
>>> args = dict(model="yolo11n.pt", data="coco8.yaml")
>>> validator = DetectionValidator(args=args)
>>> validator()

Parameters:

Name Type Description Default
dataloader DataLoader

Dataloader to use for validation.

None
save_dir Path

Directory to save results.

None
args Dict[str, Any]

Arguments for the validator.

None
_callbacks List[Any]

List of callback functions.

None
Source code in ultralytics/models/yolo/detect/val.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def __init__(self, dataloader=None, save_dir=None, args=None, _callbacks=None) -> None:
    """
    Initialize detection validator with necessary variables and settings.

    Args:
        dataloader (torch.utils.data.DataLoader, optional): Dataloader to use for validation.
        save_dir (Path, optional): Directory to save results.
        args (Dict[str, Any], optional): Arguments for the validator.
        _callbacks (List[Any], optional): List of callback functions.
    """
    super().__init__(dataloader, save_dir, args, _callbacks)
    self.is_coco = False
    self.is_lvis = False
    self.class_map = None
    self.args.task = "detect"
    self.iouv = torch.linspace(0.5, 0.95, 10)  # IoU vector for mAP@0.5:0.95
    self.niou = self.iouv.numel()
    self.metrics = DetMetrics()

build_dataset

build_dataset(
    img_path: str, mode: str = "val", batch: Optional[int] = None
) -> torch.utils.data.Dataset

Build YOLO Dataset.

Parameters:

Name Type Description Default
img_path str

Path to the folder containing images.

required
mode str

train mode or val mode, users are able to customize different augmentations for each mode.

'val'
batch int

Size of batches, this is for rect.

None

Returns:

Type Description
Dataset

YOLO dataset.

Source code in ultralytics/models/yolo/detect/val.py
271
272
273
274
275
276
277
278
279
280
281
282
283
def build_dataset(self, img_path: str, mode: str = "val", batch: Optional[int] = None) -> torch.utils.data.Dataset:
    """
    Build YOLO Dataset.

    Args:
        img_path (str): Path to the folder containing images.
        mode (str): `train` mode or `val` mode, users are able to customize different augmentations for each mode.
        batch (int, optional): Size of batches, this is for `rect`.

    Returns:
        (Dataset): YOLO dataset.
    """
    return build_yolo_dataset(self.args, img_path, batch, self.data, mode=mode, stride=self.stride)

coco_evaluate

coco_evaluate(
    stats: Dict[str, Any],
    pred_json: str,
    anno_json: str,
    iou_types: Union[str, List[str]] = "bbox",
    suffix: Union[str, List[str]] = "Box",
) -> Dict[str, Any]

Evaluate COCO/LVIS metrics using faster-coco-eval library.

Performs evaluation using the faster-coco-eval library to compute mAP metrics for object detection. Updates the provided stats dictionary with computed metrics including mAP50, mAP50-95, and LVIS-specific metrics if applicable.

Parameters:

Name Type Description Default
stats Dict[str, Any]

Dictionary to store computed metrics and statistics.

required
pred_json str | Path]

Path to JSON file containing predictions in COCO format.

required
anno_json str | Path]

Path to JSON file containing ground truth annotations in COCO format.

required
iou_types str | List[str]]

IoU type(s) for evaluation. Can be single string or list of strings. Common values include "bbox", "segm", "keypoints". Defaults to "bbox".

'bbox'
suffix str | List[str]]

Suffix to append to metric names in stats dictionary. Should correspond to iou_types if multiple types provided. Defaults to "Box".

'Box'

Returns:

Type Description
Dict[str, Any]

Updated stats dictionary containing the computed COCO/LVIS evaluation metrics.

Source code in ultralytics/models/yolo/detect/val.py
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
def coco_evaluate(
    self,
    stats: Dict[str, Any],
    pred_json: str,
    anno_json: str,
    iou_types: Union[str, List[str]] = "bbox",
    suffix: Union[str, List[str]] = "Box",
) -> Dict[str, Any]:
    """
    Evaluate COCO/LVIS metrics using faster-coco-eval library.

    Performs evaluation using the faster-coco-eval library to compute mAP metrics
    for object detection. Updates the provided stats dictionary with computed metrics
    including mAP50, mAP50-95, and LVIS-specific metrics if applicable.

    Args:
        stats (Dict[str, Any]): Dictionary to store computed metrics and statistics.
        pred_json (str | Path]): Path to JSON file containing predictions in COCO format.
        anno_json (str | Path]): Path to JSON file containing ground truth annotations in COCO format.
        iou_types (str | List[str]]): IoU type(s) for evaluation. Can be single string or list of strings.
            Common values include "bbox", "segm", "keypoints". Defaults to "bbox".
        suffix (str | List[str]]): Suffix to append to metric names in stats dictionary. Should correspond
            to iou_types if multiple types provided. Defaults to "Box".

    Returns:
        (Dict[str, Any]): Updated stats dictionary containing the computed COCO/LVIS evaluation metrics.
    """
    if self.args.save_json and (self.is_coco or self.is_lvis) and len(self.jdict):
        LOGGER.info(f"\nEvaluating faster-coco-eval mAP using {pred_json} and {anno_json}...")
        try:
            for x in pred_json, anno_json:
                assert x.is_file(), f"{x} file not found"
            iou_types = [iou_types] if isinstance(iou_types, str) else iou_types
            suffix = [suffix] if isinstance(suffix, str) else suffix
            check_requirements("faster-coco-eval>=1.6.7")
            from faster_coco_eval import COCO, COCOeval_faster

            anno = COCO(anno_json)
            pred = anno.loadRes(pred_json)
            for i, iou_type in enumerate(iou_types):
                val = COCOeval_faster(
                    anno, pred, iouType=iou_type, lvis_style=self.is_lvis, print_function=LOGGER.info
                )
                val.params.imgIds = [int(Path(x).stem) for x in self.dataloader.dataset.im_files]  # images to eval
                val.evaluate()
                val.accumulate()
                val.summarize()

                # update mAP50-95 and mAP50
                stats[f"metrics/mAP50({suffix[i][0]})"] = val.stats_as_dict["AP_50"]
                stats[f"metrics/mAP50-95({suffix[i][0]})"] = val.stats_as_dict["AP_all"]

                if self.is_lvis:
                    stats[f"metrics/APr({suffix[i][0]})"] = val.stats_as_dict["APr"]
                    stats[f"metrics/APc({suffix[i][0]})"] = val.stats_as_dict["APc"]
                    stats[f"metrics/APf({suffix[i][0]})"] = val.stats_as_dict["APf"]

            if self.is_lvis:
                stats["fitness"] = stats["metrics/mAP50-95(B)"]  # always use box mAP50-95 for fitness
        except Exception as e:
            LOGGER.warning(f"faster-coco-eval unable to run: {e}")
    return stats

eval_json

eval_json(stats: Dict[str, Any]) -> Dict[str, Any]

Evaluate YOLO output in JSON format and return performance statistics.

Parameters:

Name Type Description Default
stats Dict[str, Any]

Current statistics dictionary.

required

Returns:

Type Description
Dict[str, Any]

Updated statistics dictionary with COCO/LVIS evaluation results.

Source code in ultralytics/models/yolo/detect/val.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
def eval_json(self, stats: Dict[str, Any]) -> Dict[str, Any]:
    """
    Evaluate YOLO output in JSON format and return performance statistics.

    Args:
        stats (Dict[str, Any]): Current statistics dictionary.

    Returns:
        (Dict[str, Any]): Updated statistics dictionary with COCO/LVIS evaluation results.
    """
    pred_json = self.save_dir / "predictions.json"  # predictions
    anno_json = (
        self.data["path"]
        / "annotations"
        / ("instances_val2017.json" if self.is_coco else f"lvis_v1_{self.args.split}.json")
    )  # annotations
    return self.coco_evaluate(stats, pred_json, anno_json)

finalize_metrics

finalize_metrics() -> None

Set final values for metrics speed and confusion matrix.

Source code in ultralytics/models/yolo/detect/val.py
215
216
217
218
219
220
221
222
def finalize_metrics(self) -> None:
    """Set final values for metrics speed and confusion matrix."""
    if self.args.plots:
        for normalize in True, False:
            self.confusion_matrix.plot(save_dir=self.save_dir, normalize=normalize, on_plot=self.on_plot)
    self.metrics.speed = self.speed
    self.metrics.confusion_matrix = self.confusion_matrix
    self.metrics.save_dir = self.save_dir

get_dataloader

get_dataloader(
    dataset_path: str, batch_size: int
) -> torch.utils.data.DataLoader

Construct and return dataloader.

Parameters:

Name Type Description Default
dataset_path str

Path to the dataset.

required
batch_size int

Size of each batch.

required

Returns:

Type Description
DataLoader

Dataloader for validation.

Source code in ultralytics/models/yolo/detect/val.py
285
286
287
288
289
290
291
292
293
294
295
296
297
def get_dataloader(self, dataset_path: str, batch_size: int) -> torch.utils.data.DataLoader:
    """
    Construct and return dataloader.

    Args:
        dataset_path (str): Path to the dataset.
        batch_size (int): Size of each batch.

    Returns:
        (torch.utils.data.DataLoader): Dataloader for validation.
    """
    dataset = self.build_dataset(dataset_path, batch=batch_size, mode="val")
    return build_dataloader(dataset, batch_size, self.args.workers, shuffle=False, rank=-1)  # return dataloader

get_desc

get_desc() -> str

Return a formatted string summarizing class metrics of YOLO model.

Source code in ultralytics/models/yolo/detect/val.py
103
104
105
def get_desc(self) -> str:
    """Return a formatted string summarizing class metrics of YOLO model."""
    return ("%22s" + "%11s" * 6) % ("Class", "Images", "Instances", "Box(P", "R", "mAP50", "mAP50-95)")

get_stats

get_stats() -> Dict[str, Any]

Calculate and return metrics statistics.

Returns:

Type Description
Dict[str, Any]

Dictionary containing metrics results.

Source code in ultralytics/models/yolo/detect/val.py
224
225
226
227
228
229
230
231
232
233
def get_stats(self) -> Dict[str, Any]:
    """
    Calculate and return metrics statistics.

    Returns:
        (Dict[str, Any]): Dictionary containing metrics results.
    """
    self.metrics.process(save_dir=self.save_dir, plot=self.args.plots, on_plot=self.on_plot)
    self.metrics.clear_stats()
    return self.metrics.results_dict

init_metrics

init_metrics(model: Module) -> None

Initialize evaluation metrics for YOLO detection validation.

Parameters:

Name Type Description Default
model Module

Model to validate.

required
Source code in ultralytics/models/yolo/detect/val.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def init_metrics(self, model: torch.nn.Module) -> None:
    """
    Initialize evaluation metrics for YOLO detection validation.

    Args:
        model (torch.nn.Module): Model to validate.
    """
    val = self.data.get(self.args.split, "")  # validation path
    self.is_coco = (
        isinstance(val, str)
        and "coco" in val
        and (val.endswith(f"{os.sep}val2017.txt") or val.endswith(f"{os.sep}test-dev2017.txt"))
    )  # is COCO
    self.is_lvis = isinstance(val, str) and "lvis" in val and not self.is_coco  # is LVIS
    self.class_map = converter.coco80_to_coco91_class() if self.is_coco else list(range(1, len(model.names) + 1))
    self.args.save_json |= self.args.val and (self.is_coco or self.is_lvis) and not self.training  # run final val
    self.names = model.names
    self.nc = len(model.names)
    self.end2end = getattr(model, "end2end", False)
    self.seen = 0
    self.jdict = []
    self.metrics.names = self.names
    self.confusion_matrix = ConfusionMatrix(names=list(model.names.values()))

plot_predictions

plot_predictions(
    batch: Dict[str, Any],
    preds: List[Dict[str, Tensor]],
    ni: int,
    max_det: Optional[int] = None,
) -> None

Plot predicted bounding boxes on input images and save the result.

Parameters:

Name Type Description Default
batch Dict[str, Any]

Batch containing images and annotations.

required
preds List[Dict[str, Tensor]]

List of predictions from the model.

required
ni int

Batch index.

required
max_det Optional[int]

Maximum number of detections to plot.

None
Source code in ultralytics/models/yolo/detect/val.py
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
def plot_predictions(
    self, batch: Dict[str, Any], preds: List[Dict[str, torch.Tensor]], ni: int, max_det: Optional[int] = None
) -> None:
    """
    Plot predicted bounding boxes on input images and save the result.

    Args:
        batch (Dict[str, Any]): Batch containing images and annotations.
        preds (List[Dict[str, torch.Tensor]]): List of predictions from the model.
        ni (int): Batch index.
        max_det (Optional[int]): Maximum number of detections to plot.
    """
    # TODO: optimize this
    for i, pred in enumerate(preds):
        pred["batch_idx"] = torch.ones_like(pred["conf"]) * i  # add batch index to predictions
    keys = preds[0].keys()
    max_det = max_det or self.args.max_det
    batched_preds = {k: torch.cat([x[k][:max_det] for x in preds], dim=0) for k in keys}
    # TODO: fix this
    batched_preds["bboxes"][:, :4] = ops.xyxy2xywh(batched_preds["bboxes"][:, :4])  # convert to xywh format
    plot_images(
        images=batch["img"],
        labels=batched_preds,
        paths=batch["im_file"],
        fname=self.save_dir / f"val_batch{ni}_pred.jpg",
        names=self.names,
        on_plot=self.on_plot,
    )  # pred

plot_val_samples

plot_val_samples(batch: Dict[str, Any], ni: int) -> None

Plot validation image samples.

Parameters:

Name Type Description Default
batch Dict[str, Any]

Batch containing images and annotations.

required
ni int

Batch index.

required
Source code in ultralytics/models/yolo/detect/val.py
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
def plot_val_samples(self, batch: Dict[str, Any], ni: int) -> None:
    """
    Plot validation image samples.

    Args:
        batch (Dict[str, Any]): Batch containing images and annotations.
        ni (int): Batch index.
    """
    plot_images(
        labels=batch,
        paths=batch["im_file"],
        fname=self.save_dir / f"val_batch{ni}_labels.jpg",
        names=self.names,
        on_plot=self.on_plot,
    )

postprocess

postprocess(preds: Tensor) -> List[Dict[str, torch.Tensor]]

Apply Non-maximum suppression to prediction outputs.

Parameters:

Name Type Description Default
preds Tensor

Raw predictions from the model.

required

Returns:

Type Description
List[Dict[str, Tensor]]

Processed predictions after NMS, where each dict contains 'bboxes', 'conf', 'cls', and 'extra' tensors.

Source code in ultralytics/models/yolo/detect/val.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def postprocess(self, preds: torch.Tensor) -> List[Dict[str, torch.Tensor]]:
    """
    Apply Non-maximum suppression to prediction outputs.

    Args:
        preds (torch.Tensor): Raw predictions from the model.

    Returns:
        (List[Dict[str, torch.Tensor]]): Processed predictions after NMS, where each dict contains
            'bboxes', 'conf', 'cls', and 'extra' tensors.
    """
    outputs = ops.non_max_suppression(
        preds,
        self.args.conf,
        self.args.iou,
        nc=0 if self.args.task == "detect" else self.nc,
        multi_label=True,
        agnostic=self.args.single_cls or self.args.agnostic_nms,
        max_det=self.args.max_det,
        end2end=self.end2end,
        rotated=self.args.task == "obb",
    )
    return [{"bboxes": x[:, :4], "conf": x[:, 4], "cls": x[:, 5], "extra": x[:, 6:]} for x in outputs]

pred_to_json

pred_to_json(predn: Dict[str, Tensor], filename: str) -> None

Serialize YOLO predictions to COCO json format.

Parameters:

Name Type Description Default
predn Dict[str, Tensor]

Predictions dictionary containing 'bboxes', 'conf', and 'cls' keys with bounding box coordinates, confidence scores, and class predictions.

required
filename str

Image filename.

required
Source code in ultralytics/models/yolo/detect/val.py
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
def pred_to_json(self, predn: Dict[str, torch.Tensor], filename: str) -> None:
    """
    Serialize YOLO predictions to COCO json format.

    Args:
        predn (Dict[str, torch.Tensor]): Predictions dictionary containing 'bboxes', 'conf', and 'cls' keys
            with bounding box coordinates, confidence scores, and class predictions.
        filename (str): Image filename.
    """
    stem = Path(filename).stem
    image_id = int(stem) if stem.isnumeric() else stem
    box = ops.xyxy2xywh(predn["bboxes"])  # xywh
    box[:, :2] -= box[:, 2:] / 2  # xy center to top-left corner
    for b, s, c in zip(box.tolist(), predn["conf"].tolist(), predn["cls"].tolist()):
        self.jdict.append(
            {
                "image_id": image_id,
                "category_id": self.class_map[int(c)],
                "bbox": [round(x, 3) for x in b],
                "score": round(s, 5),
            }
        )

preprocess

preprocess(batch: Dict[str, Any]) -> Dict[str, Any]

Preprocess batch of images for YOLO validation.

Parameters:

Name Type Description Default
batch Dict[str, Any]

Batch containing images and annotations.

required

Returns:

Type Description
Dict[str, Any]

Preprocessed batch.

Source code in ultralytics/models/yolo/detect/val.py
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def preprocess(self, batch: Dict[str, Any]) -> Dict[str, Any]:
    """
    Preprocess batch of images for YOLO validation.

    Args:
        batch (Dict[str, Any]): Batch containing images and annotations.

    Returns:
        (Dict[str, Any]): Preprocessed batch.
    """
    batch["img"] = batch["img"].to(self.device, non_blocking=True)
    batch["img"] = (batch["img"].half() if self.args.half else batch["img"].float()) / 255
    for k in {"batch_idx", "cls", "bboxes"}:
        batch[k] = batch[k].to(self.device)

    return batch

print_results

print_results() -> None

Print training/validation set metrics per class.

Source code in ultralytics/models/yolo/detect/val.py
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def print_results(self) -> None:
    """Print training/validation set metrics per class."""
    pf = "%22s" + "%11i" * 2 + "%11.3g" * len(self.metrics.keys)  # print format
    LOGGER.info(pf % ("all", self.seen, self.metrics.nt_per_class.sum(), *self.metrics.mean_results()))
    if self.metrics.nt_per_class.sum() == 0:
        LOGGER.warning(f"no labels found in {self.args.task} set, can not compute metrics without labels")

    # Print results per class
    if self.args.verbose and not self.training and self.nc > 1 and len(self.metrics.stats):
        for i, c in enumerate(self.metrics.ap_class_index):
            LOGGER.info(
                pf
                % (
                    self.names[c],
                    self.metrics.nt_per_image[c],
                    self.metrics.nt_per_class[c],
                    *self.metrics.class_result(i),
                )
            )

save_one_txt

save_one_txt(
    predn: Dict[str, Tensor],
    save_conf: bool,
    shape: Tuple[int, int],
    file: Path,
) -> None

Save YOLO detections to a txt file in normalized coordinates in a specific format.

Parameters:

Name Type Description Default
predn Dict[str, Tensor]

Dictionary containing predictions with keys 'bboxes', 'conf', and 'cls'.

required
save_conf bool

Whether to save confidence scores.

required
shape Tuple[int, int]

Shape of the original image (height, width).

required
file Path

File path to save the detections.

required
Source code in ultralytics/models/yolo/detect/val.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
def save_one_txt(self, predn: Dict[str, torch.Tensor], save_conf: bool, shape: Tuple[int, int], file: Path) -> None:
    """
    Save YOLO detections to a txt file in normalized coordinates in a specific format.

    Args:
        predn (Dict[str, torch.Tensor]): Dictionary containing predictions with keys 'bboxes', 'conf', and 'cls'.
        save_conf (bool): Whether to save confidence scores.
        shape (Tuple[int, int]): Shape of the original image (height, width).
        file (Path): File path to save the detections.
    """
    from ultralytics.engine.results import Results

    Results(
        np.zeros((shape[0], shape[1]), dtype=np.uint8),
        path=None,
        names=self.names,
        boxes=torch.cat([predn["bboxes"], predn["conf"].unsqueeze(-1), predn["cls"].unsqueeze(-1)], dim=1),
    ).save_txt(file, save_conf=save_conf)

update_metrics

update_metrics(preds: List[Dict[str, Tensor]], batch: Dict[str, Any]) -> None

Update metrics with new predictions and ground truth.

Parameters:

Name Type Description Default
preds List[Dict[str, Tensor]]

List of predictions from the model.

required
batch Dict[str, Any]

Batch data containing ground truth.

required
Source code in ultralytics/models/yolo/detect/val.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def update_metrics(self, preds: List[Dict[str, torch.Tensor]], batch: Dict[str, Any]) -> None:
    """
    Update metrics with new predictions and ground truth.

    Args:
        preds (List[Dict[str, torch.Tensor]]): List of predictions from the model.
        batch (Dict[str, Any]): Batch data containing ground truth.
    """
    for si, pred in enumerate(preds):
        self.seen += 1
        pbatch = self._prepare_batch(si, batch)
        predn = self._prepare_pred(pred, pbatch)

        cls = pbatch["cls"].cpu().numpy()
        no_pred = len(predn["cls"]) == 0
        self.metrics.update_stats(
            {
                **self._process_batch(predn, pbatch),
                "target_cls": cls,
                "target_img": np.unique(cls),
                "conf": np.zeros(0) if no_pred else predn["conf"].cpu().numpy(),
                "pred_cls": np.zeros(0) if no_pred else predn["cls"].cpu().numpy(),
            }
        )
        # Evaluate
        if self.args.plots:
            self.confusion_matrix.process_batch(predn, pbatch, conf=self.args.conf)

        if no_pred:
            continue

        # Save
        if self.args.save_json:
            self.pred_to_json(predn, batch["im_file"][si])
        if self.args.save_txt:
            self.save_one_txt(
                predn,
                self.args.save_conf,
                pbatch["ori_shape"],
                self.save_dir / "labels" / f"{Path(batch['im_file'][si]).stem}.txt",
            )





📅 Created 1 year ago ✏️ Updated 10 months ago