Meet YOLO26: next-gen vision AI.

Link to this sectionPersonalizzazione del Trainer#

La pipeline di addestramento Ultralytics è costruita attorno a BaseTrainer e a trainer specifici per attività come DetectionTrainer. Queste classi gestiscono il ciclo di addestramento, la validazione, il checkpointing e la registrazione dei dati automaticamente. Quando hai bisogno di un maggiore controllo — come monitorare metriche personalizzate, regolare la ponderazione della loss o implementare pianificazioni del learning rate — puoi creare una sottoclasse del trainer e sovrascrivere metodi specifici.

Questa guida illustra sette personalizzazioni comuni:

  1. Registrazione di metriche personalizzate (F1 score) al termine di ogni epoch
  2. Aggiunta di pesi alle classi per gestire lo sbilanciamento delle classi
  3. Salvataggio del modello migliore basato su una metrica diversa
  4. Freezing della backbone per le prime N epoche, quindi unfreezing
  5. Specifica dei learning rate per livello
  6. Sincronizzazione di BatchNorm tra GPU per l'addestramento multi-GPU
  7. Configurazione del gradient clipping per la regolazione della stabilità
Prerequisiti

Prima di leggere questa guida, assicurati di avere familiarità con le basi dell'addestramento dei modelli YOLO e con la pagina Personalizzazione avanzata, che copre l'architettura di BaseTrainer.

Link to this sectionCome funzionano i trainer personalizzati#

La classe del modello YOLO accetta un parametro trainer nel metodo train(). Questo ti consente di passare la tua classe trainer personalizzata che estende il comportamento predefinito:

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer

class CustomTrainer(DetectionTrainer):
    """A custom trainer that extends DetectionTrainer with additional functionality."""

    pass  # Add your customizations here

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=10, trainer=CustomTrainer)

Il tuo trainer personalizzato eredita tutte le funzionalità da DetectionTrainer, quindi devi solo sovrascrivere i metodi specifici che desideri personalizzare.

Link to this sectionRegistrazione di metriche personalizzate#

Il passaggio di validazione calcola precision, recall e mAP. Se hai bisogno di metriche aggiuntive come l'F1 score per classe, sovrascrivi validate():

import numpy as np

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import LOGGER

class MetricsTrainer(DetectionTrainer):
    """Custom trainer that computes and logs F1 score at the end of each epoch."""

    def validate(self):
        """Run validation and compute per-class F1 scores."""
        metrics, fitness = super().validate()
        if metrics is None:
            return metrics, fitness

        if hasattr(self.validator, "metrics") and hasattr(self.validator.metrics, "box"):
            box = self.validator.metrics.box
            f1_per_class = box.f1
            class_indices = box.ap_class_index
            names = self.validator.names

            valid_f1 = f1_per_class[f1_per_class > 0]
            mean_f1 = np.mean(valid_f1) if len(valid_f1) > 0 else 0.0

            LOGGER.info(f"Mean F1 Score: {mean_f1:.4f}")
            per_class_str = [
                f"{names[i]}: {f1_per_class[j]:.3f}" for j, i in enumerate(class_indices) if f1_per_class[j] > 0
            ]
            LOGGER.info(f"Per-class F1: {per_class_str}")

        return metrics, fitness

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=5, trainer=MetricsTrainer)

Questo registra la media dell'F1 score su tutte le classi e un dettaglio per singola classe dopo ogni esecuzione della validazione.

Metriche disponibili

Il validatore fornisce accesso a molte metriche tramite self.validator.metrics.box:

AttributoDescrizione
f1F1 score per classe
image_metricsDizionario delle metriche per immagine con precision, recall, F1, TP, FP e FN
pPrecision per classe
rRecall per classe
ap50AP a IoU 0.5 per classe
apAP a IoU 0.5:0.95 per classe
mp, mrPrecision e recall medie
map50, mapMetriche mAP medie

Link to this sectionAggiunta di pesi alle classi#

