大模型应用:庖丁解牛:QKV机制详解,大模型的注意力之眼.4

简介: QKV机制是Transformer注意力的核心:Query(提问)、Key(标识)、Value(信息)三者通过点积计算相似度,Softmax归一化后加权融合Value,实现动态上下文感知。它能捕捉长程依赖,解决代词消解、一词多义等问题,支撑大模型强大语言理解能力。

一. 基础介绍

       我们先从理论角度来解释QKV机制,QKV机制是注意力机制的核心,尤其在Transformer模型中,注意力机制源于人类感知世界的方式:在处理信息时,我们会选择性地关注一部分信息,而忽略其他信息。在机器学习中,注意力机制允许模型在处理序列数据时,对不同的部分赋予不同的权重,从而更有效地利用信息。

4.2-QKV机制(引言).png

1. QKV的定义

在注意力机制中,每个输入元素会生成三个向量:Query(查询)、Key(键)和Value(值)。这些向量是通过对输入进行线性变换得到的。

  • Query(Q):表示当前元素想要查询其他元素的信息。它类似于一个提问,用来匹配其他元素的Key。
  • Key(K):表示当前元素的标识,用于被其他元素的Query匹配。Query和Key的匹配程度决定了注意力权重。
  • Value(V):表示当前元素实际提供的信息。注意力权重会作用在Value上,从而得到加权的输出。

2. 直观理解

结合图书馆来理解,好比我们去图示馆借阅书籍:

  • Value:图书馆里所有的书籍本身,包含丰富的知识和信息
  • Key:每本书的索引卡,简要描述了书的内容特征
  • Query:我们的借阅请求,比如"我想找一本关于人工智能入门的书"

借书过程就是QKV机制:

  • 1. 管理员将我们的Query与所有Key进行匹配
  • 2. 找到最相关的几本书(计算匹配度)
  • 3. 根据匹配程度决定每本书的"重要性权重"
  • 4. 把这些书的Value按照权重组合起来给你

二、计算过程

给定输入序列X ∈ R^(n×d) ,其中n是序列长度,d是特征维度。我们通过线性变换得到Q、K、V,然后计算注意力权重,公式偏数学理论,先了解大概,记住公式内容,在示例中对比逐步领悟。

1. 输入表示:X ∈ R^(n×d)

  • n:序列长度(如一句话有10个词,n=10)
  • d:每个token的嵌入维度(如BERT-base中d=768)

X = [[x₁₁, x₁₂, ..., x₁d],   # 第1个token的d维向量

      [x₂₁, x₂₂, ..., x₂d],   # 第2个token的d维向量  

       ...

      [xₙ₁, xₙ₂, ..., xₙd]]   # 第n个token的d维向量

# 假设句子:"I love AI" 有3个token,每个token用4维向量表示

X = [[0.1, 0.2, 0.3, 0.4],  # "I"的向量表示

      [0.5, 0.6, 0.7, 0.8],  # "love"的向量表示

      [0.9, 0.1, 0.2, 0.3]]  # "AI"的向量表示

# 这里 n=3, d=4

2. 线性变换:生成Q, K, V

计算公式:

  • Q = X × W_Q,其中 W_Q ∈ R^(d×d_k)
  • K = X × W_K,其中 W_K ∈ R^(d×d_k)  
  • V = X × W_V,其中 W_V ∈ R^(d×d_v)

维度变换过程:

  • 输入: X ∈ R^(n×d)
  • 经过线性变换:
  • Q = X_(n×d) × W_Q_(d×d_k),其中 Q ∈ R^(n×d_k)
  • K = X_(n×d) × W_K_(d×d_k),其中 K ∈ R^(n×d_k)  
  • V = X_(n×d) × W_V_(d×d_v),其中 V ∈ R^(n×d_v)

数学含义:

每个权重矩阵的作用:

  • W_Q - Query权重矩阵:
  • 学习如何提问
  • 将原始输入映射到查询空间
  • 决定每个token应该关注什么类型的信息
  • W_K - Key权重矩阵:
  • 学习如何被识别
  • 将原始输入映射到键空间
  • 决定每个token如何被其他token识别和匹配
  • W_V - Value权重矩阵:
  • 学习"提供什么信息"
  • 将原始输入映射到值空间
  • 决定每个token在被关注时应该贡献什么信息

实际计算示例:

