bplusplus 1.1.0__py3-none-any.whl → 1.2.0__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.

Potentially problematic release.


This version of bplusplus might be problematic. Click here for more details.

Files changed (97) hide show
  1. bplusplus/__init__.py +4 -2
  2. bplusplus/collect.py +69 -5
  3. bplusplus/hierarchical/test.py +670 -0
  4. bplusplus/hierarchical/train.py +676 -0
  5. bplusplus/prepare.py +228 -64
  6. bplusplus/resnet/test.py +473 -0
  7. bplusplus/resnet/train.py +329 -0
  8. bplusplus-1.2.0.dist-info/METADATA +249 -0
  9. bplusplus-1.2.0.dist-info/RECORD +12 -0
  10. bplusplus/yolov5detect/__init__.py +0 -1
  11. bplusplus/yolov5detect/detect.py +0 -444
  12. bplusplus/yolov5detect/export.py +0 -1530
  13. bplusplus/yolov5detect/insect.yaml +0 -8
  14. bplusplus/yolov5detect/models/__init__.py +0 -0
  15. bplusplus/yolov5detect/models/common.py +0 -1109
  16. bplusplus/yolov5detect/models/experimental.py +0 -130
  17. bplusplus/yolov5detect/models/hub/anchors.yaml +0 -56
  18. bplusplus/yolov5detect/models/hub/yolov3-spp.yaml +0 -52
  19. bplusplus/yolov5detect/models/hub/yolov3-tiny.yaml +0 -42
  20. bplusplus/yolov5detect/models/hub/yolov3.yaml +0 -52
  21. bplusplus/yolov5detect/models/hub/yolov5-bifpn.yaml +0 -49
  22. bplusplus/yolov5detect/models/hub/yolov5-fpn.yaml +0 -43
  23. bplusplus/yolov5detect/models/hub/yolov5-p2.yaml +0 -55
  24. bplusplus/yolov5detect/models/hub/yolov5-p34.yaml +0 -42
  25. bplusplus/yolov5detect/models/hub/yolov5-p6.yaml +0 -57
  26. bplusplus/yolov5detect/models/hub/yolov5-p7.yaml +0 -68
  27. bplusplus/yolov5detect/models/hub/yolov5-panet.yaml +0 -49
  28. bplusplus/yolov5detect/models/hub/yolov5l6.yaml +0 -61
  29. bplusplus/yolov5detect/models/hub/yolov5m6.yaml +0 -61
  30. bplusplus/yolov5detect/models/hub/yolov5n6.yaml +0 -61
  31. bplusplus/yolov5detect/models/hub/yolov5s-LeakyReLU.yaml +0 -50
  32. bplusplus/yolov5detect/models/hub/yolov5s-ghost.yaml +0 -49
  33. bplusplus/yolov5detect/models/hub/yolov5s-transformer.yaml +0 -49
  34. bplusplus/yolov5detect/models/hub/yolov5s6.yaml +0 -61
  35. bplusplus/yolov5detect/models/hub/yolov5x6.yaml +0 -61
  36. bplusplus/yolov5detect/models/segment/yolov5l-seg.yaml +0 -49
  37. bplusplus/yolov5detect/models/segment/yolov5m-seg.yaml +0 -49
  38. bplusplus/yolov5detect/models/segment/yolov5n-seg.yaml +0 -49
  39. bplusplus/yolov5detect/models/segment/yolov5s-seg.yaml +0 -49
  40. bplusplus/yolov5detect/models/segment/yolov5x-seg.yaml +0 -49
  41. bplusplus/yolov5detect/models/tf.py +0 -797
  42. bplusplus/yolov5detect/models/yolo.py +0 -495
  43. bplusplus/yolov5detect/models/yolov5l.yaml +0 -49
  44. bplusplus/yolov5detect/models/yolov5m.yaml +0 -49
  45. bplusplus/yolov5detect/models/yolov5n.yaml +0 -49
  46. bplusplus/yolov5detect/models/yolov5s.yaml +0 -49
  47. bplusplus/yolov5detect/models/yolov5x.yaml +0 -49
  48. bplusplus/yolov5detect/utils/__init__.py +0 -97
  49. bplusplus/yolov5detect/utils/activations.py +0 -134
  50. bplusplus/yolov5detect/utils/augmentations.py +0 -448
  51. bplusplus/yolov5detect/utils/autoanchor.py +0 -175
  52. bplusplus/yolov5detect/utils/autobatch.py +0 -70
  53. bplusplus/yolov5detect/utils/aws/__init__.py +0 -0
  54. bplusplus/yolov5detect/utils/aws/mime.sh +0 -26
  55. bplusplus/yolov5detect/utils/aws/resume.py +0 -41
  56. bplusplus/yolov5detect/utils/aws/userdata.sh +0 -27
  57. bplusplus/yolov5detect/utils/callbacks.py +0 -72
  58. bplusplus/yolov5detect/utils/dataloaders.py +0 -1385
  59. bplusplus/yolov5detect/utils/docker/Dockerfile +0 -73
  60. bplusplus/yolov5detect/utils/docker/Dockerfile-arm64 +0 -40
  61. bplusplus/yolov5detect/utils/docker/Dockerfile-cpu +0 -42
  62. bplusplus/yolov5detect/utils/downloads.py +0 -136
  63. bplusplus/yolov5detect/utils/flask_rest_api/README.md +0 -70
  64. bplusplus/yolov5detect/utils/flask_rest_api/example_request.py +0 -17
  65. bplusplus/yolov5detect/utils/flask_rest_api/restapi.py +0 -49
  66. bplusplus/yolov5detect/utils/general.py +0 -1294
  67. bplusplus/yolov5detect/utils/google_app_engine/Dockerfile +0 -25
  68. bplusplus/yolov5detect/utils/google_app_engine/additional_requirements.txt +0 -6
  69. bplusplus/yolov5detect/utils/google_app_engine/app.yaml +0 -16
  70. bplusplus/yolov5detect/utils/loggers/__init__.py +0 -476
  71. bplusplus/yolov5detect/utils/loggers/clearml/README.md +0 -222
  72. bplusplus/yolov5detect/utils/loggers/clearml/__init__.py +0 -0
  73. bplusplus/yolov5detect/utils/loggers/clearml/clearml_utils.py +0 -230
  74. bplusplus/yolov5detect/utils/loggers/clearml/hpo.py +0 -90
  75. bplusplus/yolov5detect/utils/loggers/comet/README.md +0 -250
  76. bplusplus/yolov5detect/utils/loggers/comet/__init__.py +0 -551
  77. bplusplus/yolov5detect/utils/loggers/comet/comet_utils.py +0 -151
  78. bplusplus/yolov5detect/utils/loggers/comet/hpo.py +0 -126
  79. bplusplus/yolov5detect/utils/loggers/comet/optimizer_config.json +0 -135
  80. bplusplus/yolov5detect/utils/loggers/wandb/__init__.py +0 -0
  81. bplusplus/yolov5detect/utils/loggers/wandb/wandb_utils.py +0 -210
  82. bplusplus/yolov5detect/utils/loss.py +0 -259
  83. bplusplus/yolov5detect/utils/metrics.py +0 -381
  84. bplusplus/yolov5detect/utils/plots.py +0 -517
  85. bplusplus/yolov5detect/utils/segment/__init__.py +0 -0
  86. bplusplus/yolov5detect/utils/segment/augmentations.py +0 -100
  87. bplusplus/yolov5detect/utils/segment/dataloaders.py +0 -366
  88. bplusplus/yolov5detect/utils/segment/general.py +0 -160
  89. bplusplus/yolov5detect/utils/segment/loss.py +0 -198
  90. bplusplus/yolov5detect/utils/segment/metrics.py +0 -225
  91. bplusplus/yolov5detect/utils/segment/plots.py +0 -152
  92. bplusplus/yolov5detect/utils/torch_utils.py +0 -482
  93. bplusplus/yolov5detect/utils/triton.py +0 -90
  94. bplusplus-1.1.0.dist-info/METADATA +0 -179
  95. bplusplus-1.1.0.dist-info/RECORD +0 -92
  96. {bplusplus-1.1.0.dist-info → bplusplus-1.2.0.dist-info}/LICENSE +0 -0
  97. {bplusplus-1.1.0.dist-info → bplusplus-1.2.0.dist-info}/WHEEL +0 -0
