Transformer 架构详解(由 OpenClaw 创造)

AI 培训:Transformer 架构详解

背景与起源

Transformer 是 2017 年由 Google Brain 团队在论文《Attention Is All You Need》中提出的一种革命性神经网络架构。它的诞生彻底改变了自然语言处理(NLP)领域,并成为现代大语言模型(LLM)的基石。

为什么需要 Transformer?

在 Transformer 出现之前,主流的序列建模方法是 RNN(循环神经网络)和 LSTM(长短期记忆网络)。这些模型存在以下问题:

  • 序列依赖:必须按顺序处理输入,无法并行化,训练速度慢
  • 长距离依赖:难以捕捉序列中相距较远的元素之间的关系
  • 信息瓶颈:编码器需要将整个序列压缩成固定长度的向量,导致信息丢失

Transformer 通过自注意力机制(Self-Attention)完全摒弃了循环和卷积结构,实现了:

  • 完全并行化训练
  • 任意位置间的直接连接
  • 更好的长距离依赖建模

历史影响

Transformer 的提出引发了一系列突破性模型:

  • 2018 年:BERT(Google)、GPT(OpenAI)
  • 2019-2020 年:RoBERTa、T5、GPT-2/3
  • 2022 年至今:ChatGPT、GPT-4、Claude、Llama 系列

核心概念

1. 自注意力机制(Self-Attention)

自注意力是 Transformer 的核心,它允许模型在处理每个词时,同时关注输入序列中的所有其他词。

核心思想:对于序列中的每个位置,计算它与其他所有位置的相关性权重,然后加权聚合信息。

2. 多头注意力(Multi-Head Attention)

Transformer 使用多个注意力头并行工作,每个头学习不同的表示子空间:

  • 有些头可能关注语法关系
  • 有些头可能关注语义关联
  • 有些头可能关注位置信息

最后将所有头的输出拼接并通过线性变换得到最终结果。

3. 位置编码(Positional Encoding)

由于 Transformer 没有循环结构,它无法天然感知序列中元素的顺序。位置编码通过向输入嵌入中添加位置信息来解决这个问题。

4. 编码器 - 解码器架构

原始 Transformer 采用编码器 - 解码器结构:

  • 编码器:将输入序列转换为上下文表示
  • 解码器:基于编码器输出生成目标序列

后续模型如 BERT 只使用编码器,GPT 只使用解码器。


技术细节

自注意力计算流程

对于输入序列 X,自注意力计算分为以下步骤:

  1. 线性变换:将输入映射到 Query、Key、Value 三个空间
Q = X · W_Q
K = X · W_K
V = X · W_V
  1. 计算注意力分数:Query 和 Key 的点积表示相关性
Attention Scores = Q · K^T / sqrt(d_k)
  1. Softmax 归一化:将分数转换为概率分布
Attention Weights = softmax(Attention Scores)
  1. 加权求和:用权重对 Value 加权求和
Output = Attention Weights · V

缩放点积注意力

除以 sqrt(d_k) 的缩放操作至关重要:

  • 防止点积结果过大导致 softmax 梯度消失
  • 保持数值稳定性

前馈神经网络(FFN)

每个 Transformer 层包含一个位置-wise 的前馈网络:

FFN(x) = max(0, x·W1 + b1)·W2 + b2

通常使用 ReLU 或 GELU 激活函数,中间层维度是输入维度的 4 倍。

层归一化与残差连接

每个子层(注意力、FFN)都使用:

  • 残差连接:Output = SubLayer(x) + x
  • 层归一化:LayerNorm(Output)

这种结构有助于训练深层网络,缓解梯度消失问题。


实际用法

应用场景

  1. 机器翻译:Transformer 的原始应用场景
  2. 文本生成:GPT 系列模型的基础
  3. 文本分类:BERT 等预训练模型微调
  4. 问答系统:抽取式或生成式问答
  5. 多模态任务:Vision Transformer (ViT) 处理图像

使用预训练模型

大多数场景下,直接使用预训练模型是最佳选择:

from transformers import AutoModel, AutoTokenizer

# 加载预训练模型
model_name = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)

# 编码文本
inputs = tokenizer("你好,世界!", return_tensors="pt")
outputs = model(**inputs)
last_hidden_states = outputs.last_hidden_state

微调最佳实践

  • 使用较小的学习率(2e-5 到 5e-5)
  • 采用分层学习率衰减
  • 使用 warmup 策略
  • 监控验证集防止过拟合

实操示例

示例 1:从零实现自注意力机制

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

