dgenerate-ultralytics-headless 8.3.146__py3-none-any.whl → 8.3.147__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dgenerate-ultralytics-headless
3
- Version: 8.3.146
3
+ Version: 8.3.147
4
4
  Summary: Automatically built Ultralytics package with python-opencv-headless dependency instead of python-opencv
5
5
  Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
6
6
  Maintainer-email: Ultralytics <hello@ultralytics.com>
@@ -1,4 +1,4 @@
1
- dgenerate_ultralytics_headless-8.3.146.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
1
+ dgenerate_ultralytics_headless-8.3.147.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
2
2
  tests/__init__.py,sha256=b4KP5_q-2IO8Br8YHOSLYnn7IwZS81l_vfEF2YPa2lM,894
3
3
  tests/conftest.py,sha256=JjgKSs36ZaGmmtqGmAapmFSoFF1YwyV3IZsOgqt2IVM,2593
4
4
  tests/test_cli.py,sha256=Kpfxq_RlbKK1Z8xNScDUbre6GB7neZhXZAYGI1tiDS8,5660
@@ -6,9 +6,9 @@ tests/test_cuda.py,sha256=-nQsfF3lGfqLm6cIeu_BCiXqLj7HzpL7R1GzPEc6z2I,8128
6
6
  tests/test_engine.py,sha256=Jpt2KVrltrEgh2-3Ykouz-2Z_2fza0eymL5ectRXadM,4922
7
7
  tests/test_exports.py,sha256=HmMKOTCia9ZDC0VYc_EPmvBTM5LM5eeI1NF_pKjLpd8,9677
8
8
  tests/test_integrations.py,sha256=cQfgueFhEZ8Xs-tF0uiIEhvn0DlhOH-Wqrx96LXp3D0,6303
9
- tests/test_python.py,sha256=x5m2RAVWnzu5uT5sYnx8ybHpHycToWjzfJJZUklVxqQ,27386
9
+ tests/test_python.py,sha256=_7xc7mqQxw3OsLhAdx-P85u9sqkfIXVhIloxmhBXph4,27800
10
10
  tests/test_solutions.py,sha256=tuf6n_fsI8KvSdJrnc-cqP2qYdiYqCWuVrx0z9dOz3Q,13213
11
- ultralytics/__init__.py,sha256=rr8AlK0l4sHv7KJzILIXcGq-I8vDhSKXc5B_8Lf_yO8,730
11
+ ultralytics/__init__.py,sha256=W3mbuR6Ig3pjncyYQLi3jsgDcXLijQ3MQEDEvaRagQ8,730
12
12
  ultralytics/assets/bus.jpg,sha256=wCAZxJecGR63Od3ZRERe9Aja1Weayrb9Ug751DS_vGM,137419
13
13
  ultralytics/assets/zidane.jpg,sha256=Ftc4aeMmen1O0A3o6GCDO9FlfBslLpTAw0gnetx7bts,50427
14
14
  ultralytics/cfg/__init__.py,sha256=H19EalaxuIa44J_nVBrNxMj8EAPmlZl3ecbX0-xK8y8,39600
@@ -121,7 +121,7 @@ ultralytics/data/scripts/get_coco128.sh,sha256=qmRQl_hOKrsdHrTrnyQuFIH01oDz3lfaz
121
121
  ultralytics/data/scripts/get_imagenet.sh,sha256=hr42H16bM47iT27rgS7MpEo-GeOZAYUQXgr0B2cwn48,1705
122
122
  ultralytics/engine/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6DXppv1-QUM,70
123
123
  ultralytics/engine/exporter.py,sha256=Ug0HvQSseQA9k4jb_CUGXKPg9w082W1cocwPxxtXgkM,73902
124
- ultralytics/engine/model.py,sha256=nOhlQFUTXrghmAfHLo97rji8HCt2vzIhGO6TruWvrNI,53315
124
+ ultralytics/engine/model.py,sha256=0Yslj0TPWi25CELtVQs1dRzJyJAw9-tWTlDbC6kJ0pA,53310
125
125
  ultralytics/engine/predictor.py,sha256=30fBpuwOuNT3hr8bju4coeOr-jqU_8hDYESugmowLBE,22151
