Meet YOLO26: next-gen vision AI.

Link to this section트레이너(Trainer) 사용자 지정#

Ultralytics 학습 파이프라인은 BaseTrainerDetectionTrainer와 같은 작업별 트레이너를 중심으로 구축되어 있습니다. 이 클래스들은 학습 루프, 검증, 체크포인트 저장 및 로깅 기능을 기본적으로 제공합니다. 사용자 지정 메트릭 추적, 손실 가중치 조정, 학습률 스케줄 구현 등 더 세밀한 제어가 필요할 때는 트레이너를 서브클래싱하고 특정 메서드를 재정의(override)할 수 있습니다.

본 가이드에서는 7가지 일반적인 사용자 지정 방법을 살펴봅니다:

  1. Logging custom metrics (F1 score) at the end of each epoch
  2. 클래스 불균형 처리를 위한 클래스 가중치 추가
  3. 다른 메트릭을 기준으로 최고 모델 저장
  4. 처음 N 에폭 동안 백본 동결(freezing) 후 해제
  5. 레이어별 학습률 지정
  6. 멀티 GPU 학습을 위한 BatchNorm 동기화
  7. 안정성 튜닝을 위한 그래디언트 클리핑 설정
사전 요구 사항

Before reading this guide, make sure you're familiar with the basics of training YOLO models and the Advanced Customization page, which covers the BaseTrainer architecture.

Link to this section사용자 지정 트레이너 작동 방식#

The YOLO model class accepts a trainer parameter in the train() method. This allows you to pass your own trainer class that extends the default behavior:

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의 모든 기능을 상속받으므로, 사용자 지정하려는 특정 메서드만 재정의하면 됩니다.

Link to this section사용자 지정 메트릭 로깅#

검증(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 메트릭

Link to this section클래스 가중치 추가#

데이터셋의 클래스가 불균형한 경우(예: 제조 검사 시 드문 결함 사례), 손실 함수(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]

Link to this section사용자 지정 메트릭으로 최고 모델 저장#

트레이너는 적합도(fitness)를 기준으로 best.pt를 저장하며, 기본값은 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 0.5에서의 mAP
metrics/mAP50-95(B)IoU 0.5:0.95에서의 mAP

Link to this section백본 동결 및 해제#

전이 학습(transfer learning) 워크플로우는 처음 N 에폭 동안 사전 학습된 백본을 동결하여 전체 네트워크를 미세 조정(fine-tuning)하기 전에 검출 헤드가 적응할 시간을 주는 것이 유익할 때가 많습니다. Ultralytics는 학습 시작 시 레이어를 동결하는 freeze 매개변수를 제공하며, 콜백(callback)을 사용하여 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 값이 클수록 백본이 변경되기 전에 헤드가 적응할 시간이 충분히 주어집니다.

Link to this section레이어별 학습률#

네트워크의 각 부분은 서로 다른 학습률(learning rate)을 적용할 때 효과적일 수 있습니다. 흔히 사용하는 전략은 사전 학습된 백본에 낮은 학습률을 적용하여 학습된 특징을 보존하고, 검출 헤드는 더 높은 학습률로 더 빠르게 적응하도록 하는 것입니다:

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 sectionRT-DETR 변형#

RT-DETR의 경우 두 가지 세부 조정 사항을 제외하면 패턴은 동일합니다. 백본 길이는 model.yaml["backbone"]에서 읽어오므로 동일한 트레이너가 레이어 수를 하드코딩하지 않고도 다양한 RT-DETR 변형(RT-DETR-L, RT-DETR-X, ResNet-50/101 백본)에서 작동합니다. 또한 파라미터는 각 섹션 내에서 가중치, 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)는 그룹별 기본 학습률 위에서 추가로 적용됩니다. 백본과 헤드 학습률은 모두 동일한 감쇠 스케줄을 따르며, 학습 내내 두 학습률 간의 비율을 유지합니다.

기술 결합

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

Link to this section멀티 GPU 학습을 위한 BatchNorm 동기화#

DistributedDataParallel을 사용하여 멀티 GPU에서 학습할 때 기본 BatchNorm2d 레이어는 각 GPU에서 독립적으로 통계를 계산합니다. RT-DETR 미세 조정이나 GPU당 배치 크기가 작은 레시피에서는 GPU별 배치 통계가 노이즈가 많을 수 있습니다. PyTorch의 SyncBatchNorm은 단일 전역 배치 통계를 위해 모든 랭크의 평균과 분산을 동기화하며, 이는 약간의 GPU 간 통신 오버헤드를 대가로 종종 수렴 성능을 향상시킵니다.

The conversion has to happen after the model is on the GPU but before DDP wraps it. The cleanest hook for this is set_model_attributes(), which BaseTrainer calls in exactly that window:

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 학습해당 없음 (건너뜀)

Link to this section구성 가능한 그래디언트 클리핑#

The default trainer clips gradients to max_norm=10.0 in optimizer_step(), a loose value tuned for YOLO models where gradients rarely exceed it. DETR-family detectors (RT-DETR, DEIM, DINO) typically use much tighter values such as 0.1 to stabilize the decoder's cross-attention layers, where gradient magnitudes can spike. To override the clip value, subclass the trainer and override 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

Link to this sectionFAQ#

Link to this sectionYOLO에 사용자 지정 트레이너를 전달하려면 어떻게 해야 하나요?#

Pass your custom trainer class (not an instance) to the trainer parameter in model.train():

from ultralytics import YOLO

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

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

Link to this section어떤 BaseTrainer 메서드를 재정의할 수 있나요?#

사용자 지정에 사용할 수 있는 주요 메서드:

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

전체 API 참조는 BaseTrainer 문서를 확인하십시오.

Link to this section트레이너를 서브클래싱하는 대신 콜백을 사용할 수 있습니까?#

네, 간단한 사용자 지정의 경우 콜백으로 충분한 경우가 많습니다. 사용 가능한 콜백 이벤트에는 on_train_start, on_train_epoch_start, on_train_epoch_end, on_fit_epoch_endon_model_save가 있습니다. 이를 통해 서브클래싱 없이 학습 루프에 훅을 걸 수 있습니다. 위의 백본 고정 예제가 이 접근 방식을 보여줍니다.

Link to this section모델을 서브클래싱하지 않고 손실 함수를 어떻게 사용자 지정합니까?#

변경 사항이 더 간단하다면(예: 손실 가중치 조정) 하이퍼파라미터를 직접 수정할 수 있습니다:

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

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

댓글