Py学习  »  机器学习算法

彻底搞懂深度学习-多头注意力和位置编码(动图讲解)

架构师带你玩转AI • 1 月前 • 56 次点击  
在前面的学习中,我们深入理解了自注意力机制的基本原理。但要构建真正强大的Transformer模型,还需要掌握两个关键技术:多头注意力和位置编码。这两个技术分别解决了"如何捕捉多种关系模式"和"如何处理序列位置信息"的核心问题。
本文将深入剖析这两个机制的设计原理、数学实现和实际应用,帮助你完全理解现代Transformer架构的核心组件。
Transformer Design Guide (Part 2: Modern Architecture) | Rohit Bandaru

一、多头注意力:如何捕捉多种关系模式

为什么需要多头注意力(Multi-Head Attention)?

单个注意力头只能捕捉一种关系模式,但语言中存在多种复杂的关系。

  • 语法关系:谁做了什么事(比如"小明吃苹果"中,小明是做事的人,吃是动作,苹果是被吃的东西)

  • 语义关系:意思相关的词会互相关注(比如"医生"和"医院"、"猫"和"老鼠"这些词天然有联系)

  • 位置关系:挨得近的词往往关系更密切(就像坐得近的同学更容易聊天一样)

  • 指代关系:搞清楚"它"、"他"、"她"指的是谁(比如"小猫很可爱,它在睡觉"中的"它"指的是小猫)

多头注意力让模型并行学习这些不同的关系模式,就像给模型配备了多双"眼睛",每双眼睛专注观察不同类型的语言现象。

以句子"The cat that was sleeping on the mat woke up"为例,不同的注意力头会专注于不同的语言关系。

Head 1(语法关系):

  • "cat" → "woke" (主谓关系)
  • "cat" → "sleeping" (定语关系)

Head 2(指代关系):

  • "that" → "cat" (关系代词指向)

Head 3(位置关系):

  • "sleeping" → "on" (介词关系)
  • "on" → "mat" (介词宾语)

Head 4(语义关系):

  • "cat" → "sleeping" (动作执行者)
  • "mat" → "sleeping" (地点关系)

这种分工合作的机制使模型能够同时处理语言的多个层面,大大提升了表示能力。

The Multi-head Attention Mechanism Explained!

多头注意力(Multi-Head Attention)如何实现?
多头注意力将原始的Query、Key、Value分割成多个子空间,在每个子空间内独立计算注意力,最后将结果合并。
    • 参数分配:将总维度d_model平均分配给各个头,每头维度为d_k = d_model / num_heads

    • 独立计算:每个头使用不同的权重矩阵,学习不同的表示子空间

    • 结果融合:通过连接(concatenation)和线性投影整合多头信息

    # 8个注意力头的情况def multi_head_attention(X, num_heads=8):    d_model = X.shape[-1]    d_k = d_model // num_heads    # 为每个头创建不同的Q,K,V权重    heads = []    for i in range(
    
    
        
    num_heads):        Wq_i = create_weight_matrix(d_model, d_k)        Wk_i = create_weight_matrix(d_model, d_k)        Wv_i = create_weight_matrix(d_model, d_k)        Q_i = X @ Wq_i        K_i = X @ Wk_i        V_i = X @ Wv_i        head_i = attention(Q_i, K_i, V_i)        heads.append(head_i)    # 连接所有头的输出    multi_head_output = concat(heads)  # shape: (seq_len, d_model)    # 最终线性投影    output = multi_head_output @ Wo    return output

      二、位置编码:如何处理序列位置信息

      为什么需要位置编码(Position Encoding)?

      如果你在看一本书,但是所有的字都混乱排列,没有顺序,你还能理解内容吗?显然不能。语言的意思很大程度上取决于词语的排列顺序。但自注意力机制的一个根本性问题:它对位置不敏感!

      考虑这两个句子:

      • "猫追老鼠"
      • "老鼠追猫"

      对于纯粹的自注意力机制来说,这两个句子是完全一样的,因为:

      • 它只看到了"猫"、"追"、"老鼠"这三个词
      • 但完全不知道它们的排列顺序
      • 就像一个色盲的人看不出红绿的区别一样

      但我们都知道,这两个句子的意思完全不同!第一个是猫在追老鼠,第二个是老鼠在追猫。

      Transformers Positional Encodings Explained | by João Lages | Towards AI

      位置编码 (Position Encoding)如何实现?

      既然模型看不懂位置,那我们就给每个位置做个标记,就像给每个座位贴上号码一样。位置信息的融入方式非常简单:直接相加。

      Transformers and the Power of Positional Encoding [Transformers Series]

      • 第1个位置的词,加上"第1号"的标签
      • 第2个位置的词,加上"第2号"的标签
      • 第3个位置的词,加上"第3号"的标签
      • ......

      这样,即使是同一个词"猫",出现在不同位置时,模型也能区分开:

      • 位置1的"猫" = "猫"的意思 + "第1号位置"的信息
      • 位置3的"猫" = "猫"的意思 + "第3号位置"的信息
      # 词嵌入:表示词的意思word_embedding = [0.1, 0.5, -0.2, 0.8]  # "猫"的向量表示# 位置编码:表示位置信息  position_encoding = [0.0, 0.3, 0.1, -0.1]  # 第1个位置的编码# 最终输入:意思 + 位置final_input = word_embedding + position_encoding            = [0.1, 0.8, -0.1, 0.7]  # 既有"猫"的意思,又有"第1个位置"的信息

      Transformer使用了一种很聪明的位置编码方式,叫做"正弦和余弦函数"。

      • 不同维度使用不同频率:通过 10000^(i/d_model) 创建频率梯度
      • 高频部分(低维度):变化快,精确区分相邻位置
      • 低频部分(高维度):变化慢,有效区分远距离位置
      A Gentle Introduction to Positional Encoding in Transformer Models, Part 1
          # 简化版的位置编码实现def positional_encoding(seq_len, d_model):    """    为每个位置生成独特的编码向量    seq_len: 句子长度    d_model: 向量维度    """    pos_encoding = np.zeros((seq_len, d_model))    for pos in range(seq_len):  # 对每个位置        for i in range(d_model):  # 对向量的每一维            if i % 2 == 0:  # 偶数维度用sin                pos_encoding[pos, i] = sin(pos / 10000^(i/d_model))            else:  # 奇数维度用cos                pos_encoding[pos, i] = cos(pos / 10000^((i-1)/d_model))    return pos_encoding
          这种"多频率 + 正弦余弦交替"的组合设计,让每个位置都获得了独特的高维"指纹"。就像用多个不同精度的尺子同时测量,既能区分毫米级的差异,也能区分米级的差异,从而确保任意两个位置的编码都不会相同。
          通过数学上的巧妙设计,让每个位置都有了独一无二的"身份证",这个身份证既包含精细信息(高频),又包含粗略信息(低频),正弦余弦则提供了完整的二维坐标描述。

          Python社区是高质量的Python/Django开发社区
          本文地址:http://www.python88.com/topic/185000
           
          56 次点击