126
126
  ultralytics/engine/results.py,sha256=Mb8pBTOrBtQh0PQtGVbhRZ_C1VyqYFumjLggiKCRIJs,72295
127
127
  ultralytics/engine/trainer.py,sha256=zZ2Lm7VJOlBX-Ya52ec3n3IlSn9_yM5fbsRIWGeGOyo,39556
@@ -169,11 +169,11 @@ ultralytics/models/yolo/model.py,sha256=C0wInQC6rFuFOGpdAen1s2e5LIFDmqevto8uPbpm
169
169
  ultralytics/models/yolo/classify/__init__.py,sha256=9--HVaNOfI1K7rn_rRqclL8FUAnpfeBrRqEQIaQw2xM,383
170
170
  ultralytics/models/yolo/classify/predict.py,sha256=_GiN6muuZOBrMS1KER85FE4ktcw_Onn1bZdGvpbsGCE,4618
171
171
  ultralytics/models/yolo/classify/train.py,sha256=jXErkxnsC3pBFQBrFxObF8BJyqkckcw3C_qHMSWZrsY,10312
172
- ultralytics/models/yolo/classify/val.py,sha256=G2huxA1Lf2BL4OUK0Gw43klhG3eLOFMFfhnFjmziKhQ,9721
172
+ ultralytics/models/yolo/classify/val.py,sha256=6YbsbqJA2J6Aw1kyOWj4eGGD0_--23G1Cz5p8lmYFLo,9705
173
173
  ultralytics/models/yolo/detect/__init__.py,sha256=GIRsLYR-kT4JJx7lh4ZZAFGBZj0aebokuU0A7JbjDVA,257
174
174
  ultralytics/models/yolo/detect/predict.py,sha256=ySUsdIf8dw00bzWhcxN1jZwLWKPRT2M7-N7TNL3o4zo,5387
175
175
  ultralytics/models/yolo/detect/train.py,sha256=qCWz0nvU-pQofa-_F7UhUoLQe-U1ExW0mvE5ZHnav4o,9818
176
- ultralytics/models/yolo/detect/val.py,sha256=MCXImLgaoTPDoQvQW9KZyUrtHxVW5xAY3-bxdenZe-c,19164
176
+ ultralytics/models/yolo/detect/val.py,sha256=pb9CzA8qGWGjQnp4EsoK0rlQq0rmIBppCuobNJL7QSc,19126
177
177
  ultralytics/models/yolo/obb/__init__.py,sha256=tQmpG8wVHsajWkZdmD6cjGohJ4ki64iSXQT8JY_dydo,221
178
178
  ultralytics/models/yolo/obb/predict.py,sha256=4r1eSld6TNJlk9JG56e-DX6oPL8uBBqiuztyBpxWlHE,2888
179
179
  ultralytics/models/yolo/obb/train.py,sha256=bnYFAMur7Uvbw5Dc09-S2ge7B05iGX-t37Ksgc0ef6g,3921
@@ -196,7 +196,7 @@ ultralytics/models/yolo/yoloe/train_seg.py,sha256=aCV7M8oQOvODFnU4piZdJh3tIrBJYA
196
196
  ultralytics/models/yolo/yoloe/val.py,sha256=Y0oCiqGvj8LHLrvnfPPUADSj_zNp68BVdpgcER4999E,9736
197
197
  ultralytics/nn/__init__.py,sha256=rjociYD9lo_K-d-1s6TbdWklPLjTcEHk7OIlRDJstIE,615
198
198
  ultralytics/nn/autobackend.py,sha256=uTOQyQ4v0_IZvvqAHnDsAxJv3QKe9-L2ozsZWSlZpPU,41287
199
- ultralytics/nn/tasks.py,sha256=lpFTLOd5EWII9m9v0QkNQx_73JIl0ge9nquvOMaCu4g,71923
199
+ ultralytics/nn/tasks.py,sha256=an91NTeEDnO1JKVcAYnN-xNpfYsUsAZncUVrFG6jLJg,72164
200
200
  ultralytics/nn/text_model.py,sha256=m4jDB5bzOLOS8XNmFi9oQk-skzRHiIpJy4K-_SIARR0,13498
201
201
  ultralytics/nn/modules/__init__.py,sha256=2nY0X69Z5DD5SWt6v3CUTZa5gXSzC9TQr3VTVqhyGho,3158