# 假设 d=4, d_k=3, d_v=3

W_Q = [[0.1, 0.2, 0.3],

      [0.4, 0.5, 0.6],

      [0.7, 0.8, 0.9],

      [0.2, 0.3, 0.4]]  # 4×3

# 计算第一个token的Query向量

token1 = [0.1, 0.2, 0.3, 0.4]

Q1 = [0.1×0.1 + 0.2×0.4 + 0.3×0.7 + 0.4×0.2,

     0.1×0.2 + 0.2×0.5 + 0.3×0.8 + 0.4×0.3,

     0.1×0.3 + 0.2×0.6 + 0.3×0.9 + 0.4×0.4]

  = [0.01 + 0.08 + 0.21 + 0.08,

     0.02 + 0.10 + 0.24 + 0.12,

     0.03 + 0.12 + 0.27 + 0.16]

  = [0.38, 0.48, 0.58]

3. 注意力分数:S = (Q × K^T) / √d_k

详细公式:

  • S[i,j] = (Q[i] · K[j]) / √d_k = (∑_{k=1}^{d_k} Q[i,k] × K[j,k]) / √d_k

维度变换:

  • Q ∈ R^(n×d_k), K^T ∈ R^(d_k×n)
  • S = Q_(n×d_k) × K^T_(d_k×n),其中 S ∈ R^(n×n)

数学含义:

点积相似度:

  • 测量Query向量和Key向量之间的相似性
  • 值越大表示两个token之间的关联性越强

缩放因子 1/√d_k:

  • 防止点积值过大导致softmax梯度消失
  • 当d_k很大时,点积的方差也会变大,缩放保持数值稳定性

实际意义:

  • S矩阵是关联强度矩阵:
  • S[i,j]:第i个token对第j个token的关注程度
  • 对角线元素 S[i,i]:token对自己的关注度
  • 非对角线元素 S[i,j]:token之间的相互关注度

# 示例:3个token的关联矩阵

S = [[0.9, 0.3, 0.1],   # token1: 很关注自己,不太关注其他

    [0.2, 0.8, 0.6],   # token2: 关注自己和token3  

    [0.1, 0.5, 0.7]]   # token3: 比较关注token2

4. 注意力权重:A = softmax(S)

详细公式:

  • 对于矩阵S的每一行i: A[i,j] = exp(S[i,j]) / ∑_{k=1}^n exp(S[i,k])

数学含义:

Softmax操作:

  • 将注意力分数转换为概率分布
  • 确保每行的权重和为1
  • 放大较大值,抑制较小值

概率解释:

  • A[i,j] = P(关注token_j | 当前是token_i)
  • 即:给定当前处理的是第i个token,它应该以多大概率关注第j个token

实际效果:

# Softmax前

S = [[1.0, 0.5, 0.1],

    [0.2, 2.0, 0.3],

    [0.1, 0.4, 0.8]]

# Softmax后(每行和为1)

A = [[0.57, 0.29, 0.14],   # 主要关注自己

    [0.12, 0.73, 0.15],   # 强烈关注自己

    [0.18, 0.27, 0.55]]   # 主要关注自己,也关注其他

5. 输出计算:Z = A × V

详细公式:

  • 对于输出Z的每一行i:Z[i] = ∑_{j=1}^n A[i,j] × V[j]

维度变换:

  • A ∈ R^(n×n), V ∈ R^(n×d_v)
  • Z = A_(n×n) × V_(n×d_v),其中 Z ∈ R^(n×d_v)

实际意义:

上下文感知的表示:

  • 原始输入X:每个token的独立表示
  • 输出Z:每个token包含全局上下文信息的表示

# 示例:代词消解

句子:"The cat ate the fish because it was hungry"

# 计算"it"的输出时:

Z_it = 0.02 × V_The + 0.01 × V_cat + 0.01 × V_ate +

      0.02 × V_the + 0.01 × V_fish + 0.90 × V_cat +  # 主要关注"cat"

      0.03 × V_was + 0.00 × V_hungry

6. 计算过程示例      

6.1 输入准备

假设我们有3个词的句子:"猫 吃 鱼",每个词用4维向量表示:

  • 猫: [0.8, 0.2, 0.4, 0.1]
  • 吃: [0.1, 0.9, 0.3, 0.7]  
  • 鱼: [0.3, 0.1, 0.9, 0.2]

