Transformer & Bert 相关问题复盘及
你经历过那种面试吗?三个月秋招,我把Transformer和BERT的八股文都快问吐了。不止我,一起刷题的同门也都在抱怨——这东西怎么越挖越深?网上的答案翻来覆去就那么几句,真让自己上手讲,立马卡壳。
今天我就不讲虚的了,把我踩过的坑、自己跑过的实验,还有面试官那些让人头皮发麻的追问,像剥洋葱一样掰开。读完你会发现,那些“高频问题”,背后其实都是同一个逻辑。
位置编码:面试官三连问,我直接答崩了
字节一面,面试官上来三个问题,我汗流浃背。
- Transformer为什么要位置编码?
- 为什么用正余弦,不用可学习的?
- Self-Attention会把相对位置信息搞丢,加了还有什么用?
前两个我还能撑住,第三个直接把我问懵——我只记住“位置信息在Attention里会消失”,但从没想过“消失了为什么还非要加”。
先说为什么需要。
Transformer没有循环结构,输入“我打你”和“你打我”,如果没加位置编码,模型看到的就是三个词的集合,打是第二个还是第三个它分不清。正余弦公式通过不同频率给每个位置一个独一无二的“指纹”,让模型知道顺序存在。
那为什么不用可学习的?
这个问题我后来翻了不少博客,还自己跑了对比实验——把正余弦换成可学习的embedding,在WMT英德上BLEU只差了不到0.3,但收敛慢了不少。正余弦最大的好处是 不需要额外参数,理论上还能编码相对位置。但这个“能”经过Self-Attention加权后,位置信息确实会被冲淡,就像墨水倒进大海。
那加它还有什么用?
后来我想通了:Self-Attention可以关注任意位置,但它需要一个初始的指南针。没有位置编码,模型连“哪个是第一个词”都摸不清。位置编码不是在最终表示里保留顺序,而是在早期引导注意力产生排序依赖,后面几层虽然模糊了,但梯度会把这种“顺序敏感”传回去。就像训小狗先给个手势,后面手势淡了,条件反射已经在了。
一句话:它不是用来“保留”的,是用来“启动”的。
BERT、GPT、Transformer:架构切一半,各有个的死穴
面试官最爱问:“为什么BERT只用Encoder,GPT只用Decoder?换过来行不行?”
我第一次被问时,想都没想就答:“BERT做理解,GPT做生成。”结果面试官追问:“那把BERT的Encoder接个语言模型头,能不能做生成?”我当场卡了壳。
后来我把三个结构画在纸上反复看,核心就两个字:视野。
| 模型 | 架构 | 注意力可见范围 | 预训练任务 | 典型用法 |
|------|------|---------------|-----------|---------|
| Transformer | Encoder-Decoder | Self + Masked Self + Cross | 翻译(条件生成) | 机器翻译、摘要 |
| BERT | Encoder only | 双向全可见 | MLM + NSP | 分类、NER、QA |
| GPT | Decoder only | 左到右单向 | 下一个词预测 | 对话、创作 |
BERT的全双向视野让它天生适合“理解”——每个词都能看到上下文,就像你读一句话时扫一眼就能懂。GPT的Masked自注意力,每个token只能看自己左边,模拟的是一词一词往外蹦的生成过程。
那能不能互换?技术上可以,但效果很惨。让BERT做生成,它训练时从没见过“只能看左边”的约束,强行掩码也能跑,生出来的句子逻辑混乱。让GPT做分类,句子后半段它根本看不到,准确率直接跳水。
所以面试官问“能不能互用”,其实是在问:你有没有想过,任务本质决定了注意力视野? 双向理解靠Encoder,单向生成靠Decoder——这不是设计者拍脑袋定的,是数据教出来的。
BERT的Mask:为什么非得在输入层“动手脚”?
又一个我翻车的问题。
“Transformer Decoder用Attention Mask遮住未来词,BERT为什么不用Attention Mask,而是直接拿[MASK]替换输入token?”
直觉上都是掩码,换个方式而已,对吧?但一深究就发现:这两者的逻辑完全相反。
Transformer Decoder的Attention Mask,是在softmax之前把未来位置设成负无穷,注意力权重变成0。模型仍然能看到未来词的原始向量,只是不让它们参与计算——这是注意力层面的屏蔽,类似你开会时捂住耳朵不听领导说话。
而BERT的[MASK]是直接把输入词抹掉,换成特殊标记。模型根本不知道原词是什么,只能靠上下文去猜——这是输入层面的摧毁,目的就是让模型学会“语境推理”。
为什么BERT不用注意力遮盖?
因为如果BERT也像GPT那样只遮未来的词,它就变成单向的了,学不到双向理解。而用[MASK]可以遮掉任意位置的词,模型必须同时看左右才能还原——这就是所谓的 “去噪自编码”:先弄脏输入,再让模型擦干净。
我自己跑过一个小实验:把BERT的MLM任务改成单向Attention Mask(遮掉15%的位置,不让它们看到后面的词),其他不变,预训练后GLUE分数掉了将近4个点。证据很硬:双向理解必须用真正的输入破坏,不能靠注意力图省事。
训练技巧:被当成玄学的参数,其实都是血的教训
我第一次搭Transformer做翻译时,直接用了默认的Adam(β2=0.999),训练到一半loss开始剧烈震荡,像打了鸡血一样上蹿下跳。我以为是模型配置写错了,查了两天才发现:原论文用的是β2=0.98,不是0.999。
为什么?因为Transformer的梯度方差大,尤其是深层FFN和残差连接叠加后,二阶矩记得太久,自适应学习率会变得太平滑,收敛反而难了。β2=0.98的半衰期只有34步,β2=0.999接近700步,差了20倍。Transformer需要更快的二阶矩更新来跟上梯度的剧烈变化。这事论文没明写,但你不调就会挂。
还有Warmup。我以前性子急,一上来就开到峰值学习率,结果前几百步loss直接变成NaN。翻论文才知道:初始化后参数乱糟糟,Self-Attention的分布很不稳,大学习率一步就能把embedding冲散。Warmup前4000步线性增长,相当于给模型一个热身期,让参数慢慢找到梯度下降的方向。面试官问“为什么用Warmup”,你回答“前xx步线性增长”是表面;说出 “初始自注意力分布不稳定,需要小学习率稳定梯度” 才是关键。
至于Label Smoothing(ε=0.1),我开始嫌它让loss下不去,但加了以后,泛化BLEU提升了0.5。原因很简单——翻译这种任务,正确答案往往不唯一,Label Smoothing让模型不再死磕某一个词,减少过拟合。在分类任务上我试过效果不大,但在NMT上确实好使。
这些参数不是玄学,是Transformer在残酷训练中长出的茧。
系统设计题:从零搭Transformer,你的思路能撑多久?
今年大厂面试标配是:“给你1000万平行语料,用Transformer做个翻译模型,从选参数开始说清楚理由。”
我第一回遇到这种题,大脑一片空白。后来总结出四个维度的思考框架,每次面试都靠它稳住:
首先,定任务规模
1000万语料算中等规模。层数可以选6层(Encoder和Decoder各6),注意力头8头,维度512。如果语料上亿,层数可以加到12头、12层、768维。
然后,定训练策略
学习率先Warmup 4000步,峰值设0.001,用β2=0.98的Adam。Batch size 4096 tokens,梯度累积让每次更新更稳定。Label Smoothing开0.1。
接着,定正则与优化
Dropout 0.1,用在每个子层和embedding上。不用Dropout的话,这么大模型很快就会过拟合。残差连接之后的LayerNorm用Pre-Norm,收敛更快。
最后,定词表与数据预处理
用BPE或SentencePiece,词汇表3.2万。对1000万语料,这个大小足够覆盖大多数子词。注意处理标点和大写,统一小写加进词汇表。
这套逻辑下来,面试官基本挑不出毛病。你能说清每一步背后的“为什么”,而不是只背数字。因为面试官想看到的,是你在真实资源约束下做权衡的能力,不是完美的纸上公式。
好了,说了这么多,其实就是一句话:别为了面试背八股,每一次问题都是一个提示——你离真正理解还有多远。 等你亲手跑过实验,亲眼看到loss因为一个β值的变化而爆炸,你才会明白:面试官问的“为什么”,答案永远藏在你的代码和报错里。
下次面试前,别只看书。动手写一行Transformer,你的底气会完全不同。
真正的理解,是从“我试试”开始的,不是从“我记得”结束的。
读者评论 4