Skip to content

User Tasks

About

A task defines the custom logic of a single train or inference step. A task implements the Stateful protocol, so it can store mutable state that is saved in checkpoints.

TrainTask

A TrainTask builds the model inputs from each microbatch, computes the loss and updates the metrics.

Init: create_metrics(...), dump_hparams(...).

Lifecycle, for each microbatch of a step:

  1. build_forward_inputs(...) ->
  2. compute_loss(...) ->
  3. update_metrics(...).

Exit: finalize(...).

State Management: state_dict(...), load_state_dict(...).

Events Registration: register_events(...) links your methods to event hooks.

InferenceTask

An InferenceTask defines the logic of a single inference step. It handles the forward-only flow and processes the outputs of the model (e.g. logits, hidden states).

Lifecycle, for each microbatch of a step:

  1. build_forward_inputs(...) ->
  2. process_outputs(...).

Exit: finalize(...).

State Management: state_dict(...), load_state_dict(...).

Events Registration: register_events(...) links your methods to the event bus.

Task State

The raw batch is available only in build_forward_inputs(...). The state carries side-data from build_forward_inputs to the later calls for the same microbatch. Use it for labels, masks, token counts or anything else the loss or the metrics need but the model does not return.

TState, the last type parameter of TrainTask / InferenceTask, declares the state. TState can be any PyTree:

  • a dataclass, for attribute access and strict typing;
  • a TypedDict, for dict access with checked keys;
  • a plain dict, for quick, untyped side-data;
  • None, for tasks that carry nothing.

build_forward_inputs returns the state. compute_loss, process_outputs and update_metrics read it back, fully typed.

@dataclasses.dataclass
class MyState:
    target: torch.Tensor
    num_targets: torch.Tensor

# In build_forward_inputs:
target = ctx.batch.target
state = MyState(target=target, num_targets=(target != LM_IGNORE_INDEX).sum())
return BuildForwardInputsResult(input=..., shared=..., state=state)

# Later, in compute_loss (ctx.state is typed as MyState):
loss = loss_fn(ctx.pipeline_results, ctx.state.target)

# And in update_metrics:
ctx.metrics["num_targets"].update(ctx.state.num_targets)

Tensors stored in the state are detached from the autograd graph, so the cached state never keeps the graph alive.

Task Input and Output Types

The task I/O uses the same PyTree roles as the model pipeline (see Pipeline Parallelism). TrainTask is generic over [TBatch, TPipelineInput, TSharedInput, TPipelineOutput, TState]:

  • TBatch: the raw microbatch produced by the data stream.
  • TPipelineInput: the PipelineInput fed to the first stage.
  • TSharedInput: the SharedInput passed to every stage.
  • TPipelineOutput: the PipelineOutput produced by the last stage and read in compute_loss. For a single-head model, it is the output of that head. For a model with several named heads, it holds the output of each head, keyed by head name.

build_forward_inputs returns a BuildForwardInputsResult with the input, shared and state fields.

Usage

import dataclasses

import torch

from d9d.core.dist_context import DistributedContext
from d9d.core.types import ScalarTree
from d9d.loop.control import (
    BuildForwardInputsContext,
    BuildForwardInputsResult,
    ComputeLossContext,
    ComputeLossResult,
    TrainTask,
)
from d9d.module.block.head import LM_IGNORE_INDEX, SequenceCausalLMHeadShared, SequenceCausalLMOutput
from d9d.module.model.io import SequenceHeadShared, SequenceInput, SequenceShared


@dataclasses.dataclass
class SFTBatch:
    input_ids: torch.Tensor
    position_ids: torch.Tensor
    labels: torch.Tensor


@dataclasses.dataclass
class SFTState:
    labels: torch.Tensor


class SFTTask(
    TrainTask[
        SFTBatch,
        SequenceInput,
        SequenceHeadShared[SequenceCausalLMHeadShared],
        SequenceCausalLMOutput,
        SFTState,
    ]
):
    def __init__(self, dist_ctx: DistributedContext):
        self._dist_ctx = dist_ctx

    def build_forward_inputs(
        self, ctx: BuildForwardInputsContext[SFTBatch]
    ) -> BuildForwardInputsResult[SequenceInput, SequenceHeadShared[SequenceCausalLMHeadShared], SFTState]:
        # ctx.batch contains the output of the collator.
        # The SharedInput routes position IDs to the backbone and labels to the head.
        return BuildForwardInputsResult(
            input=SequenceInput(input_ids=ctx.batch.input_ids),
            shared=SequenceHeadShared(
                sequence=SequenceShared(position_ids=ctx.batch.position_ids),
                head=SequenceCausalLMHeadShared(labels=ctx.batch.labels),
            ),
            state=SFTState(labels=ctx.batch.labels),
        )

    def dump_hparams(self) -> ScalarTree:
        return super().dump_hparams()

    def compute_loss(self, ctx: ComputeLossContext[SequenceCausalLMOutput, SFTState]) -> ComputeLossResult:
        cross_entropy = ctx.pipeline_results.cross_entropy

        # Count the valid tokens (labels that are not padding). The loss of a variable-length batch needs it.
        num_loss_tokens = (ctx.state.labels != LM_IGNORE_INDEX).sum()

        # Average loss per valid token.
        total_loss = cross_entropy.sum() / num_loss_tokens

        return ComputeLossResult(
            loss=total_loss,
            # loss_weight weights this microbatch in the gradient average across microbatches and ranks.
            # Weighting by token count gives the true per-token average when token counts differ.
            loss_weight=num_loss_tokens / 1000,
        )