202
202
  ultralytics/nn/modules/activation.py,sha256=75JcIMH2Cu9GTC2Uf55r_5YLpxcrXQDaVoeGQ0hlUAU,2233
@@ -235,7 +235,7 @@ ultralytics/trackers/utils/__init__.py,sha256=lm6MckFYCPTbqIoX7w0s_daxdjNeBeKW6D
235
235
  ultralytics/trackers/utils/gmc.py,sha256=9IvCf5MhBYY9ppVHykN02_oBWHmE98R8EaYFKaykdV0,14032
236
236
  ultralytics/trackers/utils/kalman_filter.py,sha256=PPmM0lwBMdT_hGojvfLoUsBUFMBBMNRAxKbMcQa3wJ0,21619
237
237
  ultralytics/trackers/utils/matching.py,sha256=uSYtywqi1lE_uNN1FwuBFPyISfDQXHMu8K5KH69nrRI,7160
238
- ultralytics/utils/__init__.py,sha256=CahopjtuOs7q9uKm5NX89vm8iGE8_DJlwvmvX71ezQE,59523
238
+ ultralytics/utils/__init__.py,sha256=GYsojWuYvvSCKhUtQhzv-HmLjfUJrqZXqvu8bw7HbeU,59523
239
239
  ultralytics/utils/autobatch.py,sha256=33m8YgggLIhltDqMXZ5OE-FGs2QiHrl2-LfgY1mI4cw,5119
240
240
  ultralytics/utils/autodevice.py,sha256=AvgXFt8c1Cg4icKh0Hbhhz8UmVQ2Wjyfdfkeb2C8zck,8855
241
241
  ultralytics/utils/benchmarks.py,sha256=14jidnH74g_ZCChuJF5qUnQ2YugX5amGTjea9__RlJ4,30836
@@ -247,7 +247,7 @@ ultralytics/utils/export.py,sha256=ZmxiY5Y2MuL4iBFsLr8ykbUsnvT01DCs0Kg1w3_Ikac,9
247
247
  ultralytics/utils/files.py,sha256=ZCbLGleiF0f-PqYfaxMFAWop88w7U1hpreHXl8b2ko0,8238
248
248
  ultralytics/utils/instance.py,sha256=vhqaZRGT_4K9Q3oQH5KNNK4ISOzxlf1_JjauwhuFhu0,18408
249
249
  ultralytics/utils/loss.py,sha256=fbOWc3Iu0QOJiWbi-mXWA9-1otTYlehtmUsI7os7ydM,39799
250
- ultralytics/utils/metrics.py,sha256=mD5W7yr8T8XNHE0pJx38Ivcbq0PJIFGl0pq_sUOauuo,62122
250
+ ultralytics/utils/metrics.py,sha256=N-QwG-a3ox2cUYdS7-q-cOxLdwlkkZvhA2mF5UdO3jU,63020
251
251
  ultralytics/utils/ops.py,sha256=Yjm397sirPt9wNlgHU2SeVEApeEeYX1msSg5cTBGN8g,34381
252
252
  ultralytics/utils/patches.py,sha256=GI7NXCJ5H22FGp3sIvj5rrGfwdYNRWlxFcW-Jhjgius,5181
253
253
  ultralytics/utils/plotting.py,sha256=QMwedj19XNHus5NbUY3cQI1PGDgriPhHOzGirBsxdK8,48277
@@ -266,8 +266,8 @@ ultralytics/utils/callbacks/neptune.py,sha256=j8pecmlcsM8FGzLKWoBw5xUsi5t8E5HuxY
266
266
  ultralytics/utils/callbacks/raytune.py,sha256=S6Bq16oQDQ8BQgnZzA0zJHGN_BBr8iAM_WtGoLiEcwg,1283
267
267
  ultralytics/utils/callbacks/tensorboard.py,sha256=MDPBW7aDes-66OE6YqKXXvqA_EocjzEMHWGM-8z9vUQ,5281
268
268
  ultralytics/utils/callbacks/wb.py,sha256=Tm_-aRr2CN32MJkY9tylpMBJkb007-MSRNSQ7rDJ5QU,7521
