手撕 Transformer 和手撕 bert区别

“手撕 Transformer” 和 “手撕 BERT” 虽然都涉及手动实现深度学习模型,但二者在目标、复杂度、应用场景和技术细节上存在显著差异。以下从多个维度对比分析:

一、核心目标与应用场景

对比项手撕 Transformer手撕 BERT
本质 实现 Transformer 的基础架构(编码器 + 解码器) 实现基于 Transformer 的预训练语言模型
核心任务 构建通用序列处理框架,适用于翻译、生成等任务 构建大规模预训练 + 微调的 NLP 范式
应用场景 需自定义模型结构(如语音、图像领域) 需基于预训练权重做下游任务(如文本分类)

二、技术复杂度与实现重点

1. Transformer(基础架构)

  • 关键模块:
    • 多头注意力机制:手动实现 Q/K/V 矩阵生成、维度变换、Softmax 计算(需处理数值稳定性)。
    • 位置编码:实现正弦 / 余弦函数编码或学习型编码。
    • 残差连接与 LayerNorm:处理张量形状匹配(如x + sublayer(x))。
  • 难点:
    • 多头并行计算的张量操作(如(batch, seq_len, d_model) → (batch, heads, seq_len, d_k))。
    • 编码器 - 解码器交互(Seq2Seq 任务中的 Cross-Attention)。

2. BERT(预训练模型)

  • 关键模块:
    • 仅编码器架构:丢弃 Transformer 的解码器,堆叠多层编码器(如 12 层或 24 层)。
    • 预训练任务:
      • MLM(掩码语言模型):随机掩码 15% 的 token,预测被掩码的词。
      • NSP(下一句预测):判断两句话是否连续。
    • 特殊 token 设计:[CLS]分类 token、[SEP]分隔符、[MASK]掩码符。
  • 难点:
    • 预训练数据处理(如掩码策略、句子对构建)。
    • 大规模训练优化(如混合精度、梯度累积)。

三、代码实现的核心差异

1. Transformer 核心代码示例

python
 
运行
 
 
 
 
class Transformer(nn.Module):
    def __init__(self, src_vocab_size, tgt_vocab_size, d_model, nhead, num_layers):
        super().__init__()
        # 编码器和解码器
        self.encoder = TransformerEncoder(src_vocab_size, d_model, nhead, num_layers)
        self.decoder = TransformerDecoder(tgt_vocab_size, d_model, nhead, num_layers)
        self.generator = nn.Linear(d_model, tgt_vocab_size)
        
    def forward(self, src, tgt, src_mask, tgt_mask):
        # 编码源语言
        memory = self.encoder(src, src_mask)
        # 解码目标语言(结合源语言编码)
        output = self.decoder(tgt, memory, tgt_mask, src_mask)
        return self.generator(output)
 

2. BERT 核心代码示例

python
 
运行
 
 
 
 
class BERT(nn.Module):
    def __init__(self, vocab_size, d_model, nhead, num_layers):
        super().__init__()
        # 仅需编码器(无解码器)
        self.encoder = TransformerEncoder(vocab_size, d_model, nhead, num_layers)
        # MLM预测头
        self.mlm_head = nn.Sequential(
            nn.Linear(d_model, d_model),
            nn.GELU(),
            nn.LayerNorm(d_model),
            nn.Linear(d_model, vocab_size)
        )
        # NSP预测头
        self.nsp_head = nn.Linear(d_model, 2)
        
    def forward(self, input_ids, attention_mask, token_type_ids):
        # 获取编码表示
        outputs = self.encoder(input_ids, attention_mask)
        # [CLS] token用于分类
        cls_output = outputs[:, 0, :]
        # 预测掩码token
        mlm_output = self.mlm_head(outputs)
        # 预测下一句关系
        nsp_output = self.nsp_head(cls_output)
        return mlm_output, nsp_output
 

四、数据处理与训练流程

对比项TransformerBERT
数据格式 源语言 - 目标语言对(如中英句子对) 单文本或文本对(如段落、问题 - 答案)
训练目标 最大化目标序列的生成概率 最小化 MLM 和 NSP 任务的损失
训练数据量 特定领域的平行语料(通常数百万句对) 大规模无标注文本(如 Wikipedia、BooksCorpus)
训练技巧 标签平滑、学习率预热 掩码策略(如 80% 替换为 [MASK]、10% 随机替换)

五、应用场景与扩展方向

1. Transformer 的应用

  • 神经机器翻译(如 Google Translate)。
  • 文本生成(如 GPT 系列的基础架构)。
  • 跨模态任务(如 Vision Transformer 处理图像)。

2. BERT 的应用

  • 文本分类(如情感分析)。
  • 问答系统(如 SQuAD 任务)。
  • 命名实体识别(NER)。

六、面试中的高频问题差异

Transformer 相关问题BERT 相关问题
1. 为什么需要多头注意力? 1. BERT 为什么使用 MLM 而非传统语言模型?
2. 如何处理长序列输入(如超过 512 tokens)? 2. BERT 的输入表示有哪些部分组成?
3. LayerNorm 应该放在残差连接前还是后? 3. 为什么 BERT 在微调时比从头训练效果好?

总结:选择 “手撕” 哪个更有价值?

  • 选 Transformer:适合想深入理解深度学习基础架构、需要自定义模型(如处理音频、图像)的场景。
  • 选 BERT:适合专注 NLP 任务、希望快速应用预训练模型解决实际问题的场景。

二者的关系类似于 “造汽车引擎”(Transformer)与 “改装汽车”(BERT):前者是基础能力,后者是应用创新。实际中,建议先掌握 Transformer 的核心实现,再扩展到 BERT 等变种,形成完整的技术栈。
posted @ 2025-06-22 16:11  m516606428  阅读(66)  评论(0)    收藏  举报