计算得出输入矩阵 X = [[0.8, 0.2, 0.4, 0.1], [0.1, 0.9, 0.3, 0.7], [0.3, 0.1, 0.9, 0.2]]

6.2 生成Q、K、V

模型有三个可学习的权重矩阵(开始时是随机值,通过训练学习):

  • W_Q = [[0.5, 0.2], [0.1, 0.3], [0.4, 0.6], [0.2, 0.1]] ,形状: [4, 2]
  • W_K = [[0.1, 0.5], [0.3, 0.2], [0.6, 0.4], [0.2, 0.3]]  ,形状: [4, 2]
  • W_V = [[0.2, 0.4], [0.5, 0.1], [0.3, 0.6], [0.1, 0.2]]  ,形状: [4, 2]

计算过程:

  • Q = X × W_Q
  • K = X × W_K  
  • V = X × W_V

让我们手动计算"猫"这个词的Q向量:

猫的Q = [0.8, 0.2, 0.4, 0.1] × [[0.5, 0.2], [0.1, 0.3], [0.4, 0.6], [0.2, 0.1]]

     = [0.8×0.5 + 0.2×0.1 + 0.4×0.4 + 0.1×0.2, 0.8×0.2 + 0.2×0.3 + 0.4×0.6 + 0.1×0.1]

     = [0.4 + 0.02 + 0.16 + 0.02, 0.16 + 0.06 + 0.24 + 0.01]

     = [0.6, 0.47]

计算最终得到:

Q = [[0.60, 0.47],   # 猫的Query

       [0.58, 0.90],   # 吃的Query  

       [0.72, 0.65]]   # 鱼的Query

K = [[0.32, 0.56],   # 猫的Key

       [0.50, 0.71],   # 吃的Key

       [0.68, 0.42]]   # 鱼的Key

V = [[0.35, 0.42],   # 猫的Value

       [0.62, 0.28],   # 吃的Value

       [0.54, 0.63]]   # 鱼的Value

6.3 计算注意力分数

现在计算每个Query与所有Key的匹配度:

  • 注意力分数 = Q × K^T
  • K^T = [[0.32, 0.50, 0.68], [0.56, 0.71, 0.42]]

计算过程:

  • 分数[0,0] = [0.60,0.47]·[0.32,0.56] = 0.60×0.32 + 0.47×0.56 = 0.192 + 0.263 = 0.455
  • 分数[0,1] = [0.60,0.47]·[0.50,0.71] = 0.60×0.50 + 0.47×0.71 = 0.300 + 0.334 = 0.634
  • 分数[0,2] = [0.60,0.47]·[0.68,0.42] = 0.60×0.68 + 0.47×0.42 = 0.408 + 0.197 = 0.605
  • ... 以此计算所有组合

得到注意力分数矩阵:

注意力分数 = [[0.455, 0.634, 0.605],   # 猫对猫/吃/鱼的关注度

                      [0.572, 0.869, 0.753],   # 吃对猫/吃/鱼的关注度  

                      [0.533, 0.767, 0.763]]   # 鱼对猫/吃/鱼的关注度

6.4 Softmax归一化

对每一行进行Softmax,使得每行之和为1:

  • 第一行: [0.455, 0.634, 0.605]
  • exp: [e^0.455, e^0.634, e^0.605] ≈ [1.576, 1.886, 1.831]
  • 和: 1.576 + 1.886 + 1.831 = 5.293
  • Softmax: [1.576/5.293, 1.886/5.293, 1.831/5.293] ≈ [0.298, 0.356, 0.346]

最终注意力权重:

注意力权重 = [[0.298, 0.356, 0.346],   # 猫: 35.6%关注"吃", 34.6%关注"鱼"

                     [0.246, 0.422, 0.332],   # 吃: 最关注自己(42.2%)

                     [0.276, 0.354, 0.370]]   # 鱼: 37.0%关注自己, 35.4%关注"吃"

6.5 加权求和得到输出

最后用注意力权重对Value进行加权求和:

对于"猫"这个词的输出:

输出[0] = 0.298×[0.35,0.42] + 0.356×[0.62,0.28] + 0.346×[0.54,0.63]

           = [0.104,0.125] + [0.221,0.100] + [0.187,0.218]

           = [0.512, 0.443]

最终输出:

输出 = [[0.512, 0.443],   # 猫的上下文感知表示

           [0.527, 0.422],   # 吃的上下文感知表示

           [0.519, 0.468]]   # 鱼的上下文感知表示

7. 完整流程总结

整个流程包括输入、线性变换(生成Q、K、V)、计算注意力分数、Softmax归一化、加权求和得到输出。

4.2-QKV机制的流程图 deepseek_mermaid_20251124_d74dfa.png

流程详细说明:

  • 1. 输入阶段
  • X: 原始输入序列,形状为 n×d
  • n = 序列长度(如10个词)
  • d = 每个词的向量维度(如768维)
  • 2. 线性变换阶段
  • 通过三个不同的权重矩阵生成Q、K、V:
  • Q (Query): 学习"如何提问" - 形状 n×d_k
  • K (Key): 学习"如何被识别" - 形状 n×d_k
  • V (Value): 学习"提供什么信息" - 形状 n×d_v
  • 3. 注意力计算阶段
  • S: 关联强度矩阵,形状 n×n
  • 计算每个位置对其他所有位置的关注程度
  • S[i,j] 表示第i个位置对第j个位置的关注度
  • 4. 归一化阶段
  • A: 注意力权重矩阵,形状 n×n
  • 通过Softmax确保每行的权重和为1
  • 将关注度转换为概率分布
  • 5. 输出生成阶段
  • Z: 最终输出序列,形状 n×d_v
  • 每个位置都是所有Value向量的加权和
  • 权重由注意力矩阵A决定
  • 每个token都包含了整个序列的上下文信息

三、体现的价值

1. 实际作用示例

示例1:代词消解

  • 句子:"李华看见张明,他笑了"
  • 计算过程:
  • - "他"的Query会与所有词的Key匹配
  • - 发现与"李华"、"张明"的匹配度都很高
  • - 但通过训练,模型学会"他"通常指向前面最近的人名"张明"
  • - 因此给"张明"的Value更高权重

示例2:多义词理解

  • 句子1:"苹果很好吃"  
  • 句子2:"苹果股价上涨"
  • 在句子1中:"苹果"的Query主要与"好吃"、"水果"等Key高匹配
  • 在句子2中:"苹果"的Query主要与"股价"、"公司"等Key高匹配

2. 多头注意力机制

实际中大模型使用多头注意力,让模型同时从多个角度关注信息:

4.3-多头注意力机制 deepseek_mermaid_20251124_f37753.png

比如在分析"我去银行取钱"时:

  • 头1关注:"取"→"钱"(动作-对象关系)
  • 头2关注:"银行"→"取钱"(地点-活动关系)
  • 头3关注:"我"→"取"(主体-动作关系)

