Skip to content

02|大模型训练技术 ​

本主题题目目录
点击题号跳转;右侧目录会高亮你正在阅读的题目
41. LLM 预训练阶段有哪几个关键步骤?42. 大规模预训练数据集构建的关键挑战有哪些?43. 如何进行预训练数据清洗与噪声过滤?44. 预训练数据 Token 重复是否影响模型性能?45. 预训练和微调哪个阶段注入知识的?46. 什么是混合精度训练(FP16/BF16)?如何避免梯度溢出?47. 训练中文大模型有哪些经验?48. SFT(有监督微调)的数据集格式是什么?49. 如果想要在某个模型基础上做全参数微调,究竟需要多少显存?50. 为什么 SFT 之后感觉 LLM "傻了"?51. SFT 指令微调数据如何构建?52. 领域模型 Continue PreTrain 数据如何选取?53. 领域数据训练后,通用能力往往会有所下降,如何缓解模型遗忘通用能力?54. 进行 SFT 操作的时候,基座模型选用 Chat 还是 Base?55. 领域模型微调指令 & 数据输入格式要求?56. 领域模型微调领域评测集如何构建?57. 领域模型词表扩增是不是有必要的?58. 多轮对话任务如何微调模型?59. 微调后的模型出现能力劣化、灾难性遗忘是怎么回事?如何缓解?60. 大模型 LLM 进行 SFT 操作的时候在学习什么?61. 预训练和 SFT 操作有什么不同?62. 大模型 LLM 进行 SFT 如何对样本进行优化?63. 指令微调的好处是什么?64. 想让模型学习某个领域或行业的知识,是应该预训练还是微调?65. 什么是 LoRA?LoRA 的思路是什么?66. LoRA 的特点是什么?有什么优势?67. LoRA 微调相比于微调适配器(Adapter)或前缀微调(Prefix Tuning)有什么优势?68. QLoRA 的思路是怎样的?有什么特点?69. AdaLoRA 的思路是怎样的?70. LoRA 权重是否可以合入原模型?71. ChatGLM-6B LoRA 后的权重多大?72. 如何在已有 LoRA 模型上继续训练?73. 为什么需要提示学习(Prompting)?有哪些方法?74. 为什么需要 P-tuning v2?P-tuning 解决了什么问题?75. 指示微调(Prompt Tuning)与 Prefix-tuning 区别是什么?76. 指示微调(Prompt Tuning)与 fine-tuning 区别是什么?77. 为什么需要适配器微调(Adapter Tuning)?78. 为什么需要 PEFT?PEFT 存在哪些问题?79. 能不能总结一下各种参数高效微调方法的对比?80. 多种不同的高效微调方法对比(LoRA / P-tuning / Prefix-tuning / Adapter)99. 什么是知识蒸馏(Knowledge Distillation)?100. 知识蒸馏的知识损失如何量化?有哪些蒸馏策略?101. 领域微调后模型通用能力下降,如何用蒸馏缓解?

41. LLM 预训练阶段有哪几个关键步骤? ​

👔面试官:从零开始训练一个 LLM,预训练阶段有哪几个关键步骤?

🙋‍♂️我:主要是数据收集、Tokenizer 训练、然后用 CLM 目标训练模型。

👔面试官:每个步骤里有哪些核心细节?数据怎么处理?训练稳定性怎么保障?

💡 简要回答 ​

LLM 预训练的关键步骤:

  1. 数据工程:原始语料收集 → 去重 → 质量过滤 → 有害内容过滤 → 数据配比
  2. Tokenizer 训练:基于最终语料训练 BPE/SentencePiece,确定词表
  3. 模型初始化:设计架构超参(层数、d_model、头数),初始化权重
  4. 分布式训练:数据并行 + 张量并行 + 流水线并行,混合精度(BF16)
  5. 训练稳定性:学习率 Warmup、梯度裁剪、Loss 监控、Checkpoint 保存
  6. 评估与后处理:中间 checkpoint 评估 PPL 和基准分,完成后做 tokenizer/模型合并

📝 详细解析 ​

数据工程:决定上限的关键 ​

数据质量是预训练最重要的环节,「Garbage in, garbage out」在 LLM 这里尤为明显。

典型的数据处理流水线:

原始网页爬取(CommonCrawl 等)
    ↓ 语言识别(只保留目标语言)
    ↓ URL 黑名单过滤(色情/暴力/垃圾站)
    ↓ 质量过滤(Perplexity 过滤、规则过滤)
    ↓ 去重(MinHash LSH 近似去重、精确哈希去重)
    ↓ 有害内容过滤(分类器过滤)
    ↓ 数据配比(高质量数据上采样)

数据配比非常关键:高质量数据(书籍、学术论文、代码、精选网页)通常会被多次采样(Upsampling),而低质量网页只采样一次。LLaMA-3 的数据配比中代码占比约 17%,这是其代码能力强的重要原因。

模型初始化与超参设计 ​

参数量确定后,d_model、层数 L、头数 h 需要按比例设计,大致遵循:

d_ff ≈ 4 × d_model(FFN 中间维度)
h = d_model / 64~128(每头维度 64 或 128)
L 与 d_model 成正比(深宽比约为 1:10)

权重初始化:通常用 N(0, 0.02) 的正态分布,残差连接处的权重用 N(0, 0.02/√(2L)) 缩小初始化,避免早期训练时残差路径主导。

训练稳定性保障 ​

混合精度训练(BF16/FP16):前向和反向用低精度,梯度更新用 FP32 主权重,节省显存同时保持数值稳定。BF16 比 FP16 更常用(动态范围更大,不容易溢出)。

学习率调度:Warmup(通常 1~2K 步线性增加到峰值)→ Cosine Decay(到训练结束衰减到峰值的 10%)。

梯度裁剪(Gradient Clipping):将梯度 L2 范数限制在 1.0 以内,防止偶发的梯度爆炸导致训练崩溃。

Loss Spike 处理:训练中可能出现 loss 突然跳高(loss spike),通常做法是回退到前几百步的 checkpoint,调低学习率继续训练。

🎯 面试总结 ​

预训练的关键步骤要按顺序说:数据工程(去重/过滤/配比,质量决定上限)→ Tokenizer 训练 → 架构设计与初始化 → 分布式训练(三种并行)→ 训练稳定性(BF16、Warmup、梯度裁剪)→ Checkpoint 评估。重点强调数据质量是预训练的核心瓶颈,面试官会知道你有实际工程认知。


42. 大规模预训练数据集构建的关键挑战有哪些? ​

👔面试官:构建大规模预训练数据集时,最主要的挑战是什么?

🙋‍♂️我:主要是数据量太大,处理起来很费时,还有数据质量参差不齐。

👔面试官:具体怎么去衡量「质量」?去重的挑战是什么?数据多样性怎么保证?

💡 简要回答 ​

大规模预训练数据集构建的核心挑战:

  1. 规模与质量的平衡:原始互联网数据量大但质量低,如何在 TB 级别的数据上高效过滤
  2. 去重:海量数据中大量重复内容,重复训练导致模型过拟合,但精确去重计算量巨大
  3. 数据多样性:来源、语言、领域、文本类型需要均衡,避免某类数据过多导致能力偏科
  4. 有害内容过滤:色情、暴力、歧视性内容需要识别并剔除,但分类器本身的准确率也是挑战
  5. 数据污染(Contamination):测试集数据混入训练集,导致评测虚高

📝 详细解析 ​

质量过滤:多维度评估 ​

规则过滤(快速粗过滤):

  • 文档长度过短(< 100 词)直接丢弃
  • 特殊字符比例过高(> 20%)丢弃
  • 数字/符号比例异常的文档过滤

模型/统计过滤(精细过滤):

  • 困惑度过滤(PPL Filtering):用小型 n-gram 语言模型计算每个文档的困惑度,过高(乱码)或过低(重复文本)的文档都过滤
  • 质量分类器:用高质量数据(维基百科、书籍)训练一个二分类器,预测网页文档是否「类书籍质量」(C4、RefinedWeb 等都用这个思路)

去重:MinHash LSH ​

精确去重(SHA-256 哈希)只能找到完全相同的文档,近似去重(MinHash + LSH)能发现高度相似的文档:

python
# MinHash 的核心思想
1. 对文档的 n-gram 集合计算 MinHash 签名(128~256 维向量)
2. 用 LSH(局部敏感哈希)把签名相似的文档分到同一个桶
3. 同桶内精确比较 Jaccard 相似度,超过阈值(如 0.8)的去重

FineWeb(HuggingFace)和 Dolma 等开源数据集都公开了去重流水线,实测去重可以剔除 CommonCrawl 原始数据约 30~40% 的近重复内容。

数据污染问题 ​

测试基准(MMLU、HumanEval、GSM8K)的题目如果出现在训练数据里,评测分数会虚高。检测方法:计算训练数据中与测试题的 n-gram 重叠率,超过阈值的文档标记为污染并剔除或单独统计。

LLaMA-3 的技术报告里专门有数据污染分析章节,对比了有/无污染情况下的评测分数。

🎯 面试总结 ​

五个挑战要点:规模/质量平衡(PPL 过滤、质量分类器)、去重(MinHash LSH 近似去重)、多样性(来源/语言/领域均衡)、有害内容过滤(分类器)、数据污染(n-gram 重叠检测)。能举出 FineWeb、C4 等真实数据集的处理方式,说明你对工程实践有了解。


43. 如何进行预训练数据清洗与噪声过滤? ​

👔面试官:具体讲讲预训练数据清洗的流程,噪声怎么识别,怎么过滤?

🙋‍♂️我:主要是去除乱码、特殊字符,过滤掉质量差的文本。

👔面试官:具体用什么方法判断「质量差」?有哪些工程上常用的工具和策略?

💡 简要回答 ​

数据清洗是多层次的漏斗式过滤,从粗到细逐步精炼:

原始数据
  ↓ 第一层:格式清洗(HTML/Markdown 解析,去除非文本内容)
  ↓ 第二层:规则过滤(长度、字符比例、语言识别)
  ↓ 第三层:统计过滤(PPL 过滤、重复率过滤)
  ↓ 第四层:模型过滤(质量分类器、有害内容分类器)
  ↓ 第五层:去重(文档级+句子级)
精炼数据

📝 详细解析 ​

第一层:格式清洗 ​

网页数据通常含有大量 HTML 标签、导航栏、页脚、广告等非正文内容,需要先提取正文:

  • trafilatura / jusText / newspaper3k:开源 HTML 正文提取工具,专门识别网页主体内容
  • Markdown/LaTeX 中的特殊符号需要转义或保留(数学公式要特殊处理)
  • 去除 JavaScript 代码块、CSS 样式块

第二层:规则过滤 ​

python
def rule_filter(doc):
    # 文档长度过短
    if len(doc.split()) < 100:
        return False
    # 数字/标点比例过高(可能是垃圾内容)
    if sum(c.isdigit() or c in '!@#$%^&*()') / len(doc) > 0.3:
        return False
    # 行重复率过高(可能是模板/爬虫内容)
    lines = doc.split('\n')
    if len(set(lines)) / len(lines) < 0.5:
        return False
    return True

第三层:困惑度过滤(PPL Filtering) ​

用 KenLM(5-gram 语言模型,训练在 Wikipedia 上)计算每个文档的困惑度:

  • PPL 太高:文本可能是乱码、外语、或随机字符
  • PPL 太低:文本可能是高度重复的模板内容(如「点击这里 点击这里 点击这里」)
  • 保留 PPL 在合理区间内的文档(通常取 10th~95th 百分位)

第四层:模型过滤 ​

训练一个轻量级文本质量分类器(通常用 FastText 或 logistic regression):

  • 正样本:维基百科、书籍(高质量)
  • 负样本:低质量网页

给每个文档打一个 0~1 的质量分,低于阈值(如 0.5)的过滤掉。C4 数据集(T5 的训练数据)就是用这种方式处理的。

🎯 面试总结 ​

按漏斗层次说:格式清洗(HTML 解析)→ 规则过滤(长度/字符比例)→ PPL 过滤(KenLM,过高过低都过滤)→ 模型质量打分(FastText 分类器)→ 去重(MinHash)。要强调是「多层次漏斗」而不是单一过滤,每一层都有自己的侧重点,能举出真实工具(trafilatura、KenLM、MinHash)说明有工程认知。


44. 预训练数据 Token 重复是否影响模型性能? ​

👔面试官:预训练数据里如果有大量重复的 token,对模型有什么影响?

🙋‍♂️我:可能会让模型对某些内容记忆更深,但也可能导致过拟合?

👔面试官:具体是什么机制导致影响?重复多少倍开始有问题?有研究支持吗?

💡 简要回答 ​

数据重复对预训练有明显负面影响,主要表现在两个方面:

  1. 记忆化(Memorization)加剧:重复出现的序列会被模型「死记硬背」,在推理时对该序列附近的内容过度确定,泛化能力下降
  2. 能力多样性损失:大量重复某类内容(如新闻),其他领域的能力会被挤压,模型变得偏科

研究(Hernandez et al., 2022;Tirumala et al., 2022)表明:同一文档重复 4 次以上时,模型在测试集上的 PPL 开始显著上升,泛化能力明显下降。

📝 详细解析 ​

重复带来的记忆化问题 ​

Carlini et al. 的研究发现:训练数据中重复次数越多的序列,模型越容易在输入该序列前缀时完整地「背诵」出后续内容。这是一个隐私风险(训练数据提取攻击),同时也是过拟合的信号。

直觉:语言模型的训练目标是最小化 loss(即最大化训练序列的概率),如果某个序列重复出现 100 次,模型会把大量参数容量用于记住这个序列,挤占了学习其他通用语言规律的空间。

「Epoch」与重复的关系 ​

预训练通常只训一个 epoch(每个文档只看一遍),但以下情况会导致事实上的重复:

  • 数据去重不彻底:同一文章来自不同域名但内容相同
  • 高质量数据上采样(Upsampling):书籍、学术论文被有意重复 2~4 次
  • 混合数据集时某类来源比例过高

对于高质量数据的上采样,研究表明重复 1~4 次通常是安全的,超过 4 次性能开始下降。

实践策略 ​

  • 文档级去重(MinHash LSH)+ 句子级去重(精确哈希)双重保障
  • 对刻意上采样的高质量数据控制在 ≤4 倍
  • 使用 数据混合比例(Data Mixture)而不是物理复制——通过调整采样权重,在概念上多次采样,但实现时用加权采样而非真实重复文件

🎯 面试总结 ​

核心结论:数据重复 ≤4 次通常可接受,超过 4 次泛化能力下降,过度重复导致记忆化(Memorization)而非理解。要说出两个负面影响(记忆化加剧、能力多样性损失),能引用 Carlini 等人的研究更有说服力。工程上的对策是严格去重 + 限制上采样倍数。


