随着大语言模型(Large Language Model, LLM)技术的迅速发展,理解其背后的训练流程已成为开发者和研究者的基本素养。无论是开源模型如 Qwen、Llama 系列,还是闭源系统如 ChatGPT、Claude,其能力演进都遵循一条清晰的技术路径:先通过海量数据学习语言规律,再经过多阶段精细化调整,最终成为安全、有用、可交互的智能助手。
本文系统梳理大语言模型训练的核心阶段——预训练(Pretraining)、监督微调(SFT)、奖励模型训练(RM)、强化学习微调(RL),辅以典型代码示例,帮助读者建立完整的认知框架。
后训练(post-training)并非一个严格定义的技术阶段,而是在业界和研究社区中对预训练之后所有优化步骤的统称。它涵盖了从监督微调(SFT)到偏好对齐(如 RLHF、DPO 等)的一系列方法,目标是将一个通用但“未驯化”的基础模型,转化为安全、有用、符合人类意图的 AI 助手。尽管“后训练”一词在论文或工程文档中频繁出现,但它更多是一种流程性描述,而非某个特定算法或标准阶段。
1. 预训练(Pretraining):让模型具备通用语言能力
预训练是大模型能力的起点。在此阶段,模型在 TB 级别的无标注文本(如网页、书籍、代码)上进行自监督学习,典型任务包括“预测下一个词”(causal language modeling)或“恢复被掩码的词”(masked language modeling)。
目标不是完成具体任务,而是让模型内化语言的统计规律、世界知识和基本推理能力。
该过程计算成本极高,通常需要数千 GPU 天,产出的是一个“基础模型”(如meta-llama/Llama-3-8B或Qwen/Qwen2.5-0.5B)。基础模型能够生成流畅文本,缺乏可靠、一致的指令遵循能力,也不具备对话格式意识。它像一位知识渊博但未经引导的学生——知道很多,却不知如何回应具体请求。
由于预训练涉及分布式训练、混合精度、高效数据加载等复杂工程,普通开发者通常直接使用公开的基础模型。以下是一个简化版的概念演示:
importtorchimporttorch.nnasnnfromtorch.utils.dataimportDataLoader,DatasetfromtransformersimportAutoTokenizer# ----------------------------# 1. 定义小型 Transformer 模型# ----------------------------classSimpleGPT(nn.Module):def__init__(self,vocab_size,d_model=256,nhead=4,num_layers=2,max_seq_len=128):super().__init__()self.embedding=nn.Embedding(vocab_size,d_model)self.pos_encoding=nn.Parameter(torch.zeros(1,max_seq_len,d_model))encoder_layer=nn.TransformerEncoderLayer(d_model=d_model,nhead=nhead,dim_feedforward=1024,batch_first=True)self.transformer=nn.TransformerEncoder(encoder_layer,num_layers=num_layers)self.lm_head=nn.Linear(d_model,vocab_size)defforward(self,input_ids):seq_len=input_ids.size(1)x=self.embedding(input_ids)+self.pos_encoding[:,:seq_len,:]x=self.transformer(x)logits=self.lm_head(x)returnlogits# ----------------------------# 2. 合成语料(避免 tokenizer 长度限制)# ----------------------------classSyntheticDataset(Dataset):def__init__(self,vocab_size,seq_len=64,num_samples=500):self.seq_len=seq_len# 创建一个简单的循环模式:[10, 11, 12, 13, 10, 11, 12, 13, ...]pattern=torch.tensor([10,11,12,13])total_tokens=seq_len*num_samples repeated=pattern.repeat((total_tokens//len(pattern))+1)[:total_tokens]self.data=repeated.reshape(num_samples,seq_len)def__len__(self):returnlen(self.data)def__getitem__(self,idx):returnself.data[idx]# ----------------------------# 3. 训练流程# ----------------------------defmain_pretrain():tokenizer=AutoTokenizer.from_pretrained("gpt2")tokenizer.pad_token=tokenizer.eos_token vocab_size=len(tokenizer)model=SimpleGPT(vocab_size=vocab_size,max_seq_len=128)dataset=SyntheticDataset(vocab_size=vocab_size,seq_len=64,num_samples=500)dataloader=DataLoader(dataset,batch_size=8,shuffle=True)optimizer=torch.optim.AdamW(model.parameters(),lr=5e-4)loss_fn=nn.CrossEntropyLoss()mo