☰
从零训练大模型完整流程:数据、预训练、SFT、DPO对齐与评估部署
2026/10/2 4:05:18 网站建设 项目流程

1. 为什么你要读这篇:一个完整的模型训练闭环是怎样的

前阵子有个朋友问我:网上全是"三步微调大模型"的教程,但真正从零开始预训练一个模型,到底要走完哪些流程?这个问题问得很实在。今天市面上的开源模型已经多到用不完,绝大多数人确实只需要微调,但"从零训练"这四个字背后藏着整个大模型技术的核心逻辑——数据怎么配比、loss怎么收敛、对齐怎么做、模型到底怎么才算"好",所有这些问题的答案,不在微调教程里,而在完整的训练全流程里。

这篇文章我不会讲那些百亿参数集群才能跑的东西,而是围绕一套"能落地、能复现、显存要求相对友好"的完整流程展开:数据准备、预训练、SFT监督微调、DPO/RLHF对齐、评估与部署。全程用实践视角写,每一步都告诉你为什么这么做、不这么做会踩什么坑。适合的人群是:有大模型使用经验、想理解训练原理的工程师;准备在垂直领域自己训模型的算法同学;以及那些"手上有几块卡,想折腾点真东西"的技术爱好者。

先说结论:从零训一个模型,不管规模大小,核心就是五件事——数据、预训练、指令微调、偏好对齐、评估。这五件事不是流水线式的一次性通过,而是一个反复循环、不断往回改的闭环。理解了这一点,你去看那些大厂的技术报告(比如Llama、Qwen的技术报告),会突然觉得豁然开朗。

2. 动手前的准备:硬件、框架和成本预期

2.1 硬件到底需要什么,ChatGPT这样开头,我们可以用几块消费级GPU跑起来

网上很多教程动辄就是"A100 80G集群",看着就劝退。但实话实说,如果你只是训练一个**十亿参数级别(1B~7B)**的模型,单卡24G显存(比如4090、3090、A5000)是能启动的。72B那种大模型不在本文讨论范围,属于需要有真实算力预算的团队才碰的东西。

我建议的最低配置和对应场景如下:

显存/卡型能做什么不能做什么
单卡 24G(4090/3090)预训练/继续预训练 1B~3B,SFT 7B(LoRA),DPO 7B(LoRA)全参微调 13B+
单卡 48G(A6000/L40S)全参微调 7B,预训练 3B~7B(需要合理batch)大规模预训练
双卡/四卡 24G数据并行预训练 7B,序列长度可以拉长超大模型、超长序列
多卡 A100/H800任意除了钱,几乎没有限制

这里有一个非常重要的认知:显存决定你能否跑起来,但真正决定预训练效果的是总计算量和数据质量。所以,即便你只有一张4090,训练一个1B模型,只要数据好、超参数合理,一样能做出一个"能对话、能推理、有基本常识"的可用模型。这一点后面预训练章节会详细展开。

2.2 选框架:HuggingFace Trainer、DeepSpeed还是Megatron

常见的选择有三个:

  • HuggingFace Trainer:适合单卡或小规模并行,代码量最小,调试方便,适合快速验证想法。缺点是调度开销大,特别大的模型和长序列下效率一般。
  • DeepSpeed:ZeRO系列优化器非常成熟,是目前开源社区的主流方案。搭配Trainer使用,能实现数据并行+张量并行(ZeRO-3),序列长度、batch size都可以撑得很高。
  • Megatron-LM:NVIDIA出品,适合超大模型、超大规模集群,工程复杂度非常高,普通场景用不上。

我的建议很简单:1B~13B范围,单卡或双卡用Trainer就够了,四卡以上再上DeepSpeed ZeRO-2/ZeRO-3。不要一上来就整Megatron,光配置分布式环境就能劝退一半人。

2.3 成本估算:练一个7B模型到底要花多少钱