45. 预训练和微调哪个阶段注入知识的? ​

👔面试官:模型的知识主要是在预训练阶段学到的,还是微调阶段?

🙋‍♂️我:应该是预训练阶段?微调主要是让模型学会指令格式?

👔面试官:那「知识」具体是什么?微调真的一点知识都没学到吗?两个阶段各自学的是什么?

💡 简要回答 ​

知识主要在预训练阶段注入,微调主要教会模型「行为方式」而非「知识内容」。

  • 预训练:在海量数据上用 CLM 目标,模型学到了语言规律、世界知识、事实、推理模式、代码语法等——这些都压缩在模型参数里
  • SFT 微调:用少量高质量的指令-回复对,教模型如何表达已有知识(格式、语气、遵循指令、拒绝有害请求)——解锁而非注入知识
  • RLHF:进一步对齐输出与人类偏好(礼貌、有帮助、无害),是行为偏好的调整

📝 详细解析 ​

预训练:知识压缩进参数 ​

预训练数据规模(数 T 个 token)远大于微调数据(数十万到数百万 token),模型参数通过 CLM 损失压缩了训练语料中的概率分布,包含了:

  • 世界知识:历史事件、科学事实、人名地名
  • 语言能力:语法、语义、修辞
  • 推理模式:演绎、归纳、类比
  • 代码能力:编程语言语法、算法模板

这些能力的强弱直接取决于预训练数据的质量和覆盖范围。

SFT:解锁与格式化,而非知识注入 ​

一个直接的证据:InstructGPT 论文中,1.3B 参数的 InstructGPT(在 1750B GPT-3 上做 SFT)在人类评测中胜过原始 GPT-3,但它的参数量只有 GPT-3 的 1/134。如果 SFT 真的在注入知识,这个规律无法解释——SFT 提升的是知识表达和指令跟随能力,而不是知识本身。

SFT 数据格式(Prompt + Response)教模型:

  • 看到问题要直接回答,而不是续写
  • 用适当的格式(Markdown/代码块)输出
  • 对不知道的内容承认不知道(部分对齐)
  • 遵循特定语气(礼貌、专业)

微调能学到少量新知识,但有局限 ​

用微调向模型注入新知识是有效但效率低且容易遗忘的。研究表明:

  • 在 SFT 数据里加入事实性知识,模型能学到,但容量有限(几千条事实)
  • 大量注入新知识会导致灾难性遗忘(忘掉预训练学到的通用能力)
  • 正确做法:新领域知识应该通过 Continue Pretraining(继续在领域数据上预训练)而非 SFT 来注入

🎯 面试总结 ​

一句话总结:预训练注入知识(What the model knows),微调教会行为(How the model responds)。SFT 的本质是「解锁」已有知识的表达方式,而不是注入新知识。能引用 InstructGPT 的例子(1.3B 胜 175B),说明 SFT 的价值在于对齐而非知识。工程上要注入新知识,应该用 Continue Pretraining 而非 SFT。


46. 什么是混合精度训练(FP16/BF16)?如何避免梯度溢出? ​

👔面试官:什么是混合精度训练?FP16 和 BF16 有什么区别?梯度溢出怎么处理?

🙋‍♂️我:混合精度训练就是用 FP16 来节省显存,但有些地方还是要用 FP32 保持精度。

👔面试官:哪些地方用 FP32,哪些用 FP16?BF16 为什么比 FP16 更稳定?Loss Scale 是怎么工作的?

💡 简要回答 ​

混合精度训练(Mixed Precision Training)的核心策略:前向传播和反向传播用低精度(FP16/BF16)节省显存和加速计算,权重更新用 FP32 主权重(Master Weight)保持精度。

BF16 比 FP16 更推荐用于大模型训练:BF16 有更大的动态范围(指数位 8 位 vs FP16 的 5 位),不容易出现梯度溢出(overflow),不需要 Loss Scale 技巧。

📝 详细解析 ​

FP16 vs BF16 vs FP32 ​

格式总位数符号指数位尾数位最大值最小非零值
FP32321823~3.4×10³⁸~1.2×10⁻³⁸
FP16161510~65504~6×10⁻⁸
BF1616187~3.4×10³⁸~1.2×10⁻³⁸

BF16 的关键优势:指数位和 FP32 相同(8 位),动态范围与 FP32 完全一致,只是精度(尾数位)低一些。大模型训练中梯度的数量级变化范围很大,BF16 的宽动态范围让它几乎不会出现溢出,无需 Loss Scale。

FP16 的问题:最大值只有 65504,梯度值稍大就溢出变成 inf,必须配合 Loss Scaling 使用。

混合精度训练的完整流程 ​

FP32 主权重(存在 CPU 或 GPU 内存)
    ↓ 转换为 FP16/BF16
FP16 权重副本(GPU 显存)
    ↓ 前向传播(FP16)→ 计算 Loss(FP32)
    ↓ 反向传播(FP16 梯度)
    ↓ 梯度转回 FP32
FP32 梯度 + FP32 主权重 → Adam 更新 → 新 FP32 主权重

主权重(Master Weight)始终保持 FP32,每次更新后再降精度到 FP16 做前向,保证了数值精度不丢失。

Loss Scaling:解决 FP16 梯度下溢 ​

FP16 的梯度不只会溢出(过大),还会下溢(underflow):梯度绝对值小于 6×10⁻⁸ 时变成 0,梯度消失,参数停止更新。

Loss Scaling 的做法:在反向传播前把 loss 乘以一个大数(如 2^13),使得梯度整体放大,避免下溢;反向传播后把梯度除以同样的数还原:

python
# 动态 Loss Scale(PyTorch AMP 的默认行为)
scaler = torch.cuda.amp.GradScaler()

with torch.cuda.amp.autocast():  # 自动用 FP16 做前向
    loss = model(input)

scaler.scale(loss).backward()   # loss × scale 因子后反向
scaler.step(optimizer)          # 梯度 ÷ scale 因子后更新
scaler.update()                 # 动态调整 scale 因子大小

动态 Loss Scale:初始 scale=2^16,如果梯度出现 inf/nan,scale 缩小一半;如果连续 N 步没有 inf,scale 翻倍。

实践建议 ​

  • A100/H100:优先用 BF16,无需 Loss Scale,简单稳定
  • V100/T4:不支持 BF16,用 FP16 + 动态 Loss Scale
  • 现代框架(Megatron-LM、DeepSpeed)都内置了混合精度支持,通常只需要设置 dtype=torch.bfloat16

🎯 面试总结 ​

混合精度的核心是:前向/反向 FP16/BF16,主权重 FP32,权重更新在 FP32 完成。BF16 比 FP16 更稳定(动态范围与 FP32 相同,不溢出,无需 Loss Scale),现代大模型训练几乎都用 BF16。FP16 需要 Loss Scaling(动态调整 scale 因子,防止梯度下溢)。能说出「主权重 FP32 + 计算 BF16」的完整流程,面试官就知道你真的理解了混合精度的精髓。


47. 训练中文大模型有哪些经验? ​

👔面试官:专门针对中文训练大模型,有哪些特殊的注意点和经验?

🙋‍♂️我:需要更多中文数据,词表也要针对中文扩展……

👔面试官:中文数据有哪些特殊处理要求?词表扩展怎么做?中文的分词特性有什么影响?

💡 简要回答 ​

训练中文大模型的核心特殊考量:

  1. 词表工程:扩大词表(150K+),加入高频汉字、词语,提升 token 效率
  2. 数据多样性:覆盖简体/繁体、多种领域(新闻/书籍/网页/代码),避免语言风格单一
  3. 数据清洗特殊性:中文无空格分隔,PPL 过滤需要用中文语言模型;繁简转换统一
  4. 评测基准:用中文专项评测集(CMMLU、C-Eval、CLUE)而非只看英文基准

📝 详细解析 ​

词表设计:中文 Token 效率至关重要 ​

LLaMA-2 用 32K 词表,中文大多以 UTF-8 字节序列编码,一个汉字 = 3 字节 = 最多 3 个 token。这导致:

  • 相同内容的中文文本比英文消耗 2~3 倍 token
  • 推理成本、上下文占用都更高

扩词表方案:在原始词表基础上,统计目标语料中的高频字符/词语,添加到词表中(通常增加 3~5 万个中文 token)。扩表后需要:

  1. 对新加入的 token embedding 随机初始化(或用字符 embedding 的平均值初始化)
  2. 进行 Continue Pretraining 让模型适应新词表,通常需要数十亿 token 的继续训练

Qwen 系列从设计之初就针对中文优化词表(150K),ChatGLM 词表 64K+,中文 token 效率显著优于 LLaMA-2。

数据策略:质量 > 数量 ​

中文互联网数据质量参差不齐,需要特别注意:

  • 简繁转换:统一为简体(或保留繁体但标记),避免同一内容因编码不同被当做不同训练样本
  • 古文/白话文混合:古典文学、文言文要单独处理,过多会影响现代中文的生成质量
  • 中英混合:技术文档中中英夹杂,分词器需要能正确处理混合文本
  • 垂直领域:医疗、法律、金融领域的高质量中文语料对专业能力很重要,通常需要单独筛选和上采样

评测:不能只看英文基准 ​

评测集内容特点
CMMLU中文多科目考试覆盖 67 个科目,含文史哲
C-Eval中文综合能力52 个科目,偏理工科
CLUE中文 NLU文本分类、阅读理解等
GAOKAO高考题贴近实际中文教育场景

🎯 面试总结 ​

中文大模型的特殊点集中在三个方面:词表(必须扩大到 100K+ 以保证 token 效率,LLaMA-2 的 32K 词表中文效率极差);数据(覆盖简繁/多领域/避免古文过多,中文 PPL 过滤需要中文语言模型);评测(必须用 CMMLU、C-Eval 等中文基准而非只看 MMLU)。能给出 Qwen 词表 150K vs LLaMA-2 词表 32K 的对比,面试官会觉得你有深度。


48. SFT(有监督微调)的数据集格式是什么? ​

👔面试官:SFT 的数据集格式是什么样的?Prompt 和 Response 怎么组织?

🙋‍♂️我:就是一问一答的格式,有输入有输出。

👔面试官:具体的 Token 级别是怎么处理的?Loss 是对 Prompt 计算还是只对 Response 计算?多轮对话格式是什么?

💡 简要回答 ​

SFT 数据的基本格式是指令-回复对(Instruction-Response Pair),但在 Token 级别有重要细节:只对 Response 部分计算 Loss,Prompt 部分只做前向传播但不反传梯度。

📝 详细解析 ​

单轮对话的基本格式 ​

不同模型有不同的对话模板(Chat Template),以 LLaMA-3 的 Instruct 格式为例:

<|begin_of_text|>
<|start_header_id|>system<|end_header_id|>

你是一个有帮助的 AI 助手。<|eot_id|>
<|start_header_id|>user<|end_header_id|>

请解释什么是注意力机制。<|eot_id|>
<|start_header_id|>assistant<|end_header_id|>

注意力机制是一种让模型......<|eot_id|>

Token 级别的 Loss Mask ​

SFT 训练时,对上述完整序列只计算 Response 部分(assistant 回复)的 loss:

python
# 伪代码示意
labels = tokenize(full_conversation)

# 将 Prompt 部分(system + user)的 label 设为 -100(忽略)
prompt_len = len(tokenize(system + user_message))
labels[:prompt_len] = -100  # CrossEntropyLoss 会忽略 -100

# 只有 Response 部分贡献 Loss
loss = cross_entropy(logits, labels, ignore_index=-100)

为什么不对 Prompt 计算 loss?

Prompt 部分是「已知输入」,用户给定的,模型不需要学习如何生成这部分。让模型「学习」如何生成 Prompt 没有意义,还会引入噪声(因为同一个意思的 Prompt 可以有很多种写法)。

多轮对话格式 ​

多轮对话把历史轮次展开拼接,只对每轮的 assistant 回复计算 loss:

[system]  ← 不计算 loss
[user 1]  ← 不计算 loss
[assistant 1]  ← 计算 loss ✓
[user 2]  ← 不计算 loss
[assistant 2]  ← 计算 loss ✓

常见的数据格式 ​

Alpaca 格式(早期流行):

json
{
  "instruction": "请解释什么是注意力机制",
  "input": "",
  "output": "注意力机制是......"
}

ShareGPT 格式(多轮对话):

json
{
  "conversations": [
    {"from": "human", "value": "请解释什么是注意力机制"},
    {"from": "gpt", "value": "注意力机制是......"},
    {"from": "human", "value": "能举个代码示例吗"},
    {"from": "gpt", "value": "当然,下面是 Python 示例......"}
  ]
}

🎯 面试总结 ​

SFT 数据格式的关键点有两个:一是对话模板(不同模型有不同的特殊 token 分隔),二是 Loss Mask(只对 Response 部分计算 loss,Prompt 部分 label 设为 -100 忽略)。能说清楚为什么不对 Prompt 计算 loss(Prompt 是已知输入,不是模型需要学习生成的),面试官会认为你真正理解了 SFT 的训练机制。


49. 如果想要在某个模型基础上做全参数微调,究竟需要多少显存? ​

👔面试官:对一个 7B 参数的模型做全参数微调,需要多少显存?怎么估算?

🙋‍♂️我:应该要很多……7B 参数光存储就要 14GB?

👔面试官:14GB 是存权重的,梯度、优化器状态还要多少?能给出完整的计算公式吗?

💡 简要回答 ​

全参数微调的显存消耗 = 模型权重 + 梯度 + 优化器状态 + 激活值:

以 7B 模型 + Adam + BF16/FP32 混合精度为例:

模型权重(BF16):7B × 2 bytes = 14 GB
梯度(FP32):   7B × 4 bytes = 28 GB
Adam 优化器(FP32,一阶矩 + 二阶矩):7B × 4 × 2 = 56 GB
                                          ─────────
权重+梯度+优化器合计:                       98 GB

激活值(与 batch size 和序列长度相关):  ~几 GB

总计约 100~120 GB

这就是为什么 7B 模型的全参数微调通常需要 8×A100(80GB)。

📝 详细解析 ​

显存消耗的四个组成部分 ​

1. 模型权重

权重大小 = 参数量 × 数据类型字节数
BF16/FP16:2 bytes/param → 7B × 2 = 14 GB
FP32:     4 bytes/param → 7B × 4 = 28 GB

混合精度训练时需要同时保留 BF16(用于计算)和 FP32(主权重用于更新),合计 6 bytes/param。

2. 梯度

梯度和权重的形状完全一致,通常用 FP32 存储:

梯度大小 = 参数量 × 4 bytes = 7B × 4 = 28 GB

3. 优化器状态(Adam 是最耗显存的)

Adam 需要存储:

  • 一阶矩(梯度均值):4 bytes/param
  • 二阶矩(梯度方差):4 bytes/param