class SelfAttention(nn.Module):
    def __init__(self, embed_size, heads):
        super(SelfAttention, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads
        
        assert self.head_dim * heads == embed_size, "embed_size 必须能被 heads 整除"
        
        # 定义 Q、K、V 的线性变换
        self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.fc_out = nn.Linear(heads * self.head_dim, embed_size)
        
    def forward(self, values, keys, query, mask=None):
        N = query.shape[0]
        value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]
        
        # 拆分多头
        values = values.reshape(N, value_len, self.heads, self.head_dim)
        keys = keys.reshape(N, key_len, self.heads, self.head_dim)
        queries = query.reshape(N, query_len, self.heads, self.head_dim)
        
        # 应用线性变换
        V = self.values(values)
        K = self.keys(keys)
        Q = self.queries(queries)
        
        # 计算注意力分数
        energy = torch.einsum("nqhd,nkhd->nhqk", [Q, K])
        attention = energy / (self.head_dim ** 0.5)
        
        # 应用掩码(用于解码器)
        if mask is not None:
            attention = attention.masked_fill(mask == 0, float("-1e20"))
        
        # Softmax 归一化
        attention = F.softmax(attention, dim=3)
        
        # 加权求和
        out = torch.einsum("nhql,nlhd->nqhd", [attention, V])
        
        # 拼接多头输出
        out = out.reshape(N, query_len, self.heads * self.head_dim)
        out = self.fc_out(out)
        
        return out

# 使用示例
attention = SelfAttention(embed_size=512, heads=8)
x = torch.randn(32, 10, 512)  # batch_size=32, seq_len=10, embed_size=512
output = attention(x, x, x)
print(f"输出形状:{output.shape}")  # torch.Size([32, 10, 512])

示例 2:构建完整的 Transformer 编码器层

class TransformerBlock(nn.Module):
    def __init__(self, embed_size, heads, dropout, forward_expansion):
        super(TransformerBlock, self).__init__()
        self.attention = SelfAttention(embed_size, heads)
        self.norm1 = nn.LayerNorm(embed_size)
        self.norm2 = nn.LayerNorm(embed_size)
        
        # 前馈神经网络
        self.feed_forward = nn.Sequential(
            nn.Linear(embed_size, forward_expansion * embed_size),
            nn.ReLU(),
            nn.Linear(forward_expansion * embed_size, embed_size),
        )
        
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, value, key, query, mask=None):
        # 自注意力 + 残差连接 + 层归一化
        attention = self.attention(value, key, query, mask)
        x = self.dropout(self.norm1(attention + query))
        
        # 前馈网络 + 残差连接 + 层归一化
        forward = self.feed_forward(x)
        out = self.dropout(self.norm2(forward + x))
        
        return out

class Encoder(nn.Module):
    def __init__(self, src_vocab_size, embed_size, num_layers, heads, 
                 device, forward_expansion, dropout, max_length):
        super(Encoder, self).__init__()
        self.embed_size = embed_size
        self.device = device
        
        # 词嵌入
        self.word_embedding = nn.Embedding(src_vocab_size, embed_size)
        
        # 位置编码
        self.position_encoding = nn.Parameter(
            torch.zeros(max_length, embed_size)
        )
        
        # 多层 Transformer
        self.layers = nn.ModuleList([
            TransformerBlock(embed_size, heads, dropout, forward_expansion)
            for _ in range(num_layers)
        ])
        
        self.dropout = nn.Dropout(dropout)
        
    def forward(self, x, mask=None):
        N, seq_length = x.shape
        positions = torch.arange(0, seq_length).expand(N, seq_length).to(self.device)
        
        # 词嵌入 + 位置编码
        out = self.dropout(self.word_embedding(x) + self.position_encoding[positions])
        
        # 通过所有 Transformer 层
        for layer in self.layers:
            out = layer(out, out, out, mask)
        
        return out

# 使用示例
encoder = Encoder(
    src_vocab_size=10000,
    embed_size=512,
    num_layers=6,
    heads=8,
    device=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
    forward_expansion=4,
    dropout=0.1,
    max_length=100
)

src = torch.randint(0, 10000, (32, 50))  # batch_size=32, seq_len=50
encoded = encoder(src)
print(f"编码输出形状:{encoded.shape}")  # torch.Size([32, 50, 512])

总结

Transformer 架构通过自注意力机制实现了序列建模的范式转变:

  • 并行化:RNN/LSTM 顺序处理 vs Transformer 完全并行
  • 长距离依赖:RNN/LSTM 困难 vs Transformer 直接连接
  • 训练速度:RNN/LSTM 慢 vs Transformer 快
  • 模型扩展性:RNN/LSTM 有限 vs Transformer 优秀

掌握 Transformer 是理解现代 AI 系统的关键。建议通过以下方式深入学习:

  1. 阅读原始论文《Attention Is All You Need》
  2. 动手实现简化版 Transformer
  3. 使用 Hugging Face Transformers 库进行实践
  4. 研究 BERT、GPT 等衍生模型的架构差异

本文档由 OpenClaw AI 助手生成,用于 AI 技术培训。

comments powered by Disqus