当前位置: 首页 > article >正文

Grouped-Query Attention(GQA)详解: Pytorch实现

Grouped-Query Attention(GQA)详解


Grouped-Query Attention(GQA)Multi-Query Attention(MQA) 的改进版,它通过在 多个查询头(Query Heads)之间共享 Key 和 Value,在 Multi-Head Attention(MHA)MQA 之间找到了一种折中方案。GQA 旨在在 推理速度模型质量 之间取得更好的平衡,减少 MQA 带来的模型质量下降问题,同时仍然保留比 MHA 更快的推理速度。

在这里插入图片描述
Source: https://arxiv.org/pdf/2305.13245


1. 为什么需要 Grouped-Query Attention?

在理解 GQA 之前,我们先回顾 MHA 和 MQA 的核心区别。

(1) Multi-Head Attention(MHA)

  • 每个 Query 头都有独立的 Key 和 Value
  • 优势
    • 允许不同的 Query 头关注不同的 Key-Value 信息,提高模型的表达能力。
    • 更适合复杂任务,如长序列建模和复杂推理任务。
  • 劣势
    • 推理速度慢,因为在每一步都要存储和读取 所有 Query 头的 Key 和 Value,导致 KV 缓存(KV Cache)非常大,占用大量显存和内存带宽。

(2) Multi-Query Attention(MQA)

  • 所有 Query 头共享相同的 Key 和 Value
  • 优势
    • 推理速度快,因为只需要存储和读取一个 Key-Value 组,而不是多个。
    • 显存占用低,适用于 大规模语言模型推理(如 ChatGPT)
  • 劣势
    • 不同 Query 头会关注相同的信息,导致模型表达能力下降,尤其是在长序列建模任务上(如机器翻译、摘要生成)。
    • 可能导致训练不稳定,特别是长序列输入时,训练容易出现 Loss spikes(损失值剧烈波动)

(3) GQA 的改进点

Grouped-Query Attention(GQA) 介于 MHA 和 MQA 之间:

  • GQA 不是让所有 Query 头共享同一个 Key-Value,而是分组共享
  • 假设一个模型有 8 个 Query 头
    • MHA:8 个 Query 头,每个头有自己的 Key 和 Value。
    • MQA:8 个 Query 头,所有头共享 1 组 Key 和 Value。
    • GQA(例如 GQA-4):8 个 Query 头被分成 4 组,每组共享一组 Key 和 Value。

因此,GQA 允许:

  • 部分 Query 头共享 Key-Value,但仍然保持了一定的多样性。
  • 推理速度比 MHA 快,但比 MQA 慢
  • 模型质量比 MQA 高,但比 MHA 略低

2. GQA 的数学表达

假设:

  • h 是 Query 头的总数(如 8)。
  • G 是 GQA 分组的数量(如 G=4)。
  • k, v 分别是 Key 和 Value 的维度。

对于 MHA:
Q h = X P Q , h , K h = M P K , h , V h = M P V , h Q_h = X P_{Q,h}, \quad K_h = M P_{K,h}, \quad V_h = M P_{V,h} Qh=XPQ,h,Kh=MPK,h,Vh=MPV,h
logits h = Q h K h T , weights h = softmax ( logits h ) \text{logits}_h = Q_h K_h^T, \quad \text{weights}_h = \text{softmax}(\text{logits}_h) logitsh=QhKhT,weightsh=softmax(logitsh)
O h = weights h V h , Y = ∑ h O h P O , h O_h = \text{weights}_h V_h, \quad Y = \sum_{h} O_h P_{O,h} Oh=weightshVh,Y=hOhPO,h

对于 MQA:
Q h = X P Q , h , K = M P K , V = M P V Q_h = X P_{Q,h}, \quad K = M P_K, \quad V = M P_V Qh=XPQ,h,K=MPK,V=MPV
logits h = Q h K T , weights h = softmax ( logits h ) \text{logits}_h = Q_h K^T, \quad \text{weights}_h = \text{softmax}(\text{logits}_h) logitsh=QhKT,weightsh=softmax(logitsh)
O h = weights h V , Y = ∑ h O h P O , h O_h = \text{weights}_h V, \quad Y = \sum_{h} O_h P_{O,h} Oh=weightshV,Y=hOhPO,h

对于 GQA(分组共享 K/V)
Q h = X P Q , h , K g = M P K , g , V g = M P V , g , g = ⌊ h / G ⌋ Q_h = X P_{Q,h}, \quad K_g = M P_{K,g}, \quad V_g = M P_{V,g}, \quad g = \lfloor h/G \rfloor Qh=XPQ,h,Kg=MPK,g,Vg=MPV,g,g=h/G
logits h = Q h K g T , weights h = softmax ( logits h ) \text{logits}_h = Q_h K_g^T, \quad \text{weights}_h = \text{softmax}(\text{logits}_h) logitsh=QhKgT,weightsh=softmax(logitsh)
O h = weights h V g , Y = ∑ h O h P O , h O_h = \text{weights}_h V_g, \quad Y = \sum_{h} O_h P_{O,h} Oh=weightshVg,Y=hOhPO,h

