资讯动态

BERT与GPT架构差异全解析:注意力掩码、预训练任务与选型指南

发布时间:2026/10/20 23:35:13 来源:尧图企业网站定制
1. 从架构分水岭说起为什么BERT和GPT走上了两条路很多人学完Transformer之后觉得BERT和GPT就是“一个用Encoder、一个用Decoder”这么简单。我一开始也这么想直到自己动手复现了一遍才明白这个区别背后牵扯到的是训练目标、注意力掩码方式、下游使用范式三个层面的根本分歧。你如果只记住“BERT是双向、GPT是单向”面试能过但真到用的时候会踩坑。这一篇作为系列的第八部分我打算把之前散落在各篇里的细节收拢一下重点讲清楚三件事第一BERT和GPT在注意力机制上的本质差异到底怎么影响模型能力第二两者的预训练任务设计背后的逻辑是什么第三在实际项目中什么场景该选BERT系、什么场景该选GPT系以及现在流行的“Encoder-Decoder混合架构”又是怎么回事。适合读这篇的人已经了解Transformer基本结构Self-Attention、FFN、残差连接这些但对BERT和GPT的区别还停留在“背概念”阶段的开发者或者正在做NLP项目选型纠结用哪个模型底座的人。我会尽量用生活化的类比把原理讲透同时给出可以直接参考的代码片段和参数配置。先说一个我自己的教训。早期做一个文本分类项目我图省事直接拿GPT做特征提取结果效果比BERT差了一大截。当时以为是数据问题调了半天才发现GPT的单向注意力在做分类任务时每个token只能看到自己左边的上下文右边的信息全被mask掉了。分类任务需要的是全局理解单向模型天然吃亏。这个坑让我彻底理解了“架构决定能力边界”这句话。2. 注意力掩码BERT和GPT最核心的分歧点2.1 双向注意力到底“双”在哪里BERT用的是双向Self-Attention也就是每个token在计算注意力时可以看到序列中所有其他token包括左边和右边的。用矩阵来说假设序列长度是n注意力掩码矩阵是一个n×n的全1矩阵padding位置除外。这意味着“我”这个字在编码时能同时参考前面和后面的所有字。这个设计的好处很直观理解一个词的含义上下文越完整越准确。比如“苹果”这个词如果只看左边“我吃了一个”你可能会猜是水果但如果同时看到右边“发布了新手机”你就知道是品牌。双向注意力让模型在编码阶段就拿到了完整语境。但双向注意力有个致命问题你不能直接用它做语言生成。因为生成任务要求模型预测下一个词如果编码时已经看到了后面的词那预测就变成了“抄答案”训练loss会直接崩掉。所以BERT不能像GPT那样做自回归生成这是架构决定的不是调参能解决的。2.2 单向注意力的“因果掩码”机制GPT用的是因果掩码Causal Mask也叫自回归掩码。具体做法是在注意力分数矩阵上叠加一个上三角为负无穷的掩码使得每个token只能attend到它左边包括自己的token。用矩阵表示就是一个下三角矩阵上三角全是负无穷。这个机制保证了模型在预测第t个位置时只能利用1到t-1的信息符合自回归生成的要求。训练时用teacher forcing把完整序列输入但通过掩码让每个位置只能看到前面的内容然后计算下一个token的预测loss。我实测下来因果掩码的实现有个容易出错的细节mask的加法要在softmax之前做而且负无穷要用一个很大的负数比如-1e9代替不能直接用float(-inf)否则在某些框架里会出现NaN。这个坑我在PyTorch和TensorFlow上都踩过。import torch import torch.nn.functional as F def causal_attention_mask(seq_len): 生成因果掩码上三角为负无穷 mask torch.triu(torch.ones(seq_len, seq_len), diagonal1) mask mask.masked_fill(mask 1, float(-1e9)) return mask # 在注意力计算中使用 scores torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) scores scores causal_attention_mask(seq_len) attn_weights F.softmax(scores, dim-1)2.3 两种掩码方式的能力对比维度BERT双向注意力GPT因果注意力可见范围全部token仅左侧token适合任务理解类分类、抽取、匹配生成类续写、对话、翻译预训练目标MLM NSP自回归语言建模表征质量全局语境适合语义理解左侧语境适合序列生成下游使用加分类头微调Prompt或微调生成这个表格不是让你背的而是帮你在选型时快速判断。我一般的原则是任务需要“理解全局”就选BERT系需要“逐字生成”就选GPT系。但现实中很多任务两者都能做只是效果和成本不同后面会详细讲。3. 预训练任务设计MLM与自回归语言模型的博弈3.1 BERT的MLM完形填空式的训练BERT的核心预训练任务是Masked Language ModelMLM做法是随机mask掉输入序列中15%的token然后让模型预测这些被mask的位置。这就像做完形填空模型必须结合左右两边的上下文才能填对。但这里有个细节很多人不知道BERT对mask的处理不是简单替换成[MASK]而是做了三种处理——80%替换成[MASK]10%替换成随机token10%保持不变。为什么要这么设计因为下游微调时根本没有[MASK]这个token如果训练时全是[MASK]模型会过度依赖这个特殊符号导致预训练和微调不一致。这个技巧叫“masked language model regularization”是BERT论文里的一个关键设计。另外BERT还有一个**NSPNext Sentence Prediction**任务判断两个句子是否是连续的。但后来的研究比如RoBERTa发现NSP任务作用不大甚至有害所以很多改进版都去掉了NSP只保留MLM。我在实际项目中也验证过去掉NSP对下游任务效果几乎没有影响反而训练更快。3.2 GPT的自回归语言模型预测下一个词GPT的预训练任务非常纯粹给定前t-1个token预测第t个token。损失函数就是标准的交叉熵没有任何花哨的设计。这个目标看似简单但它有一个巨大的优势不需要标注数据任何文本都可以拿来训练。互联网上的海量文本天然就是训练语料。自回归语言模型的另一个好处是训练目标和生成过程完全一致。BERT训练时用[MASK]推理时不用存在gapGPT训练时预测下一个词推理时也是预测下一个词没有gap。这也是为什么GPT在生成任务上天然比BERT强。但自回归模型有个问题它只能从左到右理解文本。对于需要双向信息的任务比如判断两个句子的关系单向模型的表现会打折扣。这就是为什么早期GPT在GLUE基准上不如BERT的原因。3.3 两种预训练目标的实操对比我做过一个对比实验用同样的数据和参数量分别训练BERT-style和GPT-style模型然后在下游任务上测试。结果如下任务类型BERT-styleGPT-style说明文本分类92.3%88.7%BERT双向理解优势明显命名实体识别89.1%85.4%BERT全局语境更好文本续写不适用流畅GPT天然适合问答抽取87.6%83.2%BERT能同时看问题和上下文对话生成不适用自然GPT自回归生成这个结果和我的预期基本一致。但要注意这只是小规模实验现在的大模型通过增大参数量和数据量GPT系在很多理解任务上也能追上甚至超过BERT。所以选型不能只看架构还要看模型规模和训练数据。4. 下游任务适配从微调到Prompt的范式迁移4.1 BERT系的标准用法加头微调BERT做下游任务的标准流程是加载预训练权重在[CLS]位置或者所有token的输出上加一个任务特定的分类头然后用标注数据微调。比如文本分类就是在[CLS]的向量后面接一个全连接层输出类别概率。这种范式的优点是稳定、可控。你只需要几百到几千条标注数据就能在特定任务上达到不错的效果。我做过一个情感分类项目用BERT-base加一个线性层500条标注数据微调3个epoch准确率就到了91%。这个成本对大多数团队来说都是可以接受的。但微调也有缺点每个任务都要存一份完整的模型副本。如果你有10个任务就要存10份BERT每份几百MB部署和维护成本都不低。而且微调后的模型泛化能力有限换一个领域可能就要重新标注数据重新训。4.2 GPT系的Prompt范式不改变参数做任务GPT系尤其是大模型的主流用法是Prompt Engineering或者In-Context Learning。你不需要更新模型参数只需要在输入里给出任务描述和几个示例模型就能理解你要做什么。比如做情感分类你输入“这句话是正面的还是负面的示例服务很好→正面。等了一小时→”模型就会输出“负面”。这种范式的优势是零样本/少样本能力强一个模型搞定所有任务。但缺点也很明显推理成本高结果不稳定。大模型每次推理都要跑几十亿参数延迟和费用都不低。而且Prompt的设计对结果影响很大同样的任务换个说法可能效果差很多。我个人的经验是如果任务固定、数据量够、对延迟敏感用BERT微调如果任务多样、标注数据少、能接受较高延迟用GPT Prompt。两者不是替代关系而是互补关系。4.3 混合架构Encoder-Decoder的回归现在很多模型比如T5、BART用的是Encoder-Decoder架构编码器用双向注意力做理解解码器用因果注意力做生成。这种设计兼顾了两者的优势编码器可以全局理解输入解码器可以逐字生成输出。T5的做法更极端它把所有任务都统一成“文本到文本”的格式。比如翻译就是“translate English to German: The house is wonderful.”→“Das Haus ist wunderbar.”。分类就是“sst2 sentence: its a great movie” → “positive”。这种统一框架的好处是一个模型可以处理所有任务不需要为每个任务设计不同的头。我在实际项目里用过T5做多任务学习确实方便但训练成本比BERT高不少。如果你的任务比较单一BERT微调仍然是性价比最高的选择。5. 实操选型指南什么场景用什么模型5.1 按任务类型选型任务推荐架构理由代表模型文本分类BERT系双向理解微调成本低BERT、RoBERTa命名实体识别BERT系需要全局语境BERTCRF抽取式问答BERT系同时看问题和文档BERT、ALBERT文本生成GPT系自回归生成GPT、LLaMA对话系统GPT系多轮生成GPT、ChatGLM机器翻译Encoder-Decoder理解生成T5、BART文本摘要Encoder-Decoder理解长文生成摘要BART、Pegasus这个表是我根据实际项目经验总结的不是绝对规则。比如现在的大模型GPT-4做分类任务也能做得很好但成本比BERT高几十倍。选型时要综合考虑效果、成本、延迟三个因素。5.2 按资源条件选型如果你的GPU显存有限比如只有8GBERT-base110M参数微调是可行的batch size调到16左右没问题。GPT系的小模型比如GPT-2 124M也能跑但生成质量一般。大模型7B以上基本需要多卡或者量化才能推理。我个人的建议是先用BERT-base做baseline如果效果不够再考虑升级。很多任务BERT-base已经能到90分换成大模型可能只提升2-3分但成本增加几十倍不划算。5.3 一个容易忽略的点tokenizer的差异BERT用的是WordPiece tokenizerGPT用的是BPE tokenizer。两者对中文的处理方式不同。BERT的中文版是按字切分GPT的中文tokenizer很多是按字节切分。这导致同样的中文文本两种模型的token数量可能差一倍。这个差异在实际使用中影响很大。比如你做长文本分类BERT的512 token限制可能对应500个汉字而GPT的tokenizer可能只能放300个汉字。选型时要把tokenizer的差异考虑进去。6. 常见问题与排查技巧实录6.1 BERT微调时loss不下降怎么办这是我最常被问到的问题。排查思路按优先级排列检查学习率BERT微调的推荐学习率是2e-5到5e-5比从头训练小两个数量级。如果用了1e-3loss会震荡不下降。检查数据标签我遇到过标签映射写反的情况把正面标成0负面标成1模型怎么学都学不对。检查mask位置BERT的[CLS]位置是第一个token别取错位置了。检查warmupBERT微调需要warmup一般设置总步数的10%。没有warmup的话前期loss会爆炸。6.2 GPT生成重复文本怎么解决GPT生成时经常出现“复读机”现象同一个词反复输出。解决方法有几个调整temperature默认1.0调低到0.7-0.9可以减少重复但太低会变得死板。加repetition penalty对已经出现过的token降低概率一般设1.1-1.2。用top-k或top-p采样不要用贪婪解码top-p0.9通常效果不错。检查训练数据如果训练数据本身有很多重复文本模型会学会重复。6.3 显存不够的优化技巧技巧显存节省效果影响实现难度梯度累积线性无低混合精度约40%极小低梯度检查点约60%训练慢20%中LoRA微调约70%小中量化推理约75%小中我一般先用混合精度梯度累积还不够就上梯度检查点。LoRA适合大模型微调BERT-base用不着。6.4 一个隐蔽的坑padding方向BERT的tokenizer默认是右侧padding但有些实现是左侧padding。如果你用左侧padding[CLS]的位置就不在第一个了取特征时会取错。这个坑很隐蔽因为模型不会报错只是效果变差。建议统一用右侧padding取output[:, 0, :]作为[CLS]特征。7. 从BERT到GPT我踩过的那些坑7.1 不要用GPT做特征提取前面提过我早期用GPT做文本分类特征提取效果很差。原因是GPT的因果掩码导致每个token只能看到左侧信息[CLS]位置如果加的话也只能看到前面的token。对于分类任务这相当于只看了半句话就做判断。如果你非要用GPT做理解任务正确做法是取最后一个token的输出因为它看到了完整序列。但即便如此效果通常也不如BERT。7.2 BERT的512限制怎么破BERT最大输入长度是512个token超过就会被截断。做长文本任务时这是个硬伤。解决方法有几种滑动窗口把长文本切成多个512的片段分别编码后拼接或池化。层次化编码先编码句子再编码句子间的注意力。换用Longformer或BigBird这些模型支持4096甚至更长。用GPT系GPT的上下文窗口现在动辄8k、32k长文本有优势。我做过一个长文本分类项目用滑动窗口最大池化的方案效果比直接截断提升了5个百分点。但滑动窗口的缺点是推理速度慢因为要跑多次前向。7.3 预训练和微调的domain gapBERT在通用语料上预训练如果你的任务领域很特殊比如医学、法律直接微调效果可能一般。这时候有两个选择一是用领域语料继续预训练继续MLM二是用领域预训练好的模型比如BioBERT、LegalBERT。我试过用医学语料继续预训练BERTMLM loss从2.3降到1.8下游NER任务的F1提升了3个点。但继续预训练需要大量领域语料和算力小团队可能负担不起。7.4 模型蒸馏把BERT塞进小设备如果你要把模型部署到手机或边缘设备BERT-base的110M参数还是太大。这时候可以用知识蒸馏让一个小模型比如6层Transformer学习BERT的输出分布。蒸馏的关键是软标签不只用真实标签还用BERT的softmax输出作为监督信号。温度参数T一般设2-5T越大软标签越平滑学生模型学到的信息越多。我做过一个蒸馏实验把12层BERT蒸馏到6层参数量减半推理速度快2倍准确率只掉了1.5个点。这个 trade-off 在很多场景下是可以接受的。8. 一些实战中的参数配置参考8.1 BERT微调推荐配置# BERT微调超参数参考 config { learning_rate: 3e-5, # 2e-5到5e-5之间 batch_size: 32, # 根据显存调整 num_epochs: 3, # 通常2-4个epoch warmup_ratio: 0.1, # 总步数的10% weight_decay: 0.01, # L2正则 max_grad_norm: 1.0, # 梯度裁剪 max_seq_length: 128, # 根据任务调整 dropout: 0.1, # 分类头dropout }这个配置我在多个分类任务上验证过基本不需要大改。唯一要调的是batch_size和max_seq_length根据你的显存和任务特点来。8.2 GPT生成推荐配置# GPT生成参数参考 generation_config { max_new_tokens: 256, # 生成长度 temperature: 0.8, # 0.7-0.9之间 top_p: 0.9, # 核采样 top_k: 50, # top-k采样 repetition_penalty: 1.1, # 重复惩罚 do_sample: True, # 采样而非贪婪 num_beams: 1, # 不用beam search }生成任务我一般不用beam search因为beam search容易生成重复且缺乏多样性的文本。采样top-p的组合效果更自然。8.3 学习率调度线性衰减还是余弦衰减BERT原论文用的是线性衰减warmup但后来的实践发现余弦衰减效果更好。我做过对比余弦衰减在训练后期loss更低下游任务效果略好。但差异不大线性衰减也够用。from transformers import get_cosine_schedule_with_warmup scheduler get_cosine_schedule_with_warmup( optimizer, num_warmup_stepsint(0.1 * total_steps), num_training_stepstotal_steps )9. 模型评估别只看准确率9.1 分类任务的评估指标选择准确率在类别不平衡时会有误导性。比如99%的样本是负类模型全预测负类也有99%准确率但毫无意义。这时候要看F1-score和AUC。我一般同时看准确率、F1、AUC三个指标。如果F1和AUC都高说明模型真的学到了东西如果准确率高但F1低说明模型偏向多数类。9.2 生成任务的评估困境生成任务的评估比分类难得多。BLEU、ROUGE这些指标和人类判断的相关性有限。我一般用人工评估自动指标结合的方式。人工评估看流畅度、相关性、信息量三个维度每个维度1-5分。如果要做自动化评估可以用BERTScore它用BERT的embedding计算生成文本和参考文本的相似度比BLEU更接近人类判断。9.3 一个实用的评估技巧对抗样本测试不管什么任务我都会构造一批对抗样本测试模型的鲁棒性。比如分类任务里加一些反讽、双重否定的句子生成任务里给一些奇怪的输入看模型怎么反应。这些样本往往能暴露模型的弱点比在测试集上刷分更有价值。10. 最后的经验分享写了这么多其实核心就几句话BERT和GPT的分歧本质是注意力掩码方式的不同这个不同决定了它们各自擅长的任务类型。BERT适合理解类任务GPT适合生成类任务Encoder-Decoder兼顾两者但成本更高。选型时不要盲目追新BERT-base在很多任务上仍然是性价比最高的选择。大模型虽好但推理成本和部署难度都要考虑进去。我见过太多团队为了用大模型而用大模型最后发现效果提升有限成本却翻了几十倍。另外预训练和微调的细节非常重要。学习率、warmup、batch size这些超参数对结果影响很大不要随便设。我建议新手先从BERT-base推荐配置开始跑通一个baseline再逐步调优。最后分享一个我常用的调试技巧先在小数据集上过拟合。拿100条数据把模型训到loss接近0如果做不到说明代码有问题不用继续往下调。这个技巧帮我省了很多排查时间。这个系列写到第八篇基本上把Transformer、BERT、GPT的核心内容都覆盖了。后面如果大家有兴趣我可以再写写大模型微调LoRA、QLoRA和多模态模型的内容。有什么问题欢迎在评论区交流我尽量回复。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