@@ -1,25 +0,0 @@
1
- FROM gcr.io/google-appengine/python
2
-
3
- # Create a virtualenv for dependencies. This isolates these packages from
4
- # system-level packages.
5
- # Use -p python3 or -p python3.7 to select python version. Default is version 2.
6
- RUN virtualenv /env -p python3
7
-
8
- # Setting these environment variables are the same as running
9
- # source /env/bin/activate.
10
- ENV VIRTUAL_ENV /env
11
- ENV PATH /env/bin:$PATH
12
-
13
- RUN apt-get update && apt-get install -y python-opencv
14
-
15
- # Copy the application's requirements.txt and run pip to install all
16
- # dependencies into the virtualenv.
17
- ADD requirements.txt /app/requirements.txt
18
- RUN pip install -r /app/requirements.txt
19
-
20
- # Add the application source code.
21
- ADD . /app
22
-
23
- # Run a WSGI server to serve the application. gunicorn must be declared as
24
- # a dependency in requirements.txt.
25
- CMD gunicorn -b :$PORT main:app
@@ -1,6 +0,0 @@
1
- # add these requirements in your app on top of the existing ones
2
- pip==23.3
3
- Flask==2.3.2
4
- gunicorn==22.0.0
5
- werkzeug>=3.0.1 # not directly required, pinned by Snyk to avoid a vulnerability
6
- zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
@@ -1,16 +0,0 @@
1
- # Ultralytics YOLOv5 🚀, AGPL-3.0 license
2
-
3
- runtime: custom
4
- env: flex
5
-
6
- service: yolov5app
7
-
8
- liveness_check:
9
- initial_delay_sec: 600
10
-
11
- manual_scaling:
12
- instances: 1
13
- resources:
14
- cpu: 1
15
- memory_gb: 4
16
- disk_size_gb: 20
@@ -1,476 +0,0 @@
1
- # Ultralytics YOLOv5 🚀, AGPL-3.0 license
2
- """Logging utils."""
3
-
4
- import json
5
- import os
6
- import warnings
7
- from pathlib import Path
8
-
9
- import pkg_resources as pkg
10
- import torch
11
-
12
- from utils.general import LOGGER, colorstr, cv2
13
- from utils.loggers.clearml.clearml_utils import ClearmlLogger
14
- from utils.loggers.wandb.wandb_utils import WandbLogger
15
- from utils.plots import plot_images, plot_labels, plot_results
16
- from utils.torch_utils import de_parallel
17
-
18
- LOGGERS = ("csv", "tb", "wandb", "clearml", "comet") # *.csv, TensorBoard, Weights & Biases, ClearML
19
- RANK = int(os.getenv("RANK", -1))
20
-
21
- try:
22
- from torch.utils.tensorboard import SummaryWriter
23
- except ImportError:
24
-
25
- def SummaryWriter(*args):
26
- """Fall back to SummaryWriter returning None if TensorBoard is not installed."""
27
- return None # None = SummaryWriter(str)
28
-
29
-
30
- try:
31
- import wandb
32
-
33
- assert hasattr(wandb, "__version__") # verify package import not local dir
34
- if pkg.parse_version(wandb.__version__) >= pkg.parse_version("0.12.2") and RANK in {0, -1}:
35
- try:
36
- wandb_login_success = wandb.login(timeout=30)
37
- except wandb.errors.UsageError: # known non-TTY terminal issue
38
- wandb_login_success = False
39
- if not wandb_login_success:
40
- wandb = None
41
- except (ImportError, AssertionError):
42
- wandb = None
43
-
44
- try:
45
- import clearml
46
-
47
- assert hasattr(clearml, "__version__") # verify package import not local dir
48
- except (ImportError, AssertionError):
49
- clearml = None
50
-
51
- try:
52
- if RANK in {0, -1}:
53
- import comet_ml
54
-
55
- assert hasattr(comet_ml, "__version__") # verify package import not local dir
56
- from utils.loggers.comet import CometLogger
57
-
58
- else:
59
- comet_ml = None
60
- except (ImportError, AssertionError):
61
- comet_ml = None
62
-
63
-
64
- def _json_default(value):
65
- """
66
- Format `value` for JSON serialization (e.g. unwrap tensors).
67
-
68
- Fall back to strings.
69
- """
70
- if isinstance(value, torch.Tensor):
71
- try:
72
- value = value.item()
73
- except ValueError: # "only one element tensors can be converted to Python scalars"
74
- pass
75
- return value if isinstance(value, float) else str(value)
76
-
77
-
78
- class Loggers:
79
- """Initializes and manages various logging utilities for tracking YOLOv5 training and validation metrics."""
80
-
81
- def __init__(self, save_dir=None, weights=None, opt=None, hyp=None, logger=None, include=LOGGERS):
82
- """Initializes loggers for YOLOv5 training and validation metrics, paths, and options."""
83
- self.save_dir = save_dir
84
- self.weights = weights
85
- self.opt = opt
86
- self.hyp = hyp
87
- self.plots = not opt.noplots # plot results
88
- self.logger = logger # for printing results to console
89
- self.include = include
90
- self.keys = [
91
- "train/box_loss",
92
- "train/obj_loss",
93
- "train/cls_loss", # train loss
94
- "metrics/precision",
95
- "metrics/recall",
96
- "metrics/mAP_0.5",
97
- "metrics/mAP_0.5:0.95", # metrics
98
- "val/box_loss",
99
- "val/obj_loss",
100
- "val/cls_loss", # val loss
101
- "x/lr0",
102
- "x/lr1",
103
- "x/lr2",
104
- ] # params
105
- self.best_keys = ["best/epoch", "best/precision", "best/recall", "best/mAP_0.5", "best/mAP_0.5:0.95"]
106
- for k in LOGGERS:
107
- setattr(self, k, None) # init empty logger dictionary
108
- self.csv = True # always log to csv
109
- self.ndjson_console = "ndjson_console" in self.include # log ndjson to console
110
- self.ndjson_file = "ndjson_file" in self.include # log ndjson to file
111
-
112
- # Messages
113
- if not comet_ml:
114
- prefix = colorstr("Comet: ")
115
- s = f"{prefix}run 'pip install comet_ml' to automatically track and visualize YOLOv5 🚀 runs in Comet"
116
- self.logger.info(s)
117
- # TensorBoard
118
- s = self.save_dir
119
- if "tb" in self.include and not self.opt.evolve:
120
- prefix = colorstr("TensorBoard: ")
121
- self.logger.info(f"{prefix}Start with 'tensorboard --logdir {s.parent}', view at http://localhost:6006/")
122
- self.tb = SummaryWriter(str(s))
123
-
124
- # W&B
125
- if wandb and "wandb" in self.include:
126
- self.opt.hyp = self.hyp # add hyperparameters
127
- self.wandb = WandbLogger(self.opt)
128
- else:
129
- self.wandb = None
130
-
131
- # ClearML
132
- if clearml and "clearml" in self.include:
133
- try:
134
- self.clearml = ClearmlLogger(self.opt, self.hyp)
135
- except Exception:
136
- self.clearml = None
137
- prefix = colorstr("ClearML: ")
138
- LOGGER.warning(
139
- f"{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging."
140
- f" See https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration#readme"
141
- )
142
-
143
- else:
144
- self.clearml = None
145
-
146
- # Comet
147
- if comet_ml and "comet" in self.include:
148
- if isinstance(self.opt.resume, str) and self.opt.resume.startswith("comet://"):
149
- run_id = self.opt.resume.split("/")[-1]
150
- self.comet_logger = CometLogger(self.opt, self.hyp, run_id=run_id)
151
-
152
- else:
153
- self.comet_logger = CometLogger(self.opt, self.hyp)
154
-
155
- else:
156
- self.comet_logger = None
157
-
158
- @property
159
- def remote_dataset(self):
160
- """Fetches dataset dictionary from remote logging services like ClearML, Weights & Biases, or Comet ML."""
161
- data_dict = None
162
- if self.clearml:
163
- data_dict = self.clearml.data_dict
164
- if self.wandb:
165
- data_dict = self.wandb.data_dict
166
- if self.comet_logger:
167
- data_dict = self.comet_logger.data_dict
168
-
169
- return data_dict
170
-
171
- def on_train_start(self):
172
- """Initializes the training process for Comet ML logger if it's configured."""
173
- if self.comet_logger:
174
- self.comet_logger.on_train_start()
175
-
176
- def on_pretrain_routine_start(self):
177
- """Invokes pre-training routine start hook for Comet ML logger if available."""
178
- if self.comet_logger:
179
- self.comet_logger.on_pretrain_routine_start()
180
-
181
- def on_pretrain_routine_end(self, labels, names):
182
- """Callback that runs at the end of pre-training routine, logging label plots if enabled."""
183
- if self.plots:
184
- plot_labels(labels, names, self.save_dir)
185
- paths = self.save_dir.glob("*labels*.jpg") # training labels
186
- if self.wandb:
187
- self.wandb.log({"Labels": [wandb.Image(str(x), caption=x.name) for x in paths]})
188
- if self.comet_logger:
189
- self.comet_logger.on_pretrain_routine_end(paths)
190
- if self.clearml:
191
- for path in paths:
192
- self.clearml.log_plot(title=path.stem, plot_path=path)
193
-
194
- def on_train_batch_end(self, model, ni, imgs, targets, paths, vals):
195
- """Logs training batch end events, plots images, and updates external loggers with batch-end data."""
196
- log_dict = dict(zip(self.keys[:3], vals))
197
- # Callback runs on train batch end
198
- # ni: number integrated batches (since train start)
199
- if self.plots:
200
- if ni < 3:
201
- f = self.save_dir / f"train_batch{ni}.jpg" # filename
202
- plot_images(imgs, targets, paths, f)
203
- if ni == 0 and self.tb and not self.opt.sync_bn:
204
- log_tensorboard_graph(self.tb, model, imgsz=(self.opt.imgsz, self.opt.imgsz))
205
- if ni == 10 and (self.wandb or self.clearml):
206
- files = sorted(self.save_dir.glob("train*.jpg"))
207
- if self.wandb:
208
- self.wandb.log({"Mosaics": [wandb.Image(str(f), caption=f.name) for f in files if f.exists()]})
209
- if self.clearml:
210
- self.clearml.log_debug_samples(files, title="Mosaics")
211
-
212
- if self.comet_logger:
213
- self.comet_logger.on_train_batch_end(log_dict, step=ni)
214
-
215
- def on_train_epoch_end(self, epoch):
216
- """Callback that updates the current epoch in Weights & Biases at the end of a training epoch."""
217
- if self.wandb:
218
- self.wandb.current_epoch = epoch + 1
219
-
220
- if self.comet_logger:
221
- self.comet_logger.on_train_epoch_end(epoch)
222
-
223
- def on_val_start(self):
224
- """Callback that signals the start of a validation phase to the Comet logger."""
225
- if self.comet_logger:
226
- self.comet_logger.on_val_start()
227
-
228
- def on_val_image_end(self, pred, predn, path, names, im):
229
- """Callback that logs a validation image and its predictions to WandB or ClearML."""
230
- if self.wandb:
231
- self.wandb.val_one_image(pred, predn, path, names, im)
232
- if self.clearml:
233
- self.clearml.log_image_with_boxes(path, pred, names, im)
234
-
235
- def on_val_batch_end(self, batch_i, im, targets, paths, shapes, out):
236
- """Logs validation batch results to Comet ML during training at the end of each validation batch."""
237
- if self.comet_logger:
238
- self.comet_logger.on_val_batch_end(batch_i, im, targets, paths, shapes, out)
239
-
240
- def on_val_end(self, nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix):
241
- """Logs validation results to WandB or ClearML at the end of the validation process."""
242
- if self.wandb or self.clearml:
243
- files = sorted(self.save_dir.glob("val*.jpg"))
244
- if self.wandb:
245
- self.wandb.log({"Validation": [wandb.Image(str(f), caption=f.name) for f in files]})
246
- if self.clearml:
247
- self.clearml.log_debug_samples(files, title="Validation")
248
-
249
- if self.comet_logger:
250
- self.comet_logger.on_val_end(nt, tp, fp, p, r, f1, ap, ap50, ap_class, confusion_matrix)
251
-
252
- def on_fit_epoch_end(self, vals, epoch, best_fitness, fi):
253
- """Callback that logs metrics and saves them to CSV or NDJSON at the end of each fit (train+val) epoch."""
254
- x = dict(zip(self.keys, vals))
255
- if self.csv:
256
- file = self.save_dir / "results.csv"
257
- n = len(x) + 1 # number of cols
258
- s = "" if file.exists() else (("%20s," * n % tuple(["epoch"] + self.keys)).rstrip(",") + "\n") # add header
259
- with open(file, "a") as f:
260
- f.write(s + ("%20.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n")
261
- if self.ndjson_console or self.ndjson_file:
262
- json_data = json.dumps(dict(epoch=epoch, **x), default=_json_default)
263
- if self.ndjson_console:
264
- print(json_data)
265
- if self.ndjson_file:
266
- file = self.save_dir / "results.ndjson"
267
- with open(file, "a") as f:
268
- print(json_data, file=f)
269
-
270
- if self.tb:
271
- for k, v in x.items():
272
- self.tb.add_scalar(k, v, epoch)
273
- elif self.clearml: # log to ClearML if TensorBoard not used
274
- self.clearml.log_scalars(x, epoch)
275
-
276
- if self.wandb:
277
- if best_fitness == fi:
278
- best_results = [epoch] + vals[3:7]
279
- for i, name in enumerate(self.best_keys):
280
- self.wandb.wandb_run.summary[name] = best_results[i] # log best results in the summary
281
- self.wandb.log(x)
282
- self.wandb.end_epoch()
283
-
284
- if self.clearml:
285
- self.clearml.current_epoch_logged_images = set() # reset epoch image limit
286
- self.clearml.current_epoch += 1
287
-
288
- if self.comet_logger:
289
- self.comet_logger.on_fit_epoch_end(x, epoch=epoch)
290
-
291
- def on_model_save(self, last, epoch, final_epoch, best_fitness, fi):
292
- """Callback that handles model saving events, logging to Weights & Biases or ClearML if enabled."""
293
- if (epoch + 1) % self.opt.save_period == 0 and not final_epoch and self.opt.save_period != -1:
294
- if self.wandb:
295
- self.wandb.log_model(last.parent, self.opt, epoch, fi, best_model=best_fitness == fi)
296
- if self.clearml:
297
- self.clearml.task.update_output_model(
298
- model_path=str(last), model_name="Latest Model", auto_delete_file=False
299
- )
300
-
301
- if self.comet_logger:
302
- self.comet_logger.on_model_save(last, epoch, final_epoch, best_fitness, fi)
303
-
304
- def on_train_end(self, last, best, epoch, results):
305
- """Callback that runs at the end of training to save plots and log results."""
306
- if self.plots:
307
- plot_results(file=self.save_dir / "results.csv") # save results.png
308
- files = ["results.png", "confusion_matrix.png", *(f"{x}_curve.png" for x in ("F1", "PR", "P", "R"))]
309
- files = [(self.save_dir / f) for f in files if (self.save_dir / f).exists()] # filter
310
- self.logger.info(f"Results saved to {colorstr('bold', self.save_dir)}")
311
-
312
- if self.tb and not self.clearml: # These images are already captured by ClearML by now, we don't want doubles
313
- for f in files:
314
- self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats="HWC")
315
-
316
- if self.wandb:
317
- self.wandb.log(dict(zip(self.keys[3:10], results)))
318
- self.wandb.log({"Results": [wandb.Image(str(f), caption=f.name) for f in files]})
319
- # Calling wandb.log. TODO: Refactor this into WandbLogger.log_model
320
- if not self.opt.evolve:
321
- wandb.log_artifact(
322
- str(best if best.exists() else last),
323
- type="model",
324
- name=f"run_{self.wandb.wandb_run.id}_model",
325
- aliases=["latest", "best", "stripped"],
326
- )
327
- self.wandb.finish_run()
328
-
329
- if self.clearml and not self.opt.evolve:
330
- self.clearml.log_summary(dict(zip(self.keys[3:10], results)))
331
- [self.clearml.log_plot(title=f.stem, plot_path=f) for f in files]
332
- self.clearml.log_model(
333
- str(best if best.exists() else last), "Best Model" if best.exists() else "Last Model", epoch
334
- )
335
-
336
- if self.comet_logger:
337
- final_results = dict(zip(self.keys[3:10], results))
338
- self.comet_logger.on_train_end(files, self.save_dir, last, best, epoch, final_results)
339
-
340
- def on_params_update(self, params: dict):
341
- """Updates experiment hyperparameters or configurations in WandB, Comet, or ClearML."""
342
- if self.wandb:
343
- self.wandb.wandb_run.config.update(params, allow_val_change=True)
344
- if self.comet_logger:
345
- self.comet_logger.on_params_update(params)
346
- if self.clearml:
347
- self.clearml.task.connect(params)
348
-
349
-
350
- class GenericLogger:
351
- """
352
- YOLOv5 General purpose logger for non-task specific logging
353
- Usage: from utils.loggers import GenericLogger; logger = GenericLogger(...).
354
-
355
- Arguments:
356
- opt: Run arguments
357
- console_logger: Console logger
358
- include: loggers to include
359
- """
360
-
361
- def __init__(self, opt, console_logger, include=("tb", "wandb", "clearml")):
362
- """Initializes a generic logger with optional TensorBoard, W&B, and ClearML support."""
363
- self.save_dir = Path(opt.save_dir)
364
- self.include = include
365
- self.console_logger = console_logger
366
- self.csv = self.save_dir / "results.csv" # CSV logger
367
- if "tb" in self.include:
368
- prefix = colorstr("TensorBoard: ")
369
- self.console_logger.info(
370
- f"{prefix}Start with 'tensorboard --logdir {self.save_dir.parent}', view at http://localhost:6006/"
371
- )
372
- self.tb = SummaryWriter(str(self.save_dir))
373
-
374
- if wandb and "wandb" in self.include:
375
- self.wandb = wandb.init(
376
- project=web_project_name(str(opt.project)), name=None if opt.name == "exp" else opt.name, config=opt
377
- )
378
- else:
379
- self.wandb = None
380
-
381
- if clearml and "clearml" in self.include:
382
- try:
383
- # Hyp is not available in classification mode
384
- hyp = {} if "hyp" not in opt else opt.hyp
385
- self.clearml = ClearmlLogger(opt, hyp)
386
- except Exception:
387
- self.clearml = None
388
- prefix = colorstr("ClearML: ")
389
- LOGGER.warning(
390
- f"{prefix}WARNING ⚠️ ClearML is installed but not configured, skipping ClearML logging."
391
- f" See https://docs.ultralytics.com/yolov5/tutorials/clearml_logging_integration"
392
- )
393
- else:
394
- self.clearml = None
395
-
396
- def log_metrics(self, metrics, epoch):
397
- """Logs metrics to CSV, TensorBoard, W&B, and ClearML; `metrics` is a dict, `epoch` is an int."""
398
- if self.csv:
399
- keys, vals = list(metrics.keys()), list(metrics.values())
400
- n = len(metrics) + 1 # number of cols
401
- s = "" if self.csv.exists() else (("%23s," * n % tuple(["epoch"] + keys)).rstrip(",") + "\n") # header
402
- with open(self.csv, "a") as f:
403
- f.write(s + ("%23.5g," * n % tuple([epoch] + vals)).rstrip(",") + "\n")
404
-
405
- if self.tb:
406
- for k, v in metrics.items():
407
- self.tb.add_scalar(k, v, epoch)
408
-
409
- if self.wandb:
410
- self.wandb.log(metrics, step=epoch)
411
-
412
- if self.clearml:
413
- self.clearml.log_scalars(metrics, epoch)
414
-
415
- def log_images(self, files, name="Images", epoch=0):
416
- """Logs images to all loggers with optional naming and epoch specification."""
417
- files = [Path(f) for f in (files if isinstance(files, (tuple, list)) else [files])] # to Path
418
- files = [f for f in files if f.exists()] # filter by exists
419
-
420
- if self.tb:
421
- for f in files:
422
- self.tb.add_image(f.stem, cv2.imread(str(f))[..., ::-1], epoch, dataformats="HWC")
423
-
424
- if self.wandb:
425
- self.wandb.log({name: [wandb.Image(str(f), caption=f.name) for f in files]}, step=epoch)
426
-
427
- if self.clearml:
428
- if name == "Results":
429
- [self.clearml.log_plot(f.stem, f) for f in files]
430
- else:
431
- self.clearml.log_debug_samples(files, title=name)
432
-
433
- def log_graph(self, model, imgsz=(640, 640)):
434
- """Logs model graph to all configured loggers with specified input image size."""
435
- if self.tb:
436
- log_tensorboard_graph(self.tb, model, imgsz)
437
-
438
- def log_model(self, model_path, epoch=0, metadata=None):
439
- """Logs the model to all configured loggers with optional epoch and metadata."""
440
- if metadata is None:
441
- metadata = {}
442
- # Log model to all loggers
443
- if self.wandb:
444
- art = wandb.Artifact(name=f"run_{wandb.run.id}_model", type="model", metadata=metadata)
445
- art.add_file(str(model_path))
446
- wandb.log_artifact(art)
447
- if self.clearml:
448
- self.clearml.log_model(model_path=model_path, model_name=model_path.stem)
449
-
450
- def update_params(self, params):
451
- """Updates logged parameters in WandB and/or ClearML if enabled."""
452
- if self.wandb:
453
- wandb.run.config.update(params, allow_val_change=True)
454
- if self.clearml:
455
- self.clearml.task.connect(params)
456
-
457
-
458
- def log_tensorboard_graph(tb, model, imgsz=(640, 640)):
459
- """Logs the model graph to TensorBoard with specified image size and model."""
460
- try:
461
- p = next(model.parameters()) # for device, type
462
- imgsz = (imgsz, imgsz) if isinstance(imgsz, int) else imgsz # expand
463
- im = torch.zeros((1, 3, *imgsz)).to(p.device).type_as(p) # input image (WARNING: must be zeros, not empty)
464
- with warnings.catch_warnings():
465
- warnings.simplefilter("ignore") # suppress jit trace warning
466
- tb.add_graph(torch.jit.trace(de_parallel(model), im, strict=False), [])
467
- except Exception as e:
468
- LOGGER.warning(f"WARNING ⚠️ TensorBoard graph visualization failure {e}")
469
-
470
-
471
- def web_project_name(project):
472
- """Converts a local project name to a standardized web project name with optional suffixes."""
473
- if not project.startswith("runs/train"):
474
- return project
475
- suffix = "-Classify" if project.endswith("-cls") else "-Segment" if project.endswith("-seg") else ""
476
- return f"YOLOv5{suffix}"