其中:

  • 在 GQA 中,每个 Query 头属于一个组 ( g g g ),每个组 共享 Key 和 Value
  • 当 ( G = 1 G = 1 G=1 ) 时,GQA 退化为 MQA。
  • 当 ( G = h G = h G=h ) 时,GQA 退化为 MHA。

3. 代码解析

GQA 代码与 MQA 类似,只是 Key 和 Value 现在是 按组分配的

def GroupedQueryAttention(X, M, mask, P_q, P_k, P_v, P_o, num_groups):"""Grouped-Query Attention 实现Args:X: 输入查询 [b, n, d]M: 输入键值存储 [b, m, d]mask: 注意力掩码 [b, h, n, m]P_q: 查询投影矩阵 [h, d, k]P_k: 共享键投影矩阵 [num_groups, d, k]P_v: 共享值投影矩阵 [num_groups, d, v]P_o: 输出投影矩阵 [h, d, v]Returns:Y: 输出张量 [b, n, d]"""# 计算 QueryQ = tf.einsum("bnd, hdk->bhnk", X, P_q)# 计算 Key 和 Value,每个组共享K = tf.einsum("bmd, gdk->bmgk", M, P_k)  # g = num_groupsV = tf.einsum("bmd, gdv->bmgv", M, P_v)# 计算注意力 logitslogits = tf.einsum("bhnk, bmgk->bhng", Q, K)# 计算 softmax 权重weights = tf.nn.softmax(logits + mask)# 计算最终的加权 ValueO = tf.einsum("bhng, bmgv->bhnv", weights, V)# 计算最终输出Y = tf.einsum("bhnv, hdv->bnd", O, P_o)return Y

4. GQA 的性能分析

论文中的实验表明:

  • 质量上,GQA 的 BLEU 得分几乎接近 MHA,明显优于 MQA。
  • 推理速度上,GQA 仅比 MQA 略慢,但比 MHA 快得多。
  • 适用于大模型推理,如 T5、GPT-4、Gemini,减少 KV 访问,提高吞吐量。

实验表明,GQA-8(8 组)质量和速度最优的选择,可以接近 MHA 的质量,同时拥有 MQA 级别的推理速度。


5. 总结

GQA 结合了 MHA 的高质量和 MQA 的高效推理,具有:

  • 更低的 KV 存储需求,推理更快。
  • 更高的模型表达能力,减少 MQA 的信息冗余问题。
  • 适用于大规模语言模型(如 LLaMA、PaLM、GPT-4)推理优化

GQA 目前已被 Google 等研究团队广泛应用于大模型推理优化,是 MQA 的重要改进方案。


Grouped-Query Attention(GQA)PyTorch 实现

以下是 Grouped-Query Attention(GQA)PyTorch 实现,它不使用 einsum,而是采用 矩阵乘法(@)、bmm() 方式进行计算,保证代码可以直接运行。

