ProcessingStage
The ProcessingStage class is the base class for all data processing stages in NeMo Curator. Each stage defines a single step in a data curation pipeline.
Import
Class Definition
Abstract Methods
inputs()
Define stage input requirements.
outputs()
Define stage output requirements.
process()
Process a single task.
Optional Lifecycle Methods
setup_on_node()
Node-level initialization (e.g., download models).
setup()
Worker-level initialization (e.g., load models).
teardown()
Cleanup after processing.
process_batch()
Vectorized batch processing for better performance.
Backend Configuration Hooks
num_workers()
Return a backend-neutral worker count. None delegates worker sizing to the executor.
num_workers is reserved as a method. A subclass that defines it as a class attribute or dataclass field raises TypeError. Override the method for a class-level default, or use stage.with_(num_workers=...) for one pipeline instance.
The exact meaning depends on the executor: Ray Data creates a fixed actor or task pool, Xenna treats it as a cluster-wide count, and Ray Actor Pool caps it to available resource capacity when necessary. See Stage Worker Sizing for the complete backend matrix.
ray_stage_spec()
Return Ray-specific stage options. Ray Data consumes the worker-pool keys below, while selected flags are also used by Ray Actor Pool. Use the RayStageSpecKeys enum rather than spelling keys manually:
xenna_stage_spec()
Return Xenna-specific stage options:
Do not put num_workers in this dictionary. Use the common num_workers() hook for a cluster-wide Xenna count. num_workers() and num_workers_per_node cannot be set together.
task_id is framework-owned. The executor adapter assigns it after either process() or process_batch() returns, so custom stages must not set or derive IDs. For deterministic lineage, preserve positional correspondence in batched code: return one task or None for every input. A batch that maps multiple inputs to a different number of outputs receives random r-prefixed IDs because parentage is ambiguous.
For source-level checkpointing and the complete mapping rules, refer to Resumable Processing.
Creating Custom Stages
Per-Stage Runtime Environments
Stages can declare isolated Python dependencies using Ray’s native runtime_env. Set runtime_env as a class variable to specify packages that should be installed in an isolated virtualenv for that stage’s workers:
You can also override runtime_env at instantiation time using with_():
All three execution backends (XennaExecutor, RayDataExecutor, RayActorPoolExecutor) support per-stage runtime environments. See the Per-Stage Runtime Environments reference for details.
Configuration with with_()
with_() deep-copies a stage and configures the copy without mutating the original. It supports portable properties and backend-specific overrides:
Both specs are shown together here only to document the arguments. In practice you set the one matching the executor you run the pipeline with — ray_stage_spec for Ray Data, xenna_stage_spec for Xenna:
Setting both is harmless — each executor reads only its own spec — but it is only useful if the same stage runs under both backends.
ray_stage_spec and xenna_stage_spec are shallow-merged: user-provided top-level keys win, while nested dictionaries are replaced rather than recursively merged. An explicit None inside a stage-spec dictionary is retained. In contrast, passing the whole ray_stage_spec=None or xenna_stage_spec=None means no override.
num_workers uses an unset sentinel internally, so omission and explicit None differ:
- Omitting
num_workerspreserves the stage’s current method result. with_(num_workers=None)resets an inherited fixed count to executor-controlled behavior.
See Stage Worker Sizing for merge examples, precedence rules, and invalid combinations. See Per-Stage Runtime Environments for dependency isolation.