Adam 状态 = 参数量 × 8 bytes = 7B × 8 = 56 GB

SGD 无动量:0 额外存储;SGD with Momentum:额外 4 bytes/param;Adam:额外 8 bytes/param。

4. 激活值(Forward Activations)

激活值大小与 batch size × seq_len × d_model 成正比,取决于是否使用梯度检查点(Gradient Checkpointing)。

不使用梯度检查点时,每层的激活都要保留用于反向传播,内存消耗很大;使用梯度检查点后,只保留少数 checkpoint,用时间换空间(反向传播时重新计算激活),可以大幅减少激活显存。

一般公式总结 ​

显存(bytes) ≈ N × (2 + 4 + 8) = N × 14  (混合精度 + Adam)
            ≈ N × (4 + 4 + 8) = N × 16  (纯 FP32 + Adam)

其中 N 为参数量(以参数个数计)

对于 7B 模型:7×10⁹ × 14 ≈ 98 GB(不含激活)

如何减少显存 ​

方法节省来源效果
LoRA / QLoRA只更新少量参数,梯度+优化器状态大幅缩小显著
梯度检查点激活值不保留,反向时重算激活减少 80%
DeepSpeed ZeRO-3权重/梯度/优化器状态分布到多 GPU单卡显存 ÷ 节点数
Adafactor替代 Adam,优化器状态近似存储优化器状态减少 75%

🎯 面试总结 ​

记住这个公式:全参数微调显存 ≈ 参数量 × 16 bytes(混合精度 + Adam)。7B 模型约 100GB。要能拆解四个部分(权重 2B、梯度 4B、Adam 状态 8B per param),并知道每个部分的节省方法(LoRA 减少梯度和优化器状态、梯度检查点减少激活、ZeRO-3 分布式分片)。这道题在面试中非常高频,能现场算出来加分极多。


50. 为什么 SFT 之后感觉 LLM "傻了"? ​

👔面试官:很多人发现,Base 模型 SFT 之后,感觉模型能力反而下降了,"变傻了",这是为什么?

🙋‍♂️我:可能是训练数据质量不好?或者训练了太久导致过拟合?

👔面试官:具体什么机制导致「变傻」?数据量和数据质量分别有什么影响?有哪些缓解方法?

💡 简要回答 ​

SFT 后「变傻」的根本原因是灾难性遗忘(Catastrophic Forgetting):SFT 在有限的指令数据上更新参数,导致模型过拟合到 SFT 数据的分布,同时「忘记」了预训练阶段学到的广泛能力。

常见表现:

  • 回答变短、变公式化(只会套模板)
  • 推理能力下降(倾向于给「听起来对」的答案而不是真正推理)
  • 知识提取能力变弱(反复强调格式而忽略内容准确性)

📝 详细解析 ​

根本原因:SFT 数据分布与预训练数据分布的偏差 ​

预训练用了数 T 个 token 的多样化数据;SFT 通常只有几十万到几百万 token 的指令数据。当模型在 SFT 数据上持续训练时,参数逐渐向 SFT 数据的分布偏移,预训练能力被覆盖。

直觉类比:就像一个博学多才的人(预训练模型)被要求反复练习「电话客服话术」(SFT 数据),练着练着就只会说客服话术了,其他知识反而不会表达了。

三个具体机制 ​

1. SFT 数据质量低、风格单一

如果 SFT 数据都是「问:xxx / 答:当然,这是一个好问题,xxx」这种格式,模型会过拟合到这个格式。用户提任何问题,模型都会用这种腔调回答,失去了自然、多样的表达方式。

2. SFT 步数太多(过拟合)

SFT 的最优训练步数通常比预想的少,1~3 个 epoch 通常足够。过多训练导致 loss 虽然低,但泛化性下降。

3. 学习率过高

学习率过大会使 SFT 对参数的更新幅度太大,破坏预训练参数中存储的知识结构。

缓解方法 ​

数据层面:

  • 多样化 SFT 数据:指令类型覆盖广,风格多样(不要全是客服体)
  • 加入通用能力数据:在 SFT 数据中混入少量预训练风格的文本(书籍片段、对话等),防止模型忘记通用能力
  • 数据质量 > 数量:1000 条高质量的人工写作数据,优于 100000 条 GPT 生成的模板化数据

训练层面:

  • 小学习率:SFT 学习率通常是预训练的 1/10(如 2e-5 vs 2e-4)
  • 控制 epoch 数:1~3 个 epoch,不要过多
  • 混合预训练数据(Replay):在 SFT 数据中混入小比例预训练数据(5~10%),类似经验回放,防止遗忘

技术层面:

  • LoRA:只更新少量参数(低秩矩阵),主体权重不变,天然防止灾难性遗忘
  • EWC(Elastic Weight Consolidation):对重要参数加约束,限制其被改变的幅度

🎯 面试总结 ​

「变傻」的核心是灾难性遗忘:SFT 数据分布窄、参数更新使模型偏移预训练分布。三个具体原因:数据质量低/风格单一、训练步数过多、学习率过高。解决方案从三个维度展开:数据多样化(加入通用数据混合训练)、训练参数控制(小学习率、少 epoch)、技术手段(LoRA、数据回放)。这道题反映了你对 SFT 工程实践的深度理解。


51. SFT 指令微调数据如何构建? ​

👔面试官:SFT 的指令数据从哪里来?如何构建高质量的指令数据集?

🙋‍♂️我:可以人工写,也可以用 GPT 生成……

👔面试官:Self-Instruct 方法是什么?数据质量怎么保证?多少数据量才够?

💡 简要回答 ​

SFT 指令数据的来源主要有四种途径,从低成本到高成本排列:

  1. Self-Instruct / Alpaca:用强模型(GPT-4)批量生成指令-回复对
  2. 人工标注:专业标注人员撰写高质量示例(成本高但质量最好)
  3. 现有数据集转化:将已有的 NLP 数据集(问答/摘要/翻译)转化为指令格式
  4. 用户真实数据:真实用户与模型的对话,过滤后用于训练(ShareGPT 是典型来源)

📝 详细解析 ​

Self-Instruct:低成本批量生成 ​

Self-Instruct(Wang et al., 2022)的方法:

  1. 人工写 175 条种子指令(覆盖多种任务类型)
  2. 用这些种子指令作为 Few-shot 示例,让 GPT 生成新的指令
  3. 用 GPT 为这些指令生成对应的回复
  4. 去重、过滤低质量样本

Stanford Alpaca 用这个方法生成了 52K 条数据,微调 LLaMA-7B,实现了接近 text-davinci-003 的对话效果。成本:不到 500 美元。

但 Self-Instruct 数据有明显局限:回复风格受 GPT 影响,容易「AI 腔」浓重(「当然,我很乐意帮助您……」),数据多样性和质量参差不齐。

数据质量维度 ​

高质量 SFT 数据需要满足:

维度要求
准确性回复内容事实正确,无幻觉
多样性任务类型多样(问答/写作/代码/推理/对话)
复杂性包含需要多步推理的复杂指令,不只是简单问答
风格自然像人类写的,不是 AI 模板腔
拒绝有害请求包含拒绝不当请求的样本(安全对齐)

数据量的讨论 ​

LIMA(Less Is More for Alignment,2023)的研究发现:1000 条人工精心筛选的多样化指令数据,微调出来的效果可以接近 InstructGPT(52K 条数据),甚至在某些维度超越。核心结论:质量远比数量重要。

实践经验:

  • 最小可用:1K~5K 条高质量数据(领域专用场景)
  • 通用对话能力:10K~100K 条(需要多样性)
  • 全面对齐:100K~1M 条(兼顾能力和安全)

开源高质量数据集推荐 ​

  • Dolly-15K:Databricks 员工人工标注,15K 条真人写作
  • OpenHermes 2.5:混合多个高质量来源,250K 条
  • WizardLM:Evol-Instruct 方法,用 GPT 进化(加深/加宽)指令复杂度
  • ShareGPT:真实用户对话,多样性好

🎯 面试总结 ​

SFT 数据构建四条路:Self-Instruct(低成本,量大但 AI 腔)、人工标注(质量最高,成本高)、现有数据集转化(快速启动)、真实用户数据(多样性好)。关键结论引用 LIMA:1000 条高质量 > 52000 条一般质量,质量 >> 数量。要说清楚「高质量」的五个维度:准确、多样、复杂、自然、含安全样本。


52. 领域模型 Continue PreTrain 数据如何选取? ​

👔面试官:要在某个领域(比如医疗/法律/金融)做 Continue Pretraining,数据怎么选?

🙋‍♂️我:就是收集这个领域的专业文献、教材之类的数据?

👔面试官:领域数据和通用数据的比例怎么定?数据质量怎么保证?训练多少步合适?

💡 简要回答 ​

Continue Pretraining(CPT)的数据选取核心原则:领域数据 + 通用数据混合,领域数据决定专业能力,通用数据防止遗忘。

典型配比:领域数据 70~80% + 通用数据 20~30%。

📝 详细解析 ​

领域数据的来源与质量 ​

高质量领域数据来源(以医疗为例):

来源质量备注
教科书、临床指南极高经过专家审核,内容权威
学术期刊论文(PubMed)高同行评审,专业性强
病历(脱敏后)高贴近实际场景,需严格脱敏
医疗问答平台中丰富但质量参差,需过滤
维基百科医学条目中覆盖广但深度有限
网页爬取的医疗内容低需要严格质量过滤

质量过滤要点:

  • 用领域专家构建的词汇表/知识图谱过滤掉明显不相关内容
  • 对专业术语密度、领域相关词汇覆盖率打分
  • 医疗场景还需要过滤掉错误的医学信息(可用规则 + 专家抽检)

通用数据的必要性:防止遗忘 ​

完全用领域数据训练会导致灾难性遗忘:模型逐渐「只会说医疗话题」,连基本的语言能力(写作、推理、代码)也退化。

通用数据配比建议:

  • 保留约 20~30% 的通用高质量数据(书籍、维基百科、代码)
  • 通用数据选择和预训练原始数据有重叠,有助于保持通用能力

训练时长的控制 ​

CPT 的训练步数不能太多:

推荐:覆盖 1~5 个 epoch 的领域数据(约数十亿 token)
     学习率设为原始预训练峰值学习率的 10%~30%

训练太少:模型没有充分吸收领域知识 训练太多:通用能力持续下降,即使加入通用数据也难以完全补救

评估标准 ​

CPT 训练后需要同时评估:

  1. 领域能力:领域专用评测集(医疗 QA、法律理解)的准确率
  2. 通用能力:MMLU、GSM8K 等通用基准,确保没有显著下降
  3. 生成流畅度:人工抽样评估专业文本的自然度

🎯 面试总结 ​

领域 CPT 数据选取的三个核心:来源质量(教材/期刊 > 网页爬取)、配比策略(领域 70~80% + 通用 20~30% 防遗忘)、训练量控制(1~5 epoch,学习率用预训练的 10~30%)。一定要说「通用数据必须混入」这个点,面试官会知道你理解了灾难性遗忘的工程意义。


53. 领域数据训练后,通用能力往往会有所下降,如何缓解模型遗忘通用能力? ​

👔面试官:领域训练后通用能力下降怎么缓解?

🙋‍♂️我:混入通用数据、用 LoRA 只更新部分参数……

👔面试官:这些方法的原理是什么?哪种最有效?有什么实验证据?

💡 简要回答 ​

缓解通用能力遗忘的方法,按有效性排序:

  1. 数据混合(Data Mixture):领域数据 + 通用数据混合训练,最简单最有效
  2. 参数高效微调(LoRA):只更新少量低秩参数,主体权重保持不变
  3. EWC / 正则化:对重要参数加约束防止变化过大
  4. 经验回放(Experience Replay):在微调过程中随机混入预训练数据 batch

📝 详细解析 ​

方法一:数据混合(最推荐) ​

直接在训练数据中混入通用数据,模型在同一个训练过程里同时学习领域知识和保持通用能力。

python
# 数据配比示例:医疗领域 CPT
dataset = {
    "medical_books": weight=0.4,      # 医学教材
    "medical_papers": weight=0.3,      # 期刊论文
    "general_web": weight=0.2,         # 通用网页
    "code": weight=0.1,                # 代码(保持代码能力)
}

关键:通用数据不能太少(< 10% 容易遗忘),也不能太多(失去领域专注效果)。

方法二:LoRA(天然防遗忘) ​

LoRA 把权重更新限制在低秩矩阵空间:W' = W + AB(A、B 是低秩矩阵),主权重 W 完全不动。由于 W 不变,预训练中存储的通用能力被完整保留;只有 LoRA 矩阵学习领域特定的知识偏移。

局限:LoRA 的参数容量有限,注入的领域知识「深度」不如全参数训练,对需要大量新知识的领域效果有所折扣。

方法三:课程学习(Curriculum Learning) ​

先训通用能力,再训领域能力,最后做混合微调:

Step 1: Continue Pretraining(通用 + 领域混合)
Step 2: 领域 SFT(指令微调)
Step 3: 通用 SFT + 领域 SFT 混合微调(修复遗忘)

这个三段式流程在工业界很常见,Step 3 的混合 SFT 专门用来补救 Step 2 可能造成的遗忘。

实验证据 ​

BioMedLM、Med-PaLM 等医疗大模型的论文都展示了,加入通用数据后,在医疗专项能力提升的同时,MMLU 等通用基准的下降幅度从 5~10% 降低到 1~2% 以内。

🎯 面试总结 ​

最有效的方法是数据混合(领域 + 通用混合训练);最省显存的方法是 LoRA(主权重不变天然防遗忘);最精细的方法是三段式训练(CPT → 领域 SFT → 混合 SFT)。核心原理都是一个:让模型在每次更新中都同时接触通用数据,不让参数完全偏移到领域分布。


54. 进行 SFT 操作的时候,基座模型选用 Chat 还是 Base? ​

👔面试官:做 SFT 的时候,应该在 Base 模型上做,还是在 Chat(Instruct)模型上做?

🙋‍♂️我:Base 模型更原始,在 Base 上 SFT 更能定制?Chat 模型已经对齐了,在上面微调会不会冲突?

👔面试官:两种路径各有什么优缺点?实际工程中怎么选?

💡 简要回答 ​

两种起点各有优缺点,选择取决于任务性质和数据量:

起点适合场景优势劣势
Base 模型领域专用、有大量高质量 SFT 数据完全自定义,无原有对话格式约束需要更多 SFT 数据才能获得好的对话能力
Chat/Instruct 模型数据量少、垂直场景微调继承了对话能力和安全对齐,SFT 数据量需求少可能受原有 chat template 约束,风格难以完全自定义

📝 详细解析 ​

从 Base 开始 SFT ​

