ultralytics 8.4.27 Improved Platform training integration (#24008)

Signed-off-by: Glenn Jocher <glenn.jocher@ultralytics.com>
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
This commit is contained in:
Glenn Jocher 2026-03-25 14:01:22 +01:00 committed by GitHub
parent a630384aa7
commit 8d8358767f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 40 additions and 11 deletions

View file

@ -23,6 +23,10 @@ keywords: platform callbacks, training callbacks, console logging, YOLO11 traini
<br><br><hr><br>
## ::: ultralytics.utils.callbacks.platform._sanitize_json_value
<br><br><hr><br>
## ::: ultralytics.utils.callbacks.platform._send
<br><br><hr><br>
@ -31,6 +35,10 @@ keywords: platform callbacks, training callbacks, console logging, YOLO11 traini
<br><br><hr><br>
## ::: ultralytics.utils.callbacks.platform._handle_control_response
<br><br><hr><br>
## ::: ultralytics.utils.callbacks.platform._upload_model
<br><br><hr><br>

View file

@ -15,4 +15,4 @@
| `device` | `str` | `None` | Specifies the device for exporting: GPU (`device=0`), CPU (`device=cpu`), MPS for Apple silicon (`device=mps`), Huawei Ascend NPU (`device=npu` or `device=npu:0`), or DLA for NVIDIA Jetson (`device=dla:0` or `device=dla:1`). TensorRT exports automatically use GPU. |
| `data` | `str` | `'coco8.yaml'` | Path to the [dataset](https://docs.ultralytics.com/datasets/) configuration file, essential for INT8 quantization calibration. If not specified with INT8 enabled, `coco8.yaml` will be used as a fallback for calibration. |
| `fraction` | `float` | `1.0` | Specifies the fraction of the dataset to use for INT8 quantization calibration. Allows for calibrating on a subset of the full dataset, useful for experiments or when resources are limited. If not specified with INT8 enabled, the full dataset will be used. |
| `end2end` | `bool` | `None` | Overrides the end-to-end mode in YOLO models that support NMS-free inference (YOLO26, YOLOv10). Setting it to `False` lets you export these models to be compatible with the traditional NMS-based postprocessing pipeline. See the [End-to-End Detection guide](../guides/end2end-detection.md) for details. |
| `end2end` | `bool` | `None` | Overrides the end-to-end mode in YOLO models that support NMS-free inference (YOLO26, YOLOv10). Setting it to `False` lets you export these models to be compatible with the traditional NMS-based postprocessing pipeline. See the [End-to-End Detection guide](../guides/end2end-detection.md) for details. |

View file

@ -22,4 +22,4 @@
| `stream` | `bool` | `False` | Enables memory-efficient processing for long videos or numerous images by returning a generator of Results objects instead of loading all frames into memory at once. |
| `verbose` | `bool` | `True` | Controls whether to display detailed inference logs in the terminal, providing real-time feedback on the prediction process. |
| `compile` | `bool` or `str` | `False` | Enables PyTorch 2.x `torch.compile` graph compilation with `backend='inductor'`. Accepts `True``"default"`, `False` → disables, or a string mode such as `"default"`, `"reduce-overhead"`, `"max-autotune-no-cudagraphs"`. Falls back to eager with a warning if unsupported. |
| `end2end` | `bool` | `None` | Overrides the end-to-end mode in YOLO models that support NMS-free inference (YOLO26, YOLOv10). Setting it to `False` lets you run prediction using the traditional NMS pipeline, additionally allowing you to make use of the `iou` argument. See the [End-to-End Detection guide](../guides/end2end-detection.md) for details. |
| `end2end` | `bool` | `None` | Overrides the end-to-end mode in YOLO models that support NMS-free inference (YOLO26, YOLOv10). Setting it to `False` lets you run prediction using the traditional NMS pipeline, additionally allowing you to make use of the `iou` argument. See the [End-to-End Detection guide](../guides/end2end-detection.md) for details. |

View file

@ -1,6 +1,6 @@
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
__version__ = "8.4.26"
__version__ = "8.4.27"
import importlib
import os

View file

@ -6,6 +6,7 @@ import re
import socket
import sys
from concurrent.futures import ThreadPoolExecutor
from math import isfinite
from pathlib import Path
from time import sleep, time
@ -157,9 +158,20 @@ def _interp_plot(plot, n=101):
return result
def _sanitize_json_value(value):
"""Replace non-finite floats in payloads with None so requests JSON encoding succeeds."""
if isinstance(value, dict):
return {k: _sanitize_json_value(v) for k, v in value.items()}
if isinstance(value, (list, tuple)):
return [_sanitize_json_value(v) for v in value]
if isinstance(value, float):
return value if isfinite(value) else None # avoid "Out of range float values are not JSON compliant" warnings
return value
def _send(event, data, project, name, model_id=None, retry=2):
"""Send event to Platform endpoint with retry logic."""
payload = {"event": event, "project": project, "name": name, "data": data}
payload = {"event": event, "project": project, "name": name, "data": _sanitize_json_value(data)}
if model_id:
payload["modelId"] = model_id
@ -193,6 +205,20 @@ def _send_async(event, data, project, name, model_id=None):
_executor.submit(_send, event, data, project, name, model_id)
def _handle_control_response(trainer, ctx, response):
"""Apply centralized stop signals returned by Platform webhook responses.
Notes:
``ctx["cancelled"]`` is the durable cancellation signal. During startup, trainer setup later resets
``trainer.stop``, so early stop requests still rely on ``on_pretrain_routine_end()`` to reapply the flag after
setup completes.
"""
if response and response.get("cancelled"):
ctx["cancelled"] = True
trainer.stop = True
LOGGER.info(f"{PREFIX}Training cancelled from Platform ⚠️")
def _upload_model(model_path, project, name, progress=False, retry=1, model_id=None):
"""Upload model checkpoint to Platform via signed URL."""
from ultralytics.utils.uploads import safe_upload
@ -347,10 +373,8 @@ def on_pretrain_routine_start(trainer):
ctx["model_slug"] = response["modelSlug"]
url = f"{PLATFORM_URL}/{project}/{ctx['model_slug']}"
LOGGER.info(f"{PREFIX}View model at {url}")
# Check for immediate cancellation (cancelled before training started)
# Note: trainer.stop is set in on_pretrain_routine_end (after _setup_train resets it)
if response.get("cancelled"):
ctx["cancelled"] = True
_handle_control_response(trainer, ctx, response)
else:
LOGGER.warning(f"{PREFIX}Training will not be tracked on Platform")
trainer.platform = None # Disable further callbacks
@ -411,10 +435,7 @@ def on_fit_epoch_end(trainer):
def _send_and_check_cancel():
"""Send epoch_end and check response for cancellation (runs in background thread)."""
response = _send("epoch_end", payload, project, name, ctx["model_id"], retry=1)
if response and response.get("cancelled"):
LOGGER.info(f"{PREFIX}Training cancelled from Platform ✅")
trainer.stop = True
ctx["cancelled"] = True
_handle_control_response(trainer, ctx, response)
_executor.submit(_send_and_check_cancel)