Transformer详解:从原理到实现的完整指南

Transformer详解:从原理到实现的完整指南

目录

  1. 引言
  2. Transformer架构概览
  3. 注意力机制详解
  4. 多头注意力机制
  5. 位置编码
  6. 前馈神经网络
  7. 残差连接与层归一化
  8. 编码器-解码器架构
  9. 数学推导详解
  10. 代码实现
  11. 训练与优化
  12. 应用与扩展

引言

Transformer是由Vaswani等人在2017年论文《Attention Is All You Need》中提出的革命性架构。它完全基于注意力机制,摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),在自然语言处理任务中取得了突破性的成果。

Transformer的主要优势:

  • 并行化训练,提高训练效率
  • 长距离依赖建模能力强
  • 可解释性好
  • 为后续的BERT、GPT等模型奠定了基础

Transformer架构概览

Transformer采用编码器-解码器(Encoder-Decoder)架构,主要组件包括:

核心组件

  1. 多头自注意力机制 (Multi-Head Self-Attention)
  2. 位置编码 (Positional Encoding)
  3. 前馈神经网络 (Feed Forward Network)
  4. 残差连接 (Residual Connection)
  5. 层归一化 (Layer Normalization)

注意力机制详解

什么是注意力机制?

注意力机制允许模型在处理序列的每个位置时,关注序列中的所有位置。这解决了RNN中信息瓶颈的问题。

缩放点积注意力 (Scaled Dot-Product Attention)

这是Transformer中使用的注意力机制的核心。

数学公式

Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dk QKT)V

其中:

  • Q Q Q:查询矩阵 (Query)
  • K K K:键矩阵 (Key)
  • V V V:值矩阵 (Value)
  • d k d_k dk:键向量的维度
详细推导
  1. 计算注意力分数
    scores = Q K T \text{scores} = QK^T scores=QKT

  2. 缩放
    scaled_scores = Q K T d k \text{scaled\_scores} = \frac{QK^T}{\sqrt{d_k}} scaled_scores=dk QKT

    缩放的目的是防止softmax函数进入饱和区域。

  3. 应用softmax
    attention_weights = softmax ( scaled_scores ) \text{attention\_weights} = \text{softmax}(\text{scaled\_scores}) attention_weights=softmax(scaled_scores)

  4. 加权求和
    output = attention_weights ⋅ V \text{output} = \text{attention\_weights} \cdot V output=attention_weightsV

注意力机制的直观理解

想象你在阅读一个句子:“The animal didn’t cross the street because it was too tired”。当模型处理"it"这个词时,注意力机制帮助模型将注意力集中在"animal"上,而不是"street"。


多头注意力机制

为什么需要多头注意力?

单一的注意力头可能只能捕获一种类型的关系。多头注意力允许模型同时关注不同位置的不同表示空间的信息。

数学表示

MultiHead ( Q , K , V ) = Concat ( head 1 , . . . , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO

其中每个注意力头计算为:
head i = Attention ( Q W i Q , K W i K , V W i V ) \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)

参数矩阵

  • W i Q ∈ R d m o d e l × d k W_i^Q \in \mathbb{R}^{d_{model} \times d_k} WiQRdmodel×dk:第i个头的查询权重矩阵
  • W i K ∈ R d m o d e l × d k W_i^K \in \mathbb{R}^{d_{model} \times d_k} WiKRdmodel×dk:第i个头的键权重矩阵
  • W i V ∈ R d m o d e l × d v W_i^V \in \mathbb{R}^{d_{model} \times d_v} WiVRdmodel×dv:第i个头的值权重矩阵
  • W O ∈ R h d v × d m o d e l W^O \in \mathbb{R}^{hd_v \times d_{model}} WORhdv×dmodel:输出权重矩阵

维度关系

通常设置: d k = d v = d m o d e l / h d_k = d_v = d_{model}/h dk=dv=dmodel/h,其中 h h h是头的数量。


位置编码

为什么需要位置编码?

注意力机制本身是排列不变的(permutation invariant),即改变输入序列的顺序不会影响输出。但在序列建模中,位置信息至关重要。

正弦位置编码

Transformer使用固定的正弦和余弦函数来编码位置信息:

P E ( p o s , 2 i ) = sin ⁡ ( p o s 1000 0 2 i / d m o d e l ) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i)=sin(100002i/dmodelpos)

P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 1000 0 2 i / d m o d e l ) PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i+1)=cos(100002i/dmodelpos)

其中:

  • p o s pos pos:位置
  • i i i:维度索引
  • d m o d e l d_{model} dmodel:模型维度

位置编码的性质

  1. 唯一性:每个位置都有唯一的编码
  2. 相对位置信息:模型可以学习到相对位置关系
  3. 外推性:可以处理比训练时更长的序列

前馈神经网络

结构

每个Transformer层都包含一个位置级的前馈网络:

FFN ( x ) = max ⁡ ( 0 , x W 1 + b 1 ) W 2 + b 2 \text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2

特点

  • 两个线性变换,中间使用ReLU激活
  • 内部维度通常是模型维度的4倍
  • 应用于序列的每个位置

残差连接与层归一化

残差连接

每个子层都使用残差连接:
output = LayerNorm ( x + Sublayer ( x ) ) \text{output} = \text{LayerNorm}(x + \text{Sublayer}(x)) output=LayerNorm(x+Sublayer(x))

层归一化

与批量归一化不同,层归一化在特征维度上进行:

LayerNorm ( x ) = γ x − μ σ + β \text{LayerNorm}(x) = \gamma \frac{x - \mu}{\sigma} + \beta LayerNorm(x)=γσxμ+β

其中:

  • μ = 1 d ∑ i = 1 d x i \mu = \frac{1}{d}\sum_{i=1}^{d} x_i μ=d1i=1dxi
  • σ = 1 d ∑ i = 1 d ( x i − μ ) 2 \sigma = \sqrt{\frac{1}{d}\sum_{i=1}^{d}(x_i - \mu)^2} σ=d1i=1d(xiμ)2

编码器-解码器架构

编码器 (Encoder)

  • 6个相同的层堆叠
  • 每层包含:多头自注意力 + 前馈网络
  • 残差连接和层归一化

解码器 (Decoder)

  • 6个相同的层堆叠
  • 每层包含:
    1. 掩码多头自注意力
    2. 编码器-解码器注意力
    3. 前馈网络

掩码机制

在解码器的自注意力中,使用掩码防止模型看到未来的信息:

mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1)
scores = scores.masked_fill(mask == 1, -1e9)

数学推导详解

注意力分数的计算复杂度

对于序列长度为 n n n的输入:

  • 计算 Q K T QK^T QKT O ( n 2 d k ) O(n^2 d_k) O(n2dk)
  • Softmax: O ( n 2 ) O(n^2) O(n2)
  • 乘以V: O ( n 2 d v ) O(n^2 d_v) O(n2dv)
  • 总复杂度: O ( n 2 d m o d e l ) O(n^2 d_{model}) O(n2dmodel)

梯度推导

对于注意力权重的梯度:

∂ L ∂ A i j = ∑ k ∂ L ∂ O i k V j k \frac{\partial L}{\partial A_{ij}} = \sum_k \frac{\partial L}{\partial O_{ik}} V_{jk} AijL=kOikLVjk

其中 A A A是注意力权重矩阵, O O O是输出。

Softmax的梯度

∂ softmax ( x i ) ∂ x j = softmax ( x i ) ( δ i j − softmax ( x j ) ) \frac{\partial \text{softmax}(x_i)}{\partial x_j} = \text{softmax}(x_i)(\delta_{ij} - \text{softmax}(x_j)) xjsoftmax(xi)=softmax(xi)(δijsoftmax(xj))


代码实现

基础注意力机制

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

class ScaledDotProductAttention(nn.Module):
    def __init__(self, d_k):
        super().__init__()
        self.d_k = d_k
        
    def forward(self, Q, K, V, mask=None):
        # 计算注意力分数
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # 应用掩码
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        
        # Softmax
        attention_weights = F.softmax(scores, dim=-1)
        
        # 加权求和
        output = torch.matmul(attention_weights, V)
        
        return output, attention_weights

多头注意力

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        assert d_model % num_heads == 0
        
        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads
        
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)
        
        self.attention = ScaledDotProductAttention(self.d_k)
        
    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)
        
        # 线性变换并重塑为多头形式
        Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        
        # 应用注意力
        attn_output, attn_weights = self.attention(Q, K, V, mask)
        
        # 连接多头
        attn_output = attn_output.transpose(1, 2).contiguous().view(
            batch_size, -1, self.d_model)
        
        # 最终线性变换
        output = self.W_o(attn_output)
        
        return output, attn_weights

位置编码

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super().__init__()
        
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * 
                           (-math.log(10000.0) / d_model))
        
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)
        
    def forward(self, x):
        return x + self.pe[:x.size(0), :]

前馈网络

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff):
        super().__init__()
        self.linear1 = nn.Linear(d_model, d_ff)
        self.linear2 = nn.Linear(d_ff, d_model)
        self.relu = nn.ReLU()
        
    def forward(self, x):
        return self.linear2(self.relu(self.linear1(x)))

编码器层

class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.self_attn = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = FeedForward(d_model, d_ff)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, x, mask=None):
        # 自注意力
        attn_output, _ = self.self_attn(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_output))
        
        # 前馈网络
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))
        
        return x

完整的Transformer编码器

