MiniSEAL / src /data /sft_dataset.py
aaronr43210's picture
Upload src
27d37fd verified
Raw History Blame Contribute Delete
1.9 kB
import torch
from torch.utils.data import Dataset
from tokenizers import Tokenizer
from typing import List, Dict
from src.common.prompts import format_prompt, resolve_eos_id, resolve_pad_id
class SFTDataset(Dataset):
"""
Dataset for Supervised Fine-Tuning.
Formats Alpaca/Instruction data by masking the prompt loss and only computing loss on the response.
"""
def __init__(self, data: List[Dict[str, str]], tokenizer: Tokenizer, max_len: int = 512):
self.samples = []
pad_token_id = resolve_pad_id(tokenizer)
eos_token_id = resolve_eos_id(tokenizer)
for item in data:
# Canonical shared prompt format (keeps SFT/DPO/inference aligned).
prompt = format_prompt(item["prompt"])
response = item["response"]
enc_prompt = tokenizer.encode(prompt).ids
enc_response = tokenizer.encode(response).ids
if eos_token_id is not None:
enc_response = enc_response + [eos_token_id]
input_ids = enc_prompt + enc_response
# -100 tells PyTorch's CrossEntropyLoss to ignore these tokens during loss calculation
labels = [-100] * len(enc_prompt) + enc_response
# Truncate or pad
if len(input_ids) > max_len:
input_ids = input_ids[:max_len]
labels = labels[:max_len]
else:
pad_len = max_len - len(input_ids)
input_ids = input_ids + [pad_token_id] * pad_len
labels = labels + [-100] * pad_len
self.samples.append((
torch.tensor(input_ids, dtype=torch.long),
torch.tensor(labels, dtype=torch.long)
))
def __len__(self):
return len(self.samples)
def __getitem__(self, idx):
return self.samples[idx]