콘텐츠로 건너뛰기

Trainer 사용자 지정

Ultralytics 파이프라인은 다음을 중심으로 구축되었습니다. BaseTrainer 및 다음과 같은 작업별 트레이너 DetectionTrainer. 이 클래스들은 훈련 루프, 검증, 체크포인트 저장 및 로깅을 즉시 처리합니다. 사용자 정의 메트릭 추적, 손실 가중치 조정 또는 학습률 스케줄 구현과 같이 더 많은 제어가 필요한 경우 트레이너를 서브클래싱하고 특정 메서드를 오버라이드할 수 있습니다.

이 가이드는 다섯 가지 일반적인 사용자 지정 방법을 안내합니다:

  1. 사용자 정의 지표(F1 스코어) 로깅: 각 에폭의 끝에 사용자 정의 지표(F1 스코어)를 로깅합니다.
  2. 클래스 불균형 처리를 위한 클래스 가중치 추가
  3. 최적 모델 저장: 다른 지표를 기반으로 최적 모델을 저장합니다.
  4. 백본 동결: 처음 N 에폭 동안 백본을 동결한 다음, 동결 해제합니다.
  5. 레이어별 학습률 지정

필수 조건

이 가이드를 읽기 전에, 기본적인 사항에 익숙한지 확인하십시오. YOLO 훈련 그리고 고급 사용자 정의 페이지, 이는 다음을 다루는 BaseTrainer 아키텍처.

맞춤형 트레이너의 작동 방식

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

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)

사용자 정의 트레이너는 모든 기능을 상속받습니다. DetectionTrainer, 따라서 사용자 지정하려는 특정 메서드만 재정의하면 됩니다.

사용자 정의 메트릭 로깅

에 지정되어 있습니다. 유효성 검사 단계 계산 정밀도, 재현율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 점수
p클래스별 정밀도
r클래스별 리콜
ap50클래스별 IoU 0.5에서의 AP
ap클래스별 IoU 0.5:0.95에서의 AP
mp, mr평균 정밀도 및 재현율
map50, map평균 AP

클래스 가중치 추가

데이터셋에 불균형 클래스(예: 제조 검사에서 드문 결함)가 존재할 경우, 손실 함수에서 과소 대표된 클래스의 가중치를 높일 수 있습니다. 이를 통해 모델이 드문 클래스에 대한 오분류를 더 강력하게 처벌하도록 합니다.

손실 함수를 커스터마이징하려면 손실 클래스, 모델, 트레이너를 서브클래스화하십시오:

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]

사용자 정의 메트릭을 통한 최적 모델 저장

트레이너가 저장합니다 best.pt 기본적으로 다음으로 설정되는 적합도(fitness) 기반 0.9 × mAP@0.5:0.95 + 0.1 × mAP@0.5. 다른 메트릭을 사용하려면 (예: 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 .5mAP
metrics/mAP50-95(B)IoU .5mAP : 0.95

백본 동결 및 해동

전이 학습 워크플로는 종종 처음 N 에포크 동안 사전 훈련된 백본을 고정함으로써 이점을 얻으며, 이는 탐지 헤드가 적응할 수 있도록 허용합니다. 미세 조정 전체 네트워크. Ultralytics freeze 훈련 시작 시 레이어를 고정하는 매개변수를 사용할 수 있으며, 콜백 N 에포크 후에 이를 해제하기 위해:

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개 레이어(백본)를 고정합니다. on_train_epoch_start 콜백은 각 에포크 시작 시 실행되며, 동결 기간이 완료되면 모든 매개변수를 동결 해제합니다.

동결할 항목 선택

  • freeze=10 처음 10개 레이어를 고정합니다(일반적으로 YOLO 백본을 의미함)
  • freeze=[0, 1, 2, 3] 인덱스로 특정 레이어를 동결합니다
  • 더 높게 FREEZE_EPOCHS 값들은 백본이 변경되기 전에 헤드가 적응할 수 있는 시간을 더 줍니다

레이어별 학습률

네트워크의 여러 부분은 서로 다른 학습률의 이점을 얻을 수 있습니다. 일반적인 전략은 사전 훈련된 백본에 대해 더 낮은 학습률을 사용하여 학습된 특징을 보존하고, 감지 헤드가 더 높은 학습률로 더 빠르게 적응하도록 하는 것입니다.

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)

학습률 스케줄러

내장 학습률 스케줄러 (cosine 또는 linear)는 그룹별 기본 학습률 위에 여전히 적용됩니다. 백본 및 헤드 학습률은 모두 동일한 감쇠 스케줄을 따르며, 훈련 내내 그들 간의 비율을 유지합니다.

기술 결합

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

FAQ

YOLO에 사용자 정의 트레이너를 전달하려면 어떻게 해야 하나요?

사용자 정의 트레이너 클래스(인스턴스가 아닌)를 trainermodel.train():

from ultralytics import YOLO

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

에 지정되어 있습니다. YOLO 클래스는 트레이너 인스턴스화를 내부적으로 처리합니다. 다음을 참조하십시오. 고급 사용자 정의 트레이너 아키텍처에 대한 자세한 내용은 해당 페이지를 참조하십시오.

어떤 BaseTrainer 메서드를 재정의할 수 있나요?

사용 가능한 주요 맞춤 설정 방법:

메서드목적
validate()검증 실행 및 메트릭 반환
build_optimizer()옵티마이저 구성
save_model()훈련 체크포인트 저장
get_model()모델 인스턴스를 반환합니다
get_validator()유효성 검사기 인스턴스를 반환합니다
get_dataloader()데이터 로더 구축
preprocess_batch()입력 배치 전처리
label_loss_items()로깅을 위한 형식 손실 항목

전체 API 참조는 다음을 참조하십시오. BaseTrainer 문서.

트레이너를 서브클래싱하는 대신 콜백을 사용할 수 있나요?

네, 더 간단한 사용자 정의의 경우, 콜백 종종 충분합니다. 사용 가능한 콜백 이벤트는 다음과 같습니다: on_train_start, on_train_epoch_start, on_train_epoch_end, on_fit_epoch_endon_model_save. 이것들은 서브클래싱 없이 훈련 루프에 연결할 수 있게 해줍니다. 위 백본 고정 예시는 이 접근 방식을 보여줍니다.

모델을 서브클래싱하지 않고 손실 함수를 사용자 정의하려면 어떻게 해야 합니까?

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

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

손실 함수의 구조적 변경(예: 클래스 가중치 추가)을 위해서는 클래스 가중치 섹션에 설명된 대로 손실 함수와 모델을 서브클래싱해야 합니다.



1개월 전 생성됨 ✏️ 1개월 전 업데이트됨
raimbekovmonuralpszr

댓글