Link to this sectionتخصيص المـدرب (Trainer)#
تعتمد دورة تدريب Ultralytics على BaseTrainer ومدربين خاصين بالمهام مثل DetectionTrainer. تتولى هذه الفئات التعامل مع دورة التدريب، والتحقق، وحفظ نقاط التفتيش (checkpointing)، وتسجيل البيانات (logging) بشكل جاهز. عندما تحتاج إلى مزيد من التحكم - مثل تتبع مقاييس مخصصة، أو تعديل وزن الخسارة، أو تنفيذ جداول معدل التعلم - يمكنك إنشاء فئة فرعية من المدرب وتجاوز أساليب محددة.
يستعرض هذا الدليل سبعة تخصيصات شائعة:
- تسجيل مقاييس مخصصة (درجة F1) في نهاية كل epoch
- إضافة أوزان الفئات للتعامل مع عدم توازن الفئات
- حفظ أفضل نموذج بناءً على مقياس مختلف
- تجميد العمود الفقري (Backbone) لأول N من الـ epochs، ثم إلغاء التجميد
- تحديد معدلات تعلم لكل طبقة
- مزامنة BatchNorm عبر GPUs للتدريب متعدد الـ GPU
- تكوين قص التدرج (gradient clipping) لضبط الاستقرار
قبل قراءة هذا الدليل، تأكد من أنك على دراية بأساسيات تدريب نماذج YOLO وصفحة التخصيص المتقدم، التي تغطي بنية BaseTrainer.
Link to this sectionكيف يعمل المدربون المخصصون#
تقبل فئة نموذج YOLO معيار trainer في طريقة 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، لذا فأنت تحتاج فقط إلى تجاوز الأساليب المحددة التي ترغب في تخصيصها.
Link to this sectionتسجيل مقاييس مخصصة#
تقوم خطوة التحقق بحساب الدقة (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 | AP عند IoU 0.5 لكل فئة |
ap | AP عند IoU 0.5:0.95 لكل فئة |
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حفظ أفضل نموذج حسب مقياس مخصص#
يحفظ المدرب 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) | mAP عند IoU 0.5 |
metrics/mAP50-95(B) | mAP عند IoU 0.5:0.95 |
Link to this sectionتجميد وإلغاء تجميد العمود الفقري (Backbone)#
غالباً ما تستفيد مهام التعلم بنقل المعرفة (Transfer learning) من تجميد العمود الفقري المدرب مسبقاً لأول N من الـ epochs، مما يسمح لرأس الكشف بالتكيف قبل ضبط الدقة (fine-tuning) للشبكة بأكملها. توفر Ultralytics معيار freeze لتجميد الطبقات في بداية التدريب، ويمكنك استخدام callback لإلغاء تجميدها بعد N من الـ epochs:
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 طبقات (العمود الفقري) عند بداية التدريب. يتم تشغيل الـ callback الخاص بـ on_train_epoch_start في بداية كل epoch ويقوم بإلغاء تجميد كافة المعلمات بمجرد اكتمال فترة التجميد.
freeze=10يجمد أول 10 طبقات (عادةً العمود الفقري في بنيات YOLO)freeze=[0, 1, 2, 3]يجمد طبقات محددة حسب الفهرس- قيم
FREEZE_EPOCHSالأعلى تمنح الرأس مزيداً من الوقت للتكيف قبل أن يتغير العمود الفقري
Link to this sectionمعدلات التعلم لكل طبقة#
يمكن أن تستفيد أجزاء مختلفة من الشبكة من معدلات تعلم (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 = []
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 sectionمتغير RT-DETR#
بالنسبة لـ RT-DETR، النمط هو نفسه مع تحسينين. يتم قراءة طول العمود الفقري من model.yaml["backbone"] بحيث يعمل نفس المدرب عبر متغيرات RT-DETR (RT-DETR-L, RT-DETR-X, بنيات ResNet-50/101) دون الحاجة إلى ترميز ثابت لأعداد الطبقات. يتم أيضاً تقسيم المعلمات إلى مجموعات الوزن، وBatchNorm، والتحيز (bias) داخل كل قسم بحيث يتم استبعاد تدهور الوزن (weight decay) من معلمات BatchNorm والتحيزات، وهو ما يطابق سياسة المدرب الافتراضية. هذا مفيد بشكل خاص لضبط دقة RT-DETR، حيث تتم تهيئة رأس فك التشفير (decoder head) بشكل عشوائي عادةً بينما يحمل العمود الفقري ميزات مدربة مسبقاً تستفيد من معدل تعلم أقل:
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 = 0.1، مما يطابق إعداد RT-DETR الأصلي مع عموده الفقري HGNetV2. تشير الأدبيات إلى توسيع النسبة عكسياً مع حجم العمود الفقري ومقياس بيانات التدريب المسبق: الأعمدة الفقرية الكبيرة المدربة مسبقاً على مجموعات بيانات ضخمة جداً (على سبيل المثال ViT-L/H المدربة باستخدام DINO، أو CLIP، أو MAE على مئات الملايين من الصور) تستخدم عادةً نسباً أصغر مثل 0.01 أو أقل للحفاظ على الميزات التي تم تعلمها جيداً، بينما تتحمل الأعمدة الفقرية الأصغر ذات التدريب المسبق الأخف نسباً أكبر مثل 0.5 أو أعلى.
لا يزال مجدول معدل التعلم المدمج (cosine أو linear) مطبقاً فوق معدلات التعلم الأساسية لكل مجموعة. سيتبع كل من معدل تعلم العمود الفقري ومعدل تعلم الرأس نفس جدول التدهور، مع الحفاظ على النسبة بينهما طوال فترة التدريب.
يمكن دمج هذه التخصيصات في فئة مدرب واحدة عن طريق تجاوز أساليب متعددة وإضافة الـ callbacks حسب الحاجة.
Link to this sectionمزامنة BatchNorm للتدريب متعدد الـ GPU#
عند التدريب على عدة وحدات GPU باستخدام DistributedDataParallel، تقوم طبقات BatchNorm2d الافتراضية بحساب الإحصائيات بشكل مستقل على كل GPU. بالنسبة لضبط دقة RT-DETR والوصفات الأخرى التي تستخدم أحجام دفعات صغيرة لكل GPU، يمكن أن تكون إحصائيات الدفعة لكل GPU صاخبة. يقوم SyncBatchNorm الخاص بـ PyTorch بمزامنة المتوسط والتباين عبر جميع الرتب للحصول على إحصائية دفعة عالمية واحدة، مما يحسن التقارب غالباً على حساب تكلفة تواصل بسيطة بين وحدات الـ GPU.
يجب أن يحدث التحويل بعد أن يكون النموذج على الـ GPU ولكن قبل أن يغلفه DDP. أنظف رابط (hook) لهذا هو 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 العادي. يعمل نفس النمط لـ YOLO عن طريق تبديل الفئة الأصلية إلى DetectionTrainer.
| السيناريو | التوصية |
|---|---|
| تدريب متعدد الـ GPU، دفعة صغيرة لكل GPU (≤ 16) | تمكين |
| تدريب متعدد الـ GPU، دفعة كبيرة لكل GPU (≥ 32) | اختياري؛ فائدة طفيفة |
| تدريب GPU واحد | غير قابل للتطبيق (تم تخطيه) |
Link to this sectionقص التدرج القابل للتكوين#
يقوم المدرب الافتراضي بقص التدرجات إلى max_norm=10.0 في optimizer_step()، وهي قيمة فضفاضة تم ضبطها لنماذج YOLO حيث نادراً ما تتجاوزها التدرجات. تستخدم كواشف عائلة DETR (RT-DETR, DEIM, DINO) عادةً قيماً أكثر صرامة مثل 0.1 لتحقيق استقرار طبقات الانتباه المتقاطع (cross-attention) لجهاز فك التشفير، حيث يمكن أن ترتفع مقادير التدرج. لتجاوز قيمة القص، أنشئ فئة فرعية للمدرب وتجاوز 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)يعمل نفس المدرب لـ YOLO عن طريق تبديل الفئة الأصلية إلى DetectionTrainer (from ultralytics.models.yolo.detect import DetectionTrainer) وتحميل نقطة تفتيش YOLO باستخدام YOLO("yolo26n.pt"). جسم optimizer_step لم يتغير.
| عائلة البنية | قيمة max_norm النموذجية |
|---|---|
| عائلة RT-DETR / DEIM / DETR | 0.1 |
| YOLO (افتراضي لـ Ultralytics) | 10.0 |
| تعطيل القص | 0 |
Link to this sectionالأسئلة الشائعة#
Link to this sectionكيف يمكنني تمرير مدرب مخصص إلى YOLO؟#
قم بتمرير فئة المدرب المخصص (وليس مثيلاً) إلى معيار trainer في model.train():
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
model.train(data="coco8.yaml", trainer=MyCustomTrainer)تتولى فئة YOLO مسؤولية إنشاء المدرب داخلياً. راجع صفحة التخصيص المتقدم لمزيد من التفاصيل حول بنية المدرب.
Link to this sectionما هي أساليب BaseTrainer التي يمكنني تجاوزها؟#
الأساليب الرئيسية المتاحة للتخصيص:
| الطريقة | الغرض |
|---|---|
validate() | تشغيل التحقق وإرجاع المقاييس |
build_optimizer() | إنشاء المحسن (optimizer) |
save_model() | حفظ نقاط فحص التدريب |
get_model() | إرجاع مثيل النموذج |
get_validator() | إرجاع مثيل المدقق |
get_dataloader() | بناء محمل البيانات dataloader |
preprocess_batch() | المعالجة الأولية لدفعة الإدخال |
label_loss_items() | تنسيق عناصر الخسارة للتسجيل |
للحصول على مرجع API الكامل، راجع توثيق BaseTrainer.
Link to this sectionهل يمكنني استخدام ردود الاتصال (callbacks) بدلاً من إنشاء فئة فرعية من المدرب؟#
نعم، بالنسبة للتخصيصات الأبسط، غالباً ما تكون ردود الاتصال (callbacks) كافية. تشمل أحداث رد الاتصال المتاحة on_train_start و on_train_epoch_start و on_train_epoch_end و on_fit_epoch_end و on_model_save. تسمح لك هذه بربط وظائفك بحلقة التدريب دون الحاجة لإنشاء فئة فرعية. يوضح مثال تجميد العمود الفقري (backbone) أعلاه هذا النهج.
Link to this sectionكيف يمكنني تخصيص دالة الخسارة (loss function) دون إنشاء فئة فرعية للنموذج؟#
إذا كان تغييرك بسيطاً (مثل ضبط مكاسب الخسارة)، يمكنك تعديل المعلمات الفائقة (hyperparameters) مباشرة:
model.train(data="coco8.yaml", box=10.0, cls=1.5, dfl=2.0)بالنسبة للتغييرات الهيكلية في الخسارة (مثل إضافة أوزان الفئات)، تحتاج إلى إنشاء فئة فرعية للخسارة والنموذج كما هو موضح في قسم أوزان الفئات.