| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| from __future__ import annotations |
|
|
| from typing import Any |
|
|
| from torch.utils.data._utils.collate import default_collate |
|
|
| from lerobot.datasets.language import LANGUAGE_COLUMNS |
|
|
| _PYTHON_LIST_KEYS = {"messages", "message_streams", "target_message_indices"} |
|
|
|
|
| def lerobot_collate_fn(batch: list[dict[str, Any] | None]) -> dict[str, Any] | None: |
| """Collate function that preserves Python-list and language fields as lists. |
| |
| Drops ``None`` samples (e.g. recipes that yielded no target message), keeps |
| rendered-message and language fields as plain Python lists, and delegates |
| every other key to PyTorch's ``default_collate``. |
| """ |
| batch = [sample for sample in batch if sample is not None] |
| if not batch: |
| return None |
|
|
| |
| |
| |
| |
| |
| preserved: dict[str, list[Any]] = {} |
| for key in _PYTHON_LIST_KEYS: |
| presence = [key in sample for sample in batch] |
| if not any(presence): |
| continue |
| if not all(presence): |
| raise ValueError( |
| f"Inconsistent batch: {sum(presence)}/{len(batch)} samples carry {key!r}; " |
| f"every sample in a batch must agree." |
| ) |
| preserved[key] = [sample[key] for sample in batch] |
| tensorizable = [ |
| { |
| key: value |
| for key, value in sample.items() |
| if key not in _PYTHON_LIST_KEYS and key not in LANGUAGE_COLUMNS |
| } |
| for sample in batch |
| ] |
| collated = default_collate(tensorizable) |
| collated.update(preserved) |
| return collated |
|
|