269
- dgenerate_ultralytics_headless-8.3.146.dist-info/METADATA,sha256=S-XDKqULYjwInhWCO3Hsz0CQNjN05mSB9T01h_3GVBs,38296
270
- dgenerate_ultralytics_headless-8.3.146.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
271
- dgenerate_ultralytics_headless-8.3.146.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
272
- dgenerate_ultralytics_headless-8.3.146.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
273
- dgenerate_ultralytics_headless-8.3.146.dist-info/RECORD,,
269
+ dgenerate_ultralytics_headless-8.3.147.dist-info/METADATA,sha256=c0vLhEyDOu3-uNxUmEhxmg7JhwjSioktuF2oMnmSpWk,38296
270
+ dgenerate_ultralytics_headless-8.3.147.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
271
+ dgenerate_ultralytics_headless-8.3.147.dist-info/entry_points.txt,sha256=YM_wiKyTe9yRrsEfqvYolNO5ngwfoL4-NwgKzc8_7sI,93
272
+ dgenerate_ultralytics_headless-8.3.147.dist-info/top_level.txt,sha256=XP49TwiMw4QGsvTLSYiJhz1xF_k7ev5mQ8jJXaXi45Q,12
273
+ dgenerate_ultralytics_headless-8.3.147.dist-info/RECORD,,
tests/test_python.py CHANGED
@@ -203,13 +203,20 @@ def test_track_stream(model):
203
203
  @pytest.mark.parametrize("task,model,data", TASK_MODEL_DATA)
204
204
  def test_val(task: str, model: str, data: str) -> None:
205
205
  """Test the validation mode of the YOLO model."""
206
- metrics = YOLO(model).val(data=data, imgsz=32)
207
- metrics.to_df()
208
- metrics.to_csv()
209
- metrics.to_xml()
210
- metrics.to_html()
211
- metrics.to_json()
212
- metrics.to_sql()
206
+ for plots in [True, False]: # Test both cases i.e. plots=True and plots=False
207
+ metrics = YOLO(model).val(data=data, imgsz=32, plots=plots)
208
+ metrics.to_df()
209
+ metrics.to_csv()
210
+ metrics.to_xml()
211
+ metrics.to_html()
212
+ metrics.to_json()
213
+ metrics.to_sql()
214
+ metrics.confusion_matrix.to_df() # Tests for confusion matrix export
215
+ metrics.confusion_matrix.to_csv()
216
+ metrics.confusion_matrix.to_xml()
217
+ metrics.confusion_matrix.to_html()
218
+ metrics.confusion_matrix.to_json()
219
+ metrics.confusion_matrix.to_sql()
213
220
 
214
221
 
215
222
  def test_train_scratch():
ultralytics/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
- __version__ = "8.3.146"
3
+ __version__ = "8.3.147"
4
4
 
5
5
  import os
6
6
 
@@ -754,7 +754,7 @@ class Model(torch.nn.Module):
754
754
  **kwargs (Any): Arbitrary keyword arguments for training configuration. Common options include:
755
755
  data (str): Path to dataset configuration file.
756
756
  epochs (int): Number of training epochs.
757
- batch_size (int): Batch size for training.
757
+ batch (int): Batch size for training.
758
758
  imgsz (int): Input image size.
759
759
  device (str): Device to run training on (e.g., 'cuda', 'cpu').
760
760
  workers (int): Number of worker threads for data loading.
@@ -79,7 +79,9 @@ class ClassificationValidator(BaseValidator):
79
79
  """Initialize confusion matrix, class names, and tracking containers for predictions and targets."""
80
80
  self.names = model.names
81
81
  self.nc = len(model.names)
82
- self.confusion_matrix = ConfusionMatrix(nc=self.nc, conf=self.args.conf, task="classify")
82
+ self.confusion_matrix = ConfusionMatrix(
83
+ nc=self.nc, conf=self.args.conf, names=self.names.values(), task="classify"
84
+ )
83
85
  self.pred = []
84
86
  self.targets = []
85
87
 
@@ -124,9 +126,7 @@ class ClassificationValidator(BaseValidator):
124
126
  self.confusion_matrix.process_cls_preds(self.pred, self.targets)
125
127
  if self.args.plots:
126
128
  for normalize in True, False:
127
- self.confusion_matrix.plot(
128
- save_dir=self.save_dir, names=self.names.values(), normalize=normalize, on_plot=self.on_plot
129
- )
129
+ self.confusion_matrix.plot(save_dir=self.save_dir, normalize=normalize, on_plot=self.on_plot)
130
130
  self.metrics.speed = self.speed
131
131
  self.metrics.confusion_matrix = self.confusion_matrix
132
132
  self.metrics.save_dir = self.save_dir
@@ -102,7 +102,7 @@ class DetectionValidator(BaseValidator):
102
102
  self.end2end = getattr(model, "end2end", False)
103
103
  self.metrics.names = self.names
104
104
  self.metrics.plot = self.args.plots
105
- self.confusion_matrix = ConfusionMatrix(nc=self.nc, conf=self.args.conf)
105
+ self.confusion_matrix = ConfusionMatrix(nc=self.nc, conf=self.args.conf, names=self.names.values())
106
106
  self.seen = 0
107
107
  self.jdict = []
108
108
  self.stats = dict(tp=[], conf=[], pred_cls=[], target_cls=[], target_img=[])
@@ -231,9 +231,7 @@ class DetectionValidator(BaseValidator):
231
231
  """Set final values for metrics speed and confusion matrix."""
232
232
  if self.args.plots:
233
233
  for normalize in True, False:
234
- self.confusion_matrix.plot(
235
- save_dir=self.save_dir, names=self.names.values(), normalize=normalize, on_plot=self.on_plot
236
- )
234
+ self.confusion_matrix.plot(save_dir=self.save_dir, normalize=normalize, on_plot=self.on_plot)
237
235
  self.metrics.speed = self.speed
238
236
  self.metrics.confusion_matrix = self.confusion_matrix
239
237
 
ultralytics/nn/tasks.py CHANGED
@@ -411,8 +411,11 @@ class DetectionModel(BaseModel):
411
411
  return self.forward(x)["one2many"]
412
412
  return self.forward(x)[0] if isinstance(m, (Segment, YOLOESegment, Pose, OBB)) else self.forward(x)
413
413
 
414
+ self.model.eval() # Avoid changing batch statistics until training begins
415
+ m.training = True # Setting it to True to properly return strides
414
416
  m.stride = torch.tensor([s / x.shape[-2] for x in _forward(torch.zeros(1, ch, s, s))]) # forward
415
417
  self.stride = m.stride
418
+ self.model.train() # Set model back to training(default) mode
416
419
  m.bias_init() # only run once
417
420
  else:
418
421
  self.stride = torch.Tensor([32]) # default stride for i.e. RTDETR
@@ -205,7 +205,7 @@ class DataExportMixin:
205
205
  to_sql: Export results to an SQLite database.
206
206
 
207
207
  Examples:
208
- >>> model = YOLO("yolov8n.pt")
208
+ >>> model = YOLO("yolo11n.pt")
209
209
  >>> results = model("image.jpg")
210
210
  >>> df = results.to_df()
211
211
  >>> print(df)
@@ -309,7 +309,7 @@ def smooth_bce(eps: float = 0.1) -> Tuple[float, float]:
309
309
  return 1.0 - 0.5 * eps, 0.5 * eps
310
310
 
311
311
 
312
- class ConfusionMatrix:
312
+ class ConfusionMatrix(DataExportMixin):
313
313
  """
314
314
  A class for calculating and updating a confusion matrix for object detection and classification tasks.
315
315
 
@@ -321,7 +321,7 @@ class ConfusionMatrix:
321
321
  iou_thres (float): The Intersection over Union threshold.
322
322
  """
323
323
 
324
- def __init__(self, nc: int, conf: float = 0.25, iou_thres: float = 0.45, task: str = "detect"):
324
+ def __init__(self, nc: int, conf: float = 0.25, iou_thres: float = 0.45, names: tuple = (), task: str = "detect"):
325
325
  """
326
326
  Initialize a ConfusionMatrix instance.
327
327
 
@@ -329,11 +329,13 @@ class ConfusionMatrix:
329
329
  nc (int): Number of classes.
330
330
  conf (float, optional): Confidence threshold for detections.
331
331
  iou_thres (float, optional): IoU threshold for matching detections to ground truth.
332
+ names (tuple, optional): Names of classes, used as labels on the plot.
332
333
  task (str, optional): Type of task, either 'detect' or 'classify'.
333
334
  """
