Transformer 模型架构详解与核心组件解析
Transformer 模型是目前自然语言处理(NLP)以及计算机视觉等领域中应用非常广泛的深度学习模型架构。它由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出,并迅速取代了传统的循环神经网络(RNN)和长短期记忆网络(LSTM)在许多任务中的主导地位。
Transformer 模型基于自注意力机制解决序列建模问题,通过编码器解码器结构实现并行计算。核心组件包括输入嵌入、位置编码、多头自注意力、前馈网络及残差连接。本文详细解析了各组件原理,提供了从零构建的 Python 代码示例,并探讨了训练优化策略与应用场景。

Transformer 模型是目前自然语言处理(NLP)以及计算机视觉等领域中应用非常广泛的深度学习模型架构。它由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出,并迅速取代了传统的循环神经网络(RNN)和长短期记忆网络(LSTM)在许多任务中的主导地位。
Transformer 模型的关键创新点是其自注意力机制,它通过自注意力机制解决了长期依赖问题,极大地提高了并行计算的效率。相比 RNN 需要按时间步顺序计算,Transformer 能够一次性处理整个序列,显著提升了训练速度。
Transformer 模型主要由编码器(Encoder)和解码器(Decoder)两部分组成,两者均采用堆叠的层结构。
编码器主要负责将输入序列转化为一组上下文相关的高维表示。它由多个相同的层组成,每个层都有两个主要子层:
此外,每个子层都包含残差连接(Residual Connection)和层归一化(Layer Normalization),以增强稳定性和性能。
解码器利用编码器的输出生成目标序列。解码器的结构与编码器类似,包含多个相同的层,但解码器的每一层有三个子层:
下面,我们一起来看一下 Transformer 中的核心组件及其数学原理。
输入嵌入层的作用是将输入序列的每个词转换为高维空间中的向量表示。在自然语言处理中,通常使用预训练的词向量如 Word2Vec 或 GloVe,或者在训练过程中与模型一起学习嵌入。这些嵌入能够捕捉词汇的语义信息并将其转换为固定大小的向量,通常大小为 512。
由于 Transformer 完全基于注意力机制并且不使用任何循环结构,它需要一种方法来利用输入序列中词的顺序信息。位置编码通过将一个相对或绝对位置的编码添加到输入嵌入中来实现。
位置编码常使用正弦和余弦函数,其公式如下所示:
$$\text{PE}(pos, 2i) = \sin(pos / 10000^{2i/d_{model}})$$ $$\text{PE}(pos, 2i+1) = \cos(pos / 10000^{2i/d_{model}})$$
这里,$pos$ 表示词的位置,$i$ 表示维度索引,$d_{model}$ 是嵌入维度。这种设计使得模型能够学习相对位置关系。
多头自注意力机制是 Transformer 的核心,它允许模型在不同的表示空间中关注输入序列的不同部分。它的主要思想是在同一时间通过多个独立的注意力头(Attention Head)来关注序列中不同部分的信息,然后将这些信息综合起来,生成更丰富的表示。
在讨论多头自注意力机制之前,首先需要理解自注意力(Self-Attention)机制。自注意力机制的目的是对输入序列中的每个元素计算一个输出,这个输出是其他所有元素的加权求和,权重由当前元素与序列中其他元素的相关度决定。
计算查询(Query)、键(Key)和值(Value) 对于序列中的每个元素 $x$,通过三个线性变换分别映射为查询向量 $Q$、键向量 $K$ 和值向量 $V$。 其中,$W^Q$、$W^K$ 和 $W^V$ 是可学习的权重矩阵。
计算注意力分数 通过计算其查询向量 $Q$ 与所有键向量 $K$ 的点积,得到该元素与其他元素的相关性(即注意力得分)。为了稳定训练过程,这些分数会除以 $\sqrt{d_k}$,其中 $d_k$ 是键向量的维度。
计算注意力权重 将注意力分数通过 Softmax 函数转换为注意力权重,使得它们和为 1。
计算注意力输出 注意力输出是值向量的加权和。
多头注意力机制通过并行地计算多组查询、键和值,来捕捉输入序列中不同子空间的依赖关系。具体来说,它将自注意力机制的计算过程复制 $h$ 次,每次使用不同的查询、键、值的线性变换。最后,将这些头的输出拼接起来,并通过一个线性变换得到最终的输出。
每个编码器和解码器层中,除了自注意力机制,还有一个独立的前馈神经网络(FFN),它用于对自注意力输出的结果进行进一步的非线性变换。FFN 由两层线性变换和一个激活函数(通常是 ReLU)组成。
FFN 的作用是通过非线性映射提升模型的表达能力,使模型能够拟合更复杂的函数关系。
为了加速训练并解决梯度消失或爆炸的问题,Transformer 在每个子层(包括自注意力机制和前馈神经网络)后面引入了残差连接和层归一化。
Masked 多头自注意力子层用于解码器的生成任务。在生成过程中,模型生成当前时间步的单词时,只能依赖之前生成的单词,而不能看到未来未生成的单词。为了确保这一点,Masked 多头自注意力机制通过在注意力矩阵中对未来位置进行掩码,使其权重为负无穷,从而保证模型只能'关注'到之前的位置。
编码器 - 解码器多头注意力子层在 Transformer 解码器中起到了关键作用,它使解码器能够有效地关注输入序列(编码器的输出),从而在生成序列时参考原始输入信息。具体来说,编码器 - 解码器多头注意力的基本思想是通过对编码器输出(Key 和 Value)和解码器当前输入(Query)来生成新的表示。
下面,我们从头开始构建一个 Transformer 模型。首先,我们来创建一个 MultiHeadAttention 类,它实现了 Transformer 中的多头自注意力机制。
import numpy as np
class MultiHeadAttention:
def __init__(self, num_hiddens: int, num_heads: int, dropout: float = 0.0, bias: bool = False):
self.num_heads = num_heads
self.num_hiddens = num_hiddens
self.d_k = self.d_v = num_hiddens // num_heads
# 初始化权重矩阵
self.W_q = np.random.rand(num_hiddens, num_hiddens)
self.W_k = np.random.rand(num_hiddens, num_hiddens)
self.W_v = np.random.rand(num_hiddens, num_hiddens)
self.W_o = np.random.rand(num_hiddens, num_hiddens)
if bias:
self.b_q = np.random.rand(num_hiddens)
self.b_k = np.random.rand(num_hiddens)
self.b_v = np.random.rand(num_hiddens)
self.b_o = np.random.rand(num_hiddens)
else:
self.b_q = self.b_k = self.b_v = self.b_o = np.zeros(num_hiddens)
def transpose_qkv(self, X: np.ndarray) -> np.ndarray:
# 调整形状以便并行计算多个 head
X = X.reshape(X.shape[0], X.shape[1], self.num_heads, -1)
X = X.transpose(0, 2, 1, 3)
return X.reshape(-1, X.shape[2], X.shape[3])
def transpose_output(self, X: np.ndarray) -> np.ndarray:
# 恢复形状
X = X.reshape(-1, self.num_heads, X.shape[1], X.shape[2])
X = X.transpose(0, 2, 1, 3)
return X.reshape(X.shape[0], X.shape[1], -1)
def scaled_dot_product_attention(self, Q: np.ndarray, K: np.ndarray, V: np.ndarray, valid_lens: np.ndarray = None) -> np.ndarray:
d_k = Q.shape[-1]
scores = np.matmul(Q, K.transpose(0, 2, 1)) / np.sqrt(d_k)
if valid_lens is not None:
mask = np.arange(scores.shape[-1]) < valid_lens[:, None]
scores = np.where(mask[:, None, :], scores, -np.inf)
attention_weights = np.exp(scores - np.max(scores, axis=-1, keepdims=True))
attention_weights /= attention_weights.sum(axis=-1, keepdims=True)
return np.matmul(attention_weights, V)
def forward(self, queries: np.ndarray, keys: np.ndarray, values: np.ndarray, valid_lens: np.ndarray = None) -> np.ndarray:
queries = self.transpose_qkv(np.dot(queries, self.W_q) + self.b_q)
keys = self.transpose_qkv(np.dot(keys, self.W_k) + self.b_k)
values = self.transpose_qkv(np.dot(values, self.W_v) + self.b_v)
if valid_lens is not None:
valid_lens = np.repeat(valid_lens, self.num_heads, axis=0)
output = self.scaled_dot_product_attention(queries, keys, values, valid_lens)
output_concat = self.transpose_output(output)
return np.dot(output_concat, self.W_o) + self.b_o
在 forward 方法中,首先对 queries、keys 和 values 进行线性变换,分别生成查询、键和值向量。然后通过 scaled_dot_product_attention 方法计算每个注意力头的输出。接下来,调用 transpose_output 方法将多个注意力头的输出拼接起来。最后,拼接后的输出通过 W_o 矩阵进行线性变换,并加上偏置 b_o,得到最终的输出。
下面,我们来看一下位置编码的实现。
def positional_encoding(seq_len: int, d_model: int) -> np.ndarray:
pos = np.arange(seq_len)[:, np.newaxis]
i = np.arange(d_model)[np.newaxis, :]
angle_rates = 1 / np.power(10000, (2 * (i // 2)) / np.float32(d_model))
pos_encoding = pos * angle_rates
pos_encoding[:, 0::2] = np.sin(pos_encoding[:, 0::2])
pos_encoding[:, 1::2] = np.cos(pos_encoding[:, 1::2])
return pos_encoding
然后,我们创建一个前馈网络。
class FeedForward:
def __init__(self, d_model: int, d_ff: int):
self.W1 = np.random.randn(d_model, d_ff) * np.sqrt(2.0 / (d_model + d_ff))
self.b1 = np.zeros(d_ff)
self.W2 = np.random.randn(d_ff, d_model) * np.sqrt(2.0 / (d_ff + d_model))
self.b2 = np.zeros(d_model)
def __call__(self, x: np.ndarray) -> np.ndarray:
return self.forward(x)
def forward(self, x: np.ndarray) -> np.ndarray:
return np.dot(np.maximum(0, np.dot(x, self.W1) + self.b1), self.W2) + self.b2
接下来,我们构建一个编码器层,将多头注意力机制与前馈神经网络相结合,构成了 Transformer 模型的核心构建块之一。
class EncoderLayer:
def __init__(self, d_model: int, num_heads: int, d_ff: int, dropout: float = 0.0, bias: bool = False):
self.d_model = d_model
self.num_heads = num_heads
self.d_ff = d_ff
self.multi_head_attention = MultiHeadAttention(d_model, num_heads, dropout, bias)
self.feed_forward = FeedForward(d_model, d_ff)
def __call__(self, x: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
return self.forward(x, mask)
def forward(self, x: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
attn_output = self.multi_head_attention.forward(x, x, x, mask)
output = self.feed_forward(attn_output)
return output
然后,我们来构建一个解码器层,它包括两个多头注意力机制和一个前馈网络。
class DecoderLayer:
def __init__(self, d_model: int, num_heads: int, d_ff: int, dropout: float = 0.0, bias: bool = False):
self.d_model = d_model
self.num_heads = num_heads
self.d_ff = d_ff
self.multi_head_attention_1 = MultiHeadAttention(d_model, num_heads, dropout, bias)
self.multi_head_attention_2 = MultiHeadAttention(d_model, num_heads, dropout, bias)
self.feed_forward = FeedForward(d_model, d_ff)
def __call__(self, x: np.ndarray, enc_output: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
return self.forward(x, enc_output, mask)
def forward(self, x: np.ndarray, enc_output: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
attn_output1 = self.multi_head_attention_1.forward(x, x, x, mask)
attn_output2 = self.multi_head_attention_2.forward(attn_output1, enc_output, enc_output, mask)
output = self.feed_forward(attn_output2)
return output
最后,我们创建一个 Transformer 类,它集成了编码器和解码器层。
class Transformer:
def __init__(self, d_model: int, num_heads: int, d_ff: int, num_layers: int, input_vocab_size: int, target_vocab_size: int, max_seq_len: int):
self.d_model = d_model
self.num_heads = num_heads
self.d_ff = d_ff
self.num_layers = num_layers
self.input_vocab_size = input_vocab_size
self.target_vocab_size = target_vocab_size
self.max_seq_len = max_seq_len
self.encoder_layers = [EncoderLayer(d_model, num_heads, d_ff) for _ in range(num_layers)]
self.decoder_layers = [DecoderLayer(d_model, num_heads, d_ff) for _ in range(num_layers)]
self.embedding = np.random.randn(input_vocab_size, d_model) * np.sqrt(2.0 / (input_vocab_size + d_model))
self.pos_encoding = positional_encoding(max_seq_len, d_model)
self.output_layer = np.random.randn(d_model, target_vocab_size) * np.sqrt(2.0 / (d_model + target_vocab_size))
def __call__(self, input_seq: np.ndarray, target_seq: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
return self.forward(input_seq, target_seq, mask)
def forward(self, input_seq: np.ndarray, target_seq: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
enc_output = self.encode(input_seq, mask)
dec_output = self.decode(target_seq, enc_output, mask)
output = np.dot(dec_output, self.output_layer)
return output
def encode(self, input_seq: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
seq_len = input_seq.shape[1]
x = self.embedding[input_seq] + self.pos_encoding[:seq_len, :]
for layer in self.encoder_layers:
x = layer(x, mask)
return x
def decode(self, target_seq: np.ndarray, enc_output: np.ndarray, mask: np.ndarray = None) -> np.ndarray:
seq_len = target_seq.shape[1]
x = self.embedding[target_seq] + self.pos_encoding[:seq_len, :]
for layer in self.decoder_layers:
x = layer(x, enc_output, mask)
return x
# 示例运行
d_model = 512
num_heads = 8
d_ff = 2048
num_layers = 6
input_vocab_size = 10000
target_vocab_size = 10000
max_seq_len = 100
# 创建 transformer 模型
transformer = Transformer(d_model, num_heads, d_ff, num_layers, input_vocab_size, target_vocab_size, max_seq_len)
# 虚拟输入和目标序列
input_seq = np.random.randint(0, input_vocab_size, (32, 50))
target_seq = np.random.randint(0, target_vocab_size, (32, 50))
# 前向传播
output = transformer(input_seq, target_seq)
print(output.shape) # Should be (batch_size, target_seq_len, target_vocab_size)
# (32, 50, 10000)
在实际应用中,训练 Transformer 模型需要注意以下几点:
Transformer 模型已广泛应用于多个领域:
Transformer 模型凭借其强大的并行计算能力和对长距离依赖的处理能力,已成为现代深度学习的主流架构。通过深入理解其核心组件如自注意力机制、位置编码及编码器 - 解码器结构,开发者可以更有效地设计和优化自己的 AI 系统。本文提供的代码示例展示了从零构建基础 Transformer 的过程,为进一步研究复杂变体奠定了坚实基础。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online