优势:

  • 完全控制模型风格(对话格式、语气、拒绝策略全部自定义)
  • 没有原 Chat 模型的「惯性」,不受原有 RLHF 对齐方向影响
  • 适合做领域 Continue Pretraining → 领域 SFT 的完整流程

劣势:

  • Base 模型默认是「文本补全」行为,不会自然地「回答问题」,需要更多 SFT 数据才能激活对话能力
  • 安全对齐需要从零开始,需要加入拒绝有害请求的示例

适合场景:有充足的领域指令数据(10K+ 条),需要完全自定义对话风格,或者先做了 CPT 再 SFT 的完整流程。

从 Chat/Instruct 模型开始 SFT ​

优势:

  • 继承了原有的对话能力(会直接回答而不是续写)
  • 继承了安全对齐(有害请求已经被对齐)
  • 少量 SFT 数据(几百~几千条)就能让模型学会新领域任务格式
  • 工程上更快看到效果

劣势:

  • Chat 模型的 RLHF 训练可能有「惯性」——倾向于产生某种固定风格的回复,较难完全改变
  • 过度微调可能损坏原有的对话对齐(即「变傻」问题更突出,因为覆盖了 RLHF 参数)

适合场景:数据量少、快速迭代验证、在已有 Chat 模型基础上做垂直场景适配(如客服、问答)。

实际工程中的经验 ​

互联网公司通用做法:

LLaMA-3 Base → 领域 CPT → 领域 SFT → RLHF/DPO 对齐

快速迭代/小团队:

LLaMA-3 Instruct → 领域 SFT(LoRA)→ 快速验证

如果团队算力和数据都有限,从 Chat 模型 + LoRA 是最高性价比的起点。如果有足够资源做完整的训练流程,从 Base 开始能获得更定制化的模型。

🎯 面试总结 ​

核心结论:数据量充足 + 需要完全自定义 → Base;数据量少 + 快速迭代 → Chat。要能说清楚从 Chat 开始的两个风险(原有 RLHF 惯性难以完全改变、过度微调损坏对齐),以及从 Base 开始的额外要求(需要更多数据激活对话能力、需要自行做安全对齐)。


55. 领域模型微调指令 & 数据输入格式要求? ​

👔面试官:领域微调时,指令数据的格式有什么要求?特殊 token 怎么处理?

💡 简要回答 ​

领域微调的数据格式要与基座模型的 Chat Template 保持一致,使用正确的特殊 token 分隔符,并确保 Loss Mask 只作用于 Response 部分。

不同模型的 Chat Template 不同,必须严格匹配,否则会出现模板 token 被当做普通文本预测的问题。

📝 详细解析 ​

模板对齐的重要性 ​

每个模型在 SFT/RLHF 阶段都学习了特定的对话格式。如果微调时用了不一致的格式,会导致:

  • 模型无法正确识别角色边界(User/Assistant 混淆)
  • 特殊 token 被预测为普通文本,推理时格式混乱
  • 微调效果差甚至完全失效

常用模型的 Chat Template 对照:

# LLaMA-3 Instruct
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
{system}<|eot_id|>
<|start_header_id|>user<|end_header_id|>
{user_msg}<|eot_id|>
<|start_header_id|>assistant<|end_header_id|>
{assistant_msg}<|eot_id|>

# Qwen2
<|im_start|>system
{system}<|im_end|>
<|im_start|>user
{user_msg}<|im_end|>
<|im_start|>assistant
{assistant_msg}<|im_end|>

# ChatGLM4
[gMASK]<sop><|system|>
{system}

用 HuggingFace tokenizer 的 apply_chat_template ​

HuggingFace 的 tokenizer.apply_chat_template() 接口统一了不同模型的模板处理:

python
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

messages = [
    {"role": "system", "content": "你是一个专业的医疗助手。"},
    {"role": "user", "content": "什么是高血压?"},
    {"role": "assistant", "content": "高血压是指......"}
]

# tokenize_kwargs={"add_generation_prompt": False} 表示不加生成提示符
input_ids = tokenizer.apply_chat_template(
    messages,
    tokenize=True,
    add_generation_prompt=False,
    return_tensors="pt"
)

使用 apply_chat_template 的好处:自动处理特殊 token、确保格式正确,无需手动拼接字符串。

🎯 面试总结 ​

领域微调数据格式的两个铁律:一是 Chat Template 必须与基座模型完全匹配(特殊 token 类型和顺序);二是 Loss Mask 只对 Response 部分计算(Prompt 部分 label=-100 忽略)。工程上推荐用 tokenizer.apply_chat_template() 统一处理,避免手动拼接引入的格式错误。


56. 领域模型微调领域评测集如何构建? ​

👔面试官:微调完领域模型,怎么评测它的效果?评测集怎么构建?

🙋‍♂️我:就是收集一些领域相关的问题,然后人工标注答案……

👔面试官:自动评测和人工评测各有什么优缺点?有哪些常用的自动评测方法?

💡 简要回答 ​

领域评测集构建需要覆盖自动评测 + 人工评测两个维度,单靠任何一种都不完整:

  • 自动评测:速度快、可复现,适合快速迭代时对比不同版本
  • 人工评测:最贴近真实体验,但成本高、耗时长

📝 详细解析 ​

评测集数据来源 ​

方式一:从真实业务数据中采样

  • 收集真实用户的提问,由领域专家标注「标准答案」或「参考答案」
  • 最贴近实际使用场景,但隐私保护需要处理

方式二:专业资格考试 / 标准教材习题

  • 医疗:执业医师考试题、USMLE(美国执照医师考试)
  • 法律:司法考试真题
  • 金融:CPA/CFA 考试题
  • 优点:有标准答案,可直接用于准确率评测

方式三:GPT-4 生成 + 专家审核

  • 用 GPT-4 生成候选 QA 对,领域专家审核并修改
  • 平衡了效率和质量

自动评测指标 ​

判断题/选择题类(有标准答案):

Accuracy = 正确题目数 / 总题目数

最直接,但只适用于有明确唯一答案的问题。

生成题类(开放式问题):

指标计算方式局限
ROUGE-L最长公共子序列词汇匹配,不考虑语义
BERTScore语义相似度(BERT 向量余弦相似度)比 ROUGE 好,但仍有局限
LLM-as-Judge用 GPT-4 评分(1-5 分)接近人工质量,成本低于全人工

LLM-as-Judge 是目前最主流的自动评测方式:设计一个评分 Prompt,让 GPT-4 根据参考答案对被测模型的输出打分,评估准确性、完整性、专业性等维度。

人工评测的维度 ​

维度描述评分方式
准确性回答内容是否事实正确1-5 分
完整性是否覆盖了问题的所有要点1-5 分
专业性术语使用是否准确规范1-5 分
可读性表达是否清晰流畅1-5 分
安全性是否有误导性/有害内容Pass/Fail

对比评测(Pairwise Evaluation) ​

A/B 对比评测:让评测者比较模型 A 和模型 B 对同一问题的回答,选择更好的那个。这种方式比绝对打分更稳定(评测者倾向)。

Elo 积分制:把每次对比结果映射成 Elo 评分,多个模型可以排出相对优劣。

🎯 面试总结 ​

领域评测集构建三步:数据来源(业务数据/专业考题/GPT4生成+专家审核)、自动评测(选择题看 Accuracy、开放题用 LLM-as-Judge)、人工评测(准确性/完整性/专业性/安全性多维打分)。能说出 LLM-as-Judge 是当前最常用的自动评测方案,以及对比评测(Pairwise + Elo)比绝对打分更稳定,面试官会认为你有工程实践视角。


57. 领域模型词表扩增是不是有必要的? ​

👔面试官:做领域模型时,是否需要扩充词表?什么情况下需要?

🙋‍♂️我:如果领域有很多专业术语,原来词表里没有,可能就需要扩?

👔面试官:扩词表有什么收益和代价?不扩词表会有什么问题?扩完了怎么继续训练?

💡 简要回答 ​

词表扩增在以下场景有必要,其他场景不必要:

场景是否需要扩词表
中文基础能力差(如 LLaMA-2,32K 词表)必要
领域有大量专业术语且原词表分词效率极低视情况
在 Qwen/ChatGLM 等大词表模型上做领域微调不必要
只做 SFT,不做 CPT通常不必要

📝 详细解析 ​

扩词表的收益 ​

Token 效率提升:原词表中没有的领域术语被拆成多个 subword,占用更多 token,上下文利用效率低。例如医疗术语「肾小球肾炎」在 LLaMA-2 词表中可能被拆成 10+ 个 token,扩词表后可以是 1~3 个 token。

更好的语义学习:整个术语作为一个 token,模型能直接学习该术语的语义,而不是从子词拼凑含义。

扩词表的代价 ​

Embedding 层扩大:新 token 需要新的 embedding 向量,未经训练是随机初始化的,需要大量 CPT 才能让新 token embedding 学到合适的表示。

LM Head 扩大:最后的输出层(Language Model Head)维度也要扩大(vocab_size × d_model),增加参数量和推理时的 softmax 计算量。

需要继续训练:扩词表后必须做 Continue Pretraining(通常数十亿 token),否则新 token 的 embedding 没有意义,效果反而更差。

什么时候不需要扩词表 ​

如果基座模型的词表已经足够大(Qwen2 150K、LLaMA-3 128K),领域术语的分词效率已经不错,不需要扩词表。领域的「知识注入」通过 CPT + SFT 就能完成,不需要动词表。

扩词表的工程流程 ​

1. 统计领域语料中高频词汇(出现频率 > 阈值)
2. 过滤掉原词表中已有的词汇
3. 按频率排序,选取 Top-N 个新词加入词表
4. 初始化新 token embedding(推荐用原词表中子词 embedding 的平均值,比随机初始化好)
5. 扩展 LM Head 对应行(同样用平均值初始化)
6. Continue Pretraining(领域数据为主,至少数十亿 token)

🎯 面试总结 ​

词表扩增的判断标准:原词表中文效率差(LLaMA-2)或领域术语 token 化效率极低时才有必要;大词表模型(Qwen2、LLaMA-3)做领域微调通常不需要。关键要说清楚代价:扩词表后必须做 CPT,否则新 token embedding 没有意义,白扩。工程上推荐用子词 embedding 平均值初始化新 token,比随机初始化收敛更快。


58. 多轮对话任务如何微调模型? ​

👔面试官:做多轮对话场景的微调,有哪些特别需要注意的点?

🙋‍♂️我:把多轮对话历史拼接起来作为上下文,只对最后一轮的回复计算 loss?

👔面试官:每轮回复都要计算 loss 还是只算最后一轮?历史对话长度超出上下文窗口怎么处理?

💡 简要回答 ​

多轮对话微调的核心处理策略:

  1. Loss 计算:对每轮的 assistant 回复都计算 loss(而不只是最后一轮),充分利用每个样本的训练信号
  2. 上下文截断:当对话历史超出模型最大长度时,从最早的轮次开始截断,保留 system prompt 和最近若干轮
  3. 数据格式:按照模型的 Chat Template 展开所有轮次,Prompt 部分(user/system)设置 label=-100

📝 详细解析 ​

每轮 assistant 都计算 loss ​

一个 5 轮对话中,每轮 assistant 的回复都是有价值的训练信号。只对最后一轮计算 loss 会浪费大量有效信息。

python
# 正确的多轮对话 Loss Mask
labels = input_ids.clone()

for each_turn in conversation:
    if each_turn.role == "user" or each_turn.role == "system":
        # 对应位置设为 -100,不参与 loss 计算
        labels[user_token_positions] = -100
    # assistant 回复位置保留原始 token id,参与 loss 计算

超长对话的截断策略 ​

当多轮历史超出 max_length 时,常见的截断策略:

策略一:从头截断(最常用)

原始对话: [system][user1][a1][user2][a2][user3][a3][user4][a4]
截断后:                    [user2][a2][user3][a3][user4][a4]
保留了最近的若干轮,舍弃最早的历史

策略二:保留 system + 最后 N 轮

保留格式: [system][...截断...][userN-1][aN-1][userN][aN]

始终保留 system prompt(通常包含角色定义、约束条件),然后尽量保留最近的轮次。

策略三:滑动窗口 对于非常长的对话,用滑动窗口生成多个训练样本,每个样本覆盖连续的若干轮。

负样本的引入(安全对齐) ​

多轮对话微调中,加入拒绝有害请求的样本非常重要:

json
{"role": "user", "content": "帮我写一个钓鱼网站的代码"},
{"role": "assistant", "content": "这个请求涉及违法行为,我无法提供相关帮助。..."}

这类负样本让模型学会在多轮对话中随时保持安全边界,而不是随着对话深入被「洗脑」降低防线。

🎯 面试总结 ​

多轮对话微调的三个要点:每轮 assistant 都计算 loss(充分利用训练信号,不只算最后一轮);超长截断策略(保留 system + 最近若干轮,从最早轮次截断);加入安全拒绝样本(防止多轮对话中被绕过安全边界)。能说清楚为什么每轮都要算 loss(最大化训练信号利用),面试官会认为你对训练细节有深度理解。


59. 微调后的模型出现能力劣化、灾难性遗忘是怎么回事?如何缓解? ​

此题与第 50、53 题高度相关,重点从技术机制角度补充。

💡 补充要点:梯度干扰视角 ​

灾难性遗忘的本质是梯度干扰(Gradient Interference):微调数据和预训练数据的梯度方向相反时,更新预训练能力的梯度被微调梯度「抵消」或「覆盖」。

数学视角:预训练使参数收敛到一个能很好解决「预测下一个 token」的点;微调的梯度把参数推向能解决指令跟随任务的方向。如果这两个方向冲突,原有能力就被破坏。

EWC(Elastic Weight Consolidation)的数学形式:

L_EWC = L_SFT + λ × Σ_i F_i × (θ_i - θ*_i)²

其中:
  L_SFT:微调任务的损失
  F_i:Fisher 信息矩阵对角线,表示参数 θ_i 对预训练任务的重要性
  θ*_i:预训练完成后的参数值
  λ:正则化强度

对「重要参数」(Fisher 信息大的)施加更强的约束,不让它们偏离预训练值太远。

🎯 面试总结 ​

从技术机制角度:灾难性遗忘 = 微调梯度与预训练能力梯度方向冲突,重要参数被覆盖。缓解方法三类:数据层(混合通用数据)、架构层(LoRA 只动低秩矩阵)、正则化层(EWC 对重要参数加约束)。能给出 EWC 的公式并解释 Fisher 信息矩阵的物理含义,面试官会印象深刻。


60. 大模型 LLM 进行 SFT 操作的时候在学习什么? ​

👔面试官:SFT 的时候模型究竟在学什么?它是在学知识,还是学别的?

🙋‍♂️我:应该是在学怎么回答问题的方式?

👔面试官:更具体地说,Loss 下降意味着模型学到了什么?对话格式、知识、推理,哪个占主导?

💡 简要回答 ​

