Files
2026-07-13 12:47:19 +08:00

64 lines
2.8 KiB
Python

# Copyright Lightning AI. Licensed under the Apache License 2.0, see LICENSE file.
import os
from dataclasses import dataclass, field
from pathlib import Path
from torch.utils.data import DataLoader
from litgpt.data import DataModule
from litgpt.tokenizer import Tokenizer
@dataclass
class LitData(DataModule):
"""Loads data using LitData's StreamingDataset given a path to a folder of preprocessed data (chunks)."""
data_path: str | Path = Path("data/")
"""The path to the data directory containing the preprocessed chunks for the streaming dataset
The path can also be a remote path (e.g., s3://). See also ``split_names`` if this path contains subfolders
for training- and validation splits."""
split_names: tuple[str, str] | None = None
"""Optional tuple for names of subfolders for training and validation under ``data_path``. If not provided,
all data under data_path will be used for training, and the validation dataloader will be identical to the
train dataloader."""
seed: int = 42
"""The random seed for shuffling the dataset."""
num_workers: int = 8
"""How many DataLoader processes to use for loading."""
batch_size: int = field(init=False, repr=False, default=1)
seq_length: int = field(init=False, repr=False, default=2048)
def __post_init__(self) -> None:
super().__init__()
if self.split_names is not None and len(self.split_names) != 2:
raise ValueError("If provided `split_names` must be a tuple of two strings, for example: ('train', 'val').")
def connect(
self, tokenizer: Tokenizer | None = None, batch_size: int = 1, max_seq_length: int | None = None
) -> None:
self.batch_size = batch_size
self.seq_length = max_seq_length + 1 # Increase by one because we need the next token as well
def train_dataloader(self) -> DataLoader:
input_dir = os.path.join(self.data_path, self.split_names[0]) if self.split_names else str(self.data_path)
return self._dataloader(input_dir=input_dir, train=True)
def val_dataloader(self) -> DataLoader:
input_dir = os.path.join(self.data_path, self.split_names[1]) if self.split_names else str(self.data_path)
return self._dataloader(input_dir=input_dir, train=False)
def _dataloader(self, input_dir: str, train: bool):
from litdata.streaming import StreamingDataLoader, StreamingDataset, TokensLoader
dataset = StreamingDataset(
input_dir=input_dir,
item_loader=TokensLoader(block_size=self.seq_length),
shuffle=train,
seed=self.seed,
)
dataloader = StreamingDataLoader(
dataset, batch_size=self.batch_size, pin_memory=True, num_workers=self.num_workers, drop_last=True
)
return dataloader