第二章:Transformer核心原理(上)——从RNN到Attention的演进,Self-Attention机制详解,QKV矩阵的计算逻辑

各位同学,欢迎来到Transformer实战课的第二讲。

今天我们要聊的,是整个Transformer大厦的地基——注意力机制。说实话,我当年刚接触这个领域时,也被QKV这些概念绕得晕头转向。但后来我发现,只要把它的演进逻辑理清楚,一切都会豁然开朗。

2.1 为什么RNN不够用了?

在Transformer出现之前,处理序列数据(比如股票价格、文本)的标配是RNN(循环神经网络)。但RNN有个天生的毛病——长距离依赖问题

什么意思呢?你想想看,如果我们要预测今天下午3点的股价,它可能跟上午10点的某个新闻有关。RNN在处理这种长距离信息时,信息会像“传话游戏”一样,越传越失真。我在做高频交易策略时,用LSTM(RNN的变体)预测5分钟后的价格,效果还行;但一旦拉到30分钟以上,模型基本就“失忆”了。

核心痛点:RNN的序列处理方式是“串行”的,必须等前一个时间步算完,才能算下一个。这导致两个问题:

  • 计算慢:无法并行,GPU算力被浪费
  • 记忆短:梯度消失/爆炸,长序列信息丢失

所以,业界一直在寻找一种能“并行计算”且“全局看数据”的机制。这就是Attention(注意力机制)登场的背景。

2.2 Attention的直觉:你在“看”什么?

Attention这个名字起得特别好。说白了,就是让模型学会“关注重点”。

举个例子,你在读一份财报时,眼睛会不自觉地聚焦在“净利润”、“营收增长率”这些关键词上,而不是每个字都同等对待。Attention机制就是干这个的——给重要的信息分配更高的权重

我记得第一次在金融文本上应用Attention时,模型自动把“黑天鹅”、“降息”这些词的权重拉得很高。嗯,这很符合交易员的直觉。

2.3 Self-Attention:自己跟自己玩注意力

早期的Attention是用于“编码器-解码器”结构的,比如机器翻译。但Transformer提出了一个更激进的想法——Self-Attention(自注意力)

什么叫“自”?就是序列内部的每个元素,都去跟序列里的所有其他元素(包括自己)计算相关性。这样一来,每个位置的输出,都融合了整个序列的信息。

我的经验:在金融时间序列上,Self-Attention特别适合捕捉“跨时间点的模式”。比如,某只股票今天放量上涨,它可能跟3天前的某个技术形态有关。Self-Attention能直接建立这种“跨步长”的连接,而不用像RNN那样一步步传递。

2.4 QKV矩阵:Attention的“三驾马车”

好,接下来是今天的硬核部分——QKV矩阵的计算逻辑。很多同学在这里被劝退,其实没那么复杂。

我们把Self-Attention想象成一个“信息检索”过程:

  • Q(Query,查询):你想找什么?
  • K(Key,键):你有什么信息?
  • V(Value,值):你实际提供的内容是什么?

举个例子,你在图书馆找书:

  • 你的问题(Q)是“量化交易策略”
  • 每本书的标签(K)是“金融”、“编程”、“统计”
  • 书的内容(V)就是实际的知识

Attention做的就是:计算Q和每个K的相似度,然后用这个相似度去加权求和对应的V。

2.4.1 数学公式与计算步骤

Self-Attention的核心公式就一个:

Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V

别怕,我们拆成三步走:

  1. 计算相似度:Q 和 K 做点积(Q * K^T),得到注意力分数。分数越高,说明越相关。
  2. 缩放与归一化:除以 sqrt(d_k)(d_k是K的维度),防止分数过大导致softmax梯度消失。然后用softmax转成概率分布(权重)。
  3. 加权求和:用上一步的权重去乘V,得到最终的输出。

避坑指南:我曾经在实现时忘记除以 sqrt(d_k),结果训练时loss直接炸了。这个缩放因子不是可有可无的,它保证了梯度的稳定性。

2.4.2 代码实现(PyTorch风格)

import torch
import torch.nn.functional as F

def self_attention(Q, K, V):
    # Q, K, V shape: (batch_size, seq_len, d_k)
    d_k = Q.size(-1)
    
    # Step 1: 计算相似度分数
    scores = torch.matmul(Q, K.transpose(-2, -1))  # (batch, seq_len, seq_len)
    
    # Step 2: 缩放 + softmax
    scaled_scores = scores / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
    attention_weights = F.softmax(scaled_scores, dim=-1)
    
    # Step 3: 加权求和
    output = torch.matmul(attention_weights, V)
    
    return output, attention_weights

这段代码虽然简单,但包含了Self-Attention的全部精髓。在实际项目中,Q、K、V通常是通过线性变换从同一个输入X得到的:

Q = X @ W_Q
K = X @ W_K
V = X @ W_V

这里的W_Q、W_K、W_V是可学习的参数矩阵。模型通过训练,自动学会如何把输入映射到合适的查询、键和值空间。

2.5 知识体系总览

为了让你对本章内容有个整体把握,我画了一张图:

Transformer核心原理(上)知识体系 RNN的局限性 Attention机制 Self-Attention Q(Query)查询 K(Key)键 V(Value)值 计算流程 Step 1 Q·K^T 计算相似度 Step 2 ÷√d_k 缩放 Step 3 Softmax 归一化 Step 4 ×V 加权输出

2.6 为什么Q和K要分开?

你可能会有疑问:为什么非要搞出Q、K、V三个矩阵?直接用输入X自己跟自己点积不行吗?

嗯,这个问题问得好。我刚开始也这么想。但后来在实践中发现,分开设计给了模型更大的灵活性

  • Q和K的角色不同:Q是“主动查询”,K是“被动被查”。通过不同的线性变换,模型可以学习到不同的语义空间。
  • 如果Q=K,那每个位置只能跟自己最相似的位置做交互,失去了“查询”的灵活性。

注意:在金融场景中,Q和K的维度d_k通常设置为64或128。太小了表达能力不够,太大了计算量爆炸且容易过拟合。我一般从64开始调,效果不好再往上加。

2.7 小结

今天我们从RNN的痛点出发,聊到了Attention的直觉,然后深入拆解了Self-Attention的QKV计算逻辑。说白了,Transformer的核心就一句话:让每个位置都能看到全局,并且学会关注该关注的

下一章我们会继续深入,看看Multi-Head Attention(多头注意力)是怎么把“单视角”变成“多视角”的,以及Transformer的完整架构是怎么拼起来的。但今天的内容,已经足够你理解Attention的本质了。


公众号:蓝海资料掘金营,微信deep3321