diff --git a/docs/en/guides/yolo-performance-metrics.md b/docs/en/guides/yolo-performance-metrics.md index d88b2ae75..a34f161e6 100644 --- a/docs/en/guides/yolo-performance-metrics.md +++ b/docs/en/guides/yolo-performance-metrics.md @@ -18,7 +18,7 @@ Performance metrics are key tools to evaluate the accuracy and efficiency of obj allowfullscreen>
- Watch: Ultralytics YOLOv8 Performance Metrics | MAP, F1 Score, Precision, IOU & Accuracy + Watch: Ultralytics YOLOv8 Performance Metrics | MAP, F1 Score, Precision, IoU & Accuracy

## Object Detection Metrics diff --git a/docs/en/reference/utils/metrics.md b/docs/en/reference/utils/metrics.md index 6851ae982..21c85066c 100644 --- a/docs/en/reference/utils/metrics.md +++ b/docs/en/reference/utils/metrics.md @@ -1,6 +1,6 @@ --- -description: Explore Ultralytics YOLO metrics tools - from confusion matrix, detection metrics, pose metrics to box IOU. Learn how to compute and plot precision-recall curves. -keywords: Ultralytics, YOLO, YOLOv3, YOLOv4, metrics, confusion matrix, detection metrics, pose metrics, box IOU, mask IOU, plot precision-recall curves, compute average precision +description: Explore Ultralytics YOLO metrics tools - from confusion matrix, detection metrics, pose metrics to box IoU. Learn how to compute and plot precision-recall curves. +keywords: Ultralytics, YOLO, YOLOv3, YOLOv4, metrics, confusion matrix, detection metrics, pose metrics, box IoU, mask IoU, plot precision-recall curves, compute average precision --- # Reference for `ultralytics/utils/metrics.py` diff --git a/ultralytics/engine/exporter.py b/ultralytics/engine/exporter.py index ed5cec57c..23b5caca3 100644 --- a/ultralytics/engine/exporter.py +++ b/ultralytics/engine/exporter.py @@ -41,6 +41,7 @@ Inference: yolov8n.tflite # TensorFlow Lite yolov8n_edgetpu.tflite # TensorFlow Edge TPU yolov8n_paddle_model # PaddlePaddle + yolov8n_ncnn_model # NCNN TensorFlow.js: $ cd .. && git clone https://github.com/zldrobit/tfjs-yolov5-example.git && cd tfjs-yolov5-example @@ -743,10 +744,10 @@ class Exporter: verbose=True, msg="https://github.com/ultralytics/ultralytics/issues/5161", ) + import onnx2tf + f = Path(str(self.file).replace(self.file.suffix, "_saved_model")) if f.is_dir(): - import shutil - shutil.rmtree(f) # delete output folder # Pre-download calibration file to fix https://github.com/PINTO0309/onnx2tf/issues/545 @@ -760,8 +761,9 @@ class Exporter: # Export to TF tmp_file = f / "tmp_tflite_int8_calibration_images.npy" # int8 calibration images file + np_data = None if self.args.int8: - verbosity = "--verbosity info" + verbosity = "info" if self.args.data: # Generate calibration data for integer quantization LOGGER.info(f"{prefix} collecting INT8 calibration images from 'data={self.args.data}'") @@ -778,16 +780,20 @@ class Exporter: # mean = images.view(-1, 3).mean(0) # imagenet mean [123.675, 116.28, 103.53] # std = images.view(-1, 3).std(0) # imagenet std [58.395, 57.12, 57.375] np.save(str(tmp_file), images.numpy()) # BHWC - int8 = f'-oiqt -qt per-tensor -cind images "{tmp_file}" "[[[[0, 0, 0]]]]" "[[[[255, 255, 255]]]]"' - else: - int8 = "-oiqt -qt per-tensor" + np_data = [["images", tmp_file, [[[[0, 0, 0]]]], [[[[255, 255, 255]]]]]] else: - verbosity = "--non_verbose" - int8 = "" - - cmd = f'onnx2tf -i "{f_onnx}" -o "{f}" -nuo {verbosity} {int8}'.strip() - LOGGER.info(f"{prefix} running '{cmd}'") - subprocess.run(cmd, shell=True) + verbosity = "error" + + LOGGER.info(f"{prefix} starting TFLite export with onnx2tf {onnx2tf.__version__}...") + onnx2tf.convert( + input_onnx_file_path=f_onnx, + output_folder_path=str(f), + not_use_onnxsim=True, + verbosity=verbosity, + output_integer_quantized_tflite=self.args.int8, + quant_type="per-tensor", # "per-tensor" (faster) or "per-channel" (slower but more accurate) + custom_input_op_name_np_data_path=np_data, + ) yaml_save(f / "metadata.yaml", self.metadata) # add metadata.yaml # Remove/rename TFLite models @@ -884,7 +890,10 @@ class Exporter: quantization = "--quantize_float16" if self.args.half else "--quantize_uint8" if self.args.int8 else "" with spaces_in_path(f_pb) as fpb_, spaces_in_path(f) as f_: # exporter can not handle spaces in path - cmd = f'tensorflowjs_converter --input_format=tf_frozen_model {quantization} --output_node_names={outputs} "{fpb_}" "{f_}"' + cmd = ( + "tensorflowjs_converter " + f'--input_format=tf_frozen_model {quantization} --output_node_names={outputs} "{fpb_}" "{f_}"' + ) LOGGER.info(f"{prefix} running '{cmd}'") subprocess.run(cmd, shell=True) @@ -1079,7 +1088,7 @@ class Exporter: # Save the model model = ct.models.MLModel(pipeline.spec, weights_dir=weights_dir) model.input_description["image"] = "Input image" - model.input_description["iouThreshold"] = f"(optional) IOU threshold override (default: {nms.iouThreshold})" + model.input_description["iouThreshold"] = f"(optional) IoU threshold override (default: {nms.iouThreshold})" model.input_description["confidenceThreshold"] = ( f"(optional) Confidence threshold override (default: {nms.confidenceThreshold})" ) diff --git a/ultralytics/models/yolo/detect/val.py b/ultralytics/models/yolo/detect/val.py index 4ca307b80..8226cd694 100644 --- a/ultralytics/models/yolo/detect/val.py +++ b/ultralytics/models/yolo/detect/val.py @@ -36,7 +36,7 @@ class DetectionValidator(BaseValidator): self.class_map = None self.args.task = "detect" self.metrics = DetMetrics(save_dir=self.save_dir, on_plot=self.on_plot) - self.iouv = torch.linspace(0.5, 0.95, 10) # iou vector for mAP@0.5:0.95 + self.iouv = torch.linspace(0.5, 0.95, 10) # IoU vector for mAP@0.5:0.95 self.niou = self.iouv.numel() self.lb = [] # for autolabelling diff --git a/ultralytics/trackers/byte_tracker.py b/ultralytics/trackers/byte_tracker.py index 7e10b8d85..01cbca975 100644 --- a/ultralytics/trackers/byte_tracker.py +++ b/ultralytics/trackers/byte_tracker.py @@ -235,7 +235,7 @@ class BYTETracker: reset_id(): Resets the ID counter of STrack. joint_stracks(tlista, tlistb): Combines two lists of stracks. sub_stracks(tlista, tlistb): Filters out the stracks present in the second list from the first list. - remove_duplicate_stracks(stracksa, stracksb): Removes duplicate stracks based on IOU. + remove_duplicate_stracks(stracksa, stracksb): Removes duplicate stracks based on IoU. """ def __init__(self, args, frame_rate=30): @@ -373,7 +373,7 @@ class BYTETracker: return [STrack(xyxy, s, c) for (xyxy, s, c) in zip(dets, scores, cls)] if len(dets) else [] # detections def get_dists(self, tracks, detections): - """Calculates the distance between tracks and detections using IOU and fuses scores.""" + """Calculates the distance between tracks and detections using IoU and fuses scores.""" dists = matching.iou_distance(tracks, detections) # TODO: mot20 # if not self.args.mot20: @@ -428,7 +428,7 @@ class BYTETracker: @staticmethod def remove_duplicate_stracks(stracksa, stracksb): - """Remove duplicate stracks with non-maximum IOU distance.""" + """Remove duplicate stracks with non-maximum IoU distance.""" pdist = matching.iou_distance(stracksa, stracksb) pairs = np.where(pdist < 0.15) dupa, dupb = [], [] diff --git a/ultralytics/utils/metrics.py b/ultralytics/utils/metrics.py index 85f539447..235db5678 100644 --- a/ultralytics/utils/metrics.py +++ b/ultralytics/utils/metrics.py @@ -24,7 +24,7 @@ def bbox_ioa(box1, box2, iou=False, eps=1e-7): Args: box1 (np.ndarray): A numpy array of shape (n, 4) representing n bounding boxes. box2 (np.ndarray): A numpy array of shape (m, 4) representing m bounding boxes. - iou (bool): Calculate the standard iou if True else return inter_area/box2_area. + iou (bool): Calculate the standard IoU if True else return inter_area/box2_area. eps (float, optional): A small value to avoid division by zero. Defaults to 1e-7. Returns: @@ -194,7 +194,7 @@ def _get_covariance_matrix(boxes): def probiou(obb1, obb2, CIoU=False, eps=1e-7): """ - Calculate the prob iou between oriented bounding boxes, https://arxiv.org/pdf/2106.06072v1.pdf. + Calculate the prob IoU between oriented bounding boxes, https://arxiv.org/pdf/2106.06072v1.pdf. Args: obb1 (torch.Tensor): A tensor of shape (N, 5) representing ground truth obbs, with xywhr format. @@ -233,7 +233,7 @@ def probiou(obb1, obb2, CIoU=False, eps=1e-7): def batch_probiou(obb1, obb2, eps=1e-7): """ - Calculate the prob iou between oriented bounding boxes, https://arxiv.org/pdf/2106.06072v1.pdf. + Calculate the prob IoU between oriented bounding boxes, https://arxiv.org/pdf/2106.06072v1.pdf. Args: obb1 (torch.Tensor | np.ndarray): A tensor of shape (N, 5) representing ground truth obbs, with xywhr format. diff --git a/ultralytics/utils/ops.py b/ultralytics/utils/ops.py index fb346a961..439f94409 100644 --- a/ultralytics/utils/ops.py +++ b/ultralytics/utils/ops.py @@ -147,7 +147,7 @@ def nms_rotated(boxes, scores, threshold=0.45): Args: boxes (torch.Tensor): (N, 5), xywhr. scores (torch.Tensor): (N, ). - threshold (float): Iou threshold. + threshold (float): IoU threshold. Returns: """ @@ -287,7 +287,7 @@ def non_max_suppression( # if merge and (1 < n < 3E3): # Merge NMS (boxes merged using weighted mean) # # Update boxes as boxes(i,4) = weights(i,n) * boxes(n,4) # from .metrics import box_iou - # iou = box_iou(boxes[i], boxes) > iou_thres # iou matrix + # iou = box_iou(boxes[i], boxes) > iou_thres # IoU matrix # weights = iou * scores[None] # box weights # x[i, :4] = torch.mm(weights, x[:, :4]).float() / weights.sum(1, keepdim=True) # merged boxes # redundant = True # require redundant detections diff --git a/ultralytics/utils/tal.py b/ultralytics/utils/tal.py index 80fee091d..9cee05008 100644 --- a/ultralytics/utils/tal.py +++ b/ultralytics/utils/tal.py @@ -121,7 +121,7 @@ class TaskAlignedAssigner(nn.Module): return align_metric, overlaps def iou_calculation(self, gt_bboxes, pd_bboxes): - """Iou calculation for horizontal bounding boxes.""" + """IoU calculation for horizontal bounding boxes.""" return bbox_iou(gt_bboxes, pd_bboxes, xywh=False, CIoU=True).squeeze(-1).clamp_(0) def select_topk_candidates(self, metrics, largest=True, topk_mask=None): @@ -231,7 +231,7 @@ class TaskAlignedAssigner(nn.Module): @staticmethod def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): """ - If an anchor box is assigned to multiple gts, the one with the highest IoI will be selected. + If an anchor box is assigned to multiple gts, the one with the highest IoU will be selected. Args: mask_pos (Tensor): shape(b, n_max_boxes, h*w) @@ -260,7 +260,7 @@ class TaskAlignedAssigner(nn.Module): class RotatedTaskAlignedAssigner(TaskAlignedAssigner): def iou_calculation(self, gt_bboxes, pd_bboxes): - """Iou calculation for rotated bounding boxes.""" + """IoU calculation for rotated bounding boxes.""" return probiou(gt_bboxes, pd_bboxes).squeeze(-1).clamp_(0) @staticmethod