DataPipeline¶
DataPipeline is a unified dataset adapter for all three trainers. It accepts HuggingFace datasets (including streaming), Python lists of strings, dicts, or numpy arrays โ and converts them into trainer-ready batches.
Modes¶
| Mode | Output per batch | Use with |
|---|---|---|
"lm" |
(B, S) int array |
TorchDistillTrainer, CachedDistillTrainer |
"embed" |
{"input_ids": (B, S), "attention_mask": (B, S)} |
EmbeddingDistillTrainer, MLMTrainer, EncoderDistillTrainer |
When label_column is set, every batch is a dict that also includes "labels" โ ready for the head trainers.
Constructor¶
DataPipeline(
source,
tokenizer = None,
batch_size = 8,
max_length = 512,
mode = "lm",
shuffle_buffer = 0,
text_column = "text",
ids_column = "input_ids",
mask_column = "attention_mask",
pad_id = 0,
drop_last = False,
label_column = None,
label_pad_id = -100,
)
| Param | Type | Default | Description |
|---|---|---|---|
source |
Dataset \| IterableDataset \| list[str] \| list[dict] \| list[np.ndarray] |
โ | Input data source |
tokenizer |
PreTrainedTokenizer |
None |
Required when source contains raw text strings |
batch_size |
int |
8 |
Examples per batch |
max_length |
int |
512 |
Truncate / pad sequences to this length |
mode |
str |
"lm" |
"lm" or "embed" |
shuffle_buffer |
int |
0 |
Reservoir buffer size for streaming shuffle. 0 = no shuffle. |
text_column |
str |
"text" |
Column name for text when source is a HF dataset of dicts |
ids_column |
str |
"input_ids" |
Column name for pre-tokenized IDs |
mask_column |
str |
"attention_mask" |
Column name for attention mask |
pad_id |
int |
0 |
Padding token ID |
drop_last |
bool |
False |
Drop the last incomplete batch |
label_column |
str |
None |
If set, emit "labels" in every batch (head training) |
label_pad_id |
int |
-100 |
Pad value for token-label sequences (ignored in the loss) |
Source types¶
HuggingFace Dataset (finite)¶
from datasets import load_dataset
from foundry import DataPipeline
ds = load_dataset("allenai/c4", "en", split="train[:10000]")
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-1.5B")
pipe = DataPipeline(source=ds, tokenizer=tok, batch_size=8, max_length=512)
len(pipe) returns the number of batches.
HuggingFace IterableDataset (streaming)¶
ds = load_dataset("allenai/c4", "en", split="train", streaming=True)
pipe = DataPipeline(
source = ds,
tokenizer = tok,
batch_size = 8,
max_length = 512,
shuffle_buffer = 10_000, # reservoir buffer
)
len(pipe) raises TypeError for streaming sources โ pass total_steps to trainer.train() to keep the LR scheduler working.
List of strings¶
texts = ["the quick brown fox", "jumps over the lazy dog", "hello world"]
pipe = DataPipeline(source=texts, tokenizer=tok, batch_size=4)
List of pre-tokenized dicts¶
examples = [
{"input_ids": [1, 2, 3, 4], "attention_mask": [1, 1, 1, 1]},
...
]
pipe = DataPipeline(source=examples, mode="embed")
List of numpy arrays¶
import numpy as np
arrays = [np.random.randint(0, 32000, (512,)) for _ in range(1000)]
pipe = DataPipeline(source=arrays, batch_size=8)
Streaming shuffle¶
For streaming sources, exact shuffle is impossible. DataPipeline implements a reservoir buffer: it reads shuffle_buffer examples into memory, then yields a random sample, replacing it with the next incoming example.
pipe = DataPipeline(
source = streaming_ds,
tokenizer = tok,
batch_size = 8,
shuffle_buffer = 50_000, # larger = better shuffle, more memory
)
For finite sources, pass shuffle=True to trainer.train() instead โ that shuffles the full dataset each epoch.
Embed mode¶
In "embed" mode, each batch is a dict ready to pass to an encoder's forward():
pipe = DataPipeline(source=ds, tokenizer=tok, mode="embed", batch_size=32)
for batch in pipe:
# batch = {"input_ids": np.array (B, S), "attention_mask": np.array (B, S)}
out = student(**{k: torch.tensor(v) for k, v in batch.items()})
Labels for head training¶
Set label_column to carry labels through to the head trainers. Each batch then includes "labels":
# Sequence labels (scalar per row) โ labels shape (B,)
rows = [{"input_ids": [1, 2, 3], "label": 0}, ...]
pipe = DataPipeline(rows, mode="embed", label_column="label")
# batch = {"input_ids": (B,S), "attention_mask": (B,S), "labels": (B,)}
# Token labels (one per token) โ padded to max_length with label_pad_id (-100)
rows = [{"input_ids": [1, 2, 3], "ner": [5, 6, 7]}, ...]
pipe = DataPipeline(rows, mode="embed", label_column="ner")
# batch["labels"] shape (B, S), padding positions = -100 (ignored in the loss)
List-valued labels are treated as token labels and padded; scalar labels are treated as sequence labels.
Length¶
Example: train with DataPipeline¶
from datasets import load_dataset
from foundry import DataPipeline, TorchDistillTrainer, TorchTrainConfig
ds = load_dataset("allenai/c4", "en", split="train", streaming=True)
tok = AutoTokenizer.from_pretrained("my_model")
pipe = DataPipeline(
source = ds,
tokenizer = tok,
batch_size = 8,
max_length = 1024,
mode = "lm",
shuffle_buffer = 20_000,
)
trainer = TorchDistillTrainer(student, teachers, TorchTrainConfig(epochs=1))
result = trainer.train(pipe, total_steps=50_000)