class TransformerEncoder(nn.Module):
    def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_len=5000):
        super().__init__()
        self.d_model = d_model
        self.embedding = nn.Embedding(vocab_size, d_model)
        self.pos_encoding = PositionalEncoding(d_model, max_len)
        
        self.layers = nn.ModuleList([
            EncoderLayer(d_model, num_heads, d_ff) 
            for _ in range(num_layers)
        ])
        
    def forward(self, x, mask=None):
        # 词嵌入 + 位置编码
        x = self.embedding(x) * math.sqrt(self.d_model)
        x = self.pos_encoding(x)
        
        # 通过编码器层
        for layer in self.layers:
            x = layer(x, mask)
            
        return x

训练与优化

学习率调度

Transformer使用特殊的学习率调度策略:

lrate = d m o d e l − 0.5 ⋅ min ⁡ ( step_num − 0.5 , step_num ⋅ warmup_steps − 1.5 ) \text{lrate} = d_{model}^{-0.5} \cdot \min(\text{step\_num}^{-0.5}, \text{step\_num} \cdot \text{warmup\_steps}^{-1.5}) lrate=dmodel0.5min(step_num0.5,step_numwarmup_steps1.5)

class TransformerLRScheduler:
    def __init__(self, d_model, warmup_steps=4000):
        self.d_model = d_model
        self.warmup_steps = warmup_steps
        
    def __call__(self, step):
        arg1 = step ** (-0.5)
        arg2 = step * (self.warmup_steps ** -1.5)
        return (self.d_model ** -0.5) * min(arg1, arg2)

标签平滑

class LabelSmoothing(nn.Module):
    def __init__(self, size, padding_idx, smoothing=0.1):
        super().__init__()
        self.criterion = nn.KLDivLoss(reduction='sum')
        self.padding_idx = padding_idx
        self.confidence = 1.0 - smoothing
        self.smoothing = smoothing
        self.size = size
        
    def forward(self, x, target):
        true_dist = x.data.clone()
        true_dist.fill_(self.smoothing / (self.size - 2))
        true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)
        true_dist[:, self.padding_idx] = 0
        mask = torch.nonzero(target.data == self.padding_idx)
        if mask.dim() > 0:
            true_dist.index_fill_(0, mask.squeeze(), 0.0)
        return self.criterion(x, true_dist)

应用与扩展

主要应用领域

  1. 机器翻译:原始论文的主要任务
  2. 文本摘要:BART, T5等模型
  3. 问答系统:BERT的主要应用之一
  4. 代码生成:CodeT5, Codex等
  5. 图像处理:Vision Transformer (ViT)

重要的Transformer变体

BERT (Bidirectional Encoder Representations from Transformers)
  • 只使用编码器
  • 双向上下文建模
  • 预训练 + 微调范式
GPT (Generative Pre-trained Transformer)
  • 只使用解码器
  • 自回归生成
  • 大规模语言模型的基础
T5 (Text-to-Text Transfer Transformer)
  • 编码器-解码器架构
  • 所有任务都转换为文本到文本

效率优化

Sparse Attention

减少注意力计算的复杂度:

  • Longformer:滑动窗口 + 全局注意力
  • BigBird:随机 + 窗口 + 全局
  • Linformer:线性复杂度
知识蒸馏

将大模型的知识转移到小模型:

def distillation_loss(student_logits, teacher_logits, labels, temperature=3.0, alpha=0.7):
    soft_loss = F.kl_div(
        F.log_softmax(student_logits / temperature, dim=-1),
        F.softmax(teacher_logits / temperature, dim=-1),
        reduction='batchmean'
    ) * (temperature ** 2)
    
    hard_loss = F.cross_entropy(student_logits, labels)
    
    return alpha * soft_loss + (1 - alpha) * hard_loss

总结

Transformer架构的成功在于其优雅的设计和强大的表示能力:

关键创新点

  1. 完全基于注意力:摒弃了RNN和CNN
  2. 并行化训练:显著提高训练效率
  3. 长距离依赖:有效捕获远程关系
  4. 可扩展性:为大规模模型奠定基础

数学美感

  • 注意力机制的矩阵乘法形式
  • 位置编码的周期性设计
  • 残差连接的梯度传播
  • 多头注意力的信息整合

实践意义

Transformer不仅改变了NLP领域,还在计算机视觉、语音识别、强化学习等领域展现出巨大潜力。从BERT到GPT,从ViT到DALL-E,Transformer架构持续推动着人工智能的发展。


参考文献

  1. Vaswani, A., et al. (2017). Attention is all you need. In NIPS.
  2. Devlin, J., et al. (2018). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.
  3. Radford, A., et al. (2019). Language Models are Unsupervised Multitask Learners.
  4. Dosovitskiy, A., et al. (2020). An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale.

本文深入探讨了Transformer的各个方面,从基础概念到高级应用。希望这篇详细的介绍能帮助你更好地理解这一重要的深度学习架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值