Se il tuo dataset presenta classi sbilanciate (ad esempio, un difetto raro nell'ispezione di produzione), puoi aumentare il peso delle classi sottorappresentate nella loss function. Ciò fa sì che il modello penalizzi maggiormente le classificazioni errate sulle classi rare.

Per personalizzare la loss, crea una sottoclasse delle classi di loss, del modello e del trainer:

import torch
from torch import nn

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.nn.tasks import DetectionModel
from ultralytics.utils import RANK
from ultralytics.utils.loss import E2ELoss, v8DetectionLoss

class WeightedDetectionLoss(v8DetectionLoss):
    """Detection loss with class weights applied to BCE classification loss."""

    def __init__(self, model, class_weights=None, tal_topk=10, tal_topk2=None):
        """Initialize loss with optional per-class weights for BCE."""
        super().__init__(model, tal_topk=tal_topk, tal_topk2=tal_topk2)
        if class_weights is not None:
            self.bce = nn.BCEWithLogitsLoss(
                pos_weight=class_weights.to(self.device),
                reduction="none",
            )

class WeightedE2ELoss(E2ELoss):
    """E2E Loss with class weights for YOLO26."""

    def __init__(self, model, class_weights=None):
        """Initialize E2E loss with weighted detection loss."""

        def weighted_loss_fn(model, tal_topk=10, tal_topk2=None):
            return WeightedDetectionLoss(model, class_weights=class_weights, tal_topk=tal_topk, tal_topk2=tal_topk2)

        super().__init__(model, loss_fn=weighted_loss_fn)

class WeightedDetectionModel(DetectionModel):
    """Detection model that uses class-weighted loss."""

    def init_criterion(self):
        """Initialize weighted loss criterion with per-class weights."""
        class_weights = torch.ones(self.nc)
        class_weights[0] = 2.0  # upweight class 0
        class_weights[1] = 3.0  # upweight rare class 1
        return WeightedE2ELoss(self, class_weights=class_weights)

class WeightedTrainer(DetectionTrainer):
    """Trainer that returns a WeightedDetectionModel."""

    def get_model(self, cfg=None, weights=None, verbose=True):
        """Return a WeightedDetectionModel."""
        model = WeightedDetectionModel(cfg, nc=self.data["nc"], verbose=verbose and RANK == -1)
        if weights:
            model.load(weights)
        return model

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=10, trainer=WeightedTrainer)
Calcolo dei pesi dal dataset

Puoi calcolare i pesi delle classi automaticamente dalla distribuzione delle etichette del tuo dataset. Un approccio comune è la ponderazione per frequenza inversa:

import numpy as np

# class_counts: number of instances per class
class_counts = np.array([5000, 200, 3000])
# Inverse frequency: rarer classes get higher weight
class_weights = max(class_counts) / class_counts
# Result: [1.0, 25.0, 1.67]
Caricamento di un modello con classi personalizzate

Le classi personalizzate come WeightedDetectionModel vengono memorizzate nel checkpoint tramite riferimento. Quando definite in uno script di training, esse appartengono al modulo __main__, quindi caricare best.pt da uno script diverso solleva un AttributeError: Can't get attribute 'WeightedDetectionModel' on <module '__main__'>.

Definisci le classi personalizzate in un modulo dedicato in modo che rimangano importabili e assicurati che quel modulo sia nel tuo PYTHONPATH al momento del caricamento.

# weighted_model.py
from ultralytics.nn.tasks import DetectionModel

class WeightedDetectionModel(DetectionModel):
    """Detection model that uses class-weighted loss."""

    ...
# inference script
from weighted_model import WeightedDetectionModel  # noqa: F401 - must be importable at checkpoint load time

from ultralytics import YOLO

model = YOLO("runs/detect/train/weights/best.pt")
metrics = model.val()

Link to this sectionSalvataggio del modello migliore tramite metrica personalizzata#

Il trainer salva best.pt in base alla fitness, che per il rilevamento è impostata di default su mAP@0.5:0.95 (pesi [0.0, 0.0, 0.0, 1.0] per [P, R, mAP@0.5, mAP@0.5:0.95]). Per utilizzare una metrica diversa (come mAP@0.5 o recall), sovrascrivi validate() e restituisci la metrica scelta come valore di fitness. La funzione integrata save_model() la utilizzerà quindi automaticamente:

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer

class CustomSaveTrainer(DetectionTrainer):
    """Trainer that saves the best model based on mAP@0.5 instead of default fitness."""

    def validate(self):
        """Override fitness to use mAP@0.5 for best model selection."""
        metrics, fitness = super().validate()
        if metrics:
            fitness = metrics.get("metrics/mAP50(B)", fitness)
            if self.best_fitness is None or fitness > self.best_fitness:
                self.best_fitness = fitness
        return metrics, fitness

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=20, trainer=CustomSaveTrainer)
Metriche disponibili

Le metriche comuni disponibili in self.metrics dopo la validazione includono:

ChiaveDescrizione
metrics/precision(B)Precision
metrics/recall(B)Recall
metrics/mAP50(B)mAP a IoU 0.5
metrics/mAP50-95(B)mAP a IoU 0.5:0.95

Link to this sectionFreezing e unfreezing della backbone#

I flussi di lavoro di transfer learning spesso traggono beneficio dal freezing della backbone preaddestrata per le prime N epoche, consentendo alla detection head di adattarsi prima del fine-tuning dell'intera rete. Ultralytics fornisce un parametro freeze per bloccare i livelli all'inizio dell'addestramento, e puoi utilizzare un callback per sbloccarli dopo N epoche:

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import LOGGER

FREEZE_EPOCHS = 5

def unfreeze_backbone(trainer):
    """Callback to unfreeze all layers after FREEZE_EPOCHS."""
    if trainer.epoch == FREEZE_EPOCHS:
        LOGGER.info(f"Epoch {trainer.epoch}: Unfreezing all layers for fine-tuning")
        for name, param in trainer.model.named_parameters():
            if not param.requires_grad:
                param.requires_grad = True
                LOGGER.info(f"  Unfroze: {name}")
        trainer.freeze_layer_names = [".dfl"]

class FreezingTrainer(DetectionTrainer):
    """Trainer with backbone freezing for first N epochs."""

    def __init__(self, *args, **kwargs):
        """Initialize and register the unfreeze callback."""
        super().__init__(*args, **kwargs)
        self.add_callback("on_train_epoch_start", unfreeze_backbone)

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=20, freeze=10, trainer=FreezingTrainer)

Il parametro freeze=10 blocca i primi 10 livelli (la backbone) all'inizio dell'addestramento. Il callback on_train_epoch_start si attiva all'inizio di ogni epoca e sblocca tutti i parametri una volta terminato il periodo di freeze.

Scegliere cosa bloccare
  • freeze=10 blocca i primi 10 livelli (solitamente la backbone nelle architetture YOLO)
  • freeze=[0, 1, 2, 3] blocca livelli specifici per indice
  • Valori di FREEZE_EPOCHS più alti danno alla head più tempo per adattarsi prima che la backbone cambi

Link to this sectionLearning rate per livello#

Parti diverse della rete possono trarre vantaggio da diversi learning rate. Una strategia comune consiste nell'utilizzare un learning rate più basso per la backbone preaddestrata per preservare le caratteristiche apprese, consentendo al contempo alla detection head di adattarsi più rapidamente con un tasso più elevato:

import torch

from ultralytics import YOLO
from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.utils import LOGGER
from ultralytics.utils.torch_utils import unwrap_model

class PerLayerLRTrainer(DetectionTrainer):
    """Trainer with different learning rates for backbone and head."""

    def build_optimizer(self, model, name="auto", lr=0.001, momentum=0.9, decay=1e-5, iterations=1e5):
        """Build optimizer with separate learning rates for backbone and head."""
        backbone_params = []
        head_params = []

        for k, v in unwrap_model(model).named_parameters():
            if not v.requires_grad:
                continue
            is_backbone = any(k.startswith(f"model.{i}.") for i in range(10))
            if is_backbone:
                backbone_params.append(v)
            else:
                head_params.append(v)

        backbone_lr = lr * 0.1

        optimizer = torch.optim.AdamW(
            [
                {"params": backbone_params, "lr": backbone_lr, "weight_decay": decay},
                {"params": head_params, "lr": lr, "weight_decay": decay},
            ],
        )

        LOGGER.info(
            f"PerLayerLR optimizer: backbone ({len(backbone_params)} params, lr={backbone_lr}) "
            f"| head ({len(head_params)} params, lr={lr})"
        )
        return optimizer

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", epochs=20, trainer=PerLayerLRTrainer)