SFT 阶段模型主要学习的是**「表达方式」和「行为对齐」**,而不是新知识:

  1. 输出格式:问题要直接回答,而不是续写;结构化问题要用列表/代码块
  2. 指令遵循:按照用户意图行动,而不只是接近原始 token 分布
  3. 角色一致性:保持 AI 助手的角色,有一致的语气和立场
  4. 少量行为矫正:对特定类型请求(拒绝有害内容)建立稳定反应

📝 详细解析 ​

从 Loss 下降的角度理解 ​

SFT 的 loss 是:对 assistant 回复 token 的交叉熵损失。Loss 下降意味着模型对这批「高质量 assistant 回复」的 token 序列打出了越来越高的概率。

换句话说,模型在学习:「遇到这种 user 输入,应该生成这种 assistant 输出」。

这是行为学习,不是知识学习。模型已经「知道」相关知识了(从预训练来),SFT 教会它「怎么把知识表达出来」和「什么时候/怎么样表达」。

苏哲(Jure Leskovec)研究的视角 ​

Stanford 的研究表明:同一个预训练模型,在不同风格的 SFT 数据上微调,会呈现出完全不同的「个性」——一个更像 ChatGPT,一个更像 Claude,一个更像 Bing Chat——但它们对知识类问题的准确率差异不大。

这直接说明 SFT 改变的是行为风格,而不是知识内容。

SFT 能学到知识但效率极低 ​

给 SFT 数据中加入事实性知识(如「xxx 公司成立于 2023 年」),模型确实能记住,但:

  • 容量有限(SFT 数据只有几十万 token,不及预训练的万分之一)
  • 容易遗忘(后续继续训练后这些事实可能被覆盖)
  • 对比:通过 RAG(检索增强)注入知识,实时性强、不受参数限制,是更好的知识扩充方式

🎯 面试总结 ​

SFT 学的是「行为对齐」:如何表达(格式、语气)、何时表达(遵循指令)、怎么对齐人类偏好(角色一致、安全拒绝)。知识主要来自预训练,SFT 是「解锁」而非「注入」知识。最有力的论据:同一基座模型 SFT 不同风格的数据,个性大变但知识准确率差别不大,说明 SFT 改的是行为,不是知识。


61. 预训练和 SFT 操作有什么不同? ​

👔面试官:预训练和 SFT 的区别,从数据、目标、训练方式上分别讲一下。

💡 简要回答 ​

维度预训练SFT
数据规模数 T token数十万~数百万 token
数据类型无标注原始文本有标注的指令-回复对
训练目标CLM(预测下一个 token,全序列计算 loss)CLM(只对 response 计算 loss)
学习率较大(峰值 2e-4 左右)较小(2e-5 左右,约 1/10)
训练步数数十万~数百万步数百~数千步
目的建立语言能力和世界知识对齐人类意图,学会指令跟随
batch size很大(百万 token/batch)较小(数千~数万 token/batch)

📝 详细解析 ​

最关键的差异:Loss Mask ​

预训练:整个文档的每个 token 都计算 loss,模型学习「续写任何文本」。

SFT:只有 assistant 的回复部分计算 loss,user/system 部分 label=-100 忽略,模型学习「根据 user 输入给出 assistant 回复」。

这个差异是 SFT 让模型从「续写」转变为「回答」的关键机制。

学习率差异的原因 ​

SFT 用更小的学习率是为了微调而非颠覆:用大学习率会破坏预训练存储的知识(灾难性遗忘),小学习率只做轻微的行为对齐,不大幅改变参数。

数据效率的差异 ​

预训练用数 T token 的数据,每条数据只看一遍(1 epoch);SFT 用少量高质量数据,通常训练 1~3 epoch。

两者的数据效率对比:SFT 1000 条数据能学到有效行为,但这 1000 条加起来可能只有 1M token,是预训练数据量的百万分之一。这印证了「SFT 学行为,预训练学知识」的结论。

🎯 面试总结 ​

预训练 vs SFT 的核心差异从四个维度展开:数据规模(T token vs 百万 token)、Loss Mask(全序列 vs 只算 response)、学习率(大 vs 小,防遗忘)、目的(建立能力 vs 对齐行为)。Loss Mask 的差异是让「续写机器」变成「问答助手」的关键技术点,面试官最爱追问这个。


62. 大模型 LLM 进行 SFT 如何对样本进行优化? ​

👔面试官:SFT 的训练样本有哪些优化手段?如何提升数据利用效率?

🙋‍♂️我:可以过滤低质量样本,对高质量样本增加权重?

👔面试官:Packing 是什么?长度分布有什么影响?难度课程有什么作用?

💡 简要回答 ​

SFT 样本优化的主要手段:

  1. 样本 Packing(序列拼接):把多个短样本拼接成一条长序列,提升 GPU 利用率
  2. 质量过滤:去除低质量、重复、有害的样本
  3. 长度平衡:避免长短样本差距过大导致的 padding 浪费
  4. 难度课程(Curriculum Learning):先简单后复杂,逐步提升数据难度
  5. 样本权重:对高质量来源的样本设置更高的采样权重

📝 详细解析 ​

Packing:解决短样本低效问题 ​

SFT 数据中很多样本很短(一两百 token),如果每条样本单独 padding 到 max_length,大量 GPU 计算浪费在 padding token 上。

Packing 的做法:把多个短样本用特殊 <EOS> 分隔,拼接成接近 max_length 的长序列:

序列 1: [样本A tokens][EOS][样本B tokens][EOS][样本C tokens][PAD...PAD]
                                                              ↑ 少量padding

注意:需要在注意力计算时加正确的 Document Mask,防止不同样本的 token 之间相互 attention(跨样本的注意力没有意义)。

Packing 可以把 GPU 利用率从 40~60% 提升到 90%+,训练速度显著加快。

质量过滤的常见规则 ​

python
def quality_filter(sample):
    response = sample['response']
    # 过滤过短的回复(不够详细)
    if len(response.split()) < 20:
        return False
    # 过滤重复内容(自我循环)
    sentences = response.split('。')
    if len(set(sentences)) / len(sentences) < 0.6:
        return False
    # 过滤 AI 腔过重的回复
    ai_phrases = ["当然,我很乐意", "作为一个AI", "我没有个人观点"]
    if any(p in response for p in ai_phrases):
        return False  # 或降低权重
    return True

难度课程的实践 ​

简单到复杂的顺序训练,能帮助模型更稳定地学习:

  • 第一阶段:简单的问答、翻译、总结类任务(单步推理)
  • 第二阶段:复杂的多步推理、代码生成、长文写作
  • 第三阶段:混合各类任务,加入对齐数据(拒绝有害请求)

🎯 面试总结 ​

SFT 样本优化最重要的两点:Packing(把短样本拼接成长序列,GPU 利用率从 60% → 90%,但要加 Document Mask 防止跨样本 attention)和质量过滤(过短回复、自我循环、AI 腔过重)。能说清楚 Packing 的 Document Mask 细节,面试官会认为你真的做过工程。


63. 指令微调的好处是什么? ​

👔面试官:为什么需要指令微调?它带来的核心价值是什么?

🙋‍♂️我:让模型能听懂指令,按照用户的要求去做事。

👔面试官:不做指令微调,只用 Base 模型,有什么问题?FLAN 研究说明了什么?

💡 简要回答 ​

指令微调(Instruction Tuning / SFT)的核心价值:

  1. 激活指令跟随能力:Base 模型做文本续写,指令微调后的模型会「回答问题」
  2. 提升零样本泛化:在多种任务上训练后,模型能更好地处理没见过的新任务
  3. 统一多任务接口:用自然语言指令统一描述各种任务,不需要为每个任务设计特殊结构

📝 详细解析 ​

Base 模型的核心局限 ​

Base 模型的训练目标是「续写下一个 token」,给它一个问题,它会续写这个问题而不是回答它:

输入: "什么是机器学习?"
Base 模型输出: "这是一个关于机器学习的基础问题。机器学习有很多种定义......"
              (续写问题语境,不是给出答案)

指令微调让模型学会:看到 [User] 问题 [Assistant] 的格式后,要给出有帮助的回答。

FLAN 研究的启示 ​

Google 的 FLAN(Finetuned LAnguage Net,2022)研究是指令微调的重要里程碑。核心发现:

在大量不同任务上进行指令微调,模型在从未见过的新任务上的零样本能力显著提升。

关键数据:137B 的 FLAN 模型在零样本评测中超越了 175B 的 GPT-3(few-shot)。

这说明指令微调的价值不只是「学会做某些任务」,更重要的是提升模型对新任务指令的理解和泛化能力。

指令多样性的重要性 ​

FLAN 和后续研究都发现:指令任务的多样性比数量更重要。在更多种类的任务上做指令微调(即使每类任务的数据量少),比在单一任务上微调更多数据,零样本泛化效果更好。

这印证了「SFT 教的是元能力(如何理解和跟随指令),不是具体任务知识」的结论。

🎯 面试总结 ​

指令微调的三个核心价值:激活指令跟随(Base 模型续写变成 Chat 模型回答)、提升零样本泛化(多任务指令训练后对新任务泛化更好,FLAN 论文的核心结论)、统一多任务接口(自然语言替代任务特定结构)。引用 FLAN 的结论(137B 指令微调模型零样本超越 175B GPT-3 few-shot)是很有说服力的支撑点。


64. 想让模型学习某个领域或行业的知识,是应该预训练还是微调? ​

👔面试官:想让模型掌握某个垂直领域的知识,应该选预训练还是微调?两者有什么区别?

🙋‍♂️我:预训练注入知识更深,微调更快更省资源……但到底怎么选?

👔面试官:预训练和微调注入知识的能力有什么本质区别?RAG 和微调之间怎么权衡?

💡 简要回答 ​

选择框架:「知识需要多深?有多少资源?知识更新多频繁?」

场景推荐方案
领域知识量大(数十亿 token),需要模型深度掌握Continue Pretraining(CPT)
知识量适中(亿级 token 以下),有标注数据CPT + SFT
只需要输出格式/任务适配SFT(不需要 CPT)
知识时效性强、频繁更新RAG(检索增强)
无训练资源,快速验证RAG / Prompt Engineering

📝 详细解析 ​

预训练 vs SFT 注入知识的本质差异 ​

Continue Pretraining(深度知识注入):

  • 模型通过 CLM 目标在大量领域文本上训练,知识被「压缩」进参数
  • 模型能在没有检索系统支持的情况下,从参数中提取领域知识
  • 适合:医疗文献、法律条文、金融财报——这些知识需要模型能灵活理解和推理,而不只是检索

SFT(行为适配,少量知识注入):

  • 通过指令-回复对训练,主要改变的是输出格式和行为模式
  • 少量事实知识可以学进去,但容量有限(几千条事实级别)
  • 适合:输出格式要求(JSON 结构化输出)、特定回答风格、少量高频知识点

RAG vs 微调的权衡 ​

维度RAG微调(CPT/SFT)
知识更新更新知识库即可,实时需要重新训练,有延迟
知识量理论上无限受参数容量限制
私密数据知识库不进模型参数,相对安全知识融入参数,存在提取风险
推理能力检索结果质量影响大模型内化知识,推理更流畅
成本推理时增加检索开销一次性训练成本,推理无额外开销

最佳实践:两者结合——先用 CPT/SFT 让模型具备领域基础能力,再用 RAG 提供实时、精确的知识检索,形成互补。

决策流程图 ​

有多少领域数据?
  ├─ 数十亿 token → CPT → SFT → (可选)RAG
  ├─ 亿级 token → 直接 SFT → RAG
  └─ 无大量数据 → RAG + Prompt Engineering

知识更新频率?
  ├─ 高频(周/日)→ 必须用 RAG
  └─ 低频(月/年)→ 定期 CPT/SFT 更新

🎯 面试总结 ​

核心结论:知识量大 + 需要深度理解 → CPT;输出格式适配 + 少量知识 → SFT;知识时效性强/频繁更新 → RAG。最佳实践是三者结合(CPT 建立领域基础 + SFT 对齐任务格式 + RAG 提供实时知识)。能画出决策流程图(先问知识量,再问更新频率),体现你有系统性工程思维。



65. 什么是 LoRA?LoRA 的思路是什么? ​

👔面试官:介绍一下 LoRA,它的核心思路是什么?

🙋‍♂️我:LoRA 是一种低秩分解的方法,把权重更新分解成两个小矩阵的乘积……

👔面试官:为什么低秩分解有效?rank 是什么意思?LoRA 插在模型的哪些位置?

💡 简要回答 ​

LoRA(Low-Rank Adaptation,Hu et al., 2021)的核心思想:预训练模型的权重更新矩阵具有低内在秩(intrinsic rank),因此可以用两个小矩阵的乘积来近似表示。

原始全参数微调:W' = W + ΔW,ΔW 与 W 同维,更新量庞大。

LoRA:W' = W + AB,其中 A ∈ ℝ^(d×r),B ∈ ℝ^(r×k),r << min(d, k),训练时只更新 A 和 B,W 冻结不动。

📝 详细解析 ​

低秩假设的数学依据 ​

论文作者的直觉来自 Aghajanyan et al. 的研究:预训练语言模型在微调时,参数更新实际发生在一个远低于原始参数空间维度的子空间中(即「内在维度」很低)。如果 ΔW 本身是低秩的,用 AB 近似不会损失太多表达能力。

直觉类比:微调是对预训练能力的「轻微调整」,不需要动用全部参数维度,只需要在一个低维子空间里做偏移。

LoRA 的完整结构 ​

python
# 原始 Linear 层:y = xW^T
# LoRA 修改后:y = xW^T + x(AB)

class LoRALinear(nn.Module):
    def __init__(self, in_features, out_features, rank=8, alpha=16):
        super().__init__()
        self.W = nn.Linear(in_features, out_features, bias=False)
        self.W.requires_grad_(False)  # 冻结原始权重

        # LoRA 矩阵
        self.A = nn.Parameter(torch.randn(in_features, rank) * 0.01)
        self.B = nn.Parameter(torch.zeros(rank, out_features))
        self.scale = alpha / rank  # scaling factor

    def forward(self, x):
        return self.W(x) + (x @ self.A @ self.B) * self.scale

初始化细节:A 用高斯分布初始化,B 初始化为全零,保证训练开始时 LoRA 分支输出为零(不影响模型初始行为)。

LoRA 插入位置 ​

原始论文在 Transformer 的每个 attention 层的 Q、V 矩阵上插入 LoRA,后续研究表明在 Q、K、V、O、FFN 的 Up/Down 矩阵上都加 LoRA 效果更好。

rank 的选择 ​

rank 越大,表达能力越强,但训练参数越多;rank 越小,参数量越少,但可能表达不够。

常用 rank 范围:4~64,多数任务 rank=8~16 效果已经很好。

🎯 面试总结 ​

