预训练、后训练、微调、对齐:大模型四阶段一文讲透,附LoRA实战

📅 发布时间:2026/9/8 13:17:28
预训练、后训练、微调、对齐:大模型四阶段一文讲透,附LoRA实战 在任何一个搜索引擎里输入“对齐”你都会看到完全不同的世界Word 排版里的段落对齐、CSS 里的 text-align、内存里的字节对齐、深度学习里的特征对齐以及最近两年热度飙升的“AI 对齐”。同一个词在不同技术栈里含义天差地别这本来就是技术圈的常态。更麻烦的是在大模型语境里“预训练、后训练、微调、对齐”这四个词还经常被混着用。面试官问一句“预训练和后训练有什么区别”不少人第一反应是这不都是训练吗其实不是。这也是我写这篇文章的原因。我的判断很明确预训练、后训练、微调、对齐不是同义词它们是同一个模型开发流水线上的四个阶段解决的是不同层面的问题。预训练决定模型的知识上限后训练决定模型能否按要求办事微调决定模型适不适合你的业务对齐决定模型愿不愿意、能不能安全地执行你的指令。理解它们之间的边界你才能真正看懂大模型公司每天在做什么也才知道自己手上的开源模型到底应该用哪种方式改造。这篇文章会用尽量通俗的方式把这四个概念讲透并在最后给出一套完整可运行的 LoRA 指令微调示例同时附上常见问题和工程建议。无论你是刚接触大模型开发的工程师还是正在做技术选型、写方案的产品或算法同学都值得把文章看完再收藏。1. 先建立整体坐标系四个概念的关系与边界把大模型想象成一条生产线上培养出来的人四个概念分别对应培养过程的不同阶段预训练相当于把一个人从“什么都不懂”培养成“读过万卷书的通才”。这个阶段模型掌握了语言、知识和推理的底子但还不会好好配合你对话。后训练相当于上岗培训。让这个通才学会听需求、按格式干活、知道什么话该说什么话不该说。微调相当于把他招进你公司后做的在岗培训。让他熟悉你的业务术语、产品风格和特定任务。对齐相当于价值观和管理制度建设。目标不是让他变聪明而是让他做事的方向和人类期望保持一致。这里需要先点破一个容易混淆的地方微调既是一种手段也指一类应用层的操作对齐既是目标也是一类训练方法的集合。在工业界后训练通常包含指令微调SFT和偏好对齐RLHF/DPO而在开源社区很多人嘴里说的“微调”其实就是在基座模型上做 LoRA 指令微调本质上是后训练的一种简化实现。四个概念的对比可以这样看概念解决什么问题核心输入训练成本产出物预训练语言能力与基础知识储备海量无标注文本极高基座模型 Base Model后训练指令理解与人类偏好指令-回答对、偏好数据中高对话/指令模型 Instruct Model微调垂直领域与业务场景适配领域标注数据中低领域定制模型对齐意图遵循与安全边界偏好数据、评估反馈中更安全、更听话的模型明白了这张坐标图后面所有内容都是在往每个格子里填充细节。2. 预训练让模型先“读万卷书”决定知识与语言上限预训练是这一切的起点。它的核心任务只有一个在海量文本上教会模型“预测下一个词”。给定前文模型预测下一个词出现的概率分布然后和真实文本做比较反向传播更新参数。这个目标叫 next token prediction。这里有一个关键点需要理解预训练不需要人工标注数据。网页文本、书籍、论文、代码库里天然就存在“上文-下文”关系模型只需要把每句话的下半截当作“答案”就能源源不断地学习。因此预训练也被称为自监督学习。网上很多人把预训练形容为“把书背下来”这句话只对了一半。模型确实把海量文本中的统计规律压缩进了参数但它不是在逐字背诵而是在训练“看完上一句推想出下一句”的能力。为了把下一个词预测准模型被迫学会语法、事实、常识、逻辑链条甚至代码的执行语义。今天大模型表现出的“知识”本质上就是这种预测能力在足够大规模数据和足够多参数下涌现出来的副产品。“预训练”的“预”字不是为了区分时间先后而是为了强调这个阶段的目标是通用的、与具体应用无关的。它不关心你之后是要做客服机器人、代码助手还是写诗工具它只负责把语言世界的一般规律装进参数里。但预训练也有明显局限只做完预训练的基座模型唯一的技能是“续写”。你给它“今天天气”它会按统计规律接上“很好”你给它“请帮我写一封邮件”它大概率会把它当成作文题继续往下写而不是立刻进入“接收指令并执行”的模式。换句话说预训练结束的模型是一个“才华横溢但不会配合的年轻人”。这也是行业后来必须引入后训练的根本原因。另外要强调一点预训练的成本极其昂贵动辄需要数千甚至上万张 GPU 卡连续训练数月。这也是为什么绝大多数团队永远不会碰预训练。在实际工作中普通工程师接触最多的是后训练里的微调和对齐环节。3. 后训练从“会续写”到“会办事”的关键转身后训练Post-training不是一个单一算法而是预训练之后所有训练阶段的统称。它的核心目的只有一个让模型从“续写机器”变成“指令执行者”。可以说真正让 ChatGPT 看起来“好用”的不是它的底座模型而是底座之后那一整套指令微调和强化学习流程。为什么行业要单独给“后训练”起一个名字因为 2023 年之后大家逐渐形成共识只做预训练的模型根本无法直接商用。模型的续写能力再强如果用户问“今天上海天气怎么样”它回一句“是的上海的天气怎么样呢”这种产品没有任何价值。必须再训练一轮让模型学会“用户问什么就答什么”并且按照人类偏好的方式和语气回答。后训练阶段常见的技术包括指令微调 SFTSupervised Fine-Tuning用人工整理的“指令-回答”对数据让模型学会有问有答的基本模式。强化学习 RLHFReinforcement Learning from Human Feedback用人类偏好信号优化模型生成策略。偏好优化 DPODirect Preference Optimization不训练奖励模型直接用偏好对数据优化策略模型实现更简单。这里顺带回应一个社区里经常被问的问题“预训练和后训练哪个薪资高”。这个问题没有标准答案但它反映出很多人确实分不清这两个阶段。预训练对分布式训练、底层优化、大规模数据工程要求极高门槛确实高后训练对数据质量、评测设计、产品理解要求高能玩明白的人同样稀缺。与其纠结哪个岗位薪资更高不如先把技术链路搞清楚。后训练和预训练的本质区别可以从数据形式和优化目标看出来维度预训练后训练数据来源无标注文本网页、书籍、代码人工整理的指令-回答对、偏好对优化目标预测下一个 token遵循指令、符合人类偏好数据质量要求重数量讲究规模重质量讲究多样性计算成本极高相对低但仍是主要开销一个容易产生的误区是后训练是在教模型新知识。严格来说不全是。后训练阶段更准确的定位是“把预训练阶段已经学到的能力引导到正确方向”。同一个模型预训练阶段几百亿个 token 都没学会的冷门知识后训练靠几十条样本也很难硬灌进去。后训练擅长的是“调教”不是“填鸭”。这也是为什么一旦发现模型缺知识第一步往往不是微调而是考虑 RAG 检索增强。4. 微调把通用模型改造成你的业务专家微调Fine-tuning是一个更偏应用层的概念。它的输入是预训练或后训练好的模型输出是一个更适配特定场景的模型。同样是“继续训练”微调的重点是把通用能力迁移到垂直领域你有一个通用对话模型想让它在你们的客服话术、产品术语、文档格式下工作这就是微调要解决的事情。微调按更新参数的范围和方式大致分成三类4.1 全量微调更新模型全部参数。效果上限最高但也最贵。不仅需要足够多的 GPU 显存来承载模型完整梯度还容易引发一个老问题灾难性遗忘。模型为了学好新任务可能在更新过程中把预训练阶段学到的通用能力破坏掉导致它在你业务上表现很好但一句正常寒暄都接不住。4.2 冻结微调冻结大部分网络层只训练靠近输出端的少量层。优点是显存和算力开销大幅下降缺点是模型内部大部分表示并未被调整效果天花板明显低于全量微调。适合算力有限、任务与原始能力差距不大的场景。4.3 LoRA 微调LoRALow-Rank Adaptation低秩适配是当前开源社区最主流的微调方式。它不直接更新原始权重矩阵而是在原始权重旁边注入两个很小的低秩矩阵训练时只更新这两个小矩阵推理时再把它们的乘积合并回原权重。用大白话解释原始权重矩阵是“资深专家的完整知识体系”你不需要让专家把毕生所学重写一遍只需要给他准备一个很薄的“行动建议手册”这个手册被放在关键决策节点上用来微调他的判断方向。LoRA 的实际效果非常惊人通常只需要训练全量参数 0.1% 到 1% 的参数量就能达到接近全量微调的效果。训练完的 adapter 体积也小可以随存随取多份 LoRA 还能插拔式切换。三种方式对比如下方式更新参数占比显存需求效果上限适合场景全量微调100%高最高数据充足、算力充足、追求最大效果冻结微调5%-20%中中算力有限、任务与原始能力差异小LoRA0.1%-1%低接近全量小团队、快速迭代、多任务切换什么时候该用微调当模型缺少你所在领域的专业术语、输出格式必须严格符合你的要求、或者需要学习特定写作风格时微调是合理的。什么时候不该用微调如果问题本质是“知识不够新”或“不知道你的私有资料”那应该优先上 RAG 检索增强而不是微调如果只是希望模型回答得更客气一点写 Prompt 就够了。微调不是万能药先想清楚缺的是“知识”还是“行为”。5. 对齐让模型听懂指令、遵循意图、守住边界对齐Alignment是这四个词里最容易被误读的一个。前面提到的“内存对齐”“字节对齐”是让数据地址按固定字节数排列属于物理层面的性能手段而 AI 对齐解决的是另一个问题让模型的行为目标和人类期望保持一致。通俗地说微调解决的是“模型能不能听懂你的话”对齐解决的是“模型愿不愿意听你的话并且在执行任务时守规矩”。一个只经过预训练的模型可能知道如何制造危险物品但它不该在对话里详细输出一个只经过普通指令微调的模型可能会为了讨好用户而编造不存在的证据。对齐要做的就是把这类风险压到最低。训练目标通常可以概括成三个 HHelpful有用、Honest诚实、Harmless无害。当然真实工程里这三个目标之间存在张力需要根据产品定位权衡。过程最经典的对齐方案是 RLHF典型流程分三步第一步是 SFT。收集人工编写的“指令-回答”对训练模型学会基本的问答格式。第二步是训练奖励模型 Reward Model。让人对同一指令的多个模型回答进行排序或打分再用这些人类偏好数据训练一个打分模型用来预测“人类更偏好哪个回答”。第三步是 PPO 强化学习。利用奖励模型给出的分数作为反馈信号不断修正策略模型的输出分布让它逐步倾向于生成更符合人类偏好的答案。这套流程思想来自 OpenAI 的 InstructGPT 论文《Training language models to follow instructions with human feedback》也是后来 ChatGPT 对话能力的关键根基。DPO 是对 RLHF 的简化它不单独训练奖励模型也不需要在线采样做 PPO而是直接用偏好数据对策略模型进行监督式优化。实现简单、训练稳定因此大量开源模型的后训练都改用了 DPO。社区里常说的“强化学习偏好数据集”正是 DPO 和 RLHF 阶段需要准备的“左回答、右回答、人类更偏好哪个”这样的标注数据。还有一个工程上必须面对的问题过度对齐。为了追求安全模型可能对所有可能涉及风险的请求一律拒答哪怕用户只是在问一个无害的常识问题。业界称之为“过于谨慎”的 refusal 行为。真正的对齐不是让模型变成一个“沉默的保险箱”而是在有用和安全之间找到平衡点。这需要大量的评测设计、数据筛选和迭代调参。到这里四个概念的关系已经很清晰预训练提供基础能力后训练让能力可用微调让能力适配业务对齐让能力朝着对人类有价值的方向发挥。接下来进入实战看它们如何在一个可运行的项目里落地。6. 完整实战用 LoRA 对 Qwen 模型做指令微调理论讲再多不如亲手跑一次。这一节我们用一个最小可行的例子对 Qwen2.5 系列的小模型做 LoRA 指令微调让它学习“用一句话解释一个 AI 概念”的能力。选择小模型是为了让大多数读者在普通显卡上也能跑通但整套流程对更大的模型同样适用。6.1 环境准备建议使用 Linux 或带 WSL2 的 WindowsPython 版本建议 3.10 以上。训练需要一块支持 CUDA 的 GPU显存 8GB 以上会比较从容如果显存不足可以把模型换成 0.5B 版本并把最大序列长度调小。先创建环境并安装依赖conda create -n lora-train python3.10 -y conda activate lora-train pip install torch transformers peft datasets accelerate版本说明本文不锁定具体版本号避免误导。实际安装时请以 PyPI 上的最新稳定版为准。需要注意transformers 和 peft 的版本兼容性一般较好但如果你同时使用 bitsandbytes 做量化一定要让 bitsandbytes 和 CUDA 版本匹配这是最容易踩的坑。6.2 准备数据集指令微调的数据通常写成 JSONL 格式每一行是一条样本字段包括指令和期望回答。在项目目录下新建train_data.jsonl{instruction: 请用一句话解释什么是大模型预训练。, output: 大模型预训练是在海量无标注文本上通过自监督学习训练模型让模型掌握语言规律和基础知识的过程。} {instruction: LoRA微调有什么优点, output: LoRA微调只训练低秩适配矩阵参数量少、显存占用低、训练速度快且多个LoRA模块可以灵活切换。} {instruction: 什么是RAG, output: RAG检索增强生成是一种让模型在生成回答前先从外部知识库检索相关内容再把检索结果作为上下文参考的技术方案。}注意这个示例数据集只有三条目的是跑通流程。真实项目中指令微调数据集一般需要至少几百到几千条高质量样本且指令要多样化覆盖你要模型掌握的各类问法。6.3 训练脚本创建train_lora.py内容如下# 文件路径train_lora.py 基于 Qwen2.5 的 LoRA 指令微调示例。 运行前请先安装依赖 pip install transformers peft datasets accelerate import torch from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, ) from peft import LoraConfig, get_peft_model from datasets import load_dataset MODEL_NAME Qwen/Qwen2.5-1.5B-Instruct DATA_FILE train_data.jsonl OUTPUT_DIR ./qwen-lora-output def build_prompt(example): 把指令和回答拼成模型需要学习的文本格式。 return { text: ( ### 指令\n f{example[instruction]}\n\n ### 回答\n f{example[output]} ) } def tokenize_fn(batch): tokenized tokenizer( batch[text], truncationTrue, max_length512, paddingmax_length, ) labels tokenized[input_ids].copy() # 把 padding 位置设为 -100避免计算损失 tokenized[labels] [ [-100 if tok tokenizer.pad_token_id else tok for tok in ex] for ex in labels ] return tokenized def main(): global tokenizer tokenizer AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_codeTrue) if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token model AutoModelForCausalLM.from_pretrained( MODEL_NAME, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue, ) model.config.use_cache False lora_config LoraConfig( r8, lora_alpha16, lora_dropout0.1, target_modules[q_proj, k_proj, v_proj, o_proj], task_typeCAUSAL_LM, ) model get_peft_model(model, lora_config) model.print_trainable_parameters() dataset load_dataset(json, data_filesDATA_FILE, splittrain) dataset dataset.map(build_prompt) tokenized_dataset dataset.map( tokenize_fn, batchedTrue, remove_columnsdataset.column_names, ) training_args TrainingArguments( output_dirOUTPUT_DIR, per_device_train_batch_size1, gradient_accumulation_steps8, learning_rate2e-4, num_train_epochs3, logging_steps10, save_steps200, save_total_limit2, bf16True, report_tonone, ) trainer Trainer( modelmodel, argstraining_args, train_datasettokenized_dataset, tokenizertokenizer, ) trainer.train() trainer.save_model(OUTPUT_DIR) if __name__ __main__: main()这段代码有几个关键点需要解释第一target_modules指定了 LoRA 要注入的层。对不同模型这个参数通常需要查阅模型官方文档。Qwen 系列一般可以挂到q_proj、k_proj、v_proj、o_proj也就是自注意力机制里的四个投影层。第二r是低秩矩阵的秩lora_alpha是缩放系数两者共同控制 LoRA 的表达能力。r越大可学习的参数越多但也不是越大越好一般从 8 或 16 起步。第三bf16需要 Ampere 架构及以上的显卡如果你的卡比较老需要改成fp16True。严格来说指令微调通常只对“回答”部分计算损失而不是对整条样本计算。这里为了演示简洁只做了 padding 位置掩码。生产环境更推荐使用trl库的SFTTrainer它在内部会正确处理回答区域的掩码。训练时如果显存不够可以减少max_length或者把模型换成更小的版本比如Qwen/Qwen2.5-0.5B-Instruct。6.4 推理验证训练完成后编写infer_lora.py加载训练好的 LoRA 权重并测试# 文件路径infer_lora.py import torch from transformers import AutoModelForCausalLM, AutoTokenizer from peft import PeftModel BASE_MODEL Qwen/Qwen2.5-1.5B-Instruct LORA_PATH ./qwen-lora-output tokenizer AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( BASE_MODEL, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue, ) # 加载 LoRA adapter并合并进原始模型 model PeftModel.from_pretrained(model, LORA_PATH) model model.merge_and_unload() model.eval() prompt ### 指令\n请用一句话解释什么是LoRA微调。\n\n### 回答\n inputs tokenizer(prompt, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate( **inputs, max_new_tokens128, do_sampleTrue, temperature0.7, ) answer tokenizer.decode(outputs[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue) print(answer)注意推理时输入格式要尽量和训练时保持一致。你训练时用“### 指令”作为引导标记推理时就必须用同样的标记否则模型不知道你在向它提要求。7. 效果验证与常见问题排查训练脚本启动后屏幕上首先会出现一行关键信息trainable params: 2,621,440 || all params: 1,548,371,968 || trainable%: 0.1693这一行告诉你 LoRA 只训练了两百多万参数占整个模型参数的 0.17% 左右。如果这里显示 trainable% 是 100%说明你的 LoRA 配置没有生效模型被当成全量参数训练了。训练过程中日志里会出现类似这样的 loss{loss: 1.83, learning_rate: 0.0002, epoch: 0.05} {loss: 1.21, learning_rate: 0.00017, epoch: 0.5} {loss: 0.87, learning_rate: 0.00011, epoch: 1.0}判断训练是否成功的标准有三个一是 loss 是否整体下降并在后期趋于平稳二是训练结束后加载 LoRA 权重的模型在你准备的测试指令上是否输出符合预期的回答三是微调后模型的基本对话能力是否仍然保留这是最容易忽略的一点。验证时最直观的做法是“前后对比”。用同一个问题分别问原始模型和微调后的模型如果原始模型回答得泛泛而谈而微调模型能按照你的业务口径回答说明微调切实改变了模型行为。需要说明我这里的示例是三句话数据集主要目的是演示流程不要指望它产生质变。下面把实战中最高频的几类问题整理成表格问题现象可能原因排查方式解决方案训练时报 CUDA OutOfMemory序列过长、batch 过大查看报错堆栈中的显存分配位置调小 max_length、batch_size或启用梯度累积loss 不下降或在 2 左右震荡学习率过高或过低、数据格式错误检查日志中 loss 曲线和学习率把学习率调到 1e-4 到 2e-4检查拼接后的文本是否有错别字训练后模型胡言乱语、答非所问灾难性遗忘或训练集噪声太大用通用问题测试原始能力减少训练 epoch增加通用指令样本降低学习率模型只会复读训练集中的固定答案过拟合观察训练集 loss 是否接近 0增加数据多样性使用 dropout提前早停加载 LoRA 后效果与训练时不一致adapter 路径错误或 base model 版本不一致检查 OUTPUT_DIR 下是否有 adapter_config.json保存和加载时必须使用同一个 base model 名称中文回答出现乱码或重复前缀温度设置过高或生成参数不当检查模型输出的原始 token id降低 temperature适当调大 repetition_penalty显存够却训练得很慢未使用混合精度查看显卡利用率开启 bf16 或 fp16开启 gradient checkpointing遇到任何问题第一步永远是看日志。训练脚本和推理脚本的日志会直接告诉你错误发生的位置绝大多数问题都能从 stack trace 里定位到是显存、依赖版本还是数据格式导致的。8. 工程最佳实践何时微调、何时别折腾很多团队第一次接触大模型时第一反应就是“我要微调一个自己的模型”。但真实工程里微调应该是最后一步而不是第一步。这里给出几条我实际项目里验证过的建议。第一数据质量远重要于数据量。50 条精挑细选、覆盖各种问法的高质量指令样本可能比 5000 条从网上批量抓来的脏数据更有用。指令微调的目的是让模型学会“行为模式”不是让它背答案。准备数据前先把你期望模型掌握的典型问题列成清单再按这个清单去造数据。第二先小规模跑通再扩大规模。永远不要一上来就在几百 GB 的数据上开训。用几十条样本、小模型、少 epoch 把整个链路跑通确认数据格式、训练脚本、推理验证都没问题再上全量数据。这条经验能帮你省下大量无效算力。第三划出评估集量化对比。微调前就留出一部分你不会参与训练的样本作为评估集。微调前后用同样的评估问题和同样的评分标准做对比而不是靠“感觉回答变好了”。如果连评估标准都没有你根本无法判断调整学习率是让模型变好了还是变差了。第四优先保存 LoRA adapter而不是全量权重。adapter 体积小、便于版本管理还能在同一个 base model 上同时挂多份不同业务的 adapter按需加载切换。发布到生产环境时再合并回原始权重做一次推理速度优化。第五如果知识是瓶颈优先上 RAG。模型不知道你的私有业务资料微调并不是唯一解甚至不是最优解。RAG 通过检索外部知识库把相关内容拼进上下文不改变任何权重修改知识只需要更新数据库不需要重训模型。一般经验是知识差很远、格式要求特殊才考虑微调内容更新频繁、需要引用出处优先 RAG。第六安全与合规意识要前置。不要使用未授权的私有数据进行微调尤其是涉及个人隐私的业务数据训练前要做好脱敏和授权确认。训练出的对话能力如果面向真实用户上线前还需要做内容安全测试设置合理的拒答策略。微调不会让模型凭空变得安全它只会把数据里的偏好模式放大。9. 总结与后续学习路线用一个准确但好记的句子总结四个概念预训练让模型“有知识”后训练让模型“会办事”微调让模型“懂你”对齐让模型“守规矩”。如果你现在刚入门我给的建议是先不要纠结晦涩的论文先把你手上的开源模型用 LoRA 完整跑一遍指令微调哪怕数据集只有几十条样本。当你能熟练完成“准备数据 → 训练 → 推理 → 对比效果”这个闭环后再回头理解 RLHF、DPO、奖励模型这些概念会发现它们不再是抽象名词而是在解决你会真实遇到的“模型不听话”“回答风格不对”“安全边界含糊”等问题。接下来值得深入的工具和方向包括工具链Hugging Face 的 PEFT 和 TRL 库、开源微调工具 LLaMA-Factory、部署工具 vLLM。论文读 LoRA 原始论文了解低秩适配原理读 InstructGPT 论文理解 RLHF 三步流程读 DPO 论文理解偏好优化的简化路线。工程延伸学习模型评估体系、指令数据集的构建与清洗、强化学习阶段的奖励模型训练、以及从单机训练到多机分布式训练的扩展方法。大模型技术迭代很快模型名字会过时但“预训练 → 后训练 → 微调 → 对齐”这条技术主线不会轻易变化。把这条主线吃透无论未来出来什么新模型你都能快速判断它解决了哪个阶段的问题也知道自己应该在哪一步动手。这套思维比追任何一个具体模型都更值钱。