Data Loading
About
A DataProvider is the factory that you supply to the train or inference loop, like ModelProvider or OptimizerProvider. Given the run context, it builds a MicrobatchPackStream. This is a Stateful iterable that yields microbatch packs and reports its length through the total_steps property.
Concepts
- A pack holds the data of one step: a sequence of microbatches.
len(pack)is the number of microbatches in that step (the gradient accumulation factor). It can vary from step to step. The loop copies packs to the device ahead of their steps (see Data Prefetching). total_stepsis the number of steps the stream yields. It isNonewhen the length is not known ahead of time, e.g. for streaming or data-dependent batching.JobScheduletakes the job duration fromJobScheduleConfig.total_stepsif it is set. It must not exceed the stream length. Otherwise,JobScheduleuses thetotal_stepsof the stream. The loop runs exactly that many steps. It cuts a longer stream short and raises an error if the stream ends earlier.- The stream is the only checkpoint boundary for the data. It saves and restores its own position per data-parallel rank, so the job resumes exactly. Prefetching iterates the stream on a background thread and can call
state_dict()after every pack. So keepstate_dict()cheap, and do not return objects that later iteration changes.
You can use the shipped AutoDataProvider for the common case, or write your own provider for full control.
Using AutoDataProvider
AutoDataProvider builds the default data stack for you. You supply the two parts that cannot be serialized: a dataset_factory and a collator. An AutoDataConfig holds the serializable settings: global_batch_size, microbatch_size, shard_indexing_mode, drop_last and loader settings. The loader settings include shuffle, num_workers, pin_memory and prefetch_factor. A PinMemoryMicrobatchPackStream does the pinning. Unlike the DataLoader option, it also pins tensors nested in dataclasses.
AutoDataProvider shards the dataset across data-parallel ranks for you. It also builds the loader, derives the gradient accumulation factor and returns the stream. So your factory returns the unsharded dataset.
- The
dataset_factoryreceives theDistributedContext, so it can guard data preparation. For example,dist_context.main_process_first()lets rank 0 fill the cache before the other ranks read it. - The
collatorcollates a list of samples into one microbatch.
The batch sizes are known, so the stream reports its total_steps. JobSchedule then derives the job duration without JobScheduleConfig.total_steps.
Writing a Custom DataProvider
A custom provider builds the same default stack by hand. It has two layers:
- A loader: any
DataLoaderProtocol(fromd9d.core.protocol). It is aStateful,Sizediterable of single collated microbatches. torchdata'sStatefulDataLoadersatisfies it directly. - A packer:
FixedCountMicrobatchPacker(microbatches_per_step=k)groupskmicrobatches into each pack, which gives gradient accumulation.drop_lastcontrols whether a short trailing pack is dropped. Training drops it, evaluation keeps it. The helpernum_microbatches_for_global_batchderivesk.
Wrap the packer in a PinMemoryMicrobatchPackStream to pin the packs, so the loop copies them to the device asynchronously. The packer and the pinning stream live in d9d.dataset.batch_iterator.
Unlike with AutoDataProvider, you own the data-parallel sharding. Shard the dataset yourself before you build the loader, e.g. with shard_dataset_data_parallel. See the Dataset Utilities documentation.
API Reference
d9d.loop.control.data_provider
Interface for providing training and inference data.
DataProvider
Bases: Protocol
Protocol for defining how the data pipeline is built.
A DataProvider is the factory the user supplies to the train/eval loop, exactly like
ModelProvider or OptimizerProvider. Given the run context, it composes and returns a
MicrobatchPackStream.
The user is responsible for sharding the dataset across data-parallel ranks (e.g. with
d9d.dataset.shard_dataset_data_parallel) inside the provider.
__call__(context)
Builds the microbatch pack stream for the job.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
InitializeDataProviderContext
|
Context for this operation. |
required |
Returns:
| Type | Description |
|---|---|
MicrobatchPackStream
|
The microbatch pack stream the loop will drive. |
InitializeDataProviderContext
dataclass
Context data required to initialize a data provider.
Attributes:
| Name | Type | Description |
|---|---|---|
dist_context |
DistributedContext
|
The distributed context containing rank and world size information. |
d9d.loop.auto.auto_data
Default data provider built from a configuration.
DatasetFactory = Callable[[DistributedContext], Dataset]
module-attribute
A callable that builds the (unsharded) dataset, given the distributed context.
It receives the context so it can guard data preparation (e.g. with dist_context.main_process_first()).
AutoDataConfig
Bases: BaseModel
Configuration for the default data pipeline.
Attributes:
| Name | Type | Description |
|---|---|---|
global_batch_size |
int
|
The total effective batch size across all replicas and accumulation. |
microbatch_size |
int
|
The number of samples in a single microbatch on a single rank. |
shard_indexing_mode |
ShardIndexingMode
|
The dataset sharding strategy. |
shuffle |
bool
|
Whether to reshuffle the data every epoch. |
drop_last |
bool
|
Whether to drop the trailing incomplete microbatch and pack. Set it to |
num_workers |
int
|
The number of subprocesses to use for data loading. |
pin_memory |
bool
|
Whether to copy the packs into pinned host memory before returning them. |
persistent_workers |
bool
|
Whether to keep worker processes alive between epochs. |
prefetch_factor |
int | None
|
The number of batches each worker prefetches ahead. |
timeout |
float
|
The timeout in seconds for collecting a batch from workers. |
AutoDataProvider
Bases: DataProvider
Data provider for the default data stack, which shards the dataset, loads microbatches and packs them per step.
The dataset is sharded across data-parallel ranks and loaded by a stateful loader at the microbatch size.
The number of microbatches per step follows from the global batch size. A FixedCountMicrobatchPacker
groups the microbatches, and a PinMemoryMicrobatchPackStream pins the packs if enabled.
For a different stack, write your own DataProvider.
__init__(dataset_factory, collator, config)
Constructs the AutoDataProvider object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset_factory
|
DatasetFactory
|
Builds the unsharded dataset given the distributed context. |
required |
collator
|
CollateFn
|
Collates individual samples into a microbatch. |
required |
config
|
AutoDataConfig
|
The serializable settings for the default stack. |
required |
d9d.dataset.batch_iterator
Composable building blocks for the batch iterator stack.
FixedCountMicrobatchPacker
Bases: MicrobatchPackStream
Microbatch pack stream that groups the microbatches of a loader into packs of microbatches_per_step.
It is the default MicrobatchPackStream. A short trailing pack (drop_last=False) is consistent across
ranks only when every rank sees the same number of microbatches, e.g. when the dataset was sharded with
pad_to_equal_size_across_shards.
Its total_steps is derived from the loader's length, and it delegates its state to the loader
(the checkpoint boundary).
total_steps
property
The number of packs (steps) this packer yields.
It includes a trailing short pack unless drop_last is set.
__init__(loader, microbatches_per_step, drop_last=True)
Constructs the FixedCountMicrobatchPacker object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loader
|
DataLoaderProtocol
|
The microbatch stream to group. |
required |
microbatches_per_step
|
int
|
The number of microbatches in each pack. |
required |
drop_last
|
bool
|
Whether to drop the trailing incomplete pack instead of yielding it short. |
True
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
__iter__()
Iterates the loader, grouping microbatches into packs.
Yields:
| Type | Description |
|---|---|
MicrobatchPack
|
A full pack, or a shorter trailing pack when |
PinMemoryMicrobatchPackStream
Bases: MicrobatchPackStream
Microbatch pack stream wrapper that copies every tensor of each pack into pinned host memory.
Pinned memory lets the loop copy packs to the device asynchronously. Unlike the pin_memory option of
torch.utils.data.DataLoader, the traversal uses d9d.core.pytree, so tensors nested in dataclasses are
pinned as well. Pinning runs in the iterating thread.
Its total_steps and state are those of the wrapped stream.
total_steps
property
The number of packs (steps) the wrapped stream yields, or None if it is unknown.
__init__(inner)
Constructs the PinMemoryMicrobatchPackStream object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inner
|
MicrobatchPackStream
|
The wrapped stream that owns the data and its position. |
required |
__iter__()
Iterates the wrapped stream, pinning each pack.
Yields:
| Type | Description |
|---|---|
MicrobatchPack
|
The next pack with all of its tensors in pinned host memory. |
num_microbatches_for_global_batch(dist_context, global_batch_size, microbatch_size)
Computes the number of microbatches per step required to reach a target global batch size.
The global batch is spread across the data-parallel ranks, and each rank processes microbatch_size samples
per microbatch. So each rank processes global_batch_size / (dp_size * microbatch_size) microbatches per
optimizer step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dist_context
|
DistributedContext
|
The distributed context. |
required |
global_batch_size
|
int
|
The total effective batch size across all replicas and accumulation. |
required |
microbatch_size
|
int
|
The number of samples in a single microbatch on a single rank. |
required |
Returns:
| Type | Description |
|---|---|
int
|
The number of microbatches per step (the gradient-accumulation factor). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |