Ultralytics YOLO27: Join the waitlist.

Advanced Customization

Both the Ultralytics YOLO command-line and Python interfaces are high-level abstractions built upon base engine executors. This guide focuses on the Trainer engine, explaining how to customize it for your specific needs.



Watch: Mastering Ultralytics YOLO: Advanced Customization
Tip

For practical examples of common trainer customizations — custom metrics, class-weighted loss, model saving, backbone freezing, and per-layer learning rates — see the Customizing Trainer guide.

BaseTrainer#

The BaseTrainer class provides a generic training routine adaptable for various tasks. Customize it by overriding specific functions or operations while adhering to the required formats. For example, integrate your own custom model and dataloader by overriding these functions:

  • get_model(cfg, weights): Builds the model to be trained.
  • get_dataloader(dataset_path, batch_size, rank, mode): Builds the dataloader.

For more details and source code, see the BaseTrainer Reference.

DetectionTrainer#

Here's how to use and customize the Ultralytics YOLO DetectionTrainer:

from ultralytics.models.yolo.detect import DetectionTrainer

trainer = DetectionTrainer(overrides={...})
trainer.train()
trained_model = trainer.best  # Get the best model

Customizing the DetectionTrainer#

To train a custom detection model not directly supported, overload the existing get_model functionality:

from ultralytics.models.yolo.detect import DetectionTrainer

class CustomTrainer(DetectionTrainer):
    def get_model(self, cfg=None, weights=None, verbose=True):
        """Loads a custom detection model given configuration and weight files."""

trainer = CustomTrainer(overrides={...})
trainer.train()

Further customize the trainer by modifying the loss function or adding a callback that runs at the end of every epoch, for example to log or upload the latest weights. Here's an example:

from ultralytics.models.yolo.detect import DetectionTrainer
from ultralytics.nn.tasks import DetectionModel

class MyCustomModel(DetectionModel):
    def init_criterion(self):
        """Initializes a custom loss function for the model."""

class CustomTrainer(DetectionTrainer):
    def get_model(self, cfg=None, weights=None, verbose=True):
        """Returns a customized detection model instance configured with specified config and weights."""
        return MyCustomModel(...)

# Callback to log model weights
def log_model(trainer):
    """Logs the path of the last model weight used by the trainer."""
    last_weight_path = trainer.last
    print(last_weight_path)

trainer = CustomTrainer(overrides={...})
trainer.add_callback("on_train_epoch_end", log_model)  # Adds to existing callbacks
trainer.train()

For more information on callback triggering events and entry points, see the Callbacks Guide.

Other Engine Components#

Customize other components like Validators and Predictors similarly. For more information, refer to the documentation for Validators and Predictors.

Using YOLO with Custom Trainers#

The YOLO model class provides a high-level wrapper for Trainer classes. You can leverage this architecture for greater flexibility in your machine learning workflows:

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

# Create a custom trainer
class MyCustomTrainer(DetectionTrainer):
    def get_model(self, cfg=None, weights=None, verbose=True):
        """Custom code implementation."""

# Initialize YOLO model
model = YOLO("yolo26n.pt")

# Train with custom trainer
results = model.train(trainer=MyCustomTrainer, data="coco8.yaml", epochs=3)

This approach allows you to maintain the simplicity of the YOLO interface while customizing the underlying training process to suit your specific requirements.