import torch
import torch.nn as nn
import torch.nn.functional as Fclass GroupedQueryAttention(nn.Module):def __init__(self, embed_dim, num_heads, num_groups, dropout=0.1):"""Grouped-Query Attention 实现Args:embed_dim: 词嵌入维度 dnum_heads: 查询头的数量 hnum_groups: 组的数量 G (1 表示 MQA, h 表示 MHA)dropout: dropout 率"""super(GroupedQueryAttention, self).__init__()assert num_heads % num_groups == 0, "num_heads 必须是 num_groups 的整数倍"self.embed_dim = embed_dimself.num_heads = num_headsself.num_groups = num_groupsself.head_dim = embed_dim // num_heads  # 每个头的维度 k# 查询(Q)投影矩阵,每个头独立self.q_proj = nn.Linear(embed_dim, embed_dim, bias=False)# 键(K)和值(V)投影矩阵,每组共享self.k_proj = nn.Linear(embed_dim, (embed_dim // num_heads) * num_groups, bias=False)self.v_proj = nn.Linear(embed_dim, (embed_dim // num_heads) * num_groups, bias=False)# 输出投影self.o_proj = nn.Linear(embed_dim, embed_dim, bias=False)# dropoutself.dropout = nn.Dropout(dropout)def forward(self, query, key, value, mask=None):"""前向传播Args:query: 查询张量,形状 [batch, seq_len, embed_dim]key: 键张量,形状 [batch, seq_len_kv, embed_dim]value: 值张量,形状 [batch, seq_len_kv, embed_dim]mask: 掩码张量,形状 [batch, 1, 1, seq_len_kv],默认 NoneReturns:输出张量,形状 [batch, seq_len, embed_dim]"""batch_size, seq_len, _ = query.shape_, seq_len_kv, _ = key.shape# 计算 Query,每个头独立Q = self.q_proj(query)  # [batch, seq_len, embed_dim]Q = Q.view(batch_size, seq_len, self.num_heads, self.head_dim)  # [batch, seq_len, num_heads, head_dim]Q = Q.permute(0, 2, 1, 3)  # [batch, num_heads, seq_len, head_dim]# 计算 Key 和 Value,按组共享K = self.k_proj(key)  # [batch, seq_len_kv, num_groups * head_dim]V = self.v_proj(value)  # [batch, seq_len_kv, num_groups * head_dim]K = K.view(batch_size, seq_len_kv, self.num_groups, self.head_dim)  # [batch, seq_len_kv, num_groups, head_dim]V = V.view(batch_size, seq_len_kv, self.num_groups, self.head_dim)  # [batch, seq_len_kv, num_groups, head_dim]K = K.permute(0, 2, 1, 3)  # [batch, num_groups, seq_len_kv, head_dim]V = V.permute(0, 2, 1, 3)  # [batch, num_groups, seq_len_kv, head_dim]# 计算注意力权重 (Q @ K^T),Query 按照组进行索引匹配group_size = self.num_heads // self.num_groupsQ_grouped = Q.view(batch_size, self.num_groups, group_size, seq_len, self.head_dim)  # [batch, num_groups, group_size, seq_len, head_dim]# 计算点积注意力attn_logits = torch.matmul(Q_grouped, K.transpose(-2, -1))  # [batch, num_groups, group_size, seq_len, seq_len_kv]# 归一化attn_logits /= self.head_dim ** 0.5# 应用掩码if mask is not None:attn_logits = attn_logits.masked_fill(mask == 0, float("-inf"))# 计算 softmax 注意力分布attn_weights = F.softmax(attn_logits, dim=-1)  # [batch, num_groups, group_size, seq_len, seq_len_kv]attn_weights = self.dropout(attn_weights)# 计算注意力加权的 ValueO = torch.matmul(attn_weights, V)  # [batch, num_groups, group_size, seq_len, head_dim]# 重新排列回原始形状O = O.permute(0, 3, 1, 2, 4).contiguous()  # [batch, seq_len, num_groups, group_size, head_dim]O = O.view(batch_size, seq_len, self.embed_dim)  # [batch, seq_len, embed_dim]# 通过最终的线性变换Y = self.o_proj(O)  # [batch, seq_len, embed_dim]return Y

5. 代码解读

  1. 参数解释

    • embed_dim: 输入嵌入维度(即 d)。
    • num_heads: 注意力头的数量(即 h)。
    • num_groups: 组的数量(如果 num_groups=1,则相当于 MQA;如果 num_groups=num_heads,则相当于 MHA)。
    • dropout: Dropout 率。
  2. 计算 Query

    • Query 使用独立的投影矩阵 self.q_proj 计算,每个 Query 头仍然是独立的。
  3. 计算 Key 和 Value

    • Key 和 Value 共享,但按照 num_groups 进行分组,每组有 head_dim 维度。
  4. 计算注意力

    • Q @ K^T 计算注意力分数。
    • softmax 归一化并应用 dropout。
    • attention_weights @ V 计算加权 Value。
  5. 重塑输出

    • 由于每个 Query 头仍然是独立的,计算完后需要重新排列回原始形状。
    • 通过 self.o_proj 进行最终的线性投影。

6. 运行示例

你可以用下面的代码来测试 GQA:

# 初始化模型
embed_dim = 64
num_heads = 8
num_groups = 4
batch_size = 2
seq_len = 10
seq_len_kv = 12gqa = GroupedQueryAttention(embed_dim, num_heads, num_groups)# 生成随机输入
query = torch.randn(batch_size, seq_len, embed_dim)
key = torch.randn(batch_size, seq_len_kv, embed_dim)
value = torch.randn(batch_size, seq_len_kv, embed_dim)# 前向传播
output = gqa(query, key, value)
print("Output shape:", output.shape)  # 预期输出 [batch_size, seq_len, embed_dim]

7. 总结

GQA 的 PyTorch 实现:

  • 完全可运行,不依赖 einsum,使用 matmul 进行计算。
  • 适用于推理优化,减少 KV 存储,提高 LLM 推理效率。
  • 兼容 MHA/MQA,通过 num_groups 控制:
    • num_groups = 1 时,相当于 MQA
    • num_groups = num_heads 时,相当于 MHA
    • num_groups = 4 时,找到 质量与推理速度的最佳平衡

这个实现可以直接用于 大模型推理加速,如 LLaMA、GPT-4、Gemini 等模型的优化!🚀

Grouped-Query Attention(GQA)结合 KV Cache 的推理优化


大语言模型(LLM) 的自回归推理过程中,每生成一个新 token,都需要计算 注意力(attention)。然而,标准 Multi-Head Attention(MHA) 需要存储并加载 所有 Key(K)和 Value(V),这会带来 显存占用过大内存带宽受限 的问题。

Grouped-Query Attention(GQA) 结合 KV Cache(Key-Value 缓存) 可以 减少存储、提高推理速度,特别适用于 GPT-4、Gemini 等大模型


1. 为什么推理时需要 KV Cache?

