大模型预训练

预计学习时间:60分钟

先讲故事

预训练今天听起来像一道工序:海量文本,预测下一个 token,账单交给集群。它能成为默认,不是某一篇论文突然规定的,而是三间屋子叠在一起之后,人们找不到更便宜的替代。

数据屋子:先有赛场,才有「规模」这个词

在语言语料被整成 Common Crawl、Books、代码库之前,视觉房间先演示了什么叫「够大的赛场」。李飞飞判断:缺的不是又一个 SIFT,而是一张能把方法比输比赢的标注图。ImageNet 公开之后,竞赛逼着所有人在同一标尺下说话。没有规模,就没有后来语言侧那条可以画在对数坐标纸上的 Scaling 曲线——Kaplan 等人写出经验律,Hoffmann 等人的 Chinchilla 再问「参数与数据怎样配才不浪费」。人物图谱 · 李飞飞 · 时刻三 · Scaling

语言预训练吃的是文本,不是 ImageNet 的图片。但「先堆可训练的数据,再谈巧妙结构」这个品味,是从那间数据屋子传染过来的。

结构屋子:时间步松开之后,堆深度才划算

RNN 时代,训练要顺着时间一步一步走,并行贵、长程依赖难。2017 年八个作者把自注意力写成骨架:序列里任何两个位置可以直接对话,训练可以铺开。时刻五 预训练从「能做」变成「值得做大规模」——因为算力可以真正吃饱和。

再往后,苏剑林等人的 RoPE、Tri Dao 的 FlashAttention、Shazeer 与 Fedus 的 MoE,都是在这个骨架上把「更长、更快、更稀疏」抠出来的群像突破。群像突破 · 第 2 章

算力屋子:游戏卡怎样变成预训练的默认账户

黄仁勋在 Denny's 里和联合创始人谈的那家公司,本来卖的是画三角形的芯片。CUDA 把卡变成可编程的并行机器;2012 年卧室里的两张 GTX 580 是一次公开课;Volta 的 Tensor Core 之后,矩阵乘变成硬件上的一等公民。没有这间屋子,预训练的「堆参数」只是纸上的愿望,账单会先把愿望掐死。硬件脉络与黄仁勋

系统群像:训得动,才叫预训练

Shoeybi 等人的 Megatron、Rajbhandari 等人的 ZeRO、Micikevicius 等人的混合精度——这些名字很少出现在大众传记里,却决定了「一个实验室能不能把千亿参数跑完」。本章 2.3 训练方法,读的就是这些人留下的约束与解法。

读完故事再进本章

下面拆目标函数、数据管线、结构零件与并行。卡住时问三句:数据从哪来的品味?结构为什么不是 RNN?这张卡为什么付得起?

预训练是大语言模型开发中最核心的阶段,通过在海量无标注数据上训练,模型获得通用语言理解和生成能力。

预训练的重要性

预训练是大语言模型的基础,决定了模型的核心能力:

  • 知识获取:从海量文本中学习事实性知识
  • 语言理解:掌握语法、语义和语用规则
  • 推理能力:建立概念间的关联和逻辑推理能力
  • 迁移学习:为下游任务提供良好的参数初始化

预训练目标与方法

自监督学习目标

大语言模型预训练主要采用自监督学习方法,无需人工标注:

# 自回归语言模型示例(GPT系列)
def autoregressive_objective(text_sequence):
    # 将文本转换为token序列
    tokens = tokenizer.encode(text_sequence)
    
    # 输入为前n-1个token,目标为预测下一个token
    inputs = tokens[:-1]
    targets = tokens[1:]
    
    # 计算预测损失
    outputs = model(inputs)
    loss = cross_entropy_loss(outputs, targets)
    return loss

预训练阶段的计算资源消耗巨大,通常需要数百至数千GPU天,成本可达数百万美元。

主流预训练范式

预训练范式代表模型任务描述特点
自回归语言模型GPT系列根据上文预测下一个词擅长文本生成
掩码语言模型BERT预测被掩盖的词擅长理解任务
前缀语言模型T5, BART序列到序列任务灵活多样
对比学习SimCSE区分相似与不相似文本学习更好的表示

预训练架构与技术

Transformer架构

大模型预训练几乎都基于Transformer架构,其核心组件包括:

  • 多头自注意力:捕捉序列中的长距离依赖
  • 前馈神经网络:处理特征转换
  • 残差连接与层归一化:保障训练稳定性

Transformer架构图

并行化技术

为处理海量数据和参数,预训练过程需要多种并行化策略:

# 使用DeepSpeed ZeRO进行分布式训练示例
import deepspeed

# 定义模型配置
ds_config = {
    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {
            "device": "cpu"
        }
    },
    "fp16": {
        "enabled": True
    }
}

# 初始化分布式训练
model_engine, optimizer, _, _ = deepspeed.initialize(
    model=model,
    model_parameters=model.parameters(),
    config=ds_config
)

# 训练循环
for batch in dataloader:
    outputs = model_engine(batch['input_ids'])
    loss = outputs.loss
    model_engine.backward(loss)
    model_engine.step()

常见并行策略:

  • 数据并行:不同设备处理不同数据批次
  • 模型并行:将模型分割到多个设备上
  • 流水线并行:按层次将模型分到不同设备
  • 张量并行:将单个操作拆分到多个设备