四、代码实现推导

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
class SimpleSelfAttention(nn.Module):
    """简单的自注意力机制实现"""
    
    def __init__(self, d_model=4, d_k=2, d_v=2):
        super(SimpleSelfAttention, self).__init__()
        self.d_model = d_model  # 输入维度
        self.d_k = d_k          # Query和Key的维度
        self.d_v = d_v          # Value的维度
        
        # 定义Q、K、V的线性变换层
        # 注意:nn.Linear的权重形状是 (out_features, in_features)
        self.W_Q = nn.Linear(d_model, d_k, bias=False)
        self.W_K = nn.Linear(d_model, d_k, bias=False)
        self.W_V = nn.Linear(d_model, d_v, bias=False)
        
        # 初始化权重,便于理解计算过程
        self._initialize_weights()
    
    def _initialize_weights(self):
        """手动初始化权重,便于跟踪计算过程"""
        # 预设的权重值,注意形状要与nn.Linear匹配
        # nn.Linear权重形状是 (out_features, in_features) = (d_k, d_model)
        preset_W_Q = torch.tensor([[0.5, 0.1, 0.4, 0.2],  # 第一行对应第一个输出维度
                                   [0.2, 0.3, 0.6, 0.1]], dtype=torch.float32)  # 第二行对应第二个输出维度
        
        preset_W_K = torch.tensor([[0.1, 0.3, 0.6, 0.2],
                                   [0.5, 0.2, 0.4, 0.3]], dtype=torch.float32)
        
        preset_W_V = torch.tensor([[0.2, 0.5, 0.3, 0.1],
                                   [0.4, 0.1, 0.6, 0.2]], dtype=torch.float32)
        
        self.W_Q.weight.data = preset_W_Q
        self.W_K.weight.data = preset_W_K
        self.W_V.weight.data = preset_W_V
    
    def forward(self, X, verbose=False):
        """
        前向传播
        Args:
            X: 输入张量 [seq_len, d_model]
            verbose: 是否打印详细计算过程
        """
        if verbose:
            print("=" * 60)
            print("QKV自注意力机制详细计算过程")
            print("=" * 60)
            print(f"输入 X (shape: {X.shape}):")
            print(X)
            print()
        
        # 步骤1: 生成Q, K, V
        Q = self.W_Q(X)  # [seq_len, d_k]
        K = self.W_K(X)  # [seq_len, d_k] 
        V = self.W_V(X)  # [seq_len, d_v]
        
        if verbose:
            print("步骤1: 生成Q, K, V")
            print(f"Q (shape: {Q.shape}):")
            print(Q)
            print(f"K (shape: {K.shape}):")
            print(K)
            print(f"V (shape: {V.shape}):")
            print(V)
            print()
        
        # 步骤2: 计算注意力分数 Q × K^T
        attention_scores = torch.matmul(Q, K.transpose(0, 1))  # [seq_len, seq_len]
        
        if verbose:
            print("步骤2: 计算注意力分数 Q × K^T")
            print(f"注意力分数矩阵 (shape: {attention_scores.shape}):")
            print(attention_scores)
            print()
            
            # 打印详细的计算过程
            print("详细点积计算:")
            for i in range(Q.shape[0]):
                for j in range(K.shape[0]):
                    dot_product = torch.dot(Q[i], K[j])
                    print(f"Q[{i}] · K[{j}] = {Q[i].detach().numpy()} · {K[j].detach().numpy()} = {dot_product:.3f}")
            print()
        
        # 步骤3: 缩放
        scaled_scores = attention_scores / np.sqrt(self.d_k)
        
        if verbose:
            print("步骤3: 缩放")
            print(f"缩放因子: 1/sqrt(d_k) = 1/sqrt({self.d_k}) = {1/np.sqrt(self.d_k):.3f}")
            print(f"缩放后的分数矩阵:")
            print(scaled_scores)
            print()
        
        # 步骤4: Softmax归一化
        attention_weights = F.softmax(scaled_scores, dim=-1)  # [seq_len, seq_len]
        
        if verbose:
            print("步骤4: Softmax归一化")
            print("对每一行进行Softmax:")
            for i in range(scaled_scores.shape[0]):
                row = scaled_scores[i]
                exp_row = torch.exp(row)
                sum_exp = torch.sum(exp_row)
                softmax_row = exp_row / sum_exp
                print(f"第{i}行: {row.detach().numpy()} -> exp: {exp_row.detach().numpy()} -> "
                      f"softmax: {softmax_row.detach().numpy()} (sum: {sum_exp:.3f})")
            print()
            
            print(f"注意力权重矩阵 (每行和为1):")
            print(attention_weights)
            print()
        
        # 步骤5: 加权求和得到输出
        output = torch.matmul(attention_weights, V)  # [seq_len, d_v]
        
        if verbose:
            print("步骤5: 加权求和得到输出")
            print("每个位置的输出计算:")
            for i in range(attention_weights.shape[0]):
                weights = attention_weights[i]
                weighted_sum = torch.zeros_like(V[0])
                for j in range(V.shape[0]):
                    contribution = weights[j] * V[j]
                    weighted_sum += contribution
                    print(f"  位置 {i}: {weights[j]:.3f} × V[{j}] {V[j].detach().numpy()} = {contribution.detach().numpy()}")
                print(f"  → 输出[{i}] = {weighted_sum.detach().numpy()}")
            print()
            
            print(f"最终输出 (shape: {output.shape}):")
            print(output)
            print("=" * 60)
        
        return output, attention_weights
