"""Dataset helpers to implement during Pretrain, SFT, and DPO stages.""" from __future__ import annotations from torch.utils.data import Dataset import random from datasets import load_dataset, Features, Sequence, Value import torch def post_processing_chat(prompt_content, empty_think_ratio=0.2): # 以80%概率移除空思考标签 if '\n\n\n\n' in prompt_content and random.random() > empty_think_ratio: prompt_content = prompt_content.replace('\n\n\n\n', '') return prompt_content def pre_processing_chat(conversations, add_system_ratio=0.2): # tool use 数据完整保留不做处理 if any(conv.get('tools') for conv in conversations): return conversations SYSTEM_PROMPTS = [ "你是一个知识丰富的AI,尽力为用户提供准确的信息。", "你是minimind,一个小巧但有用的语言模型。", "你是一个专业的AI助手,请提供有价值的回答。", "你是minimind,请尽力帮助用户解决问题。", "你是一个可靠的AI,请给出准确的回答。", "You are a helpful AI assistant.", "You are minimind, a lightweight intelligent assistant.", "You are a friendly chatbot. Please answer the user's questions carefully.", "You are a knowledgeable AI. Try your best to provide accurate information.", "You are minimind, a small but useful language model." ] # 概率性添加system if conversations[0].get('role') != 'system': if random.random() < add_system_ratio: return [{'role': 'system', 'content': random.choice(SYSTEM_PROMPTS)}] + conversations return conversations class CoursePretrainDataset(Dataset): """TODO: read jsonl text samples and return input_ids/labels. Align with: dataset/lm_dataset.py::PretrainDataset """ def __init__(self, data_path: str, tokenizer, max_length: int): self.data_path = data_path self.tokenizer = tokenizer self.max_length = max_length features = Features({'conversations': [{'role': Value('string'), 'content': Value('string'), 'reasoning_content': Value('string'), 'tools': Value('string'), 'tool_calls': Value('string')}]}) self.samples=load_dataset('json', data_files=data_path, split='train', features=features) self.bos_id=tokenizer(f'{tokenizer.bos_token}assistant\n',add_special_tokens=False).input_ids self.eos_id=tokenizer(f'{tokenizer.eos_token}\n', add_special_tokens=False).input_ids def __len__(self) -> int: raise NotImplementedError("Implement in the Pretrain dataset lesson.") def __getitem__(self, index: int): raise NotImplementedError("Implement in the Pretrain dataset lesson.") class CourseSFTDataset(Dataset): """TODO: render conversations and build SFT labels. Align with: dataset/lm_dataset.py::SFTDataset """ def __init__(self, data_path: str, tokenizer, max_length: int): self.data_path = data_path self.tokenizer = tokenizer self.max_length = max_length features = Features({'conversations': [{'role': Value('string'), 'content': Value('string'), 'reasoning_content': Value('string'), 'tools': Value('string'), 'tool_calls': Value('string')}]}) self.samples=load_dataset('json', data_files=data_path, split='train', features=features) self.bos_id=tokenizer(f'{tokenizer.bos_token}assistant\n',add_special_tokens=False).input_ids self.eos_id=tokenizer(f'{tokenizer.eos_token}\n', add_special_tokens=False).input_ids def create_chat_prompt(self, conversations): """TODO: render conversations with the tokenizer chat template. Align with: dataset/lm_dataset.py::SFTDataset.create_chat_prompt """ messages=[] tools=None for message in conversations: message=dict(message) if message.get("role")=='system' and message.get("tools"): tools = json.loads(message["tools"]) if isinstance(message["tools"], str) else message["tools"] if message.get('tool_calls') and isinstance(message["tool_calls"], str): message["tool_calls"] = json.loads(message["tool_calls"]) messages.append(message) return self.tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=False, tools=tools ) raise NotImplementedError("Implement in the SFT training lesson.") def generate_labels(self, input_ids: list[int]) -> list[int]: """TODO: keep assistant reply tokens and mask everything else as -100. Align with: dataset/lm_dataset.py::SFTDataset.generate_labels """ labels=[-100]*len(input_ids) i=0 while i int: return len(self.samples) raise NotImplementedError("Implement in the SFT dataset lesson.") def __getitem__(self, index: int): sample=self.samples[index] conversations = pre_processing_chat(sample['conversations']) prompt=self.create_chat_prompt(conversations) prompt = post_processing_chat(prompt) input_ids=self.tokenizer(prompt).input_ids[:self.max_length] input_ids+=[self.tokenizer.pad_token_id]*(self.max_length-len(input_ids)) labels=self.generate_labels(input_ids) return torch.tensor(input_ids, dtype=torch.long), torch.tensor(labels, dtype=torch.long) raise NotImplementedError("Implement in the SFT dataset lesson.") class CourseDPODataset(Dataset): """TODO: build chosen/rejected training pairs. Align with: dataset/lm_dataset.py::DPODataset """ def __init__(self, data_path: str, tokenizer, max_length: int): self.data_path = data_path self.tokenizer = tokenizer self.max_length = max_length def __len__(self) -> int: raise NotImplementedError("Implement in the DPO dataset lesson.") def __getitem__(self, index: int): raise NotImplementedError("Implement in the DPO dataset lesson.")