FAQ#

  • Customize the DetectionTrainer for specific tasks by overriding its methods to adapt to your custom model and dataloader. Start by inheriting from DetectionTrainer and redefine methods like get_model to implement custom functionalities. Here's an example:

    from ultralytics.models.yolo.detect import DetectionTrainer
    
    class CustomTrainer(DetectionTrainer):
        def get_model(self, cfg=None, weights=None, verbose=True):
            """Loads a custom detection model given configuration and weight files."""
    
    trainer = CustomTrainer(overrides={...})
    trainer.train()
    trained_model = trainer.best  # Get the best model
  • The BaseTrainer serves as the foundation for training routines, customizable for various tasks by overriding its generic methods. Key components include:

    • get_model(cfg, weights): Builds the model to be trained.
    • get_dataloader(dataset_path, batch_size, rank, mode): Builds the dataloader.
    • preprocess_batch(): Handles batch preprocessing before model forward pass.
    • set_model_attributes(): Sets model attributes based on dataset information.
    • get_validator(): Returns a validator for model evaluation.

    For more details on customization and source code, see the BaseTrainer Reference.

  • Add callbacks to monitor and modify the training process in DetectionTrainer. Here's how to add a callback to log model weights after every training epoch:

    from ultralytics.models.yolo.detect import DetectionTrainer
    
    # Callback to log model weights
    def log_model(trainer):
        """Logs the path of the last model weight used by the trainer."""
        last_weight_path = trainer.last
        print(last_weight_path)
    
    trainer = DetectionTrainer(overrides={...})
    trainer.add_callback("on_train_epoch_end", log_model)  # Adds to existing callbacks
    trainer.train()

    For more details on callback events and entry points, refer to the Callbacks Guide.

  • Ultralytics YOLO provides a high-level abstraction over its engine executors, making it well suited to rapid development and customization. Key benefits include:

    • Ease of Use: Both command-line and Python interfaces simplify complex tasks.
    • Performance: Optimized for real-time object detection and various vision AI applications.
    • Customization: Extendable with custom models, loss functions, and dataloaders.
    • Modularity: Components can be modified independently without affecting the entire pipeline.
    • Integration: Works with popular frameworks and tools in the ML ecosystem.

    Learn more about YOLO's capabilities by exploring the main Ultralytics YOLO page.

  • Yes, the DetectionTrainer can be customized for non-standard models. Inherit from DetectionTrainer and overload methods to support your specific model's needs. Here's a simple example:

    from ultralytics.models.yolo.detect import DetectionTrainer
    
    class CustomDetectionTrainer(DetectionTrainer):
        def get_model(self, cfg=None, weights=None, verbose=True):
            """Loads a custom detection model."""
    
    trainer = CustomDetectionTrainer(overrides={...})
    trainer.train()

    For comprehensive instructions and examples, review the DetectionTrainer Reference.

Comments10