def demonstrate_attention():
    """演示自注意力机制的工作过程"""
    
    # 创建模型
    attention = SimpleSelfAttention(d_model=4, d_k=2, d_v=2)
    
    # 示例输入:3个词的序列,每个词用4维向量表示
    # "猫" [0.8, 0.2, 0.4, 0.1]
    # "吃" [0.1, 0.9, 0.3, 0.7]  
    # "鱼" [0.3, 0.1, 0.9, 0.2]
    X = torch.tensor([
        [0.8, 0.2, 0.4, 0.1],  # 猫
        [0.1, 0.9, 0.3, 0.7],  # 吃
        [0.3, 0.1, 0.9, 0.2]   # 鱼
    ], dtype=torch.float32)
    
    print("输入句子: ['猫', '吃', '鱼']")
    print("每个词的向量表示:")
    words = ["猫", "吃", "鱼"]
    for i, word in enumerate(words):
        print(f"  '{word}': {X[i].numpy()}")
    print()
    
    # 前向传播,显示详细计算过程
    output, attention_weights = attention(X, verbose=True)
    
    # 可视化注意力权重
    print("\n注意力权重热力图解释:")
    print("行: 当前词(Query), 列: 被关注的词(Key)")
    print("    猫     吃     鱼")
    for i, word in enumerate(words):
        weights = attention_weights[i].detach().numpy()
        print(f"{word} {weights}")
    
    return output, attention_weights
def demonstrate_multihead_attention():
    """演示多头注意力的概念"""
    print("\n" + "=" * 70)
    print("多头注意力机制概念演示")
    print("=" * 70)
    
    # 使用PyTorch内置的多头注意力
    multihead_attn = nn.MultiheadAttention(embed_dim=4, num_heads=2, batch_first=True)
    
    # 同样的输入,但增加batch维度
    X = torch.tensor([[
        [0.8, 0.2, 0.4, 0.1],  # 猫
        [0.1, 0.9, 0.3, 0.7],  # 吃  
        [0.3, 0.1, 0.9, 0.2]   # 鱼
    ]], dtype=torch.float32)  # [batch_size=1, seq_len=3, embed_dim=4]
    
    print("输入形状:", X.shape)
    
    # 前向传播
    output, attention_weights = multihead_attn(X, X, X)
    
    print("输出形状:", output.shape)
    print("注意力权重形状:", attention_weights.shape)
    print("\n多头注意力的优势:")
    print("- 每个头可以关注不同类型的信息")
    print("- 头1可能关注: 语法关系(主谓宾)")  
    print("- 头2可能关注: 语义关系(猫→吃→鱼)")
    print("- 最终融合所有头的信息,获得更丰富的表示")
if __name__ == "__main__":
    # 演示基础自注意力
    output, weights = demonstrate_attention()
    
    # 演示多头注意力
    demonstrate_multihead_attention()

image.gif

输出结果:

输入句子: ['猫', '吃', '鱼']

每个词的向量表示:

 '猫': [0.8 0.2 0.4 0.1]

 '吃': [0.1 0.9 0.3 0.7]

 '鱼': [0.3 0.1 0.9 0.2]

============================================================

QKV自注意力机制详细计算过程

============================================================

输入 X (shape: torch.Size([3, 4])):

tensor([[0.8000, 0.2000, 0.4000, 0.1000],

       [0.1000, 0.9000, 0.3000, 0.7000],

       [0.3000, 0.1000, 0.9000, 0.2000]])

步骤1: 生成Q, K, V

Q (shape: torch.Size([3, 2])):

tensor([[0.6000, 0.4700],

       [0.4000, 0.5400],

       [0.5600, 0.6500]], grad_fn=)

K (shape: torch.Size([3, 2])):

tensor([[0.4000, 0.6300],

       [0.6000, 0.5600],

       [0.6400, 0.5900]], grad_fn=)

V (shape: torch.Size([3, 2])):

tensor([[0.3900, 0.6000],

       [0.6300, 0.4500],

       [0.4000, 0.7100]], grad_fn=)

步骤2: 计算注意力分数 Q × K^T

注意力分数矩阵 (shape: torch.Size([3, 3])):

tensor([[0.5361, 0.6232, 0.6613],

       [0.5002, 0.5424, 0.5746],

       [0.6335, 0.7000, 0.7419]], grad_fn=)

详细点积计算:

Q[0] · K[0] = [0.6        0.47000003] · [0.40000004 0.63      ] = 0.536

Q[0] · K[1] = [0.6        0.47000003] · [0.6  0.56] = 0.623

Q[0] · K[2] = [0.6        0.47000003] · [0.64000005 0.59      ] = 0.661

Q[1] · K[0] = [0.39999998 0.54      ] · [0.40000004 0.63      ] = 0.500

Q[1] · K[1] = [0.39999998 0.54      ] · [0.6  0.56] = 0.542

