造一个大模型,不管是 GPT-4、Claude 还是 Llama,本质上都要搞定五件事:
- 架构(Architecture):用什么样的神经网络?目前答案几乎统一——Transformer。
- 训练算法和损失函数(Training Algorithm & Loss):怎么训?优化什么目标?
- 数据(Data):喂什么样的数据进去?
- 评估(Evaluation):怎么判断模型好不好?
- 系统工程(Systems):怎么让训练跑得动、跑得快?
1. Tokenizer
你可能知道大模型的输入输出都是 token,但你想过一个问题没有:文本是怎么变成 token 的?
最简单的想法是按词切分——"我 喜欢 吃 苹果",每个词一个 token。但这有个问题:如果遇到一个拼写错误的词,比如"苹菓",你的词表里没有,就没法处理了。
另一个极端是按字符切分——每个字符一个 token。这倒是能处理所有情况,但序列会变得超长。你知道 Transformer 的计算复杂度是跟序列长度的平方成正比的,序列太长计算量会爆炸。
所以实际用的是一种折中方案——BPE(Byte Pair Encoding,字节对编码)。
BPE 的原理很直观:
- 先把所有文本拆成最小单元(字符级别)
- 统计哪些相邻字符组合出现得最频繁
- 把最频繁的组合合并成一个新 token
- 重复步骤 2-3,直到达到目标词表大小
举个例子。假设语料库里有这些词:token、tokenizer、to、today。
- 第一步:全拆成字符 → t, o, k, e, n, i, z, e, r, t, o, t, o, d, a, y
- 第二步:统计发现 "t" 和 "o" 出现在一起最多 → 合并成 "to" 这个新 token
- 第三步:统计发现 "to" 和 "k" 出现在一起比较多 → 合并成 "tok"
就这样一直合并下去。最终,常见的词(比如 "token")会变成一个完整的 token,而罕见的词会被拆成几个子 token。
平均下来,一个 token 大约对应 3-4 个英文字母。中文的话,一个汉字通常对应 1-2 个 token。
2. 数据
2.1 步骤 1:下载"整个互联网"
用网络爬虫爬取网页。比较常用的公开数据集是 Common Crawl,它每个月都会更新,把互联网上的新网页加进来。目前 Common Crawl 包含大约 2500 亿个页面。
2.2 步骤 2:提取正文文本
把 HTML 里的实际文本内容提取出来,去掉标签、广告、导航栏、页脚等。这一步看似简单,但实际很麻烦:
- 数学公式的提取特别难(LaTeX 格式、MathML 格式、图片格式...)
- 很多论坛和网站有固定的头部和尾部模板(boilerplate),每个页面都重复,要去掉
- 有些网站的正文是通过 JavaScript 动态加载的,爬虫可能抓不到
2.3 步骤 3:过滤有害内容
NSFW 内容、仇恨言论、个人隐私信息(PII)... 这些都要过滤掉。通常的做法是维护一个巨大的黑名单(特定网站直接排除),同时训练一个小型分类器来自动检测有害内容。
2.4 步骤 4:去重
这一步非常重要,也非常消耗计算资源。去重的对象包括:
- URL 去重:不同的 URL 可能指向同一个页面
- 内容去重:论坛的头部、尾部模板在所有帖子里都一样
- 段落去重:某些经典段落(比如常见书籍的片段)可能在互联网上被复制了成千上万次
💡 提示:如果不做去重,模型会在这些重复内容上过拟合,导致后面使用时经常背出原文。
2.5 步骤 5:启发式质量过滤
用规则来过滤低质量文档:
- 如果一个网页只有 3 个词 → 大概率没啥用
- 如果一个网页有 1000 万个词 → 可能是某种数据 dump,不是正常文章
- 如果文档中的词长分布异常(平均词长超长或超短) → 可能是乱码或机器生成
这些规则看起来很粗暴,但在 2500 亿页面的规模上,粗暴的规则反而最高效。
2.6 步骤 6:基于模型的质量过滤
这个方法很巧妙:用维基百科做正面样本。逻辑是这样的——维基百科上引用的外部链接,通常指向高质量的网站。所以你可以训练一个分类器,判断一个文档"看起来像不像被维基百科引用的那种质量"。用这个分类器给所有文档打分,保留高分的。
2.7 步骤 7:领域分类和权重调整
把数据分成不同的领域:代码、书籍、新闻、娱乐、学术论文、社交媒体...然后根据经验调整各领域的权重。业界有几个广泛认可的经验:
- 代码要多加:训练更多的代码数据居然能提升模型的推理能力,不只是代码能力。这个发现很反直觉,但已经被多个团队验证
- 书籍要多加:书籍的文本质量通常比网页高,语言更规范、逻辑更连贯
- 娱乐内容要降权:八卦、短视频文案这类内容对模型的通用能力帮助不大
过去这些权重调整主要靠人工经验("拍脑袋"),现在已经有了更系统化的自动搜索方法。
2.8 步骤 8:训练末期用高质量数据精调
在预训练的最后阶段,通常会把学习率降得很低,然后在非常高质量的数据上再过几遍——比如维基百科、精选书籍、人工标注的数据。相当于最后阶段"精修"一下。
3. 预训练(Pre-training)与后训练(Post-training)
预训练出来的模型是个什么东西?它是一个互联网文档生成器。你给它一个问题,它不会回答你,而是继续生成更多问题——因为在互联网上,一个问题后面跟的往往不是答案,而是另一个问题。
这就是为什么需要后训练——把"文档续写器"变成"问答助手"。
3.1 SFT(Supervised Fine-Tuning,监督微调)
后训练的第一步叫 SFT(Supervised Fine-Tuning,监督微调)。
怎么理解?预训练阶段,模型学到了"互联网上所有人的说话方式"——有些人写答案,有些人写问题,有些人写代码,有些人写段子。SFT 做的事情是告诉模型:"你不需要模仿所有人,你只需要模仿那种'有用的助手'的说话方式就行了。"
3.2 RLHF(Reinforcement Learning from Human Feedback)
SFT 的问题在于它是"行为克隆(Behavioral Cloning)"——直接模仿人类标注员写的答案。这有几个局限:
- 问题 1:受限于人类的生成能力。你让一个标注员写一篇关于量子物理的通俗解释,他可能写得一般。但如果你给他两篇不同的解释让他选哪篇更好,他大概率能选对。判断能力 > 生成能力——这是人类的普遍特征。RLHF 就利用了这一点:不让人类写完美答案,而是让人类在两个 AI 生成的答案里选更好的那个。
- 问题 2:SFT 可能加剧幻觉。
- 问题 3:收集人工撰写的完美答案非常贵。
RLHF 的具体流程:
- 生成候选答案:给定一个问题,让当前模型生成两个(或多个)不同的回答
- 人类标注偏好:让标注员看这两个回答,选出更好的那个
- 训练奖励模型(Reward Model):用这些偏好数据训练一个分类器,让它能自动给任意回答打分——分数越高表示越接近人类偏好
- 用强化学习优化模型:以奖励模型的打分作为奖励信号,用 PPO(近端策略优化)算法来调整语言模型的参数
3.3 DPO(Direct Preference Optimization)
DPO(Direct Preference Optimization,直接偏好优化) 是 2023 年 Stanford 提出的方法,核心思想极其简洁:不需要训练奖励模型,不需要强化学习。直接在偏好数据上做监督学习就行。
具体来说:
- 你有一对回答:一个人类更喜欢的(好答案)、一个人类不太喜欢的(差答案)
- DPO 的损失函数就是:增大好答案的生成概率,减小差答案的生成概率
4. 一个大模型的完整出生过程
4.1 第一阶段:准备数据(几个月)
- 用爬虫下载互联网网页
- 提取正文文本
- 过滤有害内容
- 去重
- 质量过滤(规则 + 模型)
- 领域分类和权重调整
- 最终清洗
4.2 第二阶段:预训练(几个月,花费几千万美金)
- 设计 tokenizer,在语料上训练 BPE
- 确定模型架构(基本就是 Transformer,调一些超参数)
- 用 Scaling Laws 确定最优的模型大小和数据量
- 在 GPU 集群上训练,监控 loss 曲线
- 训练末期用高质量数据精修
产出:基座模型(Base Model)——能续写文档,但不会回答问题。
4.3 第三阶段:监督微调 / SFT(几天)
- 收集几千到几万条高质量问答对(人工 + AI 辅助)
- 在基座模型上继续训练
- 模型学会以"助手"的口吻回答问题
产出:SFT 模型——能回答问题,但回答质量参差不齐。
4.4 第四阶段:偏好对齐 / RLHF 或 DPO(几天到几周)
- 收集偏好数据(人类标注 + AI 辅助)
- 用 PPO 或 DPO 进一步优化模型
- 迭代多轮
产出:对齐模型(Aligned Model)——回答质量稳定,懂得拒绝有害请求。
4.5 第五阶段:评估和部署
- 在多个基准测试上评估
- 内部红队测试(找安全漏洞)
- A/B 测试
- 上线,收集用户反馈
- 用反馈数据开始下一轮迭代
整个过程下来,从开始准备数据到模型上线,通常需要半年到一年。这就是为什么模型更新不是连续的——它是一个长周期的工程项目。你用的每一个 API 背后,都是一个团队几个月的高强度工作。
5. 神经网络的训练过程
神经网络通过正向传播产生预测,通过损失函数评估错误,再通过反向传播计算每个参数的贡献,最后用优化算法(如梯度下降)来调整权重和偏移量,如此循环,直到预测足够准确。
5.1 一个贯穿的例子:教会AI识别数字"3"
假设我们有一个非常简单的网络,要识别一张图片是不是数字"3"。训练数据是一张标答为"是"的图片。
5.2 步骤1:初始化参数
在训练开始前,网络就像一个刚出生的婴儿,什么都不知道。
- 操作:给所有的权重和偏移量随机赋予很小的数值。
- 目的:打破对称性,让每个神经元从不同的起点开始学习。
- 例子:网络里的连接权重
w可能是0.01,0.02,0.005等随机值。
5.3 步骤2:正向传播
我们把一张图片(输入)喂给网络,让它产生一个预测结果。
- 操作:数据从输入层进入,经过每一层隐藏层,每层都执行
z = (权重×输入) + 偏移量,然后通过激活函数(如ReLU)进行非线性变换,最终在输出层得到预测值。 - 目的:计算网络"猜"的结果是什么。
- 例子:输入图片"3"后,网络经过一通计算,在输出层给出了一个数字:
0.2。在我们的设定中,输出值越接近1,代表网络越确信它是"3"。输出0.2意味着网络认为这张图有20%的可能是"3" —— 显然是错的,因为正确答案是"是"(100%)。
5.4 步骤3:计算损失
现在我们需要知道网络猜得有多离谱。
- 操作:用一个损失函数来比较"网络的预测值"和"真实标签"。损失函数会输出一个损失值,它代表错误的程度。预测越离谱,损失值越大。
- 目的:量化这次预测的"错误总量",作为后续调整的指南针。
- 例子:使用经典的"均方误差"损失函数。
- 预测值:
0.2 - 真实值(标签):
1.0 - 损失值 = (1.0 - 0.2)² =
0.64
- 预测值:
5.5 步骤4:反向传播与参数更新
这是训练过程中最核心、最精妙的一步。网络要根据这个 0.64 的损失值,去调整前面所有层里成千上万个权重和偏移量,使得下次预测能更准一点。
- 操作:
- 反向传播:从输出层开始,反向计算损失值对每一个参数(权重、偏移量)的梯度。梯度是一个方向和一个大小,它告诉每个参数:"你应该往哪个方向调整(增大还是减小),以及调多少,才能最快地降低损失"。
- 梯度下降:拿着算出来的梯度,用一个叫优化器的东西(最基础的是随机梯度下降SGD)去更新每个参数。更新公式为:
新参数 = 旧参数 - 学习率 × 梯度
- 目的:找到让损失值变小的参数调整方向。
- 两个关键概念:
- 梯度:函数在某一点上升最快的方向。我们取它的反方向(所以是"梯度下降"),就是下降最快的方向。
- 学习率:一个超参数,控制每一步调整的步长。步子太大容易跨过最优解,步子太小训练太慢。
- 例子:反向传播计算后发现,某个权重
w1的梯度是正数+0.5。- 这意味着:
w1增大,损失值就会增大。我们需要降低损失,所以应该减小 w1。 - 假设学习率是
0.1。 - 更新公式:
新w1 = 旧w1 - 0.1 × 0.5 = 旧w1 - 0.05。 - 所有参数都按照这个逻辑进行微小的调整。
- 这意味着:
5.6 训练循环:迭代 Epoch 和 Batch
以上四个步骤,只是一次参数更新的过程。整个训练过程需要重复这个循环成千上万次。
- Epoch(轮次):完整地将所有训练数据都过一次正向传播和反向传播,叫做一个Epoch。通常需要几十、几百甚至上千个Epoch。
- Batch(批次):因为数据量可能巨大,我们不会一次把所有数据都送进去。而是把数据分成一个个小批次(例如一次32张或64张图片)。每送一个Batch,就做一次正向传播、计算损失、反向传播和参数更新。这种方式叫小批量梯度下降,是实践中的标准做法。