0%

Transformer入门

从PyTorch的积木到AI的引擎:一文读懂Transformer入门

掌握了PyTorch的核心——张量、自动微分、损失函数和优化器。已经能用torch.nn.Linear搭建网络,理解backward()如何计算梯度。是时候从“玩具模型”迈向真正驱动现代人工智能的引擎了。这个引擎,就是Transformer。

Transformer不是一种新的编程语言,也不是一个独立的软件。它是一个模型架构,一套精妙的神经网络设计蓝图。它由Google Brain团队在2017年的里程碑论文《Attention Is All You Need》中提出,并彻底颠覆了人工智能的格局。

要理解Transformer,我们必须先回到它出现之前的时代,看看它究竟解决了什么痛点。

在Transformer之前,处理序列数据(如一句话、一段音频)的主流是循环神经网络(RNN)及其变体LSTM。RNN的工作方式像一个勤奋的朗读者,它按顺序一个字一个字地处理句子。当它读到第N个词时,它只能依靠之前N-1个词留下的“记忆”(隐藏状态)来理解上下文。

这种方式有两个致命缺陷:

  • 无法并行:因为必须等前一个词处理完才能处理下一个,所以训练速度非常慢,无法充分利用GPU的强大算力。
  • 长距离依赖问题:当句子很长时,RNN很难记住开头的信息。就像你读一本长篇小说,读到结尾时可能已经忘了主角的名字。

Transformer的出现,一举解决了这两个问题。它完全摒弃了循环结构,转而拥抱一个名为自注意力(Self-Attention)的机制。这个机制的核心思想非常直观:让句子中的每个词都去“关注”句子中的所有其他词,从而直接捕捉任意两个词之间的关系,无论它们相距多远。

这种设计带来了两大革命性优势:

  • 极致并行:模型可以一次性看到整个句子,所有词的计算都可以同时进行,训练效率得到指数级提升。
  • 强大的长程建模能力:通过自注意力,句子开头的词和结尾的词可以直接“对话”,完美解决了长距离依赖问题。

凭借其无与伦比的效率和性能,Transformer迅速从自然语言处理(NLP)领域扩张到计算机视觉(CV)、语音处理乃至多模态领域,成为当今所有大语言模型(如GPT、BERT)的绝对基石。

理解了Transformer的“为什么”,我们再来拆解它的“怎么做”。一个标准的Transformer模型,其内部结构精巧而优雅,主要由以下几个核心组件构成。

在将文本输入模型之前,首先要将每个词(或子词)转换成一个计算机可以理解的数字向量,这个过程叫词嵌入(Word Embedding)。例如,“国王”和“王后”的向量在空间中的距离会很近,而“苹果”的向量则会离它们很远。

但Transformer是并行处理所有词的,它本身并不理解词的顺序。为了让模型知道“我打他”和“他打我”的区别,我们必须为每个词的嵌入向量加上一个位置编码(Positional Encoding)。这个编码是一个根据词在句子中的位置生成的独特向量,它告诉模型每个词的先后顺序。

这是Transformer的“心脏”。它的任务是让模型学会关注句子中最重要的部分。我们可以把它想象成一个信息检索系统,包含三个角色:

  • Query(查询):代表“我当前想找什么信息”。
  • Key(键):代表“我身上有什么信息”。
  • Value(值):代表“我实际包含的信息内容”。

模型通过计算Query和所有Key的相似度,来决定从对应的Value中提取多少信息。这个过程会生成一个全新的、融合了上下文信息的表示向量。

为了从不同角度理解句子,Transformer会使用多头注意力(Multi-Head Attention)。它相当于开了多个“观察视角”,有的头可能关注语法结构,有的头关注指代关系,最后将所有头的观察结果综合起来,形成一个更全面、更丰富的理解。

在注意力层之后,模型还会通过一个前馈网络(Feed-Forward Network)。这是一个简单的全连接网络,独立地对每个位置的向量进行非线性变换,进一步提取和整合特征。

一个完整的Transformer模型通常采用编码器-解码器(Encoder-Decoder)架构。

  • 编码器(Encoder):负责“阅读理解”。它接收输入句子,通过多层堆叠的自注意力和前馈网络,将其转换成一个富含上下文信息的特征表示。
  • 解码器(Decoder):负责“写作生成”。它接收编码器的输出,并以自回归的方式(即一个词接一个词地)生成目标句子。在生成每个词时,它会通过交叉注意力(Cross-Attention)机制,回头去“查阅”编码器提供的原文信息,确保翻译或生成的准确性。

从理论到实践,我们来看看如何用PyTorch这个强大的工具箱,将Transformer的设计蓝图变为现实。这就像用乐高积木,按照图纸一步步搭建出宏伟的城堡。

首先,我们需要定义模型的核心——自注意力模块。这个过程完全由PyTorch的张量运算构成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch
import torch.nn as nn
import math

class ScaledDotProductAttention(nn.Module):
def __init__(self, d_k):
super().__init__()
self.d_k = d_k # 键向量的维度
# 将一组原始分数(logits)转换成概率分布。把任意数值变成 0 到 1 之间的概率值,并且保证这些概率值加起来等于 1
self.softmax = nn.Softmax(dim=-1)