Q[1] · K[2] = [0.39999998 0.54      ] · [0.64000005 0.59      ] = 0.575

Q[2] · K[0] = [0.56       0.65000004] · [0.40000004 0.63      ] = 0.634

Q[2] · K[1] = [0.56       0.65000004] · [0.6  0.56] = 0.700

Q[2] · K[2] = [0.56       0.65000004] · [0.64000005 0.59      ] = 0.742

步骤3: 缩放

缩放因子: 1/sqrt(d_k) = 1/sqrt(2) = 0.707

缩放后的分数矩阵:

tensor([[0.3791, 0.4407, 0.4676],

       [0.3537, 0.3835, 0.4063],

       [0.4480, 0.4950, 0.5246]], grad_fn=)

步骤4: Softmax归一化

对每一行进行Softmax:

第0行: [0.37907997 0.440669   0.46760976] -> exp: [1.4609399 1.5537463 1.5961744] -> softmax: [0.31684756 0.33697537 0.34617713] (sum: 4.611)

第1行: [0.35369486 0.38353473 0.40630355] -> exp: [1.4243205 1.4674625 1.5012583] -> softmax: [0.32422197 0.33404252 0.34173554] (sum: 4.393)

第2行: [0.44795218 0.4949748  0.52460253] -> exp: [1.5651039 1.6404569 1.689787 ] -> softmax: [0.31971252 0.3351053  0.34518224] (sum: 4.895)

注意力权重矩阵 (每行和为1):

tensor([[0.3168, 0.3370, 0.3462],

       [0.3242, 0.3340, 0.3417],

       [0.3197, 0.3351, 0.3452]], grad_fn=)

步骤5: 加权求和得到输出

每个位置的输出计算:

 位置 0: 0.317 × V[0] [0.39000005 0.6000001 ] = [0.12357055 0.19010855]

 位置 0: 0.337 × V[1] [0.63 0.45] = [0.21229446 0.1516389 ]

 位置 0: 0.346 × V[2] [0.4        0.71000004] = [0.13847084 0.24578576]

 → 输出[0] = [0.47433585 0.58753324]

 位置 1: 0.324 × V[0] [0.39000005 0.6000001 ] = [0.12644659 0.19453323]

 位置 1: 0.334 × V[1] [0.63 0.45] = [0.21044679 0.15031913]

 位置 1: 0.342 × V[2] [0.4        0.71000004] = [0.13669422 0.24263225]

 → 输出[1] = [0.4735876 0.5874846]

 位置 2: 0.320 × V[0] [0.39000005 0.6000001 ] = [0.12468789 0.19182752]

 位置 2: 0.335 × V[1] [0.63 0.45] = [0.21111631 0.15079737]

 位置 2: 0.345 × V[2] [0.4        0.71000004] = [0.1380729 0.2450794]

 → 输出[2] = [0.47387707 0.5877043 ]

最终输出 (shape: torch.Size([3, 2])):

tensor([[0.4743, 0.5875],

       [0.4736, 0.5875],

       [0.4739, 0.5877]], grad_fn=)

============================================================

注意力权重热力图解释:

行: 当前词(Query), 列: 被关注的词(Key)

   猫     吃     鱼

猫 [0.31684753 0.33697534 0.3461771 ]

吃 [0.324222   0.33404252 0.34173554]

鱼 [0.3197125  0.33510527 0.34518224]

=====================================================================

多头注意力机制概念演示

=====================================================================

输入形状: torch.Size([1, 3, 4])

输出形状: torch.Size([1, 3, 4])

注意力权重形状: torch.Size([1, 3, 3])

多头注意力的优势:

- 每个头可以关注不同类型的信息

- 头1可能关注: 语法关系(主谓宾)

- 头2可能关注: 语义关系(猫→吃→鱼)

- 最终融合所有头的信息,获得更丰富的表示

五、总结

       QKV注意力机制是现代Transformer架构的核心突破,其本质是一个高效的信息检索与融合系统。该机制通过线性变换将输入序列转化为三组向量:

  • Query代表当前需要信息的"提问者"
  • Key作为其他位置的"身份标识"
  • Value则是实际承载的"信息内容"

       核心计算流程首先通过Query与所有Key的点积相似度建立关联矩阵,再经Softmax归一化为概率分布,最终对Value进行加权融合。QKV机制赋予模型动态上下文感知能力,每个位置的输出都融合了全局相关信息,而非固定窗口内的局部特征,这使模型能有效处理代词指代、一词多义等复杂语言现象。相比传统循环神经网络的序列处理,注意力机制能直接捕获任意距离的依赖关系,且完全并行化计算。

