Batching¶
Data loading and batching utilities for neural machine translation.
Overview¶
This module provides:
collate_fn: Pads variable-length sequences for batchingBucketBatchSampler: Groups similar-length sequences to minimize paddingcreate_dataloaders: Convenience function for creating train/val loaders
Quick Start¶
from torch.utils.data import DataLoader
from torchlingo.data_processing import NMTDataset, collate_fn, create_dataloaders
# Manual dataloader
dataset = NMTDataset("data/train.tsv")
loader = DataLoader(dataset, batch_size=32, collate_fn=collate_fn)
# Or use the convenience function
train_loader, val_loader = create_dataloaders(
train_file="data/train.tsv",
val_file="data/val.tsv",
batch_size=32,
)
API Reference¶
collate_fn¶
collate_fn
¶
collate_fn(batch: List[Tuple[Tensor, Tensor]], pad_idx: Optional[int] = None, config: Optional[Config] = None) -> Tuple[Tensor, Tensor]
Collate a batch of (source, target) tensor pairs with padding.
Pads all sequences in the batch to the same length (the length of the longest sequence) along the sequence dimension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch
|
list[tuple[Tensor, Tensor]]
|
List of (src, tgt) pairs where src and tgt are 1D long tensors of variable length. |
required |
pad_idx
|
int
|
Padding index value. Defaults to config.pad_idx. |
None
|
config
|
Config
|
Configuration object. Defaults to get_default_config(). |
None
|
Returns:
| Type | Description |
|---|---|
Tuple[Tensor, Tensor]
|
tuple[torch.Tensor, torch.Tensor]: A tuple containing: - src_batch (torch.Tensor): Padded source batch with shape (batch_size, max_src_len). - tgt_batch (torch.Tensor): Padded target batch with shape (batch_size, max_tgt_len). |
Notes
Used as the collate_fn for PyTorch DataLoaders. Padding is applied with batch_first=True so sequences are in (batch, seq_len) order.
Source code in src/torchlingo/data_processing/batching.py
BucketBatchSampler¶
BucketBatchSampler
¶
BucketBatchSampler(dataset: NMTDataset, batch_size: int, bucket_boundaries: Optional[List[int]] = None)
Bases: Sampler
Groups dataset samples into length buckets to minimize padding in batches.
Assigns each sample to a bucket based on its source sequence length. When iterated, yields batches where all samples come from the same bucket, reducing padding waste. Bucket boundaries are automatically computed from the data distribution if not provided.
Bucketing is particularly effective for datasets with large sequence length variance, e.g., 10-500 tokens. It reduces computational waste from padding longer samples with many pad tokens.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
NMTDataset
|
The dataset to sample from. |
required |
batch_size
|
int
|
Number of samples per batch. |
required |
bucket_boundaries
|
list[int]
|
Bucket upper boundaries in ascending order. Defaults to None, in which case boundaries are computed automatically from sequence length percentiles. |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
buckets |
list[list[int]]
|
Per-bucket list of sample indices. |
num_batches |
int
|
Total number of batches that will be yielded. |
bucket_boundaries |
list[int]
|
Upper length boundary for each bucket. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no bucket contains at least batch_size samples, so the sampler would yield zero batches (incomplete batches are dropped). This typically happens when batch_size is larger than the dataset; use a smaller batch_size or provide more data. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
NMTDataset
|
The dataset to sample from. |
required |
batch_size
|
int
|
Number of samples per batch. |
required |
bucket_boundaries
|
list[int]
|
Pre-specified bucket boundaries. If None, computed automatically. Defaults to None. |
None
|
Source code in src/torchlingo/data_processing/batching.py
__iter__
¶
Iterate over batches of sample indices.
Yields batches by: 1. Shuffling samples within each bucket independently. 2. Creating batches from each bucket (discarding incomplete batches). 3. Shuffling the list of batches. 4. Yielding batches of sample indices.
Yields:
| Type | Description |
|---|---|
List[int]
|
list[int]: Each batch is a list of sample indices, length = batch_size. |
Notes
- Incomplete batches (fewer than batch_size samples) are dropped.
- Batch order is randomized for better training dynamics.
- Within-bucket samples are shuffled for better gradient estimates.
Source code in src/torchlingo/data_processing/batching.py
__len__
¶
Return the number of complete batches.
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
Total number of batches that will be yielded. Incomplete batches (fewer than batch_size samples) are not counted. |
Source code in src/torchlingo/data_processing/batching.py
create_dataloaders¶
create_dataloaders
¶
create_dataloaders(train_file: Union[Path, NMTDataset], val_file: Optional[Union[Path, NMTDataset]] = None, batch_size: Optional[int] = None, num_workers: Optional[int] = None, use_sentencepiece: bool = False, sp_model_path: Optional[str] = None, sp_tgt_model_path: Optional[str] = None, use_bucketing: bool = False, bucket_boundaries: Optional[List[int]] = None, device: Optional[str] = None, pad_idx: Optional[int] = None, config: Optional[Config] = None) -> Tuple[DataLoader, Optional[DataLoader], BaseVocab, BaseVocab]
Create PyTorch DataLoaders for training and validation.
Constructs train and optional validation DataLoaders from structured data files. Supports two tokenization modes: simple token-based (SimpleVocab) or SentencePiece subword. Optionally uses bucketing by sequence length to minimize padding overhead.
Data must be in structured format (TSV/CSV/JSON/Parquet) with configurable source and target columns. Parallel .txt files should be merged into a single file first (see preprocessing.base.parallel_txt_to_dataframe).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
train_file
|
Path | NMTDataset
|
Path to training data file or a prebuilt NMTDataset instance. |
required |
val_file
|
Path | NMTDataset
|
Path to validation data file or a prebuilt NMTDataset instance. If None, no validation loader is created. Defaults to None. |
None
|
batch_size
|
int
|
Batch size for loaders. Defaults to config.batch_size. |
None
|
num_workers
|
int
|
Number of worker processes for data loading. Defaults to config.num_workers. |
None
|
use_sentencepiece
|
bool
|
If True, use SentencePiece models for tokenization. If False, use simple token-based vocabularies. Defaults to False. |
False
|
sp_model_path
|
str
|
Path to SentencePiece source model file. Required if use_sentencepiece=True. Defaults to config.sentencepiece_src_model. |
None
|
sp_tgt_model_path
|
str
|
Path to SentencePiece target model file. If None with use_sentencepiece=True, uses the configured target path or sp_model_path when identical. Defaults to None. |
None
|
use_bucketing
|
bool
|
If True, use BucketBatchSampler to group sequences by length. Reduces padding overhead for datasets with variable sequence lengths. Defaults to False. |
False
|
bucket_boundaries
|
list[int]
|
Pre-specified bucket boundaries for BucketBatchSampler. If None with use_bucketing=True, boundaries are computed automatically from the training data. Defaults to None. |
None
|
device
|
str
|
Device string (e.g., 'cuda', 'cpu'). Used for pin_memory optimization. Defaults to config.device. |
None
|
pad_idx
|
int
|
Padding index value. Defaults to config.pad_idx. |
None
|
config
|
Config
|
Configuration object. Defaults to get_default_config(). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
Tuple[DataLoader, Optional[DataLoader], BaseVocab, BaseVocab]
|
A 4-tuple containing: - train_loader (DataLoader): Training data loader. - val_loader (DataLoader or None): Validation data loader, or None if val_file is not provided. - src_vocab (BaseVocab): Source vocabulary. - tgt_vocab (BaseVocab): Target vocabulary. |
Raises:
| Type | Description |
|---|---|
AssertionError
|
If use_sentencepiece=True but sp_model_path is None. |
ValueError
|
If data files have incorrect format or missing columns. |
ValueError
|
If the training loader would yield 0 batches, e.g. when use_bucketing=True and batch_size is larger than every length bucket (incomplete batches are dropped), or when the training dataset is empty. Use a smaller batch_size or more data. |
Examples:
>>> train_loader, val_loader, src_vocab, tgt_vocab = create_dataloaders(
... train_file="data/train.tsv",
... val_file="data/val.tsv",
... batch_size=32,
... use_bucketing=True
... )
>>> for src_batch, tgt_batch in train_loader:
... print(src_batch.shape, tgt_batch.shape)
... break
torch.Size([32, 45]) torch.Size([32, 48])
>>> train_ds = NMTDataset("data/train.tsv")
>>> val_ds = NMTDataset("data/val.tsv", src_vocab=train_ds.src_vocab, tgt_vocab=train_ds.tgt_vocab)
>>> train_loader, val_loader, src_vocab, tgt_vocab = create_dataloaders(
... train_file=train_ds,
... val_file=val_ds,
... batch_size=32,
... )
Notes
- DataLoader pin_memory is enabled for CUDA devices to speed up transfers.
- Training loader always shuffles (or uses bucket-based shuffling).
- Validation loader does not shuffle.
- With use_bucketing=True, incomplete batches are dropped; without bucketing, the final (possibly smaller) batch is kept.
Source code in src/torchlingo/data_processing/batching.py
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 | |
Examples¶
Basic Batching¶
from torch.utils.data import DataLoader
from torchlingo.data_processing import NMTDataset, collate_fn
dataset = NMTDataset("data/train.tsv")
loader = DataLoader(
dataset,
batch_size=32,
shuffle=True,
collate_fn=collate_fn,
num_workers=4, # Parallel data loading
)
for src_batch, tgt_batch in loader:
print(f"Source: {src_batch.shape}") # [32, max_src_len]
print(f"Target: {tgt_batch.shape}") # [32, max_tgt_len]
break
Bucketed Batching¶
Bucketing groups sequences of similar length together, reducing wasted computation on padding:
from torch.utils.data import DataLoader
from torchlingo.data_processing import NMTDataset, collate_fn, BucketBatchSampler
dataset = NMTDataset("data/train.tsv")
sampler = BucketBatchSampler(dataset, batch_size=32)
loader = DataLoader(
dataset,
batch_sampler=sampler, # Note: batch_sampler, not batch_size
collate_fn=collate_fn,
)
Using create_dataloaders¶
The easiest way to create properly configured loaders:
from torchlingo.data_processing import create_dataloaders
train_loader, val_loader = create_dataloaders(
train_file="data/train.tsv",
val_file="data/val.tsv",
batch_size=32,
shuffle_train=True,
use_bucketing=True, # Optional: enable bucketing
)
With Shared Vocabularies¶
from torchlingo.data_processing import NMTDataset, create_dataloaders
# Build vocab on training data
train_dataset = NMTDataset("data/train.tsv")
# Pass to create_dataloaders
train_loader, val_loader = create_dataloaders(
train_file="data/train.tsv",
val_file="data/val.tsv",
src_vocab=train_dataset.src_vocab,
tgt_vocab=train_dataset.tgt_vocab,
batch_size=32,
)
How Padding Works¶
The collate_fn pads sequences to the maximum length in each batch:
Before padding:
Sample 1: [2, 5, 6, 3] # length 4
Sample 2: [2, 7, 8, 9, 10, 3] # length 6
Sample 3: [2, 11, 3] # length 3
After padding (to length 6):
Sample 1: [2, 5, 6, 3, 0, 0] # padded with 0s
Sample 2: [2, 7, 8, 9, 10, 3] # no padding needed
Sample 3: [2, 11, 3, 0, 0, 0] # padded with 0s
How Bucketing Works¶
BucketBatchSampler assigns sequences to buckets based on length:
Bucket 0 (len ≤ 10): [sample_3, sample_7, sample_12, ...]
Bucket 1 (len ≤ 20): [sample_1, sample_5, sample_9, ...]
Bucket 2 (len ≤ 40): [sample_2, sample_8, ...]
Bucket 3 (len > 40): [sample_4, sample_6, ...]
Batches are created from samples within the same bucket, so sequences in a batch have similar lengths.
Benefits of Bucketing¶
| Without Bucketing | With Bucketing |
|---|---|
| Random mixing of lengths | Similar lengths grouped |
| More padding tokens | Minimal padding |
| Wasted computation | Efficient computation |
Custom Bucket Boundaries¶
sampler = BucketBatchSampler(
dataset,
batch_size=32,
bucket_boundaries=[10, 25, 50, 100], # Custom boundaries
)
Configuration¶
All batching functions respect the Config object:
from torchlingo.config import Config
config = Config(
batch_size=64,
pad_idx=0,
)
train_loader, val_loader = create_dataloaders(
train_file="data/train.tsv",
val_file="data/val.tsv",
config=config,
)
Performance Tips¶
-
Use
num_workersfor parallel data loading: -
Enable bucketing for datasets with variable lengths:
-
Pin memory for GPU training:
-
Adjust batch size based on GPU memory:
- Larger batches = faster training but more memory
- Start with 32, increase until you run out of memory