Link to this sectionVariante RT-DETR#

Per RT-DETR il modello è lo stesso con due perfezionamenti. La lunghezza della backbone viene letta da model.yaml["backbone"] così che lo stesso trainer funzioni su tutte le varianti RT-DETR (RT-DETR-L, RT-DETR-X, backbone ResNet-50/101) senza dover codificare i conteggi dei livelli. I parametri sono anche suddivisi in gruppi di peso, BatchNorm e bias all'interno di ogni sezione, in modo che il weight decay sia escluso dai parametri BatchNorm e dai bias, rispettando la politica del trainer predefinito. Questo è particolarmente utile per il fine-tuning di RT-DETR, dove la decoder head è solitamente inizializzata casualmente mentre la backbone trasporta caratteristiche preaddestrate che beneficiano di un learning rate più basso:

import torch
from torch import nn

from ultralytics import RTDETR
from ultralytics.models.rtdetr.train import RTDETRTrainer
from ultralytics.utils import LOGGER, colorstr
from ultralytics.utils.torch_utils import unwrap_model

class RTDETRBackboneLRTrainer(RTDETRTrainer):
    """RT-DETR trainer with a lower learning rate for backbone parameters."""

    backbone_lr_ratio = 0.1  # backbone learning rate as a fraction of head learning rate

    def build_optimizer(self, model, name="auto", lr=0.001, momentum=0.9, decay=1e-5, iterations=1e5):
        """Build an AdamW optimizer with six param groups: head and backbone x {weight, bn, bias}."""
        # Resolve optimizer name; "auto" maps to AdamW with RT-DETR-style defaults
        canonical = {"Adam", "Adamax", "AdamW", "NAdam", "RAdam", "auto"}
        name = {x.lower(): x for x in canonical}.get(name.lower(), name)
        if name == "auto":
            name, lr, momentum = "AdamW", 1e-4, 0.9
        self.args.warmup_bias_lr = 0.0  # RT-DETR warms biases from 0, unlike YOLO's 0.1
        if name not in {"Adam", "Adamax", "AdamW", "NAdam", "RAdam"}:
            raise NotImplementedError(f"This trainer only supports AdamW-family optimizers; got {name}")

        # Identify backbone parameters from model.yaml and route each param into a (section, kind) group
        unwrapped = unwrap_model(model)
        backbone_len = len(unwrapped.yaml["backbone"])
        norm_types = tuple(v for k, v in nn.__dict__.items() if "Norm" in k)
        groups = {f"{s}_{k}": [] for s in ("head", "backbone") for k in ("weight", "bn", "bias")}

        for module_name, module in unwrapped.named_modules():
            for param_name, param in module.named_parameters(recurse=False):
                if not param.requires_grad:
                    continue
                fullname = f"{module_name}.{param_name}" if module_name else param_name
                parts = fullname.split(".")
                section = (
                    "backbone"
                    if len(parts) > 1 and parts[0] == "model" and parts[1].isdigit() and int(parts[1]) < backbone_len
                    else "head"
                )
                if "bias" in param_name:
                    kind = "bias"
                elif isinstance(module, norm_types) or "logit_scale" in fullname:
                    kind = "bn"
                else:
                    kind = "weight"
                groups[f"{section}_{kind}"].append(param)

        # Build the optimizer with per-group lr and weight decay; backbone groups use lr * backbone_lr_ratio
        backbone_lr = lr * self.backbone_lr_ratio
        param_groups = [
            {"params": groups["head_weight"], "lr": lr, "weight_decay": decay, "param_group": "weight"},
            {"params": groups["head_bn"], "lr": lr, "weight_decay": 0.0, "param_group": "bn"},
            {"params": groups["head_bias"], "lr": lr, "weight_decay": 0.0, "param_group": "bias"},
            {"params": groups["backbone_weight"], "lr": backbone_lr, "weight_decay": decay, "param_group": "weight"},
            {"params": groups["backbone_bn"], "lr": backbone_lr, "weight_decay": 0.0, "param_group": "bn"},
            {"params": groups["backbone_bias"], "lr": backbone_lr, "weight_decay": 0.0, "param_group": "bias"},
        ]
        param_groups = [pg for pg in param_groups if pg["params"]]  # drop empty groups
        optimizer = getattr(torch.optim, name)(param_groups, betas=(momentum, 0.999))

        LOGGER.info(
            f"{colorstr('optimizer:')} {name}(lr={lr}, backbone_lr={backbone_lr}) with parameter groups\n"
            f"  Head:     {len(groups['head_bn'])} bn, {len(groups['head_weight'])} weight(decay={decay}), "
            f"{len(groups['head_bias'])} bias (lr={lr})\n"
            f"  Backbone: {len(groups['backbone_bn'])} bn, {len(groups['backbone_weight'])} weight(decay={decay}), "
            f"{len(groups['backbone_bias'])} bias (lr={backbone_lr})"
        )
        return optimizer