Transformer 自回归推理 中:

  • 训练时,模型可以并行计算整个序列(一次性输入所有 token)。
  • 推理时,只能逐步生成新 token,每次只能访问过去的 Key-Value 并计算新的 Query。

标准 MHA 推理(带 KV Cache)

在推理时:

  • 之前生成的 tokens 的 Key 和 Value 可以缓存,不需要重新计算。
  • 新的 Query 需要与 缓存中的 Key/Value 计算注意力

对于 标准 MHA

  • 每个头都有独立的 Key/Value,所以 缓存大小为
    KV Cache Size = O ( b × h × seq_len × d k ) \text{KV Cache Size} = \mathcal{O}(b \times h \times \text{seq\_len} \times d_k) KV Cache Size=O(b×h×seq_len×dk)
    这对于 大模型推理来说,KV 缓存占用显存过大,特别是 h=32 或更大时。

2. GQA 如何优化推理中的 KV Cache?

Grouped-Query Attention(GQA) 中:

  • 每个 Query 组共享同一个 Key 和 Value
  • 减少了 KV 缓存大小,让推理更高效。

对于 GQA(num_groups = G)

  • 只需要 G 组 Key-Value,而不是 h 组
  • 缓存大小降低 (h/G) 倍
    KV Cache Size = O ( b × G × seq_len × d k ) \text{KV Cache Size} = \mathcal{O}(b \times G \times \text{seq\_len} \times d_k) KV Cache Size=O(b×G×seq_len×dk)
  • 例如:
    • MHA(h=32) → 需要存储 32 组 K/V
    • GQA(G=8) → 只需要存储 8 组 K/V,减少 4 倍显存占用。

这样,GQA 在推理时可以大幅减少 KV Cache 访问和存储,提高解码速度!


3. PyTorch 实现:GQA 推理(结合 KV Cache)

下面是完整的 PyTorch 实现,支持 KV Cache,并可用于 增量推理

import torch
import torch.nn as nn
import torch.nn.functional as Fclass GroupedQueryAttention(nn.Module):def __init__(self, embed_dim, num_heads, num_groups, dropout=0.1):"""Grouped-Query Attention 结合 KV CacheArgs:embed_dim: 词嵌入维度 dnum_heads: 查询头的数量 hnum_groups: 组的数量 G (1 表示 MQA, h 表示 MHA)dropout: dropout 率"""super(GroupedQueryAttention, self).__init__()assert num_heads % num_groups == 0, "num_heads 必须是 num_groups 的整数倍"self.embed_dim = embed_dimself.num_heads = num_headsself.num_groups = num_groupsself.head_dim = embed_dim // num_heads  # 每个头的维度 k# 查询(Q)投影矩阵,每个头独立self.q_proj = nn.Linear(embed_dim, embed_dim, bias=False)# 键(K)和值(V)投影矩阵,每组共享self.k_proj = nn.Linear(embed_dim, (embed_dim // num_heads) * num_groups, bias=False)self.v_proj = nn.Linear(embed_dim, (embed_dim // num_heads) * num_groups, bias=False)# 输出投影self.o_proj = nn.Linear(embed_dim, embed_dim, bias=False)# dropoutself.dropout = nn.Dropout(dropout)def forward(self, query, key, value, kv_cache=None, mask=None):"""推理时结合 KV CacheArgs:query: 查询张量 [batch, 1, embed_dim] (推理时单个 token)key: 当前 token 的键 [batch, 1, embed_dim]value: 当前 token 的值 [batch, 1, embed_dim]kv_cache: 之前的 Key-Value 缓存 (字典: {'key': K, 'value': V})mask: 注意力掩码 [batch, 1, 1, seq_len_kv]Returns:输出张量 [batch, 1, embed_dim]更新后的 KV Cache"""batch_size, _, _ = query.shape# 计算 Query,每个头独立Q = self.q_proj(query)  # [batch, 1, embed_dim]Q = Q.view(batch_size, 1, self.num_heads, self.head_dim)  # [batch, 1, num_heads, head_dim]Q = Q.permute(0, 2, 1, 3)  # [batch, num_heads, 1, head_dim]# 计算当前步的 Key 和 Value,按组共享K_new = self.k_proj(key).view(batch_size, 1, self.num_groups, self.head_dim)  # [batch, 1, num_groups, head_dim]V_new = self.v_proj(value).view(batch_size, 1, self.num_groups, self.head_dim)  # [batch, 1, num_groups, head_dim]K_new = K_new.permute(0, 2, 1, 3)  # [batch, num_groups, 1, head_dim]V_new = V_new.permute(0, 2, 1, 3)  # [batch, num_groups, 1, head_dim]# 更新 KV Cacheif kv_cache is None:K = K_newV = V_newelse:K = torch.cat([kv_cache['key'], K_new], dim=2)  # [batch, num_groups, seq_len_kv, head_dim]V = torch.cat([kv_cache['value'], V_new], dim=2)# 计算注意力 logitsgroup_size = self.num_heads // self.num_groupsQ_grouped = Q.view(batch_size, self.num_groups, group_size, 1, self.head_dim)  # [batch, num_groups, group_size, 1, head_dim]attn_logits = torch.matmul(Q_grouped, K.transpose(-2, -1))  # [batch, num_groups, group_size, 1, seq_len_kv]attn_logits /= self.head_dim ** 0.5# 应用掩码if mask is not None:attn_logits = attn_logits.masked_fill(mask == 0, float("-inf"))# 计算 softmax 注意力分布attn_weights = F.softmax(attn_logits, dim=-1)  # [batch, num_groups, group_size, 1, seq_len_kv]attn_weights = self.dropout(attn_weights)# 计算注意力加权的 ValueO = torch.matmul(attn_weights, V)  # [batch, num_groups, group_size, 1, head_dim]O = O.permute(0, 3, 1, 2, 4).contiguous()  # [batch, 1, num_groups, group_size, head_dim]O = O.view(batch_size, 1, self.embed_dim)  # [batch, 1, embed_dim]# 通过最终的线性变换Y = self.o_proj(O)  # [batch, 1, embed_dim]return Y, {'key': K, 'value': V}

