大模型为什么"聪明":从数据集划分到数据工程的一次入门梳理
很多人聊大模型时,会先想到参数量、GPU、Transformer、推理速度,但真正决定模型上限的,往往还有一个更基础的问题:数据。
如果把大模型训练类比成人学习,算力像学习时能投入的时间和精力,算法像学习方法,而数据就是教材、作业和考试题。没有高质量、结构清晰、覆盖充分的数据,再强的算力和算法也很难训练出稳定可靠的模型。
这篇文章结合一个中文点评情感分类数据集,梳理三个问题:
- LLM 的智能主要从哪里来
- 训练集、验证集、测试集分别解决什么问题
- 数据集如何划分,以及常见划分方式里容易踩的坑
一、LLM 的智能从哪里来
大模型能力通常可以粗略理解为三部分共同作用:
- 数据:模型学习语言、知识、任务模式和统计规律的来源
- 算力:支撑海量数据训练和模型参数更新的计算资源
- 算法:包括 Transformer 架构、优化方法、损失函数、训练策略等
其中,数据非常关键。
模型并不是简单地把训练语料"背下来",而是在大量样本中学习词语、句子、知识、任务目标之间的关联规律。训练之后,它需要面对从未见过的新输入,并给出尽量符合上下文、知识和任务要求的输出。
所以,大模型训练里的"聪明",更准确地说来自:
- 大规模、高质量、低噪声的数据
- 合理的数据组织方式
- 训练、验证、测试之间清晰的边界
- 持续的数据清洗、去重、评估和迭代
二、训练集、验证集、测试集分别是什么
在机器学习里,一个完整数据集通常会被拆成三部分:
| 数据集 | 英文 | 类比 | 作用 |
|---|---|---|---|
| 训练集 | training set | 教材 | 让模型学习数据中的规律 |
| 验证集 | validation set | 课后作业 | 辅助开发者调参、选模型 |
| 测试集 | test set | 期末考试 | 评估最终模型在未知数据上的泛化能力 |
1. 训练集:让模型学习规律
训练集是模型真正参与训练的数据。
比如在情感分类任务中,一条样本可能长这样:
python
{
"sentence": "纯粹的就是一般性的超市,没什么特点,就是觉得酸奶特别便宜而已......",
"label": 0,
"dataset": "dianping"
}
模型会基于大量类似样本,学习文本和标签之间的关系。比如哪些表达更可能对应负向评价,哪些表达更可能对应正向评价。
2. 验证集:帮助开发者调模型
验证集不直接参与参数训练,而是在训练过程中反复用来观察模型效果。
它的主要用途包括:
- 判断模型是否还在变好
- 调整学习率、batch size、训练轮数等超参数
- 选择不同训练方案中效果更好的版本
- 观察模型是否出现过拟合
验证集有点像平时作业。它不参与最终考试评分,但会告诉你当前学习方法有没有问题。
3. 测试集:评估最终泛化能力
测试集应该尽量只在最后使用。
它的目标是回答一个问题:模型在没有见过的数据上,表现到底怎么样?
如果开发过程中频繁查看测试集,并根据测试集结果反复调参,模型和开发决策就会逐渐"适应"测试集,最终评估结果可能虚高。这通常可以理解为测试集污染,属于数据泄漏风险的一种表现。
三、用 ModelScope 数据集做一个划分示例
示例中使用的是魔搭社区的 DAMO_NLP/yf_dianping 数据集。它是一个中文点评类文本数据集,每条样本包含:
sentence:评论文本label:分类标签dataset:数据来源标识
加载方式如下:
python
from modelscope.msdatasets import MsDataset
full_ms_ds = MsDataset.load(
"DAMO_NLP/yf_dianping",
subset_name="default",
split="train"
)
full_ms_ds[44983]
因为这个数据集原始只提供了一个 train split,所以我们需要自己再切分出训练集、验证集和测试集。
四、一个容易出错的划分方式
很多人会这样写:
python
full_hf_ds = full_ms_ds.to_hf_dataset()
split1 = full_hf_ds.train_test_split(test_size=0.1, seed=42)
train_temp_hf = split1["train"] # 90%
test_hf = split1["test"] # 10%
split2 = train_temp_hf.train_test_split(test_size=0.1, seed=42)
train_hf = split2["train"]
val_hf = split2["test"]
这段代码本身能运行,但比例并不是很多人以为的 80% / 10% / 10%。
原因是第二次切分的 test_size=0.1,切的是剩余 90% 里的 10%,所以最终比例是:
- 测试集:原始数据的
10% - 验证集:
90% * 10% = 9% - 训练集:
90% * 90% = 81%
也就是约 81% / 9% / 10%。
如果这是你想要的比例,没问题。但如果你想得到常见的 80% / 10% / 10%,代码就应该改一下。
五、正确切分 80% / 10% / 10%
一种更直观的写法是:先切出 20% 临时集合,再把这 20% 平分成验证集和测试集。
python
full_hf_ds = full_ms_ds.to_hf_dataset()
# 先切出 80% 训练集,20% 临时集合
split1 = full_hf_ds.train_test_split(test_size=0.2, seed=42)
train_hf = split1["train"] # 80%
temp_hf = split1["test"] # 20%
# 再把 20% 临时集合平分为验证集和测试集
split2 = temp_hf.train_test_split(test_size=0.5, seed=42)
val_hf = split2["train"] # 10%
test_hf = split2["test"] # 10%
print(f"训练集 train:{len(train_hf)}")
print(f"验证集 val:{len(val_hf)}")
print(f"测试集 test:{len(test_hf)}")
print("\n单条样本:", train_hf[0])
这段代码的语义更清晰:
- 训练集负责学习
- 验证集负责调参和选模型
- 测试集负责最终评估
同时,seed=42 可以保证每次随机切分结果可复现。实际项目中,固定随机种子非常重要,否则每次运行得到的数据集不同,实验结果也就很难对比。
由于样本总数不一定能被 10 整除,最终三个集合的实际条数可能会有 1 条左右的取整差异,但整体比例仍然接近 80% / 10% / 10%。
对于分类任务,还要额外关注标签分布。如果正负样本比例明显不均衡,最好使用分层抽样,让训练集、验证集、测试集里的标签比例尽量接近原始数据。否则某个集合可能恰好抽到过多正样本或负样本,评估结果会不稳定。
六、为什么不能只做一次固定划分
固定的 8:1:1 划分简单、直观,也是很多项目的默认选择。但它有一个问题:结果可能受单次随机划分影响。
比如某一次切分时,验证集刚好更简单,模型效果看起来就会偏高;或者验证集刚好更难,模型效果看起来就会偏低。
这时可以考虑交叉验证。
七、K 折交叉验证是什么
K 折交叉验证的核心思想是:让每一份数据都有机会做一次验证集。
假设 K=5,流程大致是:
- 把数据集分成 5 份
- 第 1 轮:第 1 份做验证集,其余 4 份做训练集
- 第 2 轮:第 2 份做验证集,其余 4 份做训练集
- 重复 5 轮
- 汇总 5 次验证结果,得到更稳定的评估
这里有一个细节很重要:K 折交叉验证不是同一个模型连续训练 5 次,而是每一轮通常都重新初始化并训练一个新模型。
它主要用于更可靠地评估模型表现,减少一次随机划分带来的偶然性。
不过,在大模型训练里,完整 K 折训练成本通常非常高,所以它更常见于传统机器学习、小模型、数据量较小或实验验证阶段。对于大规模模型,更常见的是维护高质量验证集、测试集和专项评测集。
八、大模型时代的数据工程更像一个循环系统
在传统项目里,数据处理可能是一次性的:
text
采集 -> 清洗 -> 标注 -> 训练
但在 LLM 时代,数据工程更像一个持续循环的系统:
text
采集 -> 清洗 -> 去重 -> 标注 -> 训练 -> 评估 -> 发现问题 -> 重新采样和清洗
其中有几个非常关键的环节。
1. 数据清洗
原始数据里经常会有乱码、重复、广告、低质量文本、格式不统一等问题。
如果这些数据直接进入训练集,模型会学习到很多噪声,最终表现也会受到影响。
2. 数据去重
去重不只是为了节省存储,更是为了降低模型记忆重复样本的风险。
如果测试集中的样本在训练集中出现过,测试结果就不再可信。模型可能不是学会了泛化,而是见过答案。
3. 数据污染检测
数据污染指的是评测数据、测试数据或答案泄漏进训练数据。
这在大模型评测中尤其重要,因为一旦测试题进入训练集,评测分数就很难代表真实能力。
4. 知识覆盖率分析
数据不是越多越好,还要看覆盖是否均衡。
如果语文类数据很多,数学、编程、英文、法律、医学等领域数据不足,模型能力就会出现明显偏科。数据工程需要持续分析不同知识领域、任务类型、难度层级的覆盖情况。
5. 多验证集与阶段性评估
验证标准不一定只有一套。
在一些复杂训练流程中,团队通常会维护多个相对固定的验证集或评测集,例如:
- 通用能力验证集
- 代码能力验证集
- 数学推理验证集
- 安全对齐验证集
- 长文本理解验证集
- 多轮对话验证集
不同训练阶段关注不同指标,评估时也会选择不同集合来观察模型短板。但要注意,同一项指标前后对比时,评测集合和统计口径应该保持稳定,否则结果就不具备可比性。
九、一个更工程化的理解
从模型训练视角看,数据集不是简单的文件集合,而是一套工程系统。
训练集决定模型能学到什么,验证集决定开发者如何调整训练过程,测试集决定最终评估是否可信。数据采集、清洗、去重、标注、污染检测、覆盖率分析,则决定了这套系统能不能持续产出高质量样本。
所以,大模型能力并不只来自"模型很大"。
更准确地说,它来自数据、算力、算法共同作用;而在很多时候,数据质量和数据组织方式,决定了模型能力的天花板。
总结
本文围绕数据集做了一个入门梳理:
- LLM 的能力来自数据、算力和算法的共同作用
- 训练集用于学习,验证集用于调参和选模型,测试集用于最终评估
- 二次随机切分时要注意比例,
90%里再切10%得到的是总量的9% - 如果想切出
80% / 10% / 10%,可以先切80% / 20%,再把20%平分 - 分类任务要关注标签分布,必要时使用分层抽样
- K 折交叉验证可以降低单次随机划分带来的偶然性
- 大模型时代的数据工程是持续循环的系统,不是一次性处理流程
一句话概括:模型之上,是数据的艺术;模型之下,是数据的地基。