这是所有人在动手前最关心的问题。我们做一个粗略估算:

  • 一个7B参数的模型,每个token的前向+反向计算量大约是 7B × 2(前向+反向)× 3(梯度更新) ≈ 42 GFLOPs/token(这是简化值,实际还要乘上一些常数)。
  • 训练数据量按100B token来算(一个中规中矩的7B模型一般需要200B以上,这里保守点),总计算量就是 42 × 100B = 4.2B GFLOPs = 4.2 × 10^18 FLOPs。
  • 一张A100 80G的FP16算力大约是 312 TFLOPS(实际有效利用率按40%算,就是125 TFLOPS左右)。

单卡训练时间 = 4.2 × 10^18 /(125 × 10^12) = 3.36 × 10^6 秒 ≈ 39天。

也就是说,单张A100练100B token的7B模型,需要约40天。换成4卡A100就是10天。换成4090呢?4090 FP16算力约82.6 TFLOPS,有效算力打四折就是33 TFLOPS,单卡要跑147天,四卡也要37天。

这个估算告诉你两件事:第一,全参预训练确实贵;第二,想省钱,就要缩小模型或缩小数据。这就是为什么我们下面会推荐"小规模数据+高质量清洗+继续预训练"的思路,而不是一上来就冲大语料。

3. 数据工程:预训练的数据质量和规模,决定模型的地基

3.1 数据从哪来:开源数据集和自采数据的分工

预训练模型的知识和语言能力几乎全部来自数据。大厂的预训练语料动辄几TB,但普通人不可能也没必要走这条路。如果你的目标是垂直领域(法律、医疗、代码、金融等),或者想要一个通用对话模型,主流的做法是用开源通用数据打底,叠加自己的领域数据做增补。

常见的开源数据源:

  • RedPajama:一个开源复刻Llama训练数据的项目,包含CommonCrawl、Wikipedia、Books、Arxiv、StackExchange等子集,质量整体不错,但需要自己清洗和去重。
  • The Pile:一个800GB左右的学术向混合数据集,代码、论文、书籍都有,做基础预训练很好用。
  • 中文语料:可以找开源的清洗后中文数据,比如WuDaoCorpora(悟道)、CLUECorpus,或者自己从CommonCrawl抓取中文子集后清洗。
  • 代码数据:GitHub代码数据可以去下载公开镜像,或者用BigQuery上的公共GitHub数据(需要自己的tokenizer处理)。

这里要特别提醒一下:开源数据不等于干净数据。CommonCrawl里大量重复页面、垃圾内容、乱码、广告文本,如果不过滤,模型会学到非常离谱的语言怪癖。我在实际处理中,清洗流程一般是:

  1. 语言识别过滤(只保留目标语言)。
  2. URL黑名单过滤(剔除成人、营销、低质UGC站点)。
  3. 页面去重(SimHash/MinHash,重复率高于0.8的直接丢弃)。
  4. 文档质量打分(用质量分类器或者规则:长度、标点比例、乱码比例等)。
  5. 去除模板化文本(如"阅读全文""发布时间"等)。

这套清洗流程本身就是一个不小的工程,好在很多步骤可以用现成工具(比如fasttext做语言识别,datasketch做MinHash去重),核心思路是宁可丢,不可脏。

3.2 数据配比:不是数据多就好,比例要对

预训练数据配比是很多人容易忽略但极其影响效果的点。不同来源的数据,对模型的能力贡献完全不同:

数据类型作用常见配比
网页文本/通用文本语言能力、常识60%~70%
书籍/长文档长文本建模、逻辑能力10%~15%
代码逻辑推理、结构化表达10%~20%
数学/科学推理能力3%~5%
对话/指令数据对话能力(通常放少量,SFT阶段才放大)0~2%

配比的核心逻辑是:通用文本提供语言基础,代码和书籍提供推理和深度,垂直数据决定模型的"专业浓度"。比例失调会导致模型偏科。

这里有个真实教训:我见过一个团队,预训练数据里加了30%的对话数据,结果模型虽然"很会聊天",但常识问答和推理明显退化。原因很简单:对话数据大多是短文本,信息量低,模型在短文本上打转,长程依赖和深度语义学得不够。所以预训练阶段的对话数据一定是少量点缀,真正的主力是长短混合的说明书、文章、代码这类信息密度高的文本。

3.3 Tokenizer训练:一个被低估的环节

Tokenizer是模型理解语言的"切词器",它的好坏直接影响模型的参数量、训练速度和最终效果。BPE(Byte Pair Encoding)是目前的主流方案,Llama、Qwen用的都是BPE或其变体。

自定义tokenizer训练时要注意:

  • 词表大小:一般建议 32K~128K。太小则每个词要用多个token表示,模型seq len浪费,推理速度也受影响;太大则embedding层参数暴增(词表128K时,embedding就占5120×128K=6.5亿参数,对7B模型来说占比很夸张)。中文场景建议 64K 起步,英文场景32K通常够用。
  • 词表必须有足够的中文字覆盖:如果直接用Llama的词表来支持中文,中文字符会被拆成多个字节token,导致训练效率低,效果也不行。这也是为什么Llama原版对中文不友好的根因。
  • 训练数据要多样:Tokenizer训练语料应该覆盖你所有的数据来源,否则预训练时会出现大量未登录字符被切碎的情况。

Tokenizer训练推荐用tokenizers库的BpeTrainer,代码很简单,这里给一个示例:

from tokenizers import Tokenizer, models, trainers, pre_tokenizers tokenizer = Tokenizer(models.BPE()) tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) trainer = trainers.BpeTrainer( vocab_size=64000, min_frequency=2, special_tokens=["<unk>", "<s>", "</s>", "<pad>"] ) files = ["data/part1.txt", "data/part2.txt"] # 训练语料路径 tokenizer.train(files, trainer) tokenizer.save("tokenizer.json")

训练完后,务必检查 tokenizer 对中文、代码缩进、特殊符号的切分情况。一个检查技巧:把一段中文和一段代码分别encode,看看切出来的token数量是否合理。如果"我们"被切成3个token,说明词表训练语料的中文占比太低,需要补充。

3.4 预训练数据制备的完整流程参考

我自己读公司的预训练数据pipeline时,会按这个顺序操作(你可以直接照搬):

  1. 收集原始数据,统一格式(jsonl,每行一个文档)。
  2. 跑语言识别和质量过滤脚本,剔除低质数据。
  3. MinHash去重,保留一个重复簇的中心。
  4. 做文档级长度过滤(过短的文档直接丢弃,过长的做截断)。
  5. 混合配比,抽样打乱,生成训练集。
  6. 训练tokenizer,将文本tokenize成id并保存为二进制文件(如mmap格式),方便训练时随机采样。
  7. 留出1%~2%数据作为验证集,用于观察loss收敛。

这个过程看起来繁琐,但预训练的成败60%取决于数据,值得花时间。我认识的很多开源模型作者,最后悔的都是当初没有在数据清洗上多花时间,而在模型结构上反复折腾。

4. 预训练实操:从随机权重到"懂语言"的核心步骤

4.1 模型的初始化和基础结构选择

对大多数从零训练的人来说,不建议自己设计新的模型结构。主流的做法是:

  • 用Llama架构(现在有大量开源实现),或者直接用transformers库的LlamaForCausalLM。
  • 也可以从已有的开源配置开始改参数(例如从一个3B配置调成1.5B),以节省时间。

定义一个小模型(1.3B)的配置大概是这样:

from transformers import LlamaConfig, LlamaForCausalLM config = LlamaConfig( vocab_size=64000, hidden_size=2048, # 隐藏层维度 intermediate_size=5504, # FFN中间维度 num_hidden_layers=24, # 层数 num_attention_heads=16, num_key_value_heads=8, # GQA,推理时节省显存 max_position_embeddings=8192, rope_theta=1000000.0, rms_norm_eps=1e-6, ) model = LlamaForCausalLM(config) print(f"参数量: {model.num_parameters() / 1e9:.2f}B")

这里说明一个容易被忽略的细节:GQA(分组查询注意力)很重要。它把KV cache降低到原来的1/群组数,能显著减少推理时的显存占用和带宽压力。如果完全没有KV cache的限制,MHA(多头注意力)也行,但小模型部署更推荐GQA。

4.2 预训练的超参数:这组参数可以无脑起步

预训练和一个好的微调在超参数上有本质区别。微调通常用很小学习率(1e-5级别),预训练需要相对大的学习率,同时配合warmup和余弦退火。

一句话推荐配置(以1B模型、24G单卡为例):

参数值说明
batch size32(动态累积)梯度更新时的有效batch
序列长度2048/4096短序列起步,稳定后再加长
学习率3e-41B模型常用范围
warmup steps1000~2000防止初期发散
学习率调度cosine decay退火到峰值的1/10
优化器AdamWbeta1=0.9, beta2=0.95
weight decay0.1常见设置
grad clip1.0防止梯度爆炸

用 Trainer + DeepSpeed 的配置示例:

training_args = TrainingArguments( output_dir="./checkpoints", per_device_train_batch_size=2, gradient_accumulation_steps=16, learning_rate=3e-4, warmup_steps=1000, lr_scheduler_type="cosine", logging_steps=10, save_steps=1000, num_train_epochs=1, fp16=True, deepspeed="ds_config.json", ) trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, )

这里有个大坑要特别提醒:batch size 和梯度累积这两个参数,很多人会配错。Trainer里的batch_size=2和gradient_accumulation_steps=16,等价于"每次真实权重更新看到了2×16=32条样本",但这两者不是完全等价的——梯度累积会让权重更新的粒度和BN等操作出错,好在Transformer里没有BN,这个影响可以忽略。真正的坑是:梯度累积过多,会导致模型"看起来在学,实际上每一步的梯度信号都是很久以前的",所以累积步数建议控制在32以内。

4.3 判断预训练是否正常:loss曲线和下游任务的早期信号

很多新手盯着loss曲线,看到loss下降就开心,看到波动就慌。实际上,预训练的loss曲线有几类典型形态,需要区分对待:

  • 健康形态:loss平稳下降,验证loss和训练loss差距不大(差距大说明过拟合,但在预训练阶段不太常见)。
  • loss spike:某个step loss突然冲到天际,通常是数据里有脏样本(比如某个文档全是特殊字符),或者学习率过大。处理方式:先减小学习率,再检查该step附近的batch数据。
  • loss停滞:训练了十几个step,loss几乎不动。大概率是学习率太低、warmup太长,或者数据本身有问题(比如全部是相同文本)。
  • loss上升不回落:典型的学习率过大导致的崩溃,需要降低学习率并恢复到早期checkpoint。

除了loss,建议同时看一个额外指标:token-wise accuracy(即模型预测下一个token的准确率)。这个指标比loss更直观,例如准确率从0%爬到30%,说明模型在真实学习;如果准确率一直在个位数徘徊,即使loss在下降,也需要警惕数据质量。

另外,预训练早期(百万token内)可以做一个小实验:给模型一段文本,看它生成的句子是否语法通顺。判断标准很简单——如果一眼看不出来是乱码,说明语言能力已经起来了。这个"人眼早期评估"效率很高,建议每个checkpoint都做一次。

4.4 继续预训练 vs 从头预训练:小规模领域模型的最优解

聊完从头训练,我想特别推荐一条"低成本曲线救国"的路线:继续预训练(Continue Pretraining)。

思路很简单:不从头初始化随机权重,而是从一个高质量的开源基座模型出发(比如Qwen2.5-1.5B、Llama-3.2-1B),用你的领域语料继续做因果语言建模训练。这样你的模型在通用语言能力上不用从头学,只需要消化领域知识即可。

继续预训练和从头预训练的区别:

对比项从头预训练继续预训练
数据量需求需要百B级通常1B~10B token即可见效
算力成本极高约为前者的1/10~1/100
通用能力来源完全靠数据积累继承基座模型
适合场景研究、构建全新模型垂直领域、企业私有化模型

我在实际项目中,大部分"从零训练"的项目其实都是继续预训练路线,性价比高得多。具体做法和从头预训练几乎一样,只是学习率要调低一些(1e-4~2e-4),warmup steps数也需要增加(因为新领域分布和原有分布差异大,需要更长的适应期)。

5. SFT监督微调:把"会续写"变成"会听话"

5.1 为什么需要SFT:预训练模型只会续写,不会对话

预训练结束的模型,本质上是一个"高级版输入法"——你给它一段文本,它只会按照统计规律继续写,但不会"回答问题"或"遵循指令"。SFT就是通过人工标注/蒸馏的高质量指令数据,教模型学会"用户说什么,我做什么"这个映射。

这样说可能更直观:预训练模型的概率分布是"给定上文,预测下文",SFT模型的条件分布是"给定指令,生成正确回答"。两者的训练目标看似一样(都是next token prediction),但数据形态决定了行为差异。SFT数据的每条样本都是(指令,回答)对,模型在大量这样的数据上学到的就不再是"续写"而是"服从与回应"。

5.2 SFT数据:质量、数量和多样性

SFT数据是决定模型"聪明不聪明"的关键,也是目前社区公认最稀缺的资源。对于数据量:

  • 通用对话能力:5万~20万条高质量指令可以做出不错的对话模型。
  • 垂直领域能力:1万~5万条领域指令就能看到明显效果。
  • 不需要海量数据:SFT数据量一旦超过百万,往往边际效应递减,甚至引入噪声。

数据多样性比数量更重要。一个典型的SFT数据集应覆盖:

  • 通用问答(常识、百科、生活)
  • 写作与创作(写文章、写邮件、改写)
  • 推理与逻辑(数学题、逻辑推断)
  • 代码与工具使用
  • 角色扮演与多轮对话
  • 拒绝回答(对于有害问题的适当拒绝)

构造指令数据时有一个关键技巧:避免"一句话指令"。真实用户的问题往往是长句、多轮、有语病的,如果在训练数据里全是"讲个笑话""解释量子力学",模型应用时遇到真实用户的长尾query就会崩。所以我会故意在数据集里混入带噪声的、口语化的、有干扰词的指令,让模型学会处理真实场景。

5.3 SFT训练:全参微调 vs LoRA

全参微调(Full Fine-tuning)会更新模型所有参数,效果上限最高,但显存和成本都高。LoRA(Low-Rank Adaptation)只在原模型旁路训练一小组低秩矩阵,显存占用小、训练快,效果在大多数场景下已经非常接近全参微调。

对比项全参微调LoRA
显存需求(7B)需~56G+需~24G即可
训练速度慢快
效果上限理论更高接近,rank够大时几乎无差
爆炸风险数据差时灾难性遗忘风险更大可控
适合场景高质量大规模数据、终极版本快速迭代、单卡资源、领域微调

我的做法是:前几轮探索用LoRA,确定数据质量满意后,再全参微调一版作为主力。LoRA的rank一般选16~64,过大没有意义,过小则容量不够。

LoRA微调代码(使用PEFT库)大概是这样:

from peft import LoraConfig, get_peft_model, TaskType lora_config = LoraConfig( task_type=TaskType.CAUSAL_LM, r=32, lora_alpha=64, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, ) model = get_peft_model(model, lora_config)

target_modules建议覆盖所有attention和FFN的投影层,效果比只挂attention层好。lora_alpha一般是r的2倍,太小更新幅度小,太大容易训练不稳定。

5.4 SFT的过拟合:如何判断"背下来了"而不是"学会了"

SFT阶段最大的陷阱是过拟合:模型在训练数据上表现完美,但一到真实场景就抓瞎。

判断标准很简单:

  • 训练loss持续下降,但验证集loss回升——过拟合信号。
  • 对训练集里的某些指令能逐字背诵式输出,但对同义改写的指令就懵——过拟合信号。
  • 模型输出变短、趋同、模板化——过拟合信号。