def forward(self, Q, K, V):
# 1. 计算Q和K的相似度 (矩阵乘法)
scores = torch.matmul(Q, K.transpose(-1, -2))

# 2. 缩放,防止点积过大导致Softmax梯度消失
scores = scores / math.sqrt(self.d_k)

# 3. 应用Softmax,得到注意力权重
attention_weights = self.softmax(scores)

# 4. 用权重对V加权求和,得到最终输出
output = torch.matmul(attention_weights, V)
return output

这段代码精确地实现了自注意力的数学公式。Q, K, V都是PyTorch张量,torch.matmul是矩阵乘法,nn.Softmax是激活函数。你看,复杂的注意力机制,底层依然是你最熟悉的PyTorch操作。

接下来,我们将多个注意力头组合起来,并加上残差连接和层归一化,构建一个完整的编码器层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super().__init__()
self.d_model = d_model # 词向量的总维度,比如512
self.num_heads = num_heads # “头”的数量,比如8个
self.d_k = d_model // num_heads # 每个“头”的维度,512/8=64

# 这三个线性层负责把输入 x 转换成 Q(查询), K(键), V(值)
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, x):
batch_size, seq_len, _ = x.shape

# 1. 线性投影并分割成多个头
# 用线性层把输入 x 转换成查询向量 Q。此时 Q 的形状是 (batch_size, seq_len, d_model)
# view().transpose(1, 2): 它把 Q 的最后一个维度(比如512)切分成 num_heads 个(比如8个)小向量,每个小向量的维度是 d_k(比如64)。然后通过转置,把“头”的维度放到前面。
# 意义是:原来我们只有一个大的查询向量,现在我们把它分成了8个“小专家”(头)。每个“小专家”都从自己的视角去观察整个句子
Q = self.W_q(x).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(x).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(x).view(batch_size, seq_len, self.num_heads, self.d_k).transpose(1, 2)

# 2. 并行计算多头注意力
head_outputs = []
# 让每一个“小专家”(头)独立工作
for i in range(self.num_heads):
head_output = self.attention(Q[:, i], K[:, i], V[:, i])
# 每个头都会输出一个结果,我们把所有头的结果都收集到 head_outputs 列表里
head_outputs.append(head_output)

# 3. 把他们的成果拼接起来。torch.cat(..., dim=-1) 会在最后一个维度上进行拼接,把8个维度为 d_k (64) 的向量,重新拼成一个维度为 d_model (8 * 64 = 512) 的大向量。
concatenated = torch.cat(head_outputs, dim=-1)

# 4. 最终线性变换。把所有“小专家”的观点综合起来,形成一个最终的、更全面的理解
output = self.W_o(concatenated)
return output

# 一个完整的编码器层还包括前馈网络和残差连接
class EncoderLayer(nn.Module):
def __init__(self, d_model, ffn_hidden, num_heads):
super().__init__()
self.attention = MultiHeadAttention(d_model, num_heads)
# 前馈网络,一个简单的两层全连接网络
self.ffn = nn.Sequential(
nn.Linear(d_model, ffn_hidden), # 先放大维度
nn.ReLU(), # 加一个非线性激活函数
nn.Linear(ffn_hidden, d_model) # 再变回原来的维度
)
# 两个层归一化,用来稳定训练
self.layer_norm1 = nn.LayerNorm(d_model)
self.layer_norm2 = nn.LayerNorm(d_model)

def forward(self, x):
# 残差连接 + 层归一化
x = self.layer_norm1(x + self.attention(x))
x = self.layer_norm2(x + self.ffn(x))
return x

通过组合这些模块,我们就可以搭建出完整的Transformer模型。这个过程让你深刻理解到,看似神秘的“大模型”,其内部是由一个个清晰、可解释的PyTorch模块精密协作而成的。

当然,在现实中,我们很少从零开始写代码。Hugging Face的transformers库提供了成千上万预训练好的Transformer模型,让我们能像搭积木一样快速应用。

1
2
3
4
5
6
7
8
9
10
11
12
import os
# 使用国内镜像
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
from transformers import pipeline

# 一行代码加载一个情感分析模型
classifier = pipeline("sentiment-analysis")

# 直接使用
result = classifier("I love learning about Transformer with PyTorch!")
print(result)
# 输出: [{'label': 'POSITIVE', 'score': 0.9998}]

这行简洁代码的背后,是Hugging Face库用PyTorch实现的、结构极其复杂的BERT或GPT模型。它已经学习了海量文本,我们只需调用它,就能获得强大的AI能力。

从PyTorch的nn.Linearbackward(),到Transformer的自注意力机制,再到Hugging Face的预训练模型,你已经走完了一条从基础到前沿的完整路径。

Transformer并非遥不可及的黑箱,它是由你熟悉的PyTorch积木搭建而成的宏伟建筑。理解它的工作原理,不仅让你能更好地使用现有的大模型,更为你未来探索和创新打开了大门。现在,你已经手握开启AI新世界的钥匙。

欢迎关注我的其它发布渠道