YOLO Vision 2026:

트레이너 사용자 정의하기#

Ultralytics 학습 파이프라인은 BaseTrainerDetectionTrainer과 같은 태스크별 트레이너를 중심으로 구축되어 있습니다. 이 클래스들은 학습 루프, 검증, 체크포인트 저장, 로깅을 기본적으로 처리합니다. 커스텀 메트릭 추적, 손실 가중치 조정, 학습률 스케줄 구현 등 더 세밀한 제어가 필요할 때는 트레이너를 상속하여 특정 메서드를 오버라이드할 수 있습니다.

이 가이드에서는 7가지 일반적인 사용자 정의 방법을 다룹니다:

  1. epoch 종료 시점에 커스텀 메트릭(F1 score) 로깅
  2. 클래스 불균형 처리를 위한 클래스 가중치 추가
  3. 다른 메트릭을 기반으로 한 최적 모델 저장
  4. 처음 N 에폭 동안 백본 동결 후 해제
  5. 레이어별 학습률 지정
  6. 다중 GPU 학습을 위한 GPU 간 BatchNorm 동기화
  7. 안정성 튜닝을 위한 그래디언트 클리핑 설정
사전 요구 사항

이 가이드를 읽기 전에 YOLO 모델 학습의 기본 사항과 BaseTrainer 아키텍처를 다루는 고급 커스터마이징(Advanced Customization) 페이지에 익숙해지시기 바랍니다.

사용자 지정 트레이너 작동 방식#

YOLO 모델 클래스는 train() 메서드에서 trainer 파라미터를 허용합니다. 이를 통해 기본 동작을 확장하는 사용자 정의 트레이너 클래스를 전달할 수 있습니다:

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

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

    # Add your customizations here

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

사용자 정의 트레이너는 DetectionTrainer의 모든 기능을 상속하므로 커스터마이즈하려는 특정 메서드만 오버라이드하면 됩니다.

사용자 지정 메트릭 로깅#

검증(validation) 단계는 정밀도(precision), 재현율(recall), mAP를 계산합니다. 클래스별 F1 점수와 같은 추가 메트릭이 필요한 경우 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)

이 코드는 모든 클래스에 걸친 평균 F1 점수와 각 검증 실행 후의 클래스별 분석 결과를 기록합니다.

사용 가능한 메트릭

검증기는 self.validator.metrics.box을 통해 다양한 메트릭에 대한 액세스를 제공합니다:

속성설명
f1클래스별 F1 점수
image_metrics정밀도, 재현율, F1, TP, FP, FN을 포함하는 이미지별 메트릭 딕셔너리
p클래스별 정밀도
r클래스별 재현율
ap50클래스별 IoU 0.5에서의 AP
ap클래스별 IoU 0.5:0.95에서의 AP
mp, mr평균 정밀도 및 재현율
map50, map평균 AP 메트릭

클래스 가중치 추가#

데이터셋의 클래스가 불균형한 경우(예: 제조 공정 검사의 희귀 결함), 손실 함수(loss function)에서 과소대표된 클래스의 가중치를 높일 수 있습니다. 이렇게 하면 모델이 희귀 클래스의 오분류에 더 큰 페널티를 부과하게 됩니다.

손실을 사용자 정의하려면 손실 클래스, 모델 및 트레이너를 상속받아야 합니다:

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)
데이터셋으로부터 가중치 계산

데이터셋의 레이블 분포를 기반으로 클래스 가중치를 자동으로 계산할 수 있습니다. 일반적인 접근 방식은 역빈도 가중치 부여입니다:

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]
사용자 지정 클래스로 모델 로드하기

WeightedDetectionModel과 같은 커스텀 클래스는 참조를 통해 체크포인트에 저장됩니다. 학습 스크립트 내에 정의될 때 이들은 __main__ 모듈에 속하므로, 다른 스크립트에서 best.pt를 로드하면 AttributeError: Can't get attribute 'WeightedDetectionModel' on <module '__main__'>이 발생합니다.

임포트가 유지될 수 있도록 전용 모듈에 커스텀 클래스를 정의하고, 로드 시점에 해당 모듈이 PYTHONPATH에 포함되어 있는지 확인하세요.

# 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()

사용자 지정 메트릭으로 최적의 모델 저장#

트레이너는 적합도(fitness)를 기준으로 best.pt을 저장하며, 탐지의 경우 기본값은 mAP@0.5:0.95입니다([P, R, mAP@0.5, mAP@0.5:0.95]에 대한 가중치 [0.0, 0.0, 0.0, 1.0]). (mAP@0.5 또는 재현율 같은) 다른 메트릭을 사용하려면 validate()를 오버라이드하고 선택한 메트릭을 적합도 값으로 반환하세요. 그러면 내장된 save_model()가 이를 자동으로 사용합니다:

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)
사용 가능한 메트릭