Ask a question, share your results, or help someone else.

  1. UltralyticsAssistantUltralyticsAssistantGitHubUltralytics

    👋 Hello, thank you for your interest in Ultralytics 🚀! We recommend visiting the Docs for new users, where you can explore numerous Python and CLI usage examples. Many common questions may already be answered there, including step-by-step guides tailored for different tasks.

    If this is a 🐛 Bug Report, please provide a minimum reproducible example to help us debug the issue.

    If you have a custom training ❓ Question, please include as much information as possible, such as dataset image samples and training logs, and make sure you are following our Tips for Best Training Results.

    Join the Ultralytics community where it suits you best! For real-time chat, head to Discord 🎧. Prefer in-depth discussions? Check out Discourse. Or explore threads on our Subreddit and connect with other users.

    Upgrade

    Upgrade to the latest ultralytics package, including all requirements, in a Python>=3.8 environment with PyTorch>=1.8 to ensure your issue is not already resolved:

    pip install -U ultralytics

    Environments

    YOLO can be run in any of the following up-to-date verified environments (with all dependencies, including CUDA/CUDNN, Python, and PyTorch preinstalled):

    Status

    Ultralytics CI

    If this badge is green, all Ultralytics CI tests are currently passing. CI tests verify correct operation of all YOLO Modes and Tasks on macOS, Windows, and Ubuntu every 24 hours and on every commit.


    This is an automated response 🤖. An Ultralytics engineer will also assist you soon!

    1. Glenn JocherGlenn JocherUltralytics

      @ablyzniuk to set a custom loss function, you can override the init_criterion method in your custom model class, as shown in the Advanced Customization documentation. This method allows you to define and initialize your loss function according to your requirements. Let me know if you need an example!

    2. ablyzniukablyzniukGitHub

      @glen-jocher thank you) I will be glad and thankfull if you will give a detailed example of training default Ultralytics Yolo(5-11 versions) with custom trainer e.t.c. I think there must be much easier and convinient way opposite what I did (I edited source code and overrides DetectionTrainer methods after)

    3. Glenn JocherGlenn JocherUltralytics(edited)

      For custom training without modifying source code, subclass DetectionTrainer and override methods like this:

      from ultralytics.models.yolo.detect import DetectionTrainer
      from ultralytics.nn.tasks import DetectionModel
      
      class CustomModel(DetectionModel):
          def init_criterion(self):
              # Your custom loss initialization here
              pass
      
      class CustomTrainer(DetectionTrainer):
          def get_model(self, cfg=None, weights=None, verbose=True):
              return CustomModel(cfg, nc=self.data["nc"], verbose=verbose)  # Replace with your model config
      
      trainer = CustomTrainer(overrides={'model': 'yolo26n.yaml', 'data': 'coco128.yaml', 'epochs': 100})
      trainer.train()

      This maintains upgrade compatibility while allowing customization. The Advanced Customization Guide shows additional methods you can override.

  2. ternausternausGitHub

    Is it possible to define custom DataLoader or Augmentation pipeline in DetectionTrainer?

    1. Paula DerrengerPaula DerrengerUltralytics

      Yes, it's definitely possible to define custom DataLoader and Augmentation pipelines in DetectionTrainer! 🚀 To do so, you'd primarily override the get_dataloader() method in a subclass of DetectionTrainer. Here's a brief example on how you might go about customizing your DataLoader:

      from ultralytics.models.yolo.detect import DetectionTrainer
      
      class CustomTrainer(DetectionTrainer):
          def get_dataloader(self, ...):
              # Your custom DataLoader logic here
              ...

      For augmentations, you can integrate them within your custom DataLoader or modify datasets accordingly. If you need further customization or to include a custom Augmentation pipeline directly tied with the models' training loop, you could adjust or extend methods in the model itself or within the get_dataloader method to apply augmentations.

      Don't forget to explore our Advanced Customization section and BaseTrainer Reference for more details on customizing training routines, models, and DataLoaders. 😄 Happy coding!

      1
  3. UttamToniUttamToniGitHub

    As mentioned in the advanced customization of ultralytics:

    from ultralytics.models.yolo.detect import DetectionTrainer trainer = DetectionTrainer(overrides={...})

    i am confuced that which file should i place in the curly brackets of overrides={...} . Is the args.yaml file is allowed , which is created after the training step? I have used the args.yaml file which is created after training step but got this error:

    /usr/local/lib/python3.10/dist-packages/ultralytics/engine/trainer.py in __init__(self, cfg, overrides, _callbacks)
         96             overrides (dict, optional): Configuration overrides. Defaults to None.
         97         """
    ---> 98         self.args = get_cfg(cfg, overrides)
         99         self.check_resume(overrides)
        100         self.device = select_device(self.args.device, self.args.batch)
    
    /usr/local/lib/python3.10/dist-packages/ultralytics/cfg/__init__.py in get_cfg(cfg, overrides)
        207         overrides = cfg2dict(overrides)
        208         if "save_dir" not in cfg:
    --> 209             overrides.pop("save_dir", None)  # special override keys to ignore
        210         check_dict_alignment(cfg, overrides)
        211         cfg = {**cfg, **overrides}  # merge cfg and overrides dicts (prefer overrides)
    
    TypeError: set.pop() takes no arguments (2 given)
    
    1. Glenn JocherGlenn JocherUltralytics(edited)

      Hello! It seems like there’s been a little confusion regarding the overrides={...} usage, and I appreciate you reaching out for clarification. 🙌

      To directly answer your question, the overrides={...} parameter is designed to accept a dictionary of configuration overrides, not a file. It's intended to programmatically override specific configuration entries. For example:

      from ultralytics.models.yolo.detect import DetectionTrainer
      
      # Example override dictionary
      overrides = {
          "batch": 16,
          "imgsz": 640,
      }
      
      trainer = DetectionTrainer(overrides=overrides)

      If you're looking to use the configurations from an args.yaml file created after training, you'd first need to read this YAML file into a Python dictionary, which you could then pass to overrides. Here's a quick way to do it:

      import yaml
      
      # Load your args.yaml content into a dictionary
      with open('path/to/your/args.yaml', 'r') as file:
          yaml_content = yaml.safe_load(file)
      
      # Now, pass the loaded dictionary to overrides
      trainer = DetectionTrainer(overrides=yaml_content)

      Regarding the error you're encountering, it appears there's a misunderstanding in how the overrides dictionary is being used or possibly an issue with the implementation. If following the above pattern doesn't resolve your issue, could you please share more details about what you're trying to achieve with the overrides? This way, I or someone from the community can offer more targeted advice. 😊

      Thank you for your patience, and looking forward to helping you get this sorted!