相关文章
|
6天前
|
JSON API 数据格式
OpenCode入门使用教程
本教程介绍如何通过安装OpenCode并配置Canopy Wave API来使用开源模型。首先全局安装OpenCode,然后设置API密钥并创建配置文件,最后在控制台中连接模型并开始交互。
2485 6
|
12天前
|
人工智能 JavaScript Linux
【Claude Code 全攻略】终端AI编程助手从入门到进阶(2026最新版)
Claude Code是Anthropic推出的终端原生AI编程助手,支持40+语言、200k超长上下文,无需切换IDE即可实现代码生成、调试、项目导航与自动化任务。本文详解其安装配置、四大核心功能及进阶技巧,助你全面提升开发效率,搭配GitHub Copilot使用更佳。
|
14天前
|
存储 人工智能 自然语言处理
OpenSpec技术规范+实例应用
OpenSpec 是面向 AI 智能体的轻量级规范驱动开发框架,通过“提案-审查-实施-归档”工作流,解决 AI 编程中的需求偏移与不可预测性问题。它以机器可读的规范为“单一真相源”,将模糊提示转化为可落地的工程实践,助力开发者高效构建稳定、可审计的生产级系统,实现从“凭感觉聊天”到“按规范开发”的跃迁。
2046 18
|
2天前
|
人工智能 API 开发者
Claude Code 国内保姆级使用指南:实测 GLM-4.7 与 Claude Opus 4.5 全方案解
Claude Code是Anthropic推出的编程AI代理工具。2026年国内开发者可通过配置`ANTHROPIC_BASE_URL`实现本地化接入:①极速平替——用Qwen Code v0.5.0或GLM-4.7,毫秒响应,适合日常编码;②满血原版——经灵芽API中转调用Claude Opus 4.5,胜任复杂架构与深度推理。
|
6天前
|
人工智能 前端开发 Docker
Huobao Drama 开源短剧生成平台:从剧本到视频
Huobao Drama 是一个基于 Go + Vue3 的开源 AI 短剧自动化生成平台,支持剧本解析、角色与分镜生成、图生视频及剪辑合成,覆盖短剧生产全链路。内置角色管理、分镜设计、视频合成、任务追踪等功能,支持本地部署与多模型接入(如 OpenAI、Ollama、火山等),搭配 FFmpeg 实现高效视频处理,适用于短剧工作流验证与自建 AI 创作后台。
953 4
|
12天前
|
人工智能 JavaScript 前端开发
【2026最新最全】一篇文章带你学会Cursor编程工具
本文介绍了Cursor的下载安装、账号注册、汉化设置、核心模式(Agent、Plan、Debug、Ask)及高阶功能,如@引用、@Doc文档库、@Browser自动化和Rules规则配置,助力开发者高效使用AI编程工具。
1516 7
|
5天前
|
人工智能 运维 前端开发
Claude Code 30k+ star官方插件,小白也能写专业级代码
Superpowers是Claude Code官方插件,由核心开发者Jesse打造,上线3个月获3万star。它集成brainstorming、TDD、系统化调试等专业开发流程,让AI写代码更规范高效。开源免费,安装简单,实测显著提升开发质量与效率,值得开发者尝试。
|
16天前
|
人工智能 测试技术 开发者
AI Coding后端开发实战:解锁AI辅助编程新范式
本文系统阐述了AI时代开发者如何高效协作AI Coding工具,强调破除认知误区、构建个人上下文管理体系,并精准判断AI输出质量。通过实战流程与案例,助力开发者实现从编码到架构思维的跃迁,成为人机协同的“超级开发者”。
1173 99
|
12天前
|
人工智能 JSON 自然语言处理
【2026最新最全】一篇文章带你学会Qoder编辑器
Qoder是一款面向程序员的AI编程助手,集智能补全、对话式编程、项目级理解、任务模式与规则驱动于一体,支持模型分级选择与CLI命令行操作,可自动生成文档、优化提示词,提升开发效率。
919 10
【2026最新最全】一篇文章带你学会Qoder编辑器