注意力机制与Transformer模型详解
立即解锁
发布时间: 2025-09-01 00:52:29 阅读量: 3 订阅数: 32 AIGC 

# 注意力机制与Transformer模型详解
## 1. 注意力机制优势概述
注意力机制在处理序列数据时相较于循环神经网络(RNN)具有显著优势,具体如下:
| 对比项 | RNN | 注意力机制 |
| ---- | ---- | ---- |
| 对序列元素的访问 | RNN将输入元素信息编码在单个隐藏向量中,理论上它是所有序列元素的浓缩表示,但实际中其表示能力有限,在序列长度达到约100个标记时,新标记会开始抹去旧标记的信息 | 注意力机制可直接访问所有输入序列元素,虽然对最大序列长度有严格限制,但截至目前,基于Transformer的大语言模型(LLM)能够处理超过32,000个标记的序列 |
| 输入序列的处理方式 | RNN按元素到达顺序逐个处理输入序列元素,无法进行并行处理 | 注意力机制完全由矩阵乘法操作组成,这些操作具有高度的并行性,使得在大型训练数据集上训练具有数十亿可训练参数的LLM成为可能 |
不过,注意力机制也存在一个缺点,即RNN能保留序列元素的顺序,而注意力机制由于其直接访问的特性无法做到这一点。不过,在Transformer编码器部分会介绍解决此限制的方法。
## 2. 注意力机制的实现
### 2.1 缩放点积注意力的实现
缩放点积注意力实现了公式 \( Attention(Q, K, V) = softmax(\frac{QK^T}{\sqrt{d_k}})V \),其中 \( Q \) 为查询, \( K \) 为键, \( V \) 为值。以下是其Python代码实现:
```python
import math
def attention(query, key, value, mask=None, dropout=None):
d_k = query.size(-1)
# 1) 和 2) 计算带缩放的对齐分数
scores = (query @ key.transpose(-2, -1)) / math.sqrt(d_k)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
# 3) 计算注意力分数(softmax)
p_attn = scores.softmax(dim=-1)
if dropout is not None:
p_attn = dropout(p_attn)
# 4) 将注意力分数应用到值上
return p_attn @ value, p_attn
```
注意力函数包含了Dropout操作,这是完整Transformer实现的一部分。这里使用了Python 3.5引入的 `@` 运算符进行矩阵乘法。
### 2.2 多头注意力(MHA)的实现
多头注意力实现公式为 \( MultiHead(Q, K, V) = Concat(head_1, head_2 \cdots head_h)W^O \),其中 \( head_i = Attention(QW_i^Q, KW_i^K, VW_i^V) \)。以下是其Python代码实现:
```python
import torch
from clones import clones # 假设clones函数已在别处实现
class MultiHeadedAttention(torch.nn.Module):
def __init__(self, h, d_model, dropout=0.1):
"""
:param h: 头的数量
:param d_model: 查询/键/值向量的长度
"""
super(MultiHeadedAttention, self).__init__()
assert d_model % h == 0
# 假设d_v始终等于d_k
self.d_k = d_model // h
self.h = h
# 创建4个全连接层
# 3个用于查询/键/值投影
# 1个用于连接所有头的输出
self.fc_layers = clones(
torch.nn.Linear(d_model, d_model), 4)
self.attn = None
self.dropout = torch.nn.Dropout(p=dropout)
def forward(self, query, key, value, mask=None):
if mask is not None:
# 相同的掩码应用于所有h个头
mask = mask.unsqueeze(1)
batch_samples = query.size(0)
# 1) 批量进行所有从d_model到h x d_k的线性投影
projections = [
l(x).view(batch_samples, -1, self.h, self.d_k)
.transpose(1, 2)
for l, x in zip(self.fc_layers, (query, key, value))
]
query, key, value = projections
# 2) 对所有投影向量批量应用注意力
x, self.attn = attention(
query, key, value,
mask=mask,
dropout=self.dropout)
# 3) 使用视图进行“连接”并应用最终的线性层
x = x.transpose
```
0
0
复制全文
相关推荐