model = RTDETR("rtdetr-l.pt")
model.train(data="coco8.yaml", epochs=20, trainer=RTDETRBackboneLRTrainer)
Scegliere `backbone_lr_ratio`

Un punto di partenza comune è backbone_lr_ratio = 0.1, che corrisponde alla configurazione originale di RT-DETR con la sua backbone HGNetV2. La letteratura suggerisce di scalare il rapporto inversamente rispetto alla dimensione della backbone e alla scala dei dati di preaddestramento: backbone grandi preaddestrate su dataset molto ampi (ad esempio ViT-L/H addestrate con DINO, CLIP o MAE su centinaia di milioni di immagini) utilizzano solitamente rapporti più piccoli come 0.01 o inferiori per preservare le caratteristiche ben apprese, mentre backbone più piccole con preaddestramento più leggero tollerano rapporti maggiori come 0.5 o superiori.

Pianificatore del learning rate

Il pianificatore del learning rate integrato (cosine o linear) si applica comunque sopra ai learning rate base per gruppo. Sia il learning rate della backbone che quello della head seguiranno la stessa pianificazione di decadimento, mantenendo il rapporto tra loro durante l'intero addestramento.

Combinazione di tecniche

Queste personalizzazioni possono essere combinate in un'unica classe trainer sovrascrivendo più metodi e aggiungendo callback secondo necessità.

Link to this sectionSynchronized BatchNorm per l'addestramento multi-GPU#

Quando si esegue l'addestramento su più GPU con DistributedDataParallel, i livelli predefiniti BatchNorm2d calcolano le statistiche in modo indipendente su ciascuna GPU. Per il fine-tuning di RT-DETR e altre ricette che utilizzano batch size ridotte per GPU, le statistiche dei batch per singola GPU possono essere rumorose. SyncBatchNorm di PyTorch sincronizza media e varianza su tutti i rank per una singola statistica di batch globale, il che spesso migliora la convergenza a costo di un piccolo overhead di comunicazione inter-GPU.

La conversione deve avvenire dopo che il modello è sulla GPU ma prima che DDP lo avvolga. L'hook più pulito per questo è set_model_attributes(), che BaseTrainer chiama esattamente in quella finestra:

from torch import nn

from ultralytics import RTDETR
from ultralytics.models.rtdetr.train import RTDETRTrainer

class SyncBNTrainer(RTDETRTrainer):
    """RT-DETR trainer that converts BatchNorm to SyncBatchNorm for multi-GPU training."""

    def set_model_attributes(self):
        """Run the parent setup, then convert BN to SyncBatchNorm when training on multiple GPUs."""
        super().set_model_attributes()
        if self.world_size > 1:
            self.model = nn.SyncBatchNorm.convert_sync_batchnorm(self.model)

model = RTDETR("rtdetr-l.pt")
model.train(data="coco8.yaml", epochs=20, device=[0, 1], trainer=SyncBNTrainer)

Il controllo world_size > 1 assicura che il trainer sia sicuro da usare anche in esecuzioni su singola GPU; su una singola GPU la conversione viene saltata e l'addestramento procede con il normale BatchNorm2d. Lo stesso schema funziona per YOLO passando la classe genitore a DetectionTrainer.