API Reference

d9d.loop.control.task

Interfaces for training and inference tasks.

BaseTask

Bases: ABC, Stateful, Generic[TBatch, TPipelineInput, TSharedInput, TState]

Abstract base class for a unit of work (task) in the training or inference loop.

Class Type Parameters:

Name Bound or Constraints Description Default
TBatch

The raw microbatch type produced by the data stream.

required
TPipelineInput

The PipelineInput fed to the first pipeline stage.

required
TSharedInput

The SharedInput fed to every pipeline stage.

required
TState

The per-microbatch side-data carried from input building to loss/output processing. Tasks that carry nothing use None.

required
build_forward_inputs(ctx) abstractmethod

Transforms one raw microbatch into arguments for the model.

Called once per microbatch in the step's pack.

Parameters:

Name Type Description Default
ctx BuildForwardInputsContext[TBatch]

Context object.

required

Returns:

Type Description
BuildForwardInputsResult[TPipelineInput, TSharedInput, TState]

Result object, including the state side-data carried to loss/output processing.

finalize(ctx)

Performs cleanup or final actions when the task execution finishes.

Parameters:

Name Type Description Default
ctx FinalizeContext

Context object.

required
load_state_dict(state_dict)

Restores the task's state from the provided dictionary.

Parameters:

Name Type Description Default
state_dict dict[str, Any]

The state dictionary to load.

required
register_events(context)

Registers task-specific event subscriptions.

Parameters:

Name Type Description Default
context RegisterTaskEventsContext

Context with the distributed context and the event bus.

required
state_dict()

Returns the state dictionary for checkpointing this task.

Returns:

Type Description
dict[str, Any]

A dictionary containing the task's state.

BuildForwardInputsContext dataclass

Bases: Generic[TBatch]

Context data to prepare inputs for the model forward pass of a single microbatch.

Attributes:

Name Type Description
batch TBatch

One raw microbatch of data produced by the data stream.

BuildForwardInputsResult dataclass

Bases: Generic[TPipelineInput, TSharedInput, TState]

The result of processing one raw microbatch into model inputs.

Attributes:

Name Type Description
input TPipelineInput

The PipelineInput passed to the model pipeline as input data (first stage only if using pipeline parallelism).

shared TSharedInput

The SharedInput passed to every pipeline stage.

state TState

Side-data (a PyTree, e.g. a TypedDict) carried to loss or output processing of the same microbatch. It holds what the loss needs but the model does not return, e.g. labels and masks.

ComputeLossContext dataclass

Bases: Generic[TPipelineOutput, TState]

Context data provided to calculate the loss during training.

Attributes:

Name Type Description
pipeline_results TPipelineOutput

The PipelineOutput returned by the model's forward pass.

state TState

The side-data this microbatch's build_forward_inputs returned.

schedule JobSchedule

The job schedule that tracks the current step.

ComputeLossResult dataclass

The result of the loss computation.

Attributes:

Name Type Description
loss Tensor

The scalar tensor representing the loss to be backpropagated.

loss_weight Tensor | None

The weight of the loss in the weighted mean used to synchronize gradients. None means a weight of 1.

CreateMetricsContext dataclass

Context data provided to initialize metrics.

CreateMetricsResult dataclass

The result of metric initialization.

Attributes:

Name Type Description
metrics dict[str, Metric]

A dictionary mapping metric names to Metric instances.

FinalizeContext dataclass

Context data provided when the task is being finalized.

InferenceTask

Bases: BaseTask[TBatch, TPipelineInput, TSharedInput, TState], ABC, Generic[TBatch, TPipelineInput, TSharedInput, TPipelineOutput, TState]

Abstract base class for inference-specific logic.

build_forward_inputs(ctx) abstractmethod

Transforms one raw microbatch into arguments for the model.

Called once per microbatch in the step's pack.

Parameters:

Name Type Description Default
ctx BuildForwardInputsContext[TBatch]

Context object.

required

Returns:

Type Description
BuildForwardInputsResult[TPipelineInput, TSharedInput, TState]

Result object, including the state side-data carried to loss/output processing.

