You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Transformer注意力可视化疑问:选哪个张量?为何不含Value?

注意力可视化的张量选择问题

我在提取模型的注意力时发现,注意力张量在和v(value)执行matmul()后形状发生了变化:

  • 变化前:attention_probs的形状为 torch.Size([1, 12, 464, 464])
  • 变化后:attention的形状变为 torch.Size([1, 464, 12, 64])
  • 最终重排为:torch.Size([464, 768])

核心问题

  1. 我应该使用哪一部分张量来可视化每个token与其他token之间的注意力?
  2. 如果需要使用matmul()之前的张量,能否解释为什么v不需要被纳入注意力计算用于可视化?

相关代码实现

qkv = self.Wqkv(hidden_states)
qkv = pad_input(qkv, indices, cu_seqlens.shape[0] - 1,
                max_seqlen_in_batch)  # batch, max_seqlen_in_batch, thd
qkv = rearrange(qkv,
                'b s (t h d) -> b s t h d',
                t=3,
                h=self.num_attention_heads)
if self.p_dropout or flash_attn_qkvpacked_func is None:
    # if we have nonzero attention dropout (e.g. during fine-tuning) or no Triton, compute attention in PyTorch
    q = qkv[:, :, 0, :, :].permute(0, 2, 1, 3)  # b h s d
    k = qkv[:, :, 1, :, :].permute(0, 2, 3, 1)  # b h d s
    v = qkv[:, :, 2, :, :].permute(0, 2, 1, 3)  # b h s d
    attention_scores = torch.matmul(q, k) / math.sqrt(
        self.attention_head_size)
    attention_scores = attention_scores + bias
    attention_probs = nn.functional.softmax(attention_scores, dim=-1)
    attention_probs = self.dropout(attention_probs)

    # Before matmul(): Torch.Size([1, 12, 464, 464])
    print(f'BUSA: attention_probs 2 shape: {attention_probs.shape}')

    attention = torch.matmul(attention_probs, v).permute(0, 2, 1,
                                                         3)  # b s h d
    # After matmul() torch.Size([1, 464, 12, 64])
    print(f'BUSA: attention shape: {attention.shape}')

else:
    # Triton implementation only supports 0 attention dropout
    convert_dtype = qkv.dtype not in [torch.float16, torch.bfloat16]
    if convert_dtype:
        # Triton implementation only supports fp16 and bf16
        ...
    else:
        attention = flash_attn_qkvpacked_func(qkv, bias)
        print(f'BUSA Triton: attention 2 shape: {attention_probs.shape}')

# attn_mask is 1 for attend and 0 for don't
attention = unpad_input_only(attention, torch.squeeze(attn_mask) == 1)

# Still the same: torch.Size([1, 12, 464, 464])
print(f'BUSA unpadded final attention shape: {attention_probs.shape}')

rearranged_attention = rearrange(attention, 'nnz h d -> nnz (h d)')

# torch.Size([464, 768]) which is [464,12,64]
print(f'REARRANGED ATTENTION: {rearranged_attention.shape}')

return rearrange(attention, 'nnz h d -> nnz (h d)')

问题解答

1. 可视化用的张量选择

你需要用matmul()之前的**attention_probs张量**来做token间的注意力可视化。

它的形状[1, 12, 464, 464]对应:

  • 第1维:batch大小(这里是1)
  • 第2维:注意力头数量(12个)
  • 第3维:当前token的位置(共464个token)
  • 第4维:被关注的token位置(共464个token)

每个元素attention_probs[b, h, i, j]代表第b个样本中,第h个注意力头里,第i个token对第j个token的注意力权重,完全对应你需要的“每个token与其他token的注意力关系”。

而matmul()之后的attention张量,已经是注意力权重和v(value)加权求和的结果,它代表的是每个token结合了其他token信息后的最终表征,不再保留token间的注意力权重关系,没法用来可视化token间的关联。

2. 为什么v不需要纳入可视化计算?

注意力机制的核心逻辑里,attention_probs本身就定义了token之间的注意力分配关系:

  • 第一步用q和k计算相似度得到attention_scores,经过softmax后得到attention_probs,这一步已经明确了每个token对其他所有token的关注程度,完全对应你要可视化的“注意力关联”。
  • 而v的作用是把这些注意力权重应用到具体的token特征上,生成最终的注意力输出(也就是模型后续层要用的表征),这是注意力机制的“特征聚合”环节,和“注意力分配关系”本身是两个独立的步骤。

简单说:你要可视化的是“谁关注了谁”,这部分信息只在attention_probs里;v是用来计算“关注后得到了什么特征”,和注意力分配的关系无关,所以不需要纳入可视化。


内容的提问来源于stack exchange,提问作者Wassim Jaoui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 03:05:58