334
335
  self.task = task
335
336
  self.matrix = np.zeros((nc + 1, nc + 1)) if self.task == "detect" else np.zeros((nc, nc))
336
337
  self.nc = nc # number of classes
338
+ self.names = list(names) # name of classes
337
339
  self.conf = 0.25 if conf in {None, 0.001} else conf # apply 0.25 if default val conf is passed
338
340
  self.iou_thres = iou_thres
339
341
 
@@ -426,14 +428,13 @@ class ConfusionMatrix:
426
428
 
427
429
  @TryExcept(msg="ConfusionMatrix plot failure")
428
430
  @plt_settings()
429
- def plot(self, normalize: bool = True, save_dir: str = "", names: tuple = (), on_plot=None):
431
+ def plot(self, normalize: bool = True, save_dir: str = "", on_plot=None):
430
432
  """
431
433
  Plot the confusion matrix using matplotlib and save it to a file.
432
434
 
433
435
  Args:
434
436
  normalize (bool, optional): Whether to normalize the confusion matrix.
435
437
  save_dir (str, optional): Directory where the plot will be saved.
436
- names (tuple, optional): Names of classes, used as labels on the plot.
437
438
  on_plot (callable, optional): An optional callback to pass plots path and data when they are rendered.
438
439
  """
439
440
  import matplotlib.pyplot as plt # scope for faster 'import ultralytics'
@@ -441,18 +442,17 @@ class ConfusionMatrix:
441
442
  array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1e-9) if normalize else 1) # normalize columns
442
443
  array[array < 0.005] = np.nan # don't annotate (would appear as 0.00)
443
444
 
444
- names = list(names)
445
445
  fig, ax = plt.subplots(1, 1, figsize=(12, 9))
446
446
  if self.nc >= 100: # downsample for large class count
447
447
  k = max(2, self.nc // 60) # step size for downsampling, always > 1
448
448
  keep_idx = slice(None, None, k) # create slice instead of array
449
- names = names[keep_idx] # slice class names
449
+ self.names = self.names[keep_idx] # slice class names
450
450
  array = array[keep_idx, :][:, keep_idx] # slice matrix rows and cols
451
451
  n = (self.nc + k - 1) // k # number of retained classes
452
452
  nc = nn = n if self.task == "classify" else n + 1 # adjust for background if needed
453
453
  else:
454
454
  nc = nn = self.nc if self.task == "classify" else self.nc + 1
455
- ticklabels = (names + ["background"]) if (0 < nn < 99) and (nn == nc) else "auto"
455
+ ticklabels = (self.names + ["background"]) if (0 < nn < 99) and (nn == nc) else "auto"
456
456
  xy_ticks = np.arange(len(ticklabels))
457
457
  tick_fontsize = max(6, 15 - 0.1 * nc) # Minimum size is 6
458
458
  label_fontsize = max(6, 12 - 0.1 * nc)
@@ -505,6 +505,26 @@ class ConfusionMatrix:
505
505
  for i in range(self.matrix.shape[0]):
506
506
  LOGGER.info(" ".join(map(str, self.matrix[i])))
507
507
 
508
+ def summary(self, **kwargs):
509
+ """Returns summary of the confusion matrix for export in different formats CSV, XML, HTML."""
510
+ import re
511
+
512
+ names = self.names if self.task == "classify" else self.names + ["background"]
513
+ clean_names, seen = [], set()
514
+ for name in names:
515
+ clean_name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
516
+ original_clean = clean_name
517
+ counter = 1
518
+ while clean_name.lower() in seen:
519
+ clean_name = f"{original_clean}_{counter}"
520
+ counter += 1
521
+ seen.add(clean_name.lower())
522
+ clean_names.append(clean_name)
523
+ return [
524
+ dict({"Predicted": clean_names[i]}, **{clean_names[j]: self.matrix[i, j] for j in range(len(clean_names))})
525
+ for i in range(len(clean_names))
526
+ ]
527
+
508
528
 
509
529
  def smooth(y: np.ndarray, f: float = 0.05) -> np.ndarray:
510
530
  """Box filter of fraction f."""