lifatsastain's picture
add src floder
45f5949
Raw
History Blame Contribute Delete
7.85 kB
import random
import csv
import json
import re
from pathlib import Path
import torch
from datasets import DownloadConfig, load_dataset
from torch.utils.data import DataLoader
from stage2_config import (
DATALOADER_NUM_WORKERS,
DATASET_NAME,
PROMPT_LEN,
ROCSTORIES_FILE,
ROCSTORIES_PROMPT_SENTENCES,
ROCSTORIES_SPLIT,
ROCSTORIES_TARGET_SENTENCES,
SEED,
)
def seed_worker(worker_id):
worker_seed = SEED + worker_id
random.seed(worker_seed)
torch.manual_seed(worker_seed)
def split_story_sentences(text):
text = " ".join(str(text).strip().split())
if not text:
return []
parts = re.split(r"(?<=[.!?])\s+", text)
return [part.strip() for part in parts if part.strip()]
def sentence_parts_from_row(row):
sentence_key_sets = [
[f"sentence{i}" for i in range(1, 6)],
[f"Sentence{i}" for i in range(1, 6)],
[f"InputSentence{i}" for i in range(1, 5)] + ["RandomFifthSentenceQuiz1"],
[f"InputSentence{i}" for i in range(1, 5)] + ["RandomFifthSentenceQuiz2"],
]
for keys in sentence_key_sets:
parts = [str(row.get(key, "")).strip() for key in keys]
if sum(bool(part) for part in parts) >= ROCSTORIES_PROMPT_SENTENCES + ROCSTORIES_TARGET_SENTENCES:
return parts
for prompt_key, continuation_key in (("prompt", "continuation"), ("Prompt", "Continuation")):
if row.get(prompt_key) and row.get(continuation_key):
parts = split_story_sentences(row[prompt_key]) + split_story_sentences(row[continuation_key])
if len(parts) >= ROCSTORIES_PROMPT_SENTENCES + ROCSTORIES_TARGET_SENTENCES:
return parts
for key in ("story", "text", "full_text", "Story", "Text"):
if row.get(key):
return split_story_sentences(row[key])
return []
def read_rocstories_rows(path):
path = Path(path)
if not path.exists():
raise FileNotFoundError(f"ROCStories file does not exist: {path}")
suffix = path.suffix.lower()
if suffix == ".jsonl":
with path.open("r", encoding="utf-8") as f:
return [json.loads(line) for line in f if line.strip()]
if suffix in (".csv", ".tsv"):
delimiter = "\t" if suffix == ".tsv" else ","
with path.open("r", newline="", encoding="utf-8") as f:
return list(csv.DictReader(f, delimiter=delimiter))
with path.open("r", encoding="utf-8") as f:
return [{"text": line.strip()} for line in f if line.strip()]
def build_rocstories_dataset(tokenizer, max_length):
if not ROCSTORIES_FILE:
raise RuntimeError(
"SLTR_DATASET=rocstories requires ROCSTORIES_FILE=/path/to/rocstories.csv"
)
suffix_len = max_length - PROMPT_LEN
if suffix_len <= 0:
raise ValueError(f"PROMPT_LEN={PROMPT_LEN} must be smaller than MAX_SEQ_LEN={max_length}")
examples = []
for row in read_rocstories_rows(ROCSTORIES_FILE):
sentences = sentence_parts_from_row(row)
needed = ROCSTORIES_PROMPT_SENTENCES + ROCSTORIES_TARGET_SENTENCES
if len(sentences) < needed:
continue
prompt_text = " ".join(sentences[:ROCSTORIES_PROMPT_SENTENCES])
target_text = " ".join(sentences[ROCSTORIES_PROMPT_SENTENCES:needed])
prompt = tokenizer(
prompt_text,
truncation=True,
max_length=PROMPT_LEN,
padding="max_length",
)
target = tokenizer(
target_text,
add_special_tokens=False,
truncation=True,
max_length=suffix_len,
padding="max_length",
)
if sum(prompt["attention_mask"]) == 0 or sum(target["attention_mask"]) == 0:
continue
input_ids = prompt["input_ids"] + target["input_ids"]
attention_mask = prompt["attention_mask"] + target["attention_mask"]
examples.append(
{
"input_ids": torch.tensor(input_ids, dtype=torch.long),
"attention_mask": torch.tensor(attention_mask, dtype=torch.long),
"prompt_token_len": torch.tensor(sum(prompt["attention_mask"]), dtype=torch.long),
"target_token_len": torch.tensor(sum(target["attention_mask"]), dtype=torch.long),
}
)
if not examples:
raise RuntimeError(
f"No ROCStories examples found in {ROCSTORIES_FILE} for split {ROCSTORIES_SPLIT}"
)
return examples
def build_stage2_dataloaders(tokenizer, train_size, batch_size, max_length):
generator = torch.Generator()
generator.manual_seed(SEED)
if DATASET_NAME == "rocstories":
examples = build_rocstories_dataset(tokenizer, max_length)
random.Random(SEED).shuffle(examples)
train_size = min(train_size, max(1, int(0.9 * len(examples))))
train_rows = examples[:train_size]
val_rows = examples[train_size:] or examples[-min(len(examples), 100):]
train_loader = DataLoader(
train_rows,
batch_size=batch_size,
shuffle=True,
num_workers=DATALOADER_NUM_WORKERS,
pin_memory=True,
worker_init_fn=seed_worker,
generator=generator,
persistent_workers=DATALOADER_NUM_WORKERS > 0,
)
val_loader = DataLoader(
val_rows,
batch_size=batch_size,
shuffle=False,
num_workers=DATALOADER_NUM_WORKERS,
pin_memory=True,
worker_init_fn=seed_worker,
persistent_workers=DATALOADER_NUM_WORKERS > 0,
)
print(
f"ROCStories batches: train={len(train_loader)} val={len(val_loader)} "
f"examples={len(examples)} prompt_slots={PROMPT_LEN} target_slots={max_length - PROMPT_LEN} "
f"split={ROCSTORIES_SPLIT}",
flush=True,
)
return train_loader, val_loader
try:
ds = load_dataset(
"wikitext",
"wikitext-103-raw-v1",
download_config=DownloadConfig(local_files_only=True),
)
print("loaded wikitext from local datasets cache", flush=True)
except Exception as exc:
print(f"local wikitext cache unavailable ({exc}) | trying online load", flush=True)
ds = load_dataset("wikitext", "wikitext-103-raw-v1")
train_size = min(train_size, len(ds["train"]))
small_train = ds["train"].select(range(train_size))
small_val = ds["validation"]
small_train = small_train.filter(lambda x: len(x["text"].strip()) > 10)
small_val = small_val.filter(lambda x: len(x["text"].strip()) > 10)
def tokenize(batch):
return tokenizer(
batch["text"],
truncation=True,
max_length=max_length,
padding="max_length",
)
train_tok = small_train.map(tokenize, batched=True)
val_tok = small_val.map(tokenize, batched=True)
train_tok.set_format(type="torch", columns=["input_ids", "attention_mask"])
val_tok.set_format(type="torch", columns=["input_ids", "attention_mask"])
train_loader = DataLoader(
train_tok,
batch_size=batch_size,
shuffle=True,
num_workers=DATALOADER_NUM_WORKERS,
pin_memory=True,
worker_init_fn=seed_worker,
generator=generator,
persistent_workers=DATALOADER_NUM_WORKERS > 0,
)
val_loader = DataLoader(
val_tok,
batch_size=batch_size,
shuffle=False,
num_workers=DATALOADER_NUM_WORKERS,
pin_memory=True,
worker_init_fn=seed_worker,
persistent_workers=DATALOADER_NUM_WORKERS > 0,
)
print(
f"train batches: {len(train_loader)} val batches: {len(val_loader)} "
f"max_length: {max_length}",
flush=True,
)
return train_loader, val_loader