4. 结论

GQA 结合 KV Cache

  • 减少存储,比 MHA 降低 ( h/G ) 倍 KV Cache 占用
  • 加速推理,减少 Key-Value 访问,适用于 大模型优化(GPT-4、Gemini)
  • PyTorch 实现可直接运行,适用于 增量推理(Streaming Inference)

GQA+KV Cache 是当前 LLM 高效推理的重要优化方向!🚀

Grouped-Query Attention(GQA)中 matmul(Q_grouped, K.transpose(-2, -1)) 的计算解析


GQA 计算注意力 logits 的过程中,我们使用了:

attn_logits = torch.matmul(Q_grouped, K.transpose(-2, -1))  

这个操作的核心是计算 Query 和 Key 之间的点积注意力分数,即:
logits = Q ⋅ K T \text{logits} = Q \cdot K^T logits=QKT
但在 GQA 中,由于 Query 头是按组共享 Key 的,因此计算方式比标准 MHA 更复杂。


1. 形状分析

首先,我们看看 Q_groupedK 的形状:

  • Q_grouped(Grouped Query)

    Q_grouped = Q.view(batch_size, num_groups, group_size, 1, head_dim)  
    

    形状变为:
    ( b a t c h , num_groups , group_size , 1 , head_dim ) (batch, \text{num\_groups}, \text{group\_size}, 1, \text{head\_dim}) (batch,num_groups,group_size,1,head_dim)
    其中:

    • num_groups:查询被分成的组数。
    • group_size:每个组的 Query 头数(num_heads / num_groups)。
    • 1:表示当前推理的单个 token(因为推理是自回归的,每次只计算一个新 token)。
    • head_dim:每个头的维度。
  • K(Key 缓存)

    K = K.transpose(-2, -1)  # 转置 K,使其可以与 Q 进行点积
    

    形状为:
    ( b a t c h , num_groups , seq_len_kv , head_dim ) (batch, \text{num\_groups}, \text{seq\_len\_kv}, \text{head\_dim}) (batch,num_groups,seq_len_kv,head_dim)
    其中:

    • seq_len_kv:当前 Key-Value 缓存中的 token 数量。
    • head_dim:每个 Key 头的维度。

2. matmul(Q_grouped, K.transpose(-2, -1)) 计算过程

现在,我们来看点积计算:

attn_logits = torch.matmul(Q_grouped, K.transpose(-2, -1))  

这个操作等价于:
logits = Q × K T \text{logits} = Q \times K^T logits=Q×KT

矩阵计算规则

假设:

  • Q_grouped 形状为 (batch, num_groups, group_size, 1, head_dim)
  • K^T 形状为 (batch, num_groups, head_dim, seq_len_kv)

由于 矩阵乘法的规则
( A ∈ R m × k ) × ( B ∈ R k × n ) = C ∈ R m × n (A \in \mathbb{R}^{m \times k}) \times (B \in \mathbb{R}^{k \times n}) = C \in \mathbb{R}^{m \times n} (ARm×k)×(BRk×n)=CRm×n
所以计算后:
logits ∈ R batch , num_groups , group_size , 1 , seq_len_kv \text{logits} \in \mathbb{R}^{\text{batch}, \text{num\_groups}, \text{group\_size}, 1, \text{seq\_len\_kv}} logitsRbatch,num_groups,group_size,1,seq_len_kv

即:

  • batch:批大小,不变。
  • num_groups:每个组独立计算注意力分数。
  • group_size:组内的 Query 头。
  • 1:当前 Query 的 token 数(因为推理时每次处理一个 token)。
  • seq_len_kv:Key 缓存的长度(即 Query 需要关注的所有历史 tokens)。

3. 举例计算