finalize(ctx)

Performs cleanup or final actions when the task execution finishes.

Parameters:

Name Type Description Default
ctx FinalizeContext

Context object.

required
load_state_dict(state_dict)

Restores the task's state from the provided dictionary.

Parameters:

Name Type Description Default
state_dict dict[str, Any]

The state dictionary to load.

required
process_outputs(ctx) abstractmethod

Processes the model outputs (e.g. saving to disk, decoding tokens).

Parameters:

Name Type Description Default
ctx ProcessOutputsContext[TPipelineOutput, TState]

Context containing the model outputs and pipeline state.

required
register_events(context)

Registers task-specific event subscriptions.

Parameters:

Name Type Description Default
context RegisterTaskEventsContext

Context with the distributed context and the event bus.

required
state_dict()

Returns the state dictionary for checkpointing this task.

Returns:

Type Description
dict[str, Any]

A dictionary containing the task's state.

InferenceTaskProvider

Bases: Protocol

Protocol for a callable that creates an InferenceTask instance.

__call__(ctx)

Creates a new InferenceTask.

Parameters:

Name Type Description Default
ctx InferenceTaskProviderContext

Context object.

required

Returns:

Type Description
InferenceTask

The new InferenceTask.

InferenceTaskProviderContext dataclass

Context data provided to the factory creating an InferenceTask.

Attributes:

Name Type Description
dist_context DistributedContext

Information about the distributed environment.

ProcessOutputsContext dataclass

Bases: Generic[TPipelineOutput, TState]

Context data provided to process outputs during inference.

Attributes:

Name Type Description
pipeline_results TPipelineOutput

The PipelineOutput returned by the model's forward pass.

state TState

The side-data this microbatch's build_forward_inputs returned.

RegisterTaskEventsContext dataclass

Context for registering task-specific events.

Attributes:

Name Type Description
dist_context DistributedContext

The distributed execution context.

event_bus EventBus

The event bus for subscribing to events.

TrainTask

Bases: BaseTask[TBatch, TPipelineInput, TSharedInput, TState], ABC, Generic[TBatch, TPipelineInput, TSharedInput, TPipelineOutput, TState]

Abstract base class for training-specific logic.

build_forward_inputs(ctx) abstractmethod

Transforms one raw microbatch into arguments for the model.

Called once per microbatch in the step's pack.

Parameters:

Name Type Description Default
ctx BuildForwardInputsContext[TBatch]

Context object.

required

Returns:

Type Description
BuildForwardInputsResult[TPipelineInput, TSharedInput, TState]

Result object, including the state side-data carried to loss/output processing.

compute_loss(ctx) abstractmethod

Calculates the loss based on model outputs.

Parameters:

Name Type Description Default
ctx ComputeLossContext[TPipelineOutput, TState]

Context object.

required

Returns:

Type Description
ComputeLossResult

Result object.

create_metrics(ctx)

Initializes metrics to be tracked during training.

Parameters:

Name Type Description Default
ctx CreateMetricsContext

Context object.

required

Returns:

Type Description
CreateMetricsResult

Result object.

dump_hparams()

Exports hyperparameters associated with this task for logging.

Returns:

Type Description
ScalarTree

A dictionary of hyperparameter names and values.

finalize(ctx)

Performs cleanup or final actions when the task execution finishes.

Parameters:

Name Type Description Default
ctx FinalizeContext

Context object.

required
load_state_dict(state_dict)

Restores the task's state from the provided dictionary.

Parameters:

Name Type Description Default
state_dict dict[str, Any]

The state dictionary to load.

required
register_events(context)

Registers task-specific event subscriptions.

Parameters:

Name Type Description Default
context RegisterTaskEventsContext

Context with the distributed context and the event bus.

required
state_dict()

Returns the state dictionary for checkpointing this task.

Returns:

Type Description
dict[str, Any]

A dictionary containing the task's state.

update_metrics(ctx)

Updates the metrics after the loss of a microbatch is computed.

Parameters:

Name Type Description Default
ctx UpdateMetricsContext[TState]

Context object.

required

TrainTaskProvider

Bases: Protocol

Protocol for a callable that creates a TrainTask instance.

__call__(ctx)

Creates a new TrainTask.

Parameters:

Name Type Description Default
ctx TrainTaskProviderContext

Context object.

required

Returns:

Type Description
TrainTask

The new TrainTask.

TrainTaskProviderContext dataclass

Context data provided to the factory creating a TrainTask.

Attributes:

Name Type Description
dist_context DistributedContext

Information about the distributed environment.

UpdateMetricsContext dataclass

Bases: Generic[TState]

Context data provided to update metrics after the loss of a microbatch is computed.

Attributes:

Name Type Description
state TState

The side-data this microbatch's build_forward_inputs returned.

metrics Mapping[str, Metric]

The dictionary of metrics to be updated.