File size: 2,294 Bytes
7bafa44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
"""
dataset.py — loads wikitext-2 or tinystories and chunks into fixed-length blocks.
"""
from __future__ import annotations

from typing import Dict

import torch
from datasets import load_dataset
from torch.utils.data import DataLoader, Dataset


class BlockDataset(Dataset):
    """Chunks a flat token sequence into non-overlapping blocks of seq_len."""

    def __init__(self, tokens: torch.Tensor, seq_len: int) -> None:
        self.seq_len = seq_len
        n_blocks = len(tokens) // (seq_len + 1)
        # +1 so we can shift for next-token targets
        self.data = tokens[: n_blocks * (seq_len + 1)].reshape(n_blocks, seq_len + 1)

    def __len__(self) -> int:
        return len(self.data)

    def __getitem__(self, idx: int) -> Dict[str, torch.Tensor]:
        chunk = self.data[idx]
        return {"input_ids": chunk}


def load_text_dataset(
    name: str = "wikitext-2",
    seq_len: int = 256,
    batch_size: int = 16,
    tokenizer_name: str = "gpt2",
) -> Dict[str, DataLoader]:
    """
    Returns {"train": DataLoader, "validation": DataLoader}.
    Supported names: "wikitext-2", "tinystories".
    """
    from transformers import AutoTokenizer

    tok = AutoTokenizer.from_pretrained(tokenizer_name)
    if tok.pad_token is None:
        tok.add_special_tokens({"pad_token": "[PAD]"})

    if name == "wikitext-2":
        raw = load_dataset("wikitext", "wikitext-2-raw-v1")
    elif name == "tinystories":
        raw = load_dataset("roneneldan/TinyStories")
    else:
        raise ValueError(f"Unknown dataset: {name}")

    def tokenize(examples):
        return tok(examples["text"], truncation=False, return_attention_mask=False)

    tokenized = raw.map(tokenize, batched=True, remove_columns=raw["train"].column_names)

    loaders = {}
    for split in ("train", "validation"):
        if split not in tokenized:
            continue
        all_ids = []
        for sample in tokenized[split]["input_ids"]:
            all_ids.extend(sample)
        flat = torch.tensor(all_ids, dtype=torch.long)
        ds = BlockDataset(flat, seq_len)
        loaders[split] = DataLoader(
            ds,
            batch_size=batch_size,
            shuffle=(split == "train"),
            num_workers=2,
            pin_memory=True,
        )

    return loaders