假设输入数据

  • Query Q_grouped

    • 形状:(batch=1, num_groups=2, group_size=2, 1, head_dim=3)
    • 假设值:
      Q_grouped = torch.tensor([[[  # Group 1[[1, 2, 3]],   # Query Head 1[[4, 5, 6]]    # Query Head 2],[  # Group 2[[7, 8, 9]],   # Query Head 3[[10, 11, 12]] # Query Head 4]]
      ], dtype=torch.float32)
      
  • Key K

    • 形状:(batch=1, num_groups=2, seq_len_kv=2, head_dim=3)
    • 假设值:
      K = torch.tensor([[[  # Group 1[0, 1, 0],  # Key 1[1, 0, 1]   # Key 2],[  # Group 2[1, 1, 1],  # Key 1[2, 2, 2]   # Key 2]]
      ], dtype=torch.float32)
      

计算步骤

  1. Key 转置K.transpose(-2, -1)

    K_T = K.transpose(-2, -1)
    

    变为:

    K_T = torch.tensor([[[  # Group 1[0, 1],  # Key Head 1[1, 0],  [0, 1]   ],[  # Group 2[1, 2],  # Key Head 2[1, 2],[1, 2]]]
    ], dtype=torch.float32)
    
  2. 矩阵乘法

    attn_logits = torch.matmul(Q_grouped, K_T)
    

    计算方式如下:

Group 1
Query Head 1 ([1, 2, 3]) 与 Key 矩阵点积:
[ 1 , 2 , 3 ] ⋅ [ 0 1 1 0 0 1 ] = [ 2 , 4 ] [1, 2, 3] \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \\ 0 & 1 \end{bmatrix} = [2, 4] [1,2,3] 010101 =[2,4]
Query Head 2 ([4, 5, 6]):

[ 4 , 5 , 6 ] ⋅ [ 0 1 1 0 0 1 ] = [ 5 , 9 ] [4, 5, 6] \cdot \begin{bmatrix} 0 & 1 \\ 1 & 0 \\ 0 & 1 \end{bmatrix} = [5, 9] [4,5,6] 010101 =[5,9]

Group 2

Query Head 3 ([7, 8, 9]):
[ 7 , 8 , 9 ] ⋅ [ 1 2 1 2 1 2 ] = [ 24 , 48 ] [7, 8, 9] \cdot \begin{bmatrix} 1 & 2 \\ 1 & 2 \\ 1 & 2 \end{bmatrix} = [24, 48] [7,8,9] 111222 =[24,48]
Query Head 4 ([10, 11, 12]):
[ 10 , 11 , 12 ] ⋅ [ 1 2 1 2 1 2 ] = [ 33 , 66 ] [10, 11, 12] \cdot \begin{bmatrix} 1 & 2 \\ 1 & 2 \\ 1 & 2 \end{bmatrix} = [33, 66] [10,11,12] 111222 =[33,66]


最终结果

计算出的 attn_logits

attn_logits = torch.tensor([[[[[2, 4]],  # Query Head 1[[5, 9]]   # Query Head 2],[[[24, 48]], # Query Head 3[[33, 66]]  # Query Head 4]]
], dtype=torch.float32)
  • 形状:(batch=1, num_groups=2, group_size=2, 1, seq_len_kv=2)

4. 结论

  • GQA 中,Query 按组匹配共享 Key,减少计算复杂度。
  • KV 缓存中仅存储 num_groups 组 Key,而非 num_heads 组 Key,节省显存。
  • 矩阵计算遵循 Query-Key 点积规则,matmul(Q_grouped, K.transpose(-2, -1)) 计算注意力分数

后记

2025年2月23日10点08分于上海,在GPT4o大模型辅助下完成。

相关文章:

Grouped-Query Attention(GQA)详解: Pytorch实现

Grouped-Query Attention(GQA)详解 Grouped-Query Attention(GQA) 是 Multi-Query Attention(MQA) 的改进版,它通过在 多个查询头(Query Heads)之间共享 Key 和 Value&am…...

docker基操

docker基操 首先就是安装docker使用docker:创建容器-制作一个镜像-加载镜像首先就是安装docker 随便找一个教程安装就可以,安装过程中主要是不能访问谷歌,下面这篇文章写了镜像的一些问题: 安装docker的网络问题 使用docker:创建容器-制作一个镜像-加载镜像 主要是参考:这篇…...

SF-HCI-SAP问题收集1

最近在做HCI的集成,是S4的环境,发现很多东西都跑不通,今天开始收集一下错误点 如果下图冲从0001变成0010,sfiom_rprq_osi表就会存数据,系统检查到此表就会报错,这个选项的作用就是自定义信息类型也能更新&a…...

当 OpenAI 不再 open,DeepSeek 如何掀起 AI 开源革命?

开源与闭源的路线之争成为了行业瞩目的焦点,DeepSeek掀起的 AI 开源风暴! 一、硅谷“斯普特尼克时刻” 1957年,苏联将人类首颗人造卫星“斯普特尼克”送上太空,美国举国震动。 这颗“篮球”般的卫星,刺痛了自诩科技霸…...

理解 logits_to_keep = logits_to_keep + 1 在 _get_per_token_logps 中的作用

理解 logits_to_keep logits_to_keep 1 在 _get_per_token_logps 中的作用 source: anaconda3/envs/xxx/lib/python3.10/site-packages/trl/trainer/grpo_trainer.py def _get_per_token_logps(self, model, input_ids, attention_mask, logits_to_keep):# We add 1 to logi…...

论文笔记-WSDM2025-ColdLLM

论文笔记-WSDM2025-Large Language Model Simulator for Cold-Start Recommendation ColdLLM:用于冷启动推荐的大语言模型模拟器摘要1.引言2.前言3.方法3.1整体框架3.1.1行为模拟3.1.2嵌入优化 3.2耦合漏斗ColdLLM3.2.1过滤模拟3.2.2精炼模拟 3.3模拟器训练3.3.1LLM…...

DeepSeek与AI幻觉

AI幻觉(AI Hallucination) 是指人工智能系统(尤其是生成式模型,如大型语言模型或图像生成模型)在输出内容时,生成与事实不符、逻辑混乱或完全虚构的信息的现象。这种现象类似于人类的“幻觉”,即…...

Linux 命令大全完整版(09)

4. 压缩与解压缩命令 ar 功能说明&#xff1a;建立或修改备存文件&#xff0c;或是从备存文件中抽取文件。语法&#xff1a;ar[-dmpqrtx][cfosSuvV][a<成员文件>][b<成员文件>][i<成员文件>][备存文件][成员文件]补充说明&#xff1a;可让您集合许多文件&a…...

deepseek_清华大学指导手册_pdf_1-5

deepseek_清华大学指导手册_pdf_1-5 无套路&#xff0c;无需关注&#xff0c;无需登录&#xff0c;无需app&#xff0c;直接下载&#xff1a; 下载地址 文件列表&#xff1a; 001_清华大学_DeepSeek从入门到精通.pdf 002_清华大学_DeepSeek如何赋能职场应用.pdf 003_清华大学…...

深度学习-127-LangGraph之基础知识(四)自定义状态添加额外字段的聊天机器人

文章目录 1 自定义状态2 自定义工具2.1 完善工具human_assistance2.2 浏览器工具baidu_search3 聊天机器人3.1 绑定工具的聊天模型3.2 聊天机器人(带记忆)4 调用图4.1 调用工具时中断4.2 人工提供信息恢复4.3 查询存储的状态4.4 手动更新状态5 参考附录使用LangGraph,在状态中…...

自定义实现简版状态机

状态机&#xff08;State Machine&#xff09;是一种用于描述系统行为的数学模型&#xff0c;广泛应用于计算机科学、工程和自动化等领域。它通过定义系统的状态、事件和转移来模拟系统的动态行为。 基本概念 状态&#xff08;State&#xff09;&#xff1a;系统在某一时刻的特…...

基于 Python Django 的校园互助平台(附源码,文档)

博主介绍&#xff1a;✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不…...

Python pip 缓存清理:全面方法与操作指南

在使用 Python 的 pip 进行包安装时&#xff0c;pip 会将下载的包缓存起来&#xff0c;以加快后续相同包的安装速度。不过&#xff0c;随着时间推移&#xff0c;缓存会占用大量磁盘空间&#xff0c;这时你可以对其进行清理。下面为你介绍不同操作系统下清理 pip 缓存的方法。 …...

Windows系统第一次运行C语言程序,环境配置,软件安装等遇到的坑及解决方法

明确需要编辑器和编译器&#xff0c;并选择自己要用什么&#xff08;我选的编辑器是VSCode&#xff1a;Visual Studio Code&#xff1b;编译器是gcc&#xff09;下载VSCode并配置环境变量&#xff08;这里没啥问题&#xff09;&#xff0c;安装C/C的拓展安装Cygwin&#xff0c;…...

Python开发Django面试题及参考答案

目录 Django 的请求生命周期是怎样的? Django 的 MTV 架构中的各个组件分别是什么? Django 的 URL 路由是如何工作的? Django 的视图函数和视图类有什么区别? Django 的模板系统是如何渲染 HTML 的? Django 的 ORM 是如何工作的? Django 的中间件是什么?它的作用是…...

PyTorch v2.6 Overview

PyTorch v2.6 Overview Python APILibraries PyTorch 是一个优化的张量库&#xff0c;用于使用 GPU 和 CPU 进行深度学习。 Python API 序号API名称解释1torchPyTorch 核心库(中文:火炬)PyTorch 的核心库&#xff0c;提供了张量操作、自动求导等基础功能。2torch.nn神经网络模…...

智慧废品回收小程序php+uniapp

废品回收小程序&#xff1a;数字化赋能环保&#xff0c;开启资源循环新时代 城市垃圾治理难题&#xff0c;废品回收小程序成破局关键 随着城市化进程加速与消费水平提升&#xff0c;我国生活垃圾总量逐年攀升&#xff0c;年均增速达5%-8%&#xff0c;其中超30%为可回收物。然…...

【p-camera-h5】 一款开箱即用的H5相机插件,支持拍照、录像、动态水印与样式高度定制化。

【开源推荐】p-camera-h5&#xff1a;一款轻量级H5相机插件开发实践 一、插件背景 在Web开发中&#xff0c;原生摄像头功能的集成往往面临以下痛点&#xff1a; 浏览器兼容性问题视频流与水印叠加实现复杂移动端适配困难功能定制成本高 为此&#xff0c;p-camera-h5 —— 一…...

python~http的请求参数中携带map

背景 调试 http GET请求的 map 参数&#xff0c;链路携带参数一直有问题&#xff0c;最终采用如下方式携带map 解决 user{"demo":"true","info":"王者"}url encode之后的效果如下所示 user%7B%22demo%22:%22true%22,%22info%22:%22…...

网页版的俄罗斯方块

1、新建一个txt文件 2、打开后将代码复制进去保存 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>俄…...

创建虚拟环境以及配置对应的项目依赖

文章目录 首先创建一个虚拟环境&#xff0c;创建一个名字为myenv,并且版本为xxx的虚拟环境 conda create --name myenv pythonxxx激活虚拟环境 conda activate myenv下载所需的依赖&#xff0c;如果有requirements.txt文件 pip install -r requirements.txt容易出现的错误&a…...

网络安全第三次练习

一、实验拓扑 二、实验要求 配置真实DNS服务信息&#xff0c;创建虚拟服务&#xff0c;配置DNS透明代理功能 三、需求分析 1.创建用户并配置认证策略 2.安全策略划分接口 3.ip与策略配置 四、实验步骤 1.划分安全策略接口 2.创建用户并进行策略认证 3.配置安全策略 4.NAT配…...

写大论文的word版本格式整理,实现自动生成目录、参考文献序号、公式序号、图表序号

前情提要&#xff1a;最近开始写大论文&#xff0c;发现由于内容很多导致用老方法一个一个改的话超级麻烦&#xff0c;需要批量自动化处理&#xff0c;尤其是序号&#xff0c;在不断有增添删减的情况时序号手动调整很慢也容易出错&#xff0c;所以搞一个格式总结&#xff0c;记…...

STM32——HAL库开发笔记22(定时器3—呼吸灯实验)(参考来源:b站铁头山羊)

本文利用前几节所学知识来实现一个呼吸灯实验&#xff1a;两颗led灯交替呼吸。 一、STM32CubeMX配置 step1&#xff1a;配置调试接口 step2&#xff1a;配置定时器 定时器1位于APB2总线上&#xff0c;如上图所示。 step3&#xff1a;配置时基单元 按照下图配置 时钟来源配置…...

GPU和FPGA的区别

GPU&#xff08;Graphics Processing Unit&#xff0c;图形处理器&#xff09;和 FPGA&#xff08;Field-Programmable Gate Array&#xff0c;现场可编程门阵列&#xff09;不是同一种硬件。 我的理解是&#xff0c;虽然都可以用于并行计算&#xff0c;但是GPU是纯计算的硬件…...

vue3页面显示tiff图片

浏览器网页一般不直接支持tiff图片的显示&#xff0c;需要用到tiff.js这个库&#xff0c;首先安装tiff.js&#xff0c;使用命令 npm install tiff.js安装。 首先&#xff0c;引入相关库 import axios from axios; import { ref } from vue; import {TIFF } from tiff.js 在v…...

玩转 Java 与 Python 交互,JEP 库来助力

文章目录 玩转 Java 与 Python 交互&#xff0c;JEP 库来助力一、背景介绍二、JEP 库是什么&#xff1f;三、如何安装 JEP 库&#xff1f;四、JEP 库的简单使用方法五、JEP 库的实际应用场景场景 1&#xff1a;数据处理场景 2&#xff1a;机器学习场景 3&#xff1a;科学计算场…...

【单片机毕业设计14-基于stm32c8t6的智能宠物养护舱系统设计】

【单片机毕业设计14-基于stm32c8t6的智能宠物养护舱系统设计】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇14-基于stm32c8t6的智能宠物养护舱系统设计 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功…...

ASUS/华硕天选4 Plus 锐龙版 FA507X FA707X 原厂Win11 22H2专业版系统 工厂文件 带ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;带一键恢复&#xff0c;以及机器所有的驱动和软件。 支持型号&#xff1a;FA507XU FA507XV FA507XQ FA507XJ FA507XI, FA707XV, FA707XU, FA707XQ, FA707XJ, FA707XI, FA707XIN 系统版本&#xff1a;Windo…...

从头再来!社招找工作——算法题复习九:动态规划

从头再来&#xff01;社招找工作——算法题复习九&#xff1a;动态规划 动态规划斐波那数列跳台阶跳台阶/爬楼梯最小花费跳台阶 最长公共子序列矩阵矩阵路线总数矩阵路线总数有障碍物矩阵的最小路径和三角形的最小路径和 买卖股票的最佳时机&#xff08;T1天 / 当日不可卖&…...