검증 후 self.metrics에서 사용할 수 있는 일반적인 메트릭은 다음과 같습니다:

설명
metrics/precision(B)정밀도
metrics/recall(B)재현율
metrics/mAP50(B)IoU 0.5에서의 mAP
metrics/mAP50-95(B)IoU 0.5:0.95에서의 mAP

백본 동결 및 해제#

전이 학습(Transfer learning) 워크플로우는 처음 N 에폭 동안 사전 학습된 백본을 동결하여, 전체 네트워크를 파인튜닝(fine-tuning)하기 전에 탐지 헤드가 적응할 수 있도록 시간을 주는 방식이 유용한 경우가 많습니다. Ultralytics는 학습 시작 시 레이어를 동결하는 freeze 파라미터를 제공하며, N 에폭 후에 이를 해제하기 위해 콜백(callback)을 사용할 수 있습니다:

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)

freeze=10 파라미터는 학습 시작 시 처음 10개 레이어(인덱스 0-9)를 동결하며, 이는 YOLO26 백본의 대부분을 다룹니다. 백본은 레이어 0-10에 걸쳐 있으므로 freeze=10은 마지막 C2PSA 블록(레이어 10)을 학습 가능한 상태로 둡니다. 전체 백본을 동결하려면 freeze=11를 사용하세요. on_train_epoch_start 콜백은 각 에폭의 시작 부분에서 실행되며 동결 기간이 완료되면 모든 파라미터를 해제합니다.

동결 대상 선택
  • freeze=10은 처음 10개 레이어, 인덱스 0-9를 동결합니다(YOLO26 백본의 대부분이며, 레이어 10의 마지막 C2PSA 블록을 포함하려면 freeze=11을 사용하세요).
  • freeze=[0, 1, 2, 3]은 인덱스별로 특정 레이어를 동결합니다.
  • 더 높은 FREEZE_EPOCHS 값은 백본이 변경되기 전에 헤드가 적응할 수 있는 시간을 더 많이 제공합니다.

레이어별 학습률#

네트워크의 서로 다른 부분은 서로 다른 학습률(learning rates)의 혜택을 받을 수 있습니다. 일반적인 전략은 학습된 특징을 보존하기 위해 사전 학습된 백본에는 더 낮은 학습률을 사용하고, 탐지 헤드는 더 높은 학습률로 더 빠르게 적응할 수 있도록 하는 것입니다:

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 = []

        unwrapped = unwrap_model(model)
        backbone_len = len(unwrapped.yaml["backbone"])  # YOLO26 backbone spans layers 0-10 (C2PSA at layer 10)

        for k, v in unwrapped.named_parameters():
            if not v.requires_grad:
                continue
            is_backbone = any(k.startswith(f"model.{i}.") for i in range(backbone_len))
            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)

RT-DETR 변형#

RT-DETR의 경우 두 가지 세부 조정을 거치면 패턴은 동일합니다. 백본 길이는 model.yaml["backbone"]에서 읽어오므로 하드코딩된 레이어 수 없이도 동일한 트레이너가 RT-DETR 변형(RT-DETR-L, RT-DETR-X, ResNet-50/101 백본)에서 작동합니다. 또한 각 섹션 내에서 파라미터가 weight, BatchNorm, bias 그룹으로 분할되어 BatchNorm 파라미터 및 바이어스에서 가중치 감쇠(weight decay)가 제외되며, 이는 기본 트레이너의 정책과 일치합니다. 이는 디코더 헤드가 일반적으로 무작위로 초기화되는 반면 백본은 더 낮은 학습률의 이점을 받는 사전 학습된 특징을 유지하는 RT-DETR 파인튜닝에 특히 유용합니다:

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)
`backbone_lr_ratio` 선택

일반적인 시작점은 HGNetV2 백본을 사용하는 원래 RT-DETR 설정과 일치하는 backbone_lr_ratio = 0.1입니다. 문헌에 따르면 백본 크기 및 사전 학습 데이터 스케일에 반비례하여 비율을 조정하는 것이 좋습니다. 수억 장의 이미지로 DINO, CLIP, 또는 MAE를 사용하여 학습된 ViT-L/H와 같이 매우 큰 데이터셋에서 사전 학습된 대형 백본은 잘 학습된 특징을 보존하기 위해 일반적으로 0.01 이하의 더 작은 비율을 사용하며, 가벼운 사전 학습을 거친 소형 백본은 0.5 이상의 더 큰 비율을 허용합니다.

학습률 스케줄러

내장된 학습률 스케줄러(cosine 또는 linear)는 그룹별 기본 학습률 위에 계속 적용됩니다. 백본과 헤드의 학습률 모두 동일한 감쇠 스케줄을 따르며, 학습 과정 내내 두 학습률 간의 비율을 유지합니다.

기술 결합