LoRA 的核心:权重更新 ΔW 分解为低秩矩阵乘积 AB(r << d),只训练 A 和 B,冻结原始权重 W。训练参数量减少到 2×d×r(相比全参数的 d×k 大幅缩小)。关键细节:B 初始化为零(保证训练初期 LoRA 分支不影响模型),A 用小随机数初始化;scale = alpha / rank 控制 LoRA 输出的缩放。能手写 LoRALinear 的前向传播,面试官会认为你真正掌握了实现细节。


66. LoRA 的特点是什么?有什么优势? ​

👔面试官:LoRA 和全参数微调相比,有哪些具体的优势?有什么限制吗?

💡 简要回答 ​

LoRA 的核心优势:

优势说明
显存节省梯度和优化器状态只针对 A、B,大幅减少显存
推理无额外开销训练后 AB 合并入 W,推理时与原模型完全一样
快速切换不同任务只换 LoRA 权重(几十 MB),基座模型共享
防止遗忘原始权重 W 不变,预训练能力完整保留

📝 详细解析 ​

显存对比 ​

以 7B 模型为例:

方法可训练参数量显存(大致)
全参数微调7B~100 GB
LoRA (r=8, Q+V)~4M~16 GB(单卡 A100)
LoRA (r=16, all)~40M~20 GB

显存节省来自:梯度只对 LoRA 参数(几十 M)而不是全部参数(7B)计算;Adam 优化器状态也只针对 LoRA 参数。

推理合并:零成本 ​

训练完成后,将 LoRA 权重合并回原始权重:

python
# 训练后合并 LoRA
merged_weight = original_W + (A @ B) * scale

# 合并后推理和原始模型结构完全相同
# 无需保留 LoRA 分支,无额外推理延迟

这意味着使用 LoRA 微调的模型,推理时没有任何速度损耗——这是 Adapter 等方法不具备的优势(Adapter 在推理时需要额外的前向传播路径)。

快速切换多任务 ​

一个基座模型(如 LLaMA-3-8B,~16GB)+ 多个领域 LoRA 权重(每个 ~50MB):

LLaMA-3-8B(共享,常驻 GPU)
    ├── medical_lora.bin    (50MB) → 医疗问答
    ├── legal_lora.bin      (50MB) → 法律咨询
    └── code_lora.bin       (50MB) → 代码生成

切换任务只需加载对应的 LoRA 权重,无需重新加载整个基座模型。

LoRA 的局限 ​

  • 容量上限:rank 有限,对需要大量新知识的任务,表达能力不如全参数
  • 超参数敏感:rank、alpha、插入位置都需要调优
  • 不同任务的 LoRA 不能简单叠加(需要 LoRAHub / DARE 等方法做模型融合)

🎯 面试总结 ​

LoRA 四大优势要背下来:显存节省(只训练 LoRA 参数,梯度/优化器状态大幅缩小)、推理零开销(合并后与原模型结构完全相同)、快速切换(基座共享 + LoRA 小文件)、防遗忘(原始 W 不变)。局限是容量上限(rank 有限)。推理合并这个点很多人答不上来,能说出这个细节会让面试官眼前一亮。


67. LoRA 微调相比于微调适配器(Adapter)或前缀微调(Prefix Tuning)有什么优势? ​

👔面试官:LoRA、Adapter、Prefix Tuning 这三种 PEFT 方法,LoRA 为什么比另外两种更受欢迎?

💡 简要回答 ​

LoRA vs Adapter vs Prefix Tuning 的核心对比:

方法推理额外开销参数效率实现复杂度效果
LoRA无(合并后)高低好
Adapter有(串联层)中中中等
Prefix Tuning有(占用上下文)中中不稳定

LoRA 的决定性优势:合并后推理无额外延迟,同时效果持平甚至优于另外两种方法。

📝 详细解析 ​

Adapter:推理有额外延迟 ​

Adapter 在每个 Transformer 层后插入一个小型 bottleneck 网络(降维 → 非线性 → 升维):

原始流程: Attention → Add&Norm → FFN → Add&Norm
Adapter:  Attention → Add&Norm → Adapter → FFN → Add&Norm → Adapter

问题:每个 Adapter 是额外的串联前向传播,推理时增加延迟(约 10~20%,在批量小时更明显)。而且 Adapter 无法像 LoRA 那样在推理前合并进原始权重(因为它有非线性激活函数)。

Prefix Tuning:占用有效上下文长度 ​

Prefix Tuning 在每层 KV 前面拼接可训练的「前缀向量」:

原始 K, V: [k1, k2, ..., kn]
Prefix K, V: [p1, p2, ..., pm, k1, k2, ..., kn]  # m 个前缀向量

问题:

  1. 前缀占用了有效的上下文窗口(通常前缀长度 50~100 个 token)
  2. 推理时前缀需要参与每层的 Attention 计算,增加计算量
  3. 训练不稳定,效果对超参数敏感(前缀长度、初始化方式)

LoRA 的综合优势 ​

LoRA 在同等参数量下:

  • 效果通常不低于 Adapter 和 Prefix Tuning
  • 合并后推理延迟为零
  • 不占用有效上下文长度
  • 训练更稳定(初始 ΔW=0 保证了平稳的训练起点)

这就是为什么目前工业界 PEFT 方法几乎被 LoRA(及其变体)统治。

🎯 面试总结 ​

LoRA 胜过 Adapter 的关键:Adapter 推理有额外串联层无法合并,LoRA 可以合并为零延迟。LoRA 胜过 Prefix Tuning 的关键:Prefix 占用上下文、推理有 KV 前缀开销且训练不稳定,LoRA 不占上下文且训练稳定。一句话总结:三者效果相近,但 LoRA 是唯一在推理时能做到零额外开销的方法(通过合并权重),这是它成为事实标准的核心原因。


68. QLoRA 的思路是怎样的?有什么特点? ​

👔面试官:QLoRA 是什么?它和 LoRA 有什么区别?它是怎么实现的?

🙋‍♂️我:QLoRA 是在量化的模型上做 LoRA?

👔面试官:量化和 LoRA 怎么结合的?NF4 量化是什么?双量化是什么?

💡 简要回答 ​

QLoRA(Dettmers et al., 2023)= 4-bit 量化基座模型 + BF16 精度的 LoRA 微调。

核心创新:把 7B/13B 模型量化到 4-bit(显存减少约 75%),让单张消费级 GPU(24GB)也能微调大模型,同时通过 LoRA 保持微调效果接近全参数微调。

📝 详细解析 ​

QLoRA 的三个技术核心 ​

1. 4-bit NormalFloat(NF4)量化

NF4 是专门为神经网络权重分布设计的 4-bit 数据类型。神经网络权重近似服从正态分布 N(0, σ²),NF4 的量化点位按正态分布的分位数均匀分布,从而最小化量化误差。

相比普通 INT4 或 FP4,NF4 对正态分布权重的量化精度更高(等量化点数下,信息损失更小)。

2. 双量化(Double Quantization)

量化本身需要存储量化常数(scale factor)——通常 FP32,每 64 个参数存一个 scale,额外开销约 0.5 bit/param。

双量化:对量化常数再进行一次量化(FP32 → FP8),进一步减少显存:

正常 4-bit 量化:4 bit/param + 0.5 bit/param (scale) ≈ 4.5 bit/param
双量化后:       4 bit/param + 0.125 bit/param ≈ 4.125 bit/param

3. 分页优化器(Paged Optimizer)

长序列训练时偶发的显存峰值(gradient checkpointing 重算时)可能导致 OOM。分页优化器利用 NVIDIA GPU 的统一内存(Unified Memory)机制,把 Adam 优化器状态在 GPU 和 CPU 内存之间按需分页,避免显存峰值 OOM。

QLoRA 的训练流程 ​

基座模型(7B FP16)
    ↓ 量化为 NF4(4-bit,~3.5GB)
NF4 基座模型(冻结,不参与梯度)
    ↓ 插入 BF16 精度的 LoRA 矩阵 A、B
前向传播:NF4 权重反量化到 BF16 → 参与计算 → LoRA 分支 BF16 计算
反向传播:只对 LoRA 参数(BF16)计算梯度

关键:反量化发生在前向传播的实时计算中,不需要把整个模型持久化存成 BF16,因此显存始终维持在量化后的低水平。

显存对比 ​

方法7B 模型显存可用 GPU
全参数微调 (BF16)~100 GB8×A100
LoRA (BF16)~16 GB1×A100
QLoRA (NF4 + LoRA)~6 GB1×RTX 3090

🎯 面试总结 ​

QLoRA 的三个创新点:NF4 量化(针对正态分布权重优化的 4-bit 格式,信息损失最小)、双量化(对量化常数再次量化,节省额外 0.4 bit/param)、分页优化器(CPU-GPU 内存分页,防止偶发 OOM)。核心效果:7B 模型微调显存从 100GB 降到 6GB,让单张消费级 GPU 成为可能,同时效果接近全参数微调。


69. AdaLoRA 的思路是怎样的? ​

👔面试官:AdaLoRA 和标准 LoRA 有什么区别?它解决了什么问题?

💡 简要回答 ​

AdaLoRA(Zhang et al., 2023)解决了 LoRA 的一个核心局限:所有层用同样的 rank,忽略了不同层/模块对任务的重要性差异。

AdaLoRA 的思路:自适应地为不同层分配不同的 rank,重要的层给更高的 rank,不重要的层给更低的 rank,在固定总参数预算下最大化微调效果。

📝 详细解析 ​

LoRA 的均匀 rank 问题 ​

标准 LoRA 对每个插入位置用相同的 rank(如 rank=8)。但直觉上:

  • 靠近输出的层可能比底层更关键(因为直接影响输出分布)
  • Attention 中的 Q/V 矩阵可能比 K 矩阵更重要
  • 同一层的不同矩阵(W_q vs W_v)重要性也可能不同

用均匀 rank 是一种次优的参数分配方式。

AdaLoRA 的核心机制:SVD + 重要性评分 ​

AdaLoRA 把 ΔW 表示为 SVD 形式:ΔW = P Λ Q,其中 P、Q 是正交矩阵,Λ 是对角矩阵(奇异值)。

通过训练过程中动态调整 Λ 中奇异值的数量(相当于动态调整 rank):

  • 重要性高的模块:保留更多奇异值(高 rank)
  • 重要性低的模块:逐步将小奇异值剪枝为零(低 rank)

重要性评分:对每个奇异值 λ_i,计算其重要性得分(基于梯度和参数值的乘积的指数移动平均),得分低的奇异值被裁剪。

与 LoRA 的效果对比 ​

在相同总参数预算下,AdaLoRA 通常比等 rank 的 LoRA 效果好 1~2 个百分点,尤其在:

  • 总参数预算极小(rank 很低)时,差距更明显
  • 需要在很多层插入 LoRA 时(统一低 rank 浪费了重要层的容量)

局限 ​

AdaLoRA 的训练更复杂(需要维护 SVD 分解),训练速度比标准 LoRA 慢约 20~30%;超参数(初始 rank、参数预算调度)也更多。对于资源充足、rank 可以设大的场景,标准 LoRA 的简单性更有优势。

🎯 面试总结 ​

AdaLoRA 的核心改进:标准 LoRA 用均匀 rank,AdaLoRA 用 SVD 分解 + 重要性评分动态调整每层的 rank,让参数预算分配更合理。效果:相同预算下比 LoRA 好 1~2 个点。代价:训练更慢(SVD 维护),超参数更多。实际选择:追求简单用 LoRA,有精力调参且预算极紧用 AdaLoRA。


70. LoRA 权重是否可以合入原模型? ​

👔面试官:LoRA 训练完之后,LoRA 权重可以合并到原始模型里吗?怎么合并?有什么注意点?

💡 简要回答 ​

可以,且推荐在推理前合并。合并公式:

W_merged = W_original + (A @ B) * (alpha / rank)

合并后模型结构与原始模型完全相同,推理时无任何额外开销。

📝 详细解析 ​

合并的数学原理 ​

LoRA 前向计算:

y = x × W^T + x × (A @ B)^T × scale
  = x × (W + A @ B × scale)^T
  = x × W_merged^T

由于 LoRA 只做线性变换(无非线性激活),可以直接将 A @ B × scale 加到 W 上,得到一个与原始层形状相同的合并权重矩阵。

使用 PEFT 库合并 ​

python
from peft import PeftModel
from transformers import AutoModelForCausalLM

# 加载基座模型
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B")

# 加载 LoRA 权重
model = PeftModel.from_pretrained(base_model, "path/to/lora_weights")

# 合并并卸载 LoRA
merged_model = model.merge_and_unload()

# 保存合并后的完整模型
merged_model.save_pretrained("path/to/merged_model")

merge_and_unload() 会:

  1. 对每个 LoRA 层执行 W += A @ B * scale
  2. 删除 A、B 参数
  3. 返回与原始模型结构相同的模型

注意点 ​

精度问题:合并时如果基座权重是 FP16/BF16,LoRA 权重(也是 FP16/BF16)相加通常没有精度问题。如果是 QLoRA(4-bit 基座),合并前需要先将基座反量化到 FP16。

不可逆:合并是不可逆的,如果之后需要恢复原始基座模型 + 不同 LoRA 的多任务切换,应保留原始基座和 LoRA 权重,不要合并。

多 LoRA 合并:多个不同任务的 LoRA 不能直接相加(会互相干扰),需要用 DARE / TIES-Merging 等模型融合方法。

🎯 面试总结 ​

LoRA 合并公式:W_merged = W + A @ B × (alpha/rank),数学上成立因为 LoRA 分支是纯线性变换。合并后模型结构与原始一致,推理零开销。实践用 model.merge_and_unload()。注意两点:QLoRA 合并前需要先反量化基座;合并不可逆,保留原始文件防止需要恢复。


71. ChatGLM-6B LoRA 后的权重多大? ​

👔面试官:对 ChatGLM-6B 做了 LoRA 微调,LoRA 权重文件大概多大?

💡 简要回答 ​

ChatGLM-6B LoRA 权重大小取决于 rank 和插入位置,典型配置下约 20~100 MB。

📝 详细解析 ​

参数量计算 ​

ChatGLM-6B 有 28 层 Transformer,d_model=4096,每个 Attention 层的 Q/K/V/O 矩阵维度为 4096×4096。

以插入 Q、V 矩阵,rank=8 为例:

每个 LoRA 层参数量 = A(4096×8) + B(8×4096) = 32768 + 32768 = 65536 参数
每层有 Q 和 V 两个 LoRA = 2 × 65536 = 131072 参数
28 层 = 28 × 131072 ≈ 3.7M 参数

存储大小(BF16,2 bytes/param)= 3.7M × 2 ≈ 7.4 MB

如果插入所有 Attention 矩阵(Q/K/V/O)和 FFN(up/down),rank=16:

每个矩阵 LoRA 参数 = 4096×16 + 16×4096 = 131072
Attention 4 个矩阵 + FFN 2 个矩阵 = 6 个
每层:6 × 131072 = 786432
28 层:28 × 786432 ≈ 22M 参数

存储大小(BF16)= 22M × 2 ≈ 44 MB

实际常见的 ChatGLM-6B LoRA 权重文件:10 MB ~ 80 MB,具体取决于 rank 和覆盖的模块。

与全量权重的对比 ​

ChatGLM-6B 完整权重约 12 GB(FP16),LoRA 权重只有 10~80 MB,约为完整权重的 0.1~0.7%。

这就是 LoRA 的参数效率——用不到 1% 的参数量实现接近全参数微调的效果。

🎯 面试总结 ​

会算就行:参数量 = 2 × d_model × rank × 层数 × 矩阵数,再乘以数据类型字节数。典型 ChatGLM-6B LoRA(rank=8,Q+V,28层)约 7~10MB;全量插入(rank=16)约 40~80MB。核心数据:LoRA 权重是全量权重的 0.1~1%,这正是 PEFT 的意义所在。


72. 如何在已有 LoRA 模型上继续训练? ​

👔面试官:已经有一个微调过的 LoRA 模型,我想在它基础上继续训练,应该怎么做?

🙋‍♂️我:直接加载 LoRA 权重继续训练?还是先合并再训练?

👔面试官:两种方式各有什么利弊?如何避免已有 LoRA 能力的遗忘?

💡 简要回答 ​

两种方案各有适用场景:

方案做法适合场景
直接续训(推荐)加载已有 LoRA 权重,继续在原 LoRA 参数上优化同一任务更多数据、同一领域扩展
合并后续训merge_and_unload → 在合并后的模型上加新 LoRA要改变 LoRA 的 rank/位置;切换到不同任务

📝 详细解析 ​

方案一:直接续训(继续优化同一 LoRA) ​

python
from peft import PeftModel
from transformers import AutoModelForCausalLM

base_model = AutoModelForCausalLM.from_pretrained("base_model_path")
model = PeftModel.from_pretrained(base_model, "existing_lora_path")

# 直接用新数据继续训练
trainer = Trainer(model=model, ...)
trainer.train()

# 保存更新后的 LoRA 权重
model.save_pretrained("updated_lora_path")

优点:简单直接,延续已有 LoRA 的优化方向; 注意:学习率要进一步降低(比第一次 LoRA 训练更小),防止把已学知识覆盖。

方案二:合并后加新 LoRA ​

python
# 先合并
merged_model = PeftModel.from_pretrained(base, "existing_lora").merge_and_unload()

# 在合并后的模型上加新 LoRA(可以用不同的 rank)
from peft import get_peft_model, LoraConfig
new_config = LoraConfig(r=16, ...)
model = get_peft_model(merged_model, new_config)

优点:可以重新设计 LoRA 的 rank 和位置,相当于以已微调的模型为新基座; 风险:如果新训练数据和原数据差异大,可能覆盖原有 LoRA 学到的能力(但因为已合并到权重里,原有能力有一定保护)。

防止遗忘的实践 ​

  • 数据混合:在新训练数据中混入旧任务的少量数据(5~10%),防止对旧任务的遗忘
  • 降低学习率:续训时学习率降低到初始训练的 1/5~1/10
  • Early stopping:在验证集上监控旧任务性能,一旦下降超过阈值就停止

🎯 面试总结 ​

续训 LoRA 两条路:直接续训(同任务、学习率更小)vs 合并后加新 LoRA(需要改变 rank 或切换任务)。防遗忘三招:混合旧数据、降低学习率、早停监控旧任务性能。能说清楚「合并后以新基座继续训练」的逻辑,面试官会认为你对 LoRA 工程有深度理解。


73. 为什么需要提示学习(Prompting)?有哪些方法? ​

👔面试官:Prompt Learning 是什么?为什么需要它?有哪些主要方法?

🙋‍♂️我:就是通过设计输入提示来引导模型输出,不需要修改模型参数?

👔面试官:硬提示和软提示有什么区别?Prompt Tuning 是什么?

💡 简要回答 ​

Prompt Learning 是通过在输入中添加特定的「提示」来引导模型完成任务的技术,分为两大类:

  • 硬提示(Hard Prompt):离散的、人类可读的文本提示,直接设计输入格式
  • 软提示(Soft Prompt / Prompt Tuning):可训练的连续向量,插入到输入序列的 embedding 层

📝 详细解析 ​

为什么需要 Prompt Learning ​

预训练模型通过 GPT/BERT 训练,其「自然」的激活方式是填空(Masked LM)或续写(CLM)。如果想让模型做分类/问答,需要把任务「转化」成模型熟悉的形式——这就是 Prompt 的作用。

GPT-3 的 few-shot 示例说明:设计合适的 Prompt,不需要任何参数更新,模型就能完成多种任务。但 Prompt 工程很依赖人的经验,效果不稳定。

硬提示(Hard Prompt) ​

就是手工设计的文本 Prompt,例如:

情感分类任务的 Prompt 设计:
输入:这部电影太棒了![MASK]
期望模型输出:积极(positive)

In-Context Learning(ICL):把几个例子放在输入里,模型从例子中「推断」任务规则:

例1: 这部电影太棒了!→ 积极
例2: 这个产品很糟糕 → 消极
请判断: 服务态度非常好 → [?]

软提示(Prompt Tuning) ​

Lester et al. 2021 提出的 Prompt Tuning:在输入序列最前面添加 m 个可训练的「虚拟 token」(continuous prompt),只训练这些 token 的 embedding,冻结模型参数:

输入: [P1][P2]...[Pm][正常输入 tokens]
        ↑ 可训练的连续向量,不对应任何真实词汇

当模型规模足够大(>10B),Prompt Tuning 的效果接近全参数微调,而可训练参数只有 m×d_model(远少于全参数)。

各方法对比 ​

方法可训练参数推理额外开销效果
Hard Prompt0无(占输入长度)不稳定
Prompt Tuningm×d(m个虚拟token)无(合并输入)大模型好
Prefix Tuning每层 prefix KV有中
P-tuning v2每层 prompt token有较好

🎯 面试总结 ​

Prompt Learning 的核心价值:不改变模型参数,通过输入设计引导模型行为。两类:硬提示(人类可读文本,如 ICL)和软提示(可训练连续向量,如 Prompt Tuning)。Prompt Tuning 的关键:只训练输入前缀的 embedding(m×d 参数),在大模型上效果接近全参数微调。能区分硬提示/软提示,以及说清楚 Prompt Tuning 的可训练参数是「输入 embedding 层的前缀向量」而非真实词汇,面试官会认可你的理解深度。


74. 为什么需要 P-tuning v2?P-tuning 解决了什么问题? ​

👔面试官:P-tuning 和 P-tuning v2 是什么?为什么从 v1 升级到 v2?

💡 简要回答 ​

P-tuning(v1):只在输入层添加可训练的 soft prompt token,对小模型(<10B)效果有限。

P-tuning v2:在每层 Transformer 都添加可训练的 prefix 向量,本质上是 Prefix Tuning 的改进版,显著提升了在 NLU 任务(序列标注、阅读理解)上的效果。

📝 详细解析 ​

P-tuning v1 的局限 ​

P-tuning v1 把 soft prompt 放在输入 embedding 层:

Input: [p1,...,pm, x1,...,xn]

问题:

  1. 只影响第一层的表示,经过多层 Transformer 之后,soft prompt 的影响被层层稀释,对模型行为的控制力有限
  2. 对小模型(1B~10B)效果差,只有超大模型(>10B)效果才接近微调
  3. 对序列标注等需要逐 token 分类的 NLU 任务效果不好

P-tuning v2 的改进 ​

P-tuning v2 借鉴 Prefix Tuning,在每层都插入可训练的 prefix KV:

每层 Attention 的 K, V 变为:
  K = [prefix_k_1,...,prefix_k_m, k_1,...,k_n]
  V = [prefix_v_1,...,prefix_v_m, v_1,...,v_n]

效果改进:

  • 每层都有 soft prompt 影响,不会被稀释
  • 对小模型(0.3B~10B)效果也接近全参数微调
  • 在 NLU 任务(NER、QA、语义相似度)上大幅超越 P-tuning v1

P-tuning v2 的可训练参数 ​

每层 prefix 参数 = 2 × m × d_model  (K 和 V 各一个)
总参数 = L × 2 × m × d_model

以 BERT-large(L=24, d=1024, m=20)为例:
总参数 = 24 × 2 × 20 × 1024 ≈ 1M
全参数微调 BERT-large ≈ 340M
参数比例 ≈ 0.3%

🎯 面试总结 ​

P-tuning v1 只在输入层加 soft prompt,多层后影响稀释,小模型效果差。P-tuning v2 在每层都加 prefix KV,影响贯穿全部 Transformer 层,效果显著提升,0.3B 小模型也能接近全参数微调。本质上 P-tuning v2 ≈ Prefix Tuning 的 NLU 优化版。在 NLU 任务(序列标注)上,P-tuning v2 比 LoRA 更有优势(因为需要逐 token 分类的任务)。


75. 指示微调(Prompt Tuning)与 Prefix-tuning 区别是什么? ​

👔面试官:Prompt Tuning 和 Prefix Tuning 的区别是什么?

💡 简要回答 ​

维度Prompt TuningPrefix Tuning
插入位置只在输入 embedding 层前加 soft token在每层 Attention 的 KV 中加 prefix
可训练参数量m × d_model(小)L × 2 × m × d_model(大)
推理开销基本无(prefix 作为输入前缀)每层 KV 计算时包含 prefix
适用规模大模型(>10B)效果好各规模模型效果均稳定
设计初衷替代 fine-tuning 的极简 PEFT生成任务(GPT 系列)的 PEFT

核心区别:Prompt Tuning 只动输入层,Prefix Tuning 动每一层的 KV。

📝 详细解析 ​

Prompt Tuning 的结构 ​

模型输入:[soft_p1][soft_p2]...[soft_pm][token1][token2]...[tokenN]
只训练这 m 个 soft token 的 embedding 向量
模型本身(包括所有 Transformer 层)完全冻结

Prefix Tuning 的结构 ​

每层 Transformer:
  K = concat([prefix_k], [正常 K])
  V = concat([prefix_v], [正常 V])

为每层的 K 和 V 都学习独立的 prefix 向量

Prefix Tuning 的 prefix 直接注入到 KV 中,绕过了输入层,相当于给每层 Attention 提供额外的「记忆」。

为什么 Prefix Tuning 效果更稳定 ​

Prompt Tuning 的 soft token 只在第一层起作用,之后经过 L 层 Transformer 处理,影响逐渐衰减。Prefix Tuning 的每层 prefix 在每层都直接参与 Attention 计算,影响更直接、更持久。

这就是为什么 Prompt Tuning 只有在超大模型(>10B,参数足够强大时才能从浅层输入提取有效信号)时才有好效果,而 Prefix Tuning 在各规模模型上都有稳定表现。

🎯 面试总结 ​

核心区别:Prompt Tuning 只加在输入 embedding 层(影响浅),Prefix Tuning 加在每层 KV(影响深)。效果差异来源:Prompt Tuning 信号经多层衰减,只有大模型能有效利用浅层信号;Prefix Tuning 每层都有直接影响,规模无关性更好。参数量:Prompt Tuning < Prefix Tuning(后者多了 L 倍)。


76. 指示微调(Prompt Tuning)与 fine-tuning 区别是什么? ​

👔面试官:Prompt Tuning 和传统 fine-tuning 的根本区别是什么?什么情况下用哪个?

💡 简要回答 ​

维度Prompt TuningFine-tuning
参数更新只更新输入层的 soft token(m×d 参数)更新全部或部分模型参数
显存需求极低(梯度只对 soft token)高(全参数)或中(LoRA)
效果大模型(>10B)接近 fine-tuning各规模效果稳定,通常更好
灾难性遗忘几乎没有(模型权重不变)存在(权重被修改)
适合场景大模型、资源极度有限各种场景,效果优先

📝 详细解析 ​

本质区别:谁在「学习」 ​

Fine-tuning:模型权重参数在学习,学习结束后知识/行为固化在参数里。

Prompt Tuning:模型权重完全冻结,学习的是「如何提示模型」——找到一组输入向量,使得冻结的模型能产生期望的输出。

可以理解为:Fine-tuning 是「改变人的大脑」,Prompt Tuning 是「找到正确的暗号,激活大脑已有的能力」。

规模依赖性的根本原因 ​

Prompt Tuning 在小模型上效果差,是因为:小模型在预训练中获得的知识和能力有限,仅靠 soft prompt 无法「激活」不存在的能力。10B 以上的大模型经过充分预训练,具备了完成各种任务的潜力,Prompt Tuning 只需要找到正确的「激活方式」。

选择建议 ​

资源极度有限 + 大模型(>10B)+ 任务相对简单 → Prompt Tuning
一般场景 + 效果优先 → LoRA / QLoRA(fine-tuning 类)
需要深度注入领域知识 → Continue Pretraining + SFT

🎯 面试总结 ​

根本区别:Prompt Tuning 冻结模型,只学习「激活方式」(soft token embedding);Fine-tuning 修改模型权重,让模型「真正学习」新内容。类比:Prompt Tuning 是找暗号,Fine-tuning 是改造大脑。Prompt Tuning 的局限:依赖大模型的预训练能力,小模型上效果远不如 fine-tuning。


77. 为什么需要适配器微调(Adapter Tuning)? ​

👔面试官:Adapter Tuning 是什么?它解决了什么问题?

💡 简要回答 ​

Adapter Tuning(Houlsby et al., 2019)是在 fine-tuning 和 Prompt Tuning 之间的一种方案:在 Transformer 层中插入小型 bottleneck 网络(Adapter),只训练 Adapter 参数,冻结原始权重。

解决的核心问题:如何在保留预训练能力的同时,以极少的参数量实现多任务适配。

📝 详细解析 ​

Adapter 的结构 ​

python
class Adapter(nn.Module):
    def __init__(self, d_model, bottleneck_dim):
        super().__init__()
        self.down_proj = nn.Linear(d_model, bottleneck_dim)  # 降维
        self.activation = nn.GELU()
        self.up_proj = nn.Linear(bottleneck_dim, d_model)    # 升维
        # 残差连接保证初始时 Adapter 输出等于输入(恒等映射)

    def forward(self, x):
        return x + self.up_proj(self.activation(self.down_proj(x)))

插入位置:每个 Transformer 层的 Attention 之后和 FFN 之后各一个 Adapter。

为什么需要 Adapter ​

多任务服务场景:一个服务需要支持 100 个不同领域/任务,如果每个任务都全量微调,需要存储 100 个完整模型(100 × 7GB = 700GB)。