控制过拟合的方法:

  1. 数据增强:对指令做同义改写、随机插入无义词、改变标点等。
  2. 提高数据多样性:同一种能力,用100种不同的问法。
  3. 早停:监控验证集loss,一旦回升立即停止。
  4. 降低LoRA rank:如果用的是LoRA,rank过大更容易过拟合。
  5. 增大dropout:LoRA的dropout提到0.1会显著提升泛化能力。

我自己的经验是:SFT阶段模型的能力上限更多由数据决定,而不是由训练步数决定。训10遍同一批高质量数据,不如训1遍一万条多样化的数据。那些"多训几个epoch效果更好"的说法,在SFT这种小数据场景下通常是过拟合的温床,我基本只用1~2个epoch。

6. DPO与RLHF:偏好对齐,让模型说出"人更爱听"的话

6.1 SFT解决"能不能",RLHF/DPO解决"好不好"

SFT之后,模型已经会"说话"了,但回答的质量参差不齐:有的啰嗦、有的傲慢、有的编造事实、有的违反安全规则。偏好对齐阶段就是要让模型学会"哪些回答更好、哪些回答要拒绝"。

传统RLHF的流程是:

  1. 训练一个奖励模型(Reward Model),给单条回答打分。
  2. 用强化学习(PPO)优化策略模型,最大化奖励模型分数。

但PPO的工程复杂度很高——需要同时加载4个模型(Actor、Critic、Reward、Reference),训练稳定性差,超参数极其敏感。这也是为什么很多开源项目都在往DPO迁移。

6.2 DPO核心原理:把对齐变成一个简单的分类问题

DPO(Direct Preference Optimization)是2023年提出的方法,核心洞察非常漂亮:我们不需要显式地训练一个奖励模型,也不需要跑PPO循环,直接用一个偏好数据集(chosen vs rejected),用类似排序损失的方式更新策略模型即可。

DPO的损失函数本质上是最大化"好回答相对坏回答的似然差":

L = - log σ(β * (log(p_θ(y_chosen|x) / p_ref(y_chosen|x)) - log(p_θ(y_rejected|x) / p_ref(y_rejected|x))))

直观理解:它试图让模型增大好回答的概率、减小坏回答的概率,同时用reference model(SFT模型)拉住不让模型"飘得太远"。

DPO的实现非常简单,TRL库直接支持:

from trl import DPOTrainer, DPOConfig training_args = DPOConfig( output_dir="./dpo_checkpoints", beta=0.1, # 温度系数:越大越强调偏好,越小越贴近参考模型 per_device_train_batch_size=2, learning_rate=1e-6, max_length=2048, max_prompt_length=1024, ) dpo_trainer = DPOTrainer( model=model, # SFT后的模型 ref_model=ref_model, # SFT后的原始权重(冻结) args=training_args, train_dataset=preference_dataset, )

6.3 DPO数据构造:从哪收集偏好数据

DPO的效果几乎完全取决于偏好数据质量。常见的数据来源:

  • 人工标注:让标注员对比两个模型回答,选更好的。质量最高,成本也最高。
  • 模型蒸馏:用GPT-4/Claude等顶级API生成回答作为chosen,自己的模型回答作为rejected。成本低,但会"向闭源模型看齐"。
  • 规则/社区反馈:从社区问答中提取高质量回答和低质量回答(比如采纳答案 vs 未采纳答案)。

构造偏好数据时的注意点:

  • chosen和rejected差异要明确:如果两个回答水平相当,模型很难学到有效的偏好信号。宁可去掉这些样本。
  • 覆盖维度要多元:偏好不只是"答案正不正确",还包括:有没有礼貌、有没有过度推理、有没有编造细节、有没有偏离问题。
  • 比例控制在1%~10%:DPO数据量不需要大,通常几千到几万条就能起效。过多反而可能导致模型在某个偏好维度上过于激进。

6.4 什么时候该用PPO而不是DPO

DPO确实省事,但有它的天花板。PPO在某些场景仍然不可替代:

场景DPOPPO
数据预算小/标注困难合适需要大量RM反馈
创新性任务(需要探索)较弱强
多目标优化(安全vs有用)需人工造数据可以通过RM权重调节
工程复杂度低高
训练稳定性较稳定高度依赖超参

我的建议:99%的垂直领域对齐用DPO就够了。只有当你需要精细控制"模型在边界情况上怎么做"(比如内容安全策略、复杂产品规则),才值得上PPO。PPO的RLHF从搭建到稳定,没有两周时间下不来,且对工程师的RL功底有要求。

7. 评估体系:模型好不好,不能只靠"感觉"

7.1 评估的三个层次:自动指标、基准测试、人类评估

模型训练完,所有人都会问一句:效果怎么样?但"怎么样"必须拆成可验证的问题。我的评估框架分三层:

第一层:自动指标

  • Perplexity(困惑度):衡量语言模型对文本的建模能力,越低越好。但PPL和实际对话质量不是完全正相关,只能做粗粒度监控。
  • ROUGE/BLEU:适合摘要、翻译类任务,不适合开放对话。
  • 参考模型对比:拿另一个更强的模型(如GPT-4)给回答打分,是当前开源社区最流行的自动评估方式。

第二层:基准测试

通用模型常用的有:

  • MMLU(综合知识)
  • C-Eval(中文综合知识)
  • GSM8K(数学推理)
  • HumanEval(代码生成)
  • BBH(复杂推理)

跑这些基准测试,注意两点:

  • 遵循标准的few-shot设置,不同prompt设置会显著影响分数。
  • 基准分数只是参考,不要为了刷分专门调prompt,否则就失真了。

第三层:人类评估

这是最终标准。找5~10个人,把模型输出和参考输出混在一起盲评,关注点可以拆分:

  • 准确性:事实是否错误
  • 完整性:是否回答了问题的所有方面
  • 逻辑性:推理是否连贯
  • 语气与风格:是否符合需求
  • 安全性:是否有有害内容

人类评估的评分卡可以表格化,例如:

维度说明评分(1-5)
事实准确性是否有幻觉/编造4
指令遵循是否完全按要求执行3
逻辑连贯推理是否自洽5
风格适配是否符合指定风格4
安全性是否包含有害内容5

7.2 评估集怎么建:垂直领域必须自己造题

通用基准测试只能验证通用能力,垂直领域的模型必须自己构造评估集。构造方法:

  1. 从你的业务场景收集真实用户query,整理成500~1000条。
  2. 每条query手工构建标准答案/参考答案。
  3. 再混入对抗性样本(有害请求、越狱问题、边界模糊场景)。
  4. 评估时用LLM-as-Judge + 人工抽检相结合。

LLM-as-Judge的prompt可以参考:

你是评估助手。请根据以下标准,对AI助手的回答进行打分(1-5): 1. 是否准确回答了用户问题 2. 是否包含无关/错误信息 3. 格式是否正确 4. 语气是否专业友好 用户问题:{query} AI回答:{response} 评分(只输出数字和简短理由):

这种评估方式成本低、可复现,适合在迭代过程中快速筛优。但最终版本建议人工复核至少100条,因为自动评估本身有偏差。

7.3 一次完整的迭代流程:如何评估后反向改进

评估的目的不只是打分,而是定位问题。我的迭代流程是:

  1. 用评估集跑一轮评测,把模型的bad case整理出来。
  2. 对bad case归类:是数据缺失?还是指令理解错误?还是偏好对齐不足?
  3. 如果是数据缺失,回到SFT/预训练数据侧补充数据。
  4. 如果是指令理解,改进SFT数据构造和指令格式。
  5. 如果是偏好/安全,回到DPO阶段补充偏好数据。

整套流程通常要转两三轮,模型质量才会进入一个稳定期。千万不要觉得评估做完就结束了——评估结果必须反哺数据,这才是大模型训练的闭环。

8. 从训练到部署:量化、推理加速和服务化

8.1 合并LoRA权重与模型量化

训练完成后,第一个步骤是整合权重。如果用了LoRA,需要把adapter合并回base model:

from peft import PeftModel merged_model = PeftModel.from_pretrained(base_model, "path_to_lora_adapter") merged_model = merged_model.merge_and_unload() merged_model.save_pretrained("merged_model")

部署时如果显存或吞吐有压力,做4bit量化:

  • GPTQ:适合GPU部署,能用AutoGPTQ库离线量化。
  • AWQ:激活感知量化,效果和质量比GPTQ更好,也是GPU部署。
  • GGUF:适合CPU或Apple Silicon、Ollama等工具部署。

对7B模型做4bit量化后,显存占用大约从14G降到5G左右,很多消费级显卡都能跑推理了。

8.2 推理框架选型:vLLM、TGI还是Ollama

  • vLLM:目前吞吐最高的推理框架,支持PagedAttention,适合生产环境,多卡部署也方便。
  • TGI(Text Generation Inference):HuggingFace出的,和transformers生态兼容最好。
  • Ollama:傻瓜式本地部署工具,适合个人电脑跑模型玩,但不适合高并发服务。

对生产场景,我的建议是vLLM。启动服务很简单:

vllm serve ./merged_model \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ --port 8000

如果你的模型是自己训练的、用的是HuggingFace格式,vLLM可以直接识别,非常方便。

8.3 推理优化三板斧:KV Cache、前缀缓存、投机解码

部署之后,压测吞吐(每秒请求数)和延迟(首字延迟、总延迟),如果性能不够,考虑三板斧:

  • KV Cache:vLLM默认开启,可以通过--kv-cache-dtype fp8进一步减显存。
  • Prefix Cache:针对系统提示词(system prompt)完全固定的场景,vLLM的--enable-prefix-caching能复用前缀计算,多轮对话或RAG场景吞吐能提升不少。
  • Speculative Decoding:用一个小的草稿模型先生成多个候选token,大模型一次验证,延迟可以下降2~3倍。vLLM已经支持,配置--speculative-config即可。

这些优化做完,7B模型的推理通常能到 300~800 tokens/s(单卡A100级别),这是一个可以接受的生产性能。

9. 全流程复盘与写在最后的体会

整套流程走下来,最大的感受是:大模型训练不是单一技术问题,而是数据工程、算法理解、工程能力的综合较量。

给我留下最深印象的一件小事发生在做DPO的时候。第一次跑DPO,我用了一套2000条的高质量偏好数据,beta设成0.5,结果训练后模型回答变得"过度回避"——连简单的常识问题都开始"作为AI,我不能…"这样回复。后来把beta降到0.1,重新训练,效果立马正常了。这件事让我明白,偏好对齐的"调节旋钮"非常敏感,一个参数不对,模型行为可能从一个极端跳到另一个极端。所以做DPO一定要有小批量实验的流程,先用小数据、小beta反复试,确定了再放大规模。

如果是个人玩家,我最后的建议是:不要轻易尝试真的从随机权重开始训一个上亿参数的模型。即便你有一张4090,从头训一个1B模型,光是让loss下降到能看的水平就需要数周时间。做个100M~300M的小模型练手,把全流程跑通,然后在真实业务里用继续预训练+LoRA+SFT+DPO的路径来生产模型,这个性价比是最高的。

路线可以这样规划:

  1. 先用一个小数据集(比如几千万token)训练一个小模型(100M~300M),熟悉整个pipeline。
  2. 再拿一个开源基座模型(Qwen/Llama 1B~7B),做继续预训练、SFT、DPO。
  3. 每训练一版,都要有定量的评估报告,知道瓶颈在哪,反哺下一轮。

这样下来,两三个月你就能拥有一套完整的、可以复用的"自己训模型"的能力。这个能力,比任何单一模型都值钱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询