이러한 사용자 정의들은 여러 메서드를 재정의하고 필요에 따라 콜백을 추가함으로써 단일 트레이너 클래스로 결합할 수 있습니다.

멀티 GPU 학습을 위한 동기화된 BatchNorm#

DistributedDataParallel을 사용하여 여러 GPU에서 학습할 때 기본 BatchNorm2d 레이어는 각 GPU에서 독립적으로 통계치를 계산합니다. GPU당 작은 배치 크기를 사용하는 RT-DETR 파인튜닝 및 기타 레시피의 경우, GPU별 배치 통계치가 불안정할 수 있습니다. PyTorch의 SyncBatchNorm은 단일 전역 배치 통계를 위해 모든 랭크에 걸쳐 평균과 분산을 동결하며, 이는 약간의 GPU 간 통신 오버헤드 비용으로 수렴성을 종종 향상시킵니다.

변환은 모델이 GPU에 올라간 후 DDP가 이를 감싸기 전에 이루어져야 합니다. 이를 위한 가장 깔끔한 훅은 set_model_attributes()이며, BaseTrainer은 정확히 그 시점에 이를 호출합니다:

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)

world_size > 1 가드는 트레이너가 단일 GPU 실행에서도 안전하게 사용될 수 있도록 보장합니다. 단일 GPU에서는 변환이 건너뛰어지고 일반 BatchNorm2d로 학습이 진행됩니다. 부모 클래스를 DetectionTrainer로 전환하면 YOLO에서도 동일한 패턴이 작동합니다.

SyncBatchNorm 사용 시기
시나리오권장 사항
멀티 GPU 학습, 작은 GPU당 배치 (≤ 16)활성화
멀티 GPU 학습, 큰 GPU당 배치 (≥ 32)선택 사항; 경미한 이점
단일 GPU 학습해당 없음 (건너뜀)

구성 가능한 그래디언트 클리핑#

기본 트레이너는 그라디언트가 이를 초과하는 경우가 드문 YOLO 모델에 맞춰진 헐거운 값인 optimizer_step()에서 max_norm=10.0(으)로 그라디언트를 클리핑합니다. RT-DETR, DEIM, DINO와 같은 DETR 계열 검출기는 그라디언트 크기가 급증할 수 있는 디코더의 크로스 어텐션 레이어를 안정화하기 위해 일반적으로 0.1와 같이 훨씬 더 엄격한 값을 사용합니다. 클립 값을 재정의하려면 트레이너를 서브클래싱하고 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)

부모 클래스를 DetectionTrainer (from ultralytics.models.yolo.detect import DetectionTrainer)으로 전환하고 YOLO("yolo26n.pt")로 YOLO 체크포인트를 로드하면 동일한 트레이너가 YOLO에서도 작동합니다. optimizer_step 본문은 변경되지 않습니다.

일반적인 `clip_grad_norm` 값
아키텍처 제품군일반적인 max_norm
RT-DETR / DEIM / DETR 제품군0.1
YOLO (Ultralytics 기본값)10.0
클리핑 비활성화0

FAQ#

  • 인스턴스가 아닌 커스텀 트레이너 클래스를 model.train()trainer 파라미터에 전달하십시오:

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

    YOLO 클래스는 내부적으로 트레이너 인스턴스화를 처리합니다. 트레이너 아키텍처에 대한 자세한 내용은 고급 커스터마이징(Advanced Customization) 페이지를 참조하세요.

  • 사용자 정의를 위해 제공되는 주요 메서드:

    메서드목적
    validate()검증을 실행하고 메트릭을 반환합니다
    build_optimizer()옵티마이저를 구성합니다
    save_model()학습 체크포인트를 저장합니다
    get_model()모델 인스턴스를 반환합니다
    get_validator()검증기 인스턴스를 반환합니다
    get_dataloader()데이터로더를 빌드합니다
    preprocess_batch()입력 배치를 전처리합니다
    label_loss_items()로깅을 위해 손실 항목의 형식을 지정합니다

    전체 API 레퍼런스는 BaseTrainer 문서를 참조하세요.

  • 그렇습니다. 더 간단한 커스터마이징의 경우 콜백(callbacks)만으로 충분한 경우가 많습니다. 사용 가능한 콜백 이벤트에는 on_train_start, on_train_epoch_start, on_train_epoch_end, on_fit_epoch_end, on_model_save가 있습니다. 이를 통해 서브클래싱 없이 학습 루프에 훅을 걸 수 있습니다. 위의 백본 동결 예시가 이 접근 방식을 보여줍니다.

  • 변경 사항이 더 간단한 경우(예: 손실 게인 조정) 하이퍼파라미터(hyperparameters)를 직접 수정할 수 있습니다:

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

    손실에 대한 구조적 변경(예: 클래스 가중치 추가)의 경우 클래스 가중치 섹션에 표시된 대로 손실과 모델을 서브클래싱해야 합니다.

댓글