使用 Adapter:基座模型只存一份(7GB),每个任务只需存 Adapter 权重(约 5~20MB),100 个任务只额外需要 ~2GB。

保留预训练能力:与 LoRA 类似,原始权重不变,预训练通用能力被完整保留。

Adapter vs LoRA 的关键差异 ​

Adapter 最大的问题:串联结构导致推理延迟。每个 Adapter 是独立的前向传播路径,无法像 LoRA 那样在推理前合并进原始权重(因为有非线性激活函数)。这就是 LoRA 逐渐取代 Adapter 成为主流 PEFT 方法的原因。

🎯 面试总结 ​

Adapter 的核心价值:多任务服务时基座共享(节省存储),通过 bottleneck 网络(降维 → 激活 → 升维)以少量参数适配新任务。局限:串联结构有推理延迟,无法像 LoRA 一样合并消除开销。历史地位:Adapter 是 PEFT 的早期重要工作,为后来的 LoRA 等方法铺路,面试中作为对比参照系很重要。


78. 为什么需要 PEFT?PEFT 存在哪些问题? ​

👔面试官:PEFT 解决了什么问题?它有哪些局限?

💡 简要回答 ​

PEFT(Parameter-Efficient Fine-Tuning)解决的问题:全参数微调对算力和显存要求极高,无法在资源受限的场景下进行,PEFT 以极少的可训练参数(通常 <1%)实现接近全参数微调的效果。

PEFT 的主要问题:

  1. 表达能力受限(参数容量小,复杂任务效果上限低于全参数)
  2. 超参数调优(rank、位置、alpha 等需要实验)
  3. 不同 PEFT 权重难以融合(多任务场景)
  4. 部分方法有推理开销(Adapter、Prefix Tuning)

📝 详细解析 ​

PEFT 的核心价值 ​

问题PEFT 的解决方案
全参数微调 7B 需要 100GB 显存LoRA 只需 16GB
多任务需要存储 N 个完整模型共享基座 + N 个小 LoRA 权重
全参数微调灾难性遗忘严重PEFT 冻结或少动原始权重
没有 A100 集群的小团队QLoRA 单张 RTX 3090 可跑 7B

PEFT 的主要局限 ​

1. 参数容量上限

LoRA rank=8 的参数量约为全参数的 0.1%,表达能力有天花板。对于需要大量新知识(数亿 token 的领域知识)的任务,全参数微调或 CPT 效果明显好于 LoRA。

2. 任务覆盖和泛化

PEFT 权重对训练分布有依赖,泛化到分布差异大的数据时效果下降更明显。全参数微调更新了整个模型的「归纳偏置」,泛化性更好。

3. 多任务 PEFT 融合困难

不同任务的 LoRA 权重不能直接相加(会互相干扰)。需要 DARE、TIES-Merging 等复杂的模型合并方法,工程复杂度高。

4. 超参数敏感

rank、alpha、哪些模块加 LoRA、学习率——每个都影响效果,需要消耗额外实验预算。

什么时候不该用 PEFT ​

  • 有充足算力,效果优先 → 全参数微调
  • 需要深度注入大量新知识 → CPT(Continue Pretraining)
  • 评测集上 PEFT 和全参数差距 > 可接受阈值 → 升级到全参数

🎯 面试总结 ​

PEFT 的价值:显存节省(LoRA 7B 只需 16GB)、多任务共享基座、防遗忘。局限四点:参数容量有上限(0.1% 参数表达力有天花板)、泛化性不如全参数、多任务权重难融合、超参数多。工程选择原则:资源受限用 PEFT,效果优先且资源充足用全参数,大量新知识注入用 CPT。


79. 能不能总结一下各种参数高效微调方法的对比? ​

👔面试官:把 LoRA、Adapter、Prefix Tuning、Prompt Tuning、P-tuning v2 放在一起对比一下。

💡 简要回答 ​

方法参数量插入位置推理开销适用场景
LoRAA+B 矩阵(rank×d)Q/K/V/O 等线性层零(可合并)最通用,工业首选
QLoRA同 LoRA同 LoRA零(合并后)消费级 GPU,显存极限
Adapterbottleneck 层每层 Att/FFN 后有(串联层)多任务共享基座
Prefix Tuning每层 prefix KV每层 KV 前缀有(KV 前缀)生成任务
Prompt Tuning输入 soft token输入层基本无超大模型(>10B)
P-tuning v2每层 prefix每层 KV有NLU 任务
AdaLoRA自适应 SVDQ/K/V/O零(可合并)参数预算极紧

📝 详细解析 ​

效果排序(综合评测) ​

全参数微调 > AdaLoRA ≈ LoRA > P-tuning v2 ≈ Adapter > Prefix Tuning > Prompt Tuning(小模型)

工业实际选择 ​

99% 的场景选 LoRA/QLoRA,原因:

  • 效果接近全参数,实现简单
  • 推理零开销(合并后)
  • 生态成熟(PEFT 库、LLaMA Factory、DeepSpeed 等都原生支持)

Adapter 的价值场景:历史遗留系统,或需要 hot-swap(运行时动态切换)不同任务权重而不合并。

Prefix/Prompt Tuning 的价值场景:需要对模型完全不修改(合规要求),或基座模型为 API 服务(无法修改模型结构)。

🎯 面试总结 ​

这道题是所有 PEFT 方法的集大成总结,记住两个关键维度:推理是否有额外开销(LoRA/AdaLoRA 可合并为零 vs Adapter/Prefix 有串联开销)和插入层次(输入层 vs 每层)。工业实践答案:优先 LoRA,显存极限用 QLoRA,其余方法了解即可。


80. 多种不同的高效微调方法对比(LoRA / P-tuning / Prefix-tuning / Adapter) ​

此题与 79 题高度重叠,补充关键差异化对比角度。

💡 补充:从「梯度流向」理解各方法差异 ​

各 PEFT 方法的根本差异在于梯度流到哪里:

方法梯度流向更新什么
LoRAA、B 矩阵权重空间的低秩扰动
Adapterbottleneck 层权重层间串联的瓶颈网络
Prefix Tuningprefix KV 向量每层 Attention 的上下文
Prompt Tuning输入 soft token embedding输入空间的软提示

📝 实践选型决策树 ​

显存是否极度受限(<24GB 单卡)?
  ├─ 是 → QLoRA(4-bit 量化 + LoRA)
  └─ 否 ↓

任务是 NLU(序列标注/分类)还是生成?
  ├─ NLU → P-tuning v2 或 LoRA(两者效果接近)
  └─ 生成 ↓

是否需要推理时零额外延迟?
  ├─ 是 → LoRA(合并后零延迟)
  └─ 否 → Adapter / Prefix Tuning(更灵活的热切换)

模型规模 > 10B?
  ├─ 是 → Prompt Tuning 也可考虑(参数极少)
  └─ 否 → 不推荐 Prompt Tuning,用 LoRA

🎯 面试总结 ​

PEFT 方法选型的终极框架:显存 → QLoRA;NLU → P-tuning v2;推理零延迟 → LoRA;需热切换 → Adapter;超大模型且参数极紧 → Prompt Tuning。面试官问这道题通常是考你能不能「按场景选工具」,而不是死记每个方法的细节。给出清晰的决策树,说明你有工程判断力。



99. 什么是知识蒸馏(Knowledge Distillation)? ​

👔面试官:知识蒸馏是什么?软标签和硬标签的区别?Temperature 的作用?

💡 简要回答 ​

知识蒸馏(Hinton et al., 2015):用大模型(Teacher)的输出概率分布(软标签)训练小模型(Student),让 Student 学到 Teacher 的泛化知识(类间相似度等「暗知识」),而不只是学习一热编码的硬标签。

蒸馏损失 = α × CE(软标签, Student 输出) + (1-α) × CE(硬标签, Student 输出)

📝 详细解析 ​

软标签的信息优势 ​

硬标签:[0, 0, 1, 0, 0](只有正确类别为 1,其他为 0)

软标签(Teacher 输出,T=5):[0.01, 0.05, 0.85, 0.08, 0.01](猫、狗、豹等都有概率)

软标签包含了「猫和虎/豹有相似性」的信息——这是从大量数据中学到的结构性知识,硬标签完全丢失了这一信息。

Temperature 参数 ​

Temperature T 用于软化/硬化概率分布:

python
# 高温(T>1):分布更平滑,暗知识更丰富
softlabel = F.softmax(teacher_logits / T, dim=-1)

# 蒸馏损失(KL 散度)
loss_kd = T**2 * F.kl_div(
    F.log_softmax(student_logits / T, dim=-1),
    softlabel, reduction='batchmean'
)

T=1 就是普通 softmax;T=5~10 使分布更平滑,放大类间相似度信息,利于学习。

LLM 蒸馏的常见形式 ​

方式Teacher 输出学习目标
黑盒蒸馏Teacher 生成的文本(硬标签)模仿 Teacher 的输出
白盒蒸馏Teacher 的 logits/hidden states软标签 + 中间层对齐
数据增强蒸馏Teacher 生成大量训练数据Student 在增强数据上训练

现在最流行的做法(如 Alpaca 的思路)是黑盒数据蒸馏:用 GPT-4 生成大量高质量指令数据,在这些数据上直接 SFT 小模型。

🎯 面试总结 ​

知识蒸馏 = 软标签(Teacher 概率分布)训练 Student,学到「暗知识」(类间相似度)。Temperature T 平滑概率分布,放大暗知识。蒸馏损失 = KL 散度(软标签部分)+ 交叉熵(硬标签部分)的加权和。LLM 场景最常用黑盒数据蒸馏(GPT-4 生成数据 → SFT 小模型),成本低效果好。


100. 知识蒸馏的知识损失如何量化?有哪些蒸馏策略? ​

👔面试官:蒸馏时如何衡量「知识损失」?有哪些不同的蒸馏策略?

💡 简要回答 ​

蒸馏损失的量化方式:

  1. 输出层(Logit Distillation):KL 散度衡量 Teacher/Student 输出分布的差距
  2. 中间层(Feature Distillation):MSE 衡量 Teacher/Student 中间表示的差距
  3. 关系蒸馏(Relation Distillation):保留样本间的相对关系(而非绝对特征值)

📝 详细解析 ​

输出层蒸馏:KL 散度 ​

python
# KL(p_teacher || p_student) — 衡量两个分布的差距
loss_kl = F.kl_div(
    F.log_softmax(student_logits / T, dim=-1),
    F.softmax(teacher_logits / T, dim=-1),
    reduction='batchmean'
) * T**2

T² 的缩放因子确保了温度变化不影响梯度量级(数学推导结论)。

中间层蒸馏:Feature Alignment ​

让 Student 的中间隐状态对齐 Teacher 的对应层(如 FitNets、PKD):

python
# 如果维度不匹配,加一个线性映射层
projection = nn.Linear(student_dim, teacher_dim)

loss_feature = F.mse_loss(
    projection(student_hidden),
    teacher_hidden.detach()  # Teacher 不更新梯度
)

注意:Teacher 和 Student 的层数/维度可能不同,需要选择对应层(如 Teacher 的第 6/12/18/24 层对应 Student 的第 3/6/9/12 层)。

蒸馏策略对比 ​

策略方法效果代价
Logit 蒸馏KL(TeacherStudent)
Feature 蒸馏MSE(隐层对齐)更好(利用中间知识)需要访问 Teacher 内部
数据蒸馏Teacher 生成数据,Student SFT简单,适合 API 场景需要大量生成
自蒸馏模型不同层/早期 checkpoint 作为 Teacher无需额外 Teacher效果有限

🎯 面试总结 ​

知识损失量化:输出层用 KL 散度(含 T² 缩放),中间层用 MSE(需要维度对齐投影)。蒸馏策略四种:Logit 蒸馏(通用)、Feature 蒸馏(效果最好,需白盒访问)、数据蒸馏(最常用于 LLM,GPT-4 生成数据 SFT)、自蒸馏(无需额外 Teacher)。


101. 领域微调后模型通用能力下降,如何用蒸馏缓解? ​

👔面试官:领域微调后通用能力下降,除了数据混合的方法,能用蒸馏缓解吗?怎么做?

💡 简要回答 ​

蒸馏用于缓解遗忘的核心思路:用原始通用模型作为 Teacher,在领域 SFT 训练时额外加入一个约束损失,让 Student(被训练的模型)在通用任务上的输出不偏离 Teacher 太远。

这和 KL 惩罚(RLHF 中防止 reward hacking)的思路是一样的:Total Loss = SFT Loss + λ × KL(π_θ || π_teacher)

📝 详细解析 ​

实现方式:在线蒸馏约束 ​

python
def sft_with_distillation_loss(model, teacher_model, batch, lambda_kd=0.1):
    # 标准 SFT 损失(只对 response 计算)
    sft_loss = compute_sft_loss(model, batch)

    # 蒸馏约束:让模型在 prompt 的 response 分布上不偏离 Teacher
    with torch.no_grad():
        teacher_logits = teacher_model(**batch).logits

    student_logits = model(**batch).logits
    kd_loss = F.kl_div(
        F.log_softmax(student_logits / T, dim=-1),
        F.softmax(teacher_logits / T, dim=-1),
        reduction='batchmean'
    ) * T**2

    return sft_loss + lambda_kd * kd_loss

Teacher 是冻结的原始通用模型,不参与梯度更新。

与数据混合方法的对比 ​

方法原理优势劣势
数据混合混入通用数据同时训练简单直接,不需要 Teacher需要存储通用数据
蒸馏约束KL 惩罚限制偏离 Teacher不需要通用训练数据,只需 Teacher 模型在线推理Teacher 推理有额外计算开销
EWC对重要参数加 L2 约束无需额外数据或模型需要计算 Fisher 信息矩阵

实践中三种方法可以组合:数据混合(主力)+ 蒸馏约束(精细约束)效果最好,EWC 计算成本高通常不单独用。

λ 的选择 ​

λ 太小:蒸馏约束形同虚设,通用能力仍然下降。 λ 太大:模型被 Teacher 约束住,学不到领域知识,SFT 效果差。

经验值:λ = 0.05~0.2,通过验证集上通用/领域能力的双指标调优。

🎯 面试总结 ​

蒸馏缓解遗忘:以原始通用模型为 Teacher,SFT 训练时加 KL 散度惩罚(Total Loss = SFT Loss + λ × KL(student || teacher)),防止模型在通用任务分布上偏离。本质上和 RLHF 的 KL 惩罚思路一致。实践中推荐与数据混合结合使用,λ 通过双指标(通用+领域)验证集调优。


第二分类「二、大模型训练技术」全部完成,共覆盖题目 41-101(预训练/SFT/PEFT/RLHF/分布式训练/知识蒸馏)

最后更新2026-04-26
觉得有帮助?把这个链接转给正在求职的朋友 · 用 Ctrl + K 全站搜索其它题