预训练数据处理

数据质量与规模

数据质量和规模是决定预训练效果的关键因素:

  • 规模要求:通常需要数百GB至数TB级别的文本
  • 质量控制:需要严格的过滤和清洗流程
  • 多样性:覆盖多种领域、风格和知识领域

预训练数据流水线

# 预训练数据处理流水线示例
def pretrain_data_pipeline(raw_data_path, output_path, tokenizer):
    # 1. 加载原始数据
    texts = load_raw_texts(raw_data_path)
    
    # 2. 清洗数据
    cleaned_texts = [clean_text(text) for text in texts]
    
    # 3. 去重
    unique_texts = deduplicate(cleaned_texts)
    
    # 4. 分词
    tokenized_data = []
    for text in unique_texts:
        tokens = tokenizer.encode(text)
        tokenized_data.append(tokens)
    
    # 5. 打包为训练所需格式
    training_data = package_for_training(tokenized_data)
    
    # 6. 保存
    save_to_disk(training_data, output_path)

主流预训练模型解析

GPT系列模型

自回归语言模型的代表,使用decoder-only架构:

  • GPT-1:首个大规模Transformer预训练模型
  • GPT-2:扩大模型规模,增强生成能力
  • GPT-3:1750亿参数,展现出强大的少样本学习能力
  • GPT-4:多模态能力,更高的对齐程度

BERT系列模型

掩码语言模型的代表,使用encoder-only架构:

  • BERT:双向编码表示,擅长理解任务
  • RoBERTa:优化BERT训练过程,提升性能
  • DeBERTa:解耦注意力机制,提升表示能力

T5系列模型

seq2seq预训练模型,使用encoder-decoder架构:

  • T5:将所有NLP任务统一为文本到文本格式
  • mT5:多语言版本,支持100多种语言
  • Flan-T5:通过指令微调增强泛化能力

预训练超参数与优化

关键超参数

预训练过程中的主要超参数及其影响:

超参数典型值影响
批量大小256-2048影响优化稳定性和收敛速度
学习率1e-4至6e-4影响训练速度和最终性能
预热步数总步数的10%防止早期不稳定
序列长度512-4096影响捕获长依赖的能力
权重衰减0.01-0.1控制过拟合

混合精度训练

通过FP16或BF16精度提升训练效率:

# PyTorch混合精度训练示例
from torch.cuda.amp import autocast, GradScaler

# 创建梯度缩放器
scaler = GradScaler()

# 训练循环
for batch in dataloader:
    # 使用自动混合精度
    with autocast():
        outputs = model(batch['input_ids'])
        loss = outputs.loss
    
    # 缩放梯度以防止下溢
    scaler.scale(loss).backward()
    
    # 更新参数
    scaler.step(optimizer)
    scaler.update()
    optimizer.zero_grad()

预训练挑战与解决方案

技术挑战

预训练过程中的主要技术挑战:

  • 显存限制:解决方案包括梯度累积、混合精度、模型并行
  • 训练不稳定:解决方案包括梯度裁剪、学习率预热、FP32精度累加
  • 训练时间长:解决方案包括分布式训练、优化器改进、高效硬件

成本挑战

降低预训练成本的主要方法:

  • 高效架构设计:如MoE(Mixture of Experts)、FlashAttention
  • 预训练-继续预训练:基于已有模型继续训练
  • 参数高效微调:降低适应特定领域的成本

近年来,开源社区的努力使得预训练成本大幅降低,已有多个高质量开源预训练模型可供选择和继续训练。

预训练评估指标

评估预训练效果的主要指标:

  • 困惑度(Perplexity):衡量模型预测下一个token的准确性
  • 交叉熵损失:直接反映模型预测质量
  • 下游任务性能:在理解、生成等任务上的表现
  • 知识测试:针对事实性知识的问答准确率
# 计算困惑度示例
import torch
import numpy as np

def calculate_perplexity(model, dataloader):
    model.eval()
    total_loss = 0
    total_tokens = 0
    
    with torch.no_grad():
        for batch in dataloader:
            outputs = model(batch['input_ids'])
            loss = outputs.loss * batch['input_ids'].size(1)
            total_loss += loss.item()
            total_tokens += batch['input_ids'].size(1)
    
    # 困惑度 = exp(平均交叉熵损失)
    perplexity = np.exp(total_loss / total_tokens)
    return perplexity

预训练最佳实践

  1. 数据优先:投入足够资源确保高质量、多样化的预训练数据
  2. 渐进式扩展:从小模型开始,验证后再扩展至更大规模
  3. 持续监控:实时跟踪损失、梯度和资源利用情况
  4. 断点恢复:设置定期检查点,防止计算资源浪费
  5. 硬件选择:针对预算和需求选择合适的硬件平台

预训练未来趋势

  • 多模态预训练:融合文本、图像、音频等多种模态
  • 长序列建模:更高效地处理长文本和长依赖
  • 高效架构:降低计算成本的新型注意力机制和架构
  • 知识融合:结合结构化知识库增强预训练效果

预训练技术仍在快速发展,持续关注学术界和工业界的最新进展有助于把握前沿方向。