Quando usare SyncBatchNorm
ScenarioRaccomandazione
Addestramento multi-GPU, batch ridotto per GPU (≤ 16)Abilita
Addestramento multi-GPU, batch grande per GPU (≥ 32)Opzionale; beneficio minimo
Addestramento su singola GPUNon applicabile (saltato)

Link to this sectionGradient clipping configurabile#

Il trainer predefinito tronca i gradienti a max_norm=10.0 in optimizer_step(), un valore ampio calibrato per i modelli YOLO dove i gradienti raramente lo superano. I rilevatori della famiglia DETR (RT-DETR, DEIM, DINO) utilizzano solitamente valori molto più ristretti come 0.1 per stabilizzare i livelli di cross-attention del decoder, dove le magnitudini del gradiente possono subire picchi. Per sovrascrivere il valore di clipping, crea una sottoclasse del trainer e sovrascrivi optimizer_step():

import torch

from ultralytics import RTDETR
from ultralytics.models.rtdetr.train import RTDETRTrainer

class CustomClipTrainer(RTDETRTrainer):
    """RT-DETR trainer with configurable gradient clipping."""

    clip_grad_norm = 0.1  # max gradient norm; set to 0 to disable clipping

    def optimizer_step(self):
        """Run an optimizer step with a configurable gradient-norm clip."""
        self.scaler.unscale_(self.optimizer)
        if self.clip_grad_norm > 0:
            torch.nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=self.clip_grad_norm)
        self.scaler.step(self.optimizer)
        self.scaler.update()
        self.optimizer.zero_grad()
        if self.ema:
            self.ema.update(self.model)

model = RTDETR("rtdetr-l.pt")
model.train(data="coco8.yaml", epochs=20, trainer=CustomClipTrainer)

Lo stesso trainer funziona per YOLO passando la classe genitore a DetectionTrainer (from ultralytics.models.yolo.detect import DetectionTrainer) e caricando un checkpoint YOLO con YOLO("yolo26n.pt"). Il corpo di optimizer_step rimane invariato.

Valori tipici di `clip_grad_norm`
Famiglia di architettureTipico max_norm
Famiglia RT-DETR / DEIM / DETR0.1
YOLO (Predefinito Ultralytics)10.0
Disabilita clipping0

Link to this sectionFAQ#

Link to this sectionCome passo un trainer personalizzato a YOLO?#

Passa la tua classe trainer personalizzata (non un'istanza) al parametro trainer in model.train():

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", trainer=MyCustomTrainer)

La classe YOLO gestisce l'istanziazione del trainer internamente. Consulta la pagina Personalizzazione avanzata per ulteriori dettagli sull'architettura del trainer.

Link to this sectionQuali metodi di BaseTrainer posso sovrascrivere?#

Metodi chiave disponibili per la personalizzazione:

MetodoScopo
validate()Esegui la validazione e restituisci le metriche
build_optimizer()Costruisci l'ottimizzatore
save_model()Salva i checkpoint dell'addestramento
get_model()Restituisci l'istanza del modello
get_validator()Restituisci l'istanza del validatore
get_dataloader()Costruisci il dataloader
preprocess_batch()Pre-elabora il batch di input
label_loss_items()Formatta gli elementi della loss per il logging

Per il riferimento completo dell'API, consulta la documentazione di BaseTrainer.

Link to this sectionPosso usare i callback invece di creare una sottoclasse del trainer?#

Sì, per personalizzazioni più semplici, i callback sono spesso sufficienti. Gli eventi di callback disponibili includono on_train_start, on_train_epoch_start, on_train_epoch_end, on_fit_epoch_end e on_model_save. Questi ti permettono di collegarti al ciclo di addestramento senza creare una sottoclasse. L'esempio del blocco del backbone qui sopra dimostra questo approccio.

Link to this sectionCome posso personalizzare la funzione di loss senza creare una sottoclasse del modello?#

Se la tua modifica è più semplice (come la regolazione dei guadagni della loss), puoi modificare direttamente gli iperparametri:

model.train(data="coco8.yaml", box=10.0, cls=1.5, dfl=2.0)

Per modifiche strutturali alla loss (come l'aggiunta di pesi alle classi), devi creare una sottoclasse della loss e del modello come mostrato nella sezione sui pesi delle classi.

Commenti