Minimind预训练和微调的数据集构建区别
·
它们的核心区别在于其设计目标和数据处理方式,这直接对应了预训练 (Pre-training) 和 监督微调 (Supervised Fine-Tuning, SFT) 这两个阶段的根本不同。
PretrainDataset(预训练):目标是让模型学习通用的语言知识。它处理的是大段的、非结构化的文本,训练模型预测序列中的下一个词。SFTDataset(监督微调):目标是让模型学习遵循指令和进行对话。它处理的是结构化的“指令-回答”或“多轮对话”数据,只训练模型去预测助手的回答部分。
核心区别对比
| 特性 | PretrainDataset (预训练) |
SFTDataset (监督微调) |
|---|---|---|
| 训练目标 | 学习语言的通用模式、语法、事实知识。成为一个文本续写器。 | 学习如何根据用户输入(指令/问题)生成有用的、符合要求的回答。成为一个对话助手。 |
| 输入数据格式 | 非结构化的纯文本。通常是一个 JSON 对象,包含一个 'text' 字段。 |
结构化的对话数据。通常是一个 JSON 对象,包含一个 'conversations' 列表。 |
| 数据处理核心 | 直接对整段 'text' 进行 Tokenize。 |
使用 apply_chat_template 将 'conversations' 列表转换成符合特定聊天格式(如 ChatML)的字符串。 |
损失计算 (loss_mask) |
在所有非填充 (non-padding) 的 token 上计算损失。模型需要学习预测整个文本序列。 | 只在“助手回答”部分的 token 上计算损失。模型被强制只学习如何生成回答,而不会去学习预测用户的输入。 |
| 代码实现关键点 | loss_mask = (input_ids != self.tokenizer.pad_token_id) |
_generate_loss_mask 函数,它会定位到 `< |
详细代码层面解释
1. 输入数据 (Input Data)
-
PretrainDataset:- 它期望的数据是这样的 JSONL 文件:
{"text": "第一篇维基百科文章的内容..."} {"text": "第二本小说的内容..."} - 在
__getitem__中,它直接处理sample['text']。
- 它期望的数据是这样的 JSONL 文件:
-
SFTDataset:- 它期望的数据是这样的 JSONL 文件,包含多轮对话:
{"conversations": [{"content": "你好"}, {"content": "你好!有什么可以帮助你的吗?"}]} {"conversations": [{"content": "帮我写一首关于月亮的诗"}, {"content": "好的,当然。静夜思,床前明月光..."}]} - 在
__getitem__中,它处理的是sample['conversations']。
- 它期望的数据是这样的 JSONL 文件,包含多轮对话:
2. 数据处理与格式化 (Data Processing)
-
PretrainDataset:- 就是将长文本进行 tokenize,然后截断或填充到
max_length。 encoding = self.tokenizer(str(sample['text']), ...)
- 就是将长文本进行 tokenize,然后截断或填充到
-
SFTDataset:- 有一个关键的
_create_chat_prompt方法。 - 这个方法使用
tokenizer.apply_chat_template,它会把对话列表转换成一个带有特殊标记的字符串。例如,上面的对话可能会被转换成:<|im_start|>user 你好<|im_end|> <|im_start|>assistant 你好!有什么可以帮助你的吗?<|im_end|> - 这个格式化的过程对于让模型理解角色(谁是用户,谁是助手)至关重要。
- 有一个关键的
3. 损失掩码 (loss_mask) - 这是最关键的区别!
-
PretrainDataset:loss_mask的生成非常简单:loss_mask = (input_ids != self.tokenizer.pad_token_id)。- 这意味着,只要一个 token 不是填充符
[PAD],模型在预测它的时候就会计算损失。 - 效果:模型学习预测整个文本中的每一个词。
-
SFTDataset:loss_mask的生成非常精巧,在_generate_loss_mask函数中实现。- 它会遍历 tokenized 之后的
input_ids,精确地找到助手回答的起始标记 (<|im_start|>assistant) 和结束标记 (<|im_end|>)。 - 然后,它只将助手回答部分的 token 对应的
loss_mask位置设为 1,其他所有部分(包括用户的提问和特殊标记)都为 0。 - 效果:在反向传播和参数更新时,只有
loss_mask为 1 的位置才会对梯度有贡献。这等于是在告诉模型:“你不需要学习如何说出用户的话,你只需要学习如何在我(助手)该说话的时候,说出正确的话。”
4. 训练样本的构建 (X, Y)
两个类在这一步是相同的:
X = torch.tensor(input_ids[:-1], ...)Y = torch.tensor(input_ids[1:], ...)
这都是标准语言模型的 “next token prediction” 任务,即用前面的序列 X 来预测下一个词 Y。但由于 loss_mask 的存在,SFTDataset 在计算损失时会忽略掉大部分 Y 中的 token。
-
预训练 (
PretrainDataset) 就像是通识教育。一个人通过阅读海量的书籍、文章、网页(非结构化文本),学习语法、常识和推理能力。他学习的目标是理解并能补全任何一句话。 -
监督微调 (
SFTDataset) 就像是岗前培训。这个人已经具备了通用语言能力,现在要培训他成为一名客服。培训材料是大量的“客户问题-标准回答”对话录(结构化数据)。在培训中,我们只考核他回答的好不好(只在助手回答部分计算 loss),而不会去考核他复述客户问题的能力。通过这种方式,他学会了如何扮演好“客服”这个特定角色。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)