TorchMetrics Documentation

repository·master·Indexed 25 days ago

https://github.com/lightning-ai/torchmetrics

A standardized, scalable collection of over 100 PyTorch metric implementations designed for distributed training. TorchMetrics provides a consistent interface to reduce boilerplate, automatic state accumulation and synchronization across multiple devices, and seamless integration with PyTorch Lightning. It supports domain-specific metrics for audio, image, and text, and allows for the implementation of custom metrics by subclassing torchmetrics.Metric.

Tokens
55.4K
Snippets
61
Records
423
Agent score
81%

What's inside TorchMetrics

  1. What is TorchMetrics

    master

    TorchMetrics is a collection of over 100 PyTorch metric implementations designed for distributed and scalable PyTorch applications.

    Key Features

    • Standardized Interface: Increases reproducibility across projects.
    • Reduced Boilerplate: Simplifies the implementation of common metrics.
    • Automatic Accumulation: Handles the accumulation of metric states over multiple batches automatically.
    • Distributed Training Optimization: Metrics are optimized for distributed environments.
    • Automatic Synchronization: Handles synchronization of metric states between multiple devices (e.g., multiple GPUs).

    Integration with PyTorch Lightning

    When used with PyTorch Lightning, you get additional benefits:

    • Automatic Device Placement: Module metrics are automatically moved to the correct device (CPU/GPU).
    • Native Logging: Seamless support for logging metrics within Lightning to further reduce boilerplate.
  2. Overview of TorchMetrics features

    master

    TorchMetrics is a collection of over 100 PyTorch metric implementations designed to provide a standardized interface for machine learning evaluation. Key features include:

    • Standardized Interface: Increases reproducibility across different projects.
    • Reduced Boilerplate: Simplifies the implementation of common evaluation tasks.
    • Distributed Training Compatibility: Works seamlessly with multi-device setups.
    • Automatic Accumulation: Handles the accumulation of metric states over multiple batches automatically.
    • Automatic Synchronization: Synchronizes metric states across multiple devices during distributed training.

    When used with PyTorch Lightning, metrics are automatically placed on the same device as your model, and torchmetrics.Metric objects can be logged directly to reduce additional boilerplate.

  3. Use Extended Edit Distance for text metrics

    master

    The ExtendedEditDistance metric and its functional counterpart extended_edit_distance are used to measure the edit distance between text sequences.

    There are two ways to use this:

    1. Module Interface: Use the torchmetrics.text.ExtendedEditDistance class for stateful metric tracking (e.g., accumulating results over multiple batches in a training loop).
    2. Functional Interface: Use torchmetrics.functional.text.extended_edit_distance for a stateless calculation on a single set of inputs.
  4. Use the Perceptual Evaluation of Speech Quality (PESQ) metric

    master

    TorchMetrics provides two interfaces for calculating the Perceptual Evaluation of Speech Quality (PESQ): a Module interface for stateful metric tracking (ideal for training loops) and a Functional interface for stateless, one-off calculations.

    Module Interface

    Use the torchmetrics.audio.pesq.PerceptualEvaluationSpeechQuality class when you need to accumulate results over multiple batches. This class maintains internal state and allows you to call .update() with new data and .compute() to get the final score.

    Functional Interface

    Use torchmetrics.functional.audio.pesq.perceptual_evaluation_speech_quality for a direct calculation on a single set of inputs without maintaining state.

  5. Use the Deep Noise Suppression Mean Opinion Score (DNSMOS) metric

    master

    The DeepNoiseSuppressionMeanOpinionScore metric (and its functional counterpart) is used to evaluate audio quality in the context of deep noise suppression. It provides a Mean Opinion Score (MOS) to assess how well noise has been suppressed and the resulting quality of the audio.

    Module Interface

    You can use the class-based interface by initializing torchmetrics.audio.dnsmos.DeepNoiseSuppressionMeanOpinionScore. This is useful when you want to maintain state across multiple batches (e.g., during a training or validation loop in PyTorch Lightning).

    Functional Interface

    For stateless, one-off calculations, use the functional interface: torchmetrics.functional.audio.dnsmos.deep_noise_suppression_mean_opinion_score.

  6. Choose between Module and Functional metrics

    master

    TorchMetrics provides two interfaces:

    1. Module-based metrics: These are classes that maintain state. They provide advanced features like syncing across DDP nodes, aggregation over batches, and tight integration with PyTorch Lightning. Use these for most training and validation workflows.
    2. Functional metrics: These follow a simple input -> output paradigm. They do not maintain state and do not support DDP syncing or batch aggregation. Use these if you only need to compute a value once without tracking state across steps.
  7. Core API: update(), compute(), and reset()

    master

    TorchMetrics provides a consistent API for metric development. The base Metric class inherits from torch.nn.Module, allowing you to call the metric instance directly (which invokes forward()).

    • update(*args, **kwargs): Updates the internal state of the metric with new data.
    • compute(): Calculates the final metric value based on the accumulated state. In distributed mode (DDP), this automatically syncs and reduces state across all processes.
    • reset(): Resets the internal state to its initial values. This is essential for reusing a metric instance or clearing state between epochs.
    • metric(...): Calling the metric directly (the forward method) performs both an update() on the input and returns the current metric value for that specific input.
  8. Use list states for complex metrics

    master

    Some metrics require access to individual batch states (e.g., for ranking or correlation). In these cases, you can initialize states with an empty list as the default value in add_state.

    Key requirements for list states:

    • Set dist_reduce_fx="cat" in add_state to concatenate tensors across batches/processes.
    • In update(), append the batch tensors to the list (e.g., self.preds.append(preds)).
    • In compute(), use the dim_zero_cat helper function from torchmetrics.utilities to standardize the list into a single concatenated tensor. This ensures compatibility between distributed and non-distributed modes.

    Warning: Calling reset() clears the list state entirely. If you need the data after a reset, you must manually copy it using copy.deepcopy before calling reset().

    from torchmetrics import Metric
    from torchmetrics.utilities import dim_zero_cat
    
    class MySpearmanCorrCoef(Metric):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.add_state("preds", default=[], dist_reduce_fx="cat")
            self.add_state("target", default=[], dist_reduce_fx="cat")
    
        def update(self, preds: Tensor, target: Tensor) -> None:
            self.preds.append(preds)
            self.target.append(target)
    
        def compute(self):
            # Use dim_zero_cat to handle list states correctly in all modes
            preds = dim_zero_cat(self.preds)
            target = dim_zero_cat(self.target)
            # ... computation logic ...
            return corrcoef
  9. Use module-based metrics for automatic accumulation and synchronization

    master

    Module-based metrics (subclasses of torchmetrics.Metric) are designed to automate state management. They handle:

    • Automatic accumulation of metric states over multiple batches.
    • Automatic synchronization of states across multiple devices (CPUs, single GPUs, or multi-GPU/multi-node setups).
    • Metric arithmetic.

    To use a module metric, initialize it, move it to the desired device using .to(device), and call it on your predictions and targets. Use .compute() to retrieve the final accumulated result and .reset() to clear the internal state for a new epoch or evaluation cycle.

    import torch
    import torchmetrics
    
    # initialize metric
    metric = torchmetrics.classification.Accuracy(task="multiclass", num_classes=5)
    
    # move the metric to device
    device = "cuda" if torch.cuda.is_available() else "cpu"
    metric.to(device)
    
    n_batches = 10
    for i in range(n_batches):
        preds = torch.randn(10, 5).softmax(dim=-1).to(device)
        target = torch.randint(5, (10,)).to(device)
    
        # metric on current batch
        acc = metric(preds, target)
        print(f"Accuracy on batch {i}: {acc}")
    
    # metric on all batches using custom accumulation
    acc = metric.compute()
    print(f"Accuracy on all data: {acc}")
  10. Log TorchMetrics objects directly in Lightning

    master

    The recommended way to log metrics in Lightning is to pass the metric object itself to self.log.

    When you log a Metric object directly:

    1. Lightning uses the on_step and on_epoch flags from self.log(...) to determine logging frequency.
    2. If on_epoch=True, Lightning automatically calls .compute() at the end of the epoch to log the final value.

    Important Constraints:

    • self.log only supports scalar tensors. Metrics that return non-scalar outputs (like ConfusionMatrix, ROC, MeanAveragePrecision, or ROUGEScore) must be handled manually by computing their values and logging the resulting scalars/dictionaries.
    • The sync_dist, sync_dist_group, and reduce_fx flags in self.log(...) do not affect Metric objects, as these objects handle their own distributed synchronization logic internally. This does not apply to the functional metric API.
    class MyModule(LightningModule):
        def __init__(self, num_classes):
            super().__init__()
            self.train_acc = torchmetrics.classification.Accuracy(task="multiclass", num_classes=num_classes)
            self.valid_acc = torchmetrics.classification.Accuracy(task="multiclass", num_classes=num_classes)
    
        def training_step(self, batch, batch_idx):
            x, y = batch
            preds = self(x)
            self.train_acc(preds, y)
            # Logging the object directly
            self.log('train_acc', self.train_acc, on_step=True, on_epoch=False)
    
        def validation_step(self, batch, batch_idx):
            logits, y = batch
            self.valid_acc(logits, y)
            # Logging the object directly with epoch-level computation
            self.log('valid_acc', self.valid_acc, on_step=True, on_epoch=True)
  11. How modular metrics work in TorchMetrics

    master

    Modular metrics in TorchMetrics are stateful objects that inherit from the Metric base class. They are designed for the typical deep learning workflow where data arrives in batches. Instead of requiring all predictions and targets to be available at once (like Scikit-learn), modular metrics use an online accumulation pattern:

    1. self.add_state: Used in the __init__ method to define internal states that need to be accumulated. These states are automatically synchronized across multiple devices (GPUs/TPUs) in distributed environments.
    2. update(preds, target): Accumulates the current batch of data into the global states.
    3. compute(): Processes the accumulated states to return the final metric value.
    4. forward(preds, target): Inherited from torch.nn.Module, this can be used to both get the metric for the current batch and accumulate the global state simultaneously.

    This architecture allows for seamless scaling to multi-device training, as TorchMetrics handles the cross-device synchronization of the defined states.

    import torch
    from torch import tensor, Tensor
    from torchmetrics import Metric
    
    class Accuracy(Metric):
        def __init__(self):
            super().__init__()
            # Define states to be accumulated and synchronized
            self.add_state("correct", default=tensor(0), dist_reduce_fx="sum")
            self.add_state("total", default=tensor(0), dist_reduce_fx="sum")
    
        def update(self, preds: Tensor, target: Tensor) -> None:
            # Accumulate current batch into global states
            self.correct += torch.sum(preds == target)
            self.total += target.numel()
    
        def compute(self) -> Tensor:
            # Return final metric value from accumulated states
            return self.correct / self.total