【如果笔记对你有帮助,欢迎关注&点赞&收藏,收到正反馈会加快更新!谢谢支持!】

一、位置编码介绍

  • 为什么需要位置编码(Position Encoding)?
    • Transformer架构的核心是自注意力机制,通过计算序列中任意两个元素之间的关系来提取信息。然而,自注意力机制本身是位置无关的(例如,对于“猫在椅子上”和“椅子在猫上”,自注意力机制在没有位置信息的情况下会认为这两个序列是等价的)
  • 多模态大模型中位置编码的作用:
    • 提供顺序信息
    • 增强模型表达能力(理解句子的语法结构、图像的空间位置、图像中对象的位置与文本描述之间的对应关系等)
    • 捕捉长距离的依赖关系
  • 常用的位置编码类型:
    • 绝对位置编码:正弦位置编码,可学习位置编码
    • 相对位置编码:Transformer-XL相对位置编码,T5相对位置编码,旋转位置编码(RoPE),ALiBi位置编码

 二、绝对位置编码

2.1 正弦位置编码(Transformer的位置编码)

  • sin和cos交替,通过线性变换矩阵得到位置编码
  • 为什么不是相对位置编码【也是正弦位置编码的缺点】:在计算Attention的时候要通过projection变成qkv(投影矩阵变换破坏掉位置的相对性),映射后的正余弦波乘积不再具有单调性
  • 代码:
    import numpy as np
    import torch
    
    def sinusoidal_position_encoding(max_len, d_model):
        """
        生成正弦位置编码矩阵
        :param max_len: 序列的最大长度
        :param d_model: 嵌入的维度
        :return: 位置编码矩阵,形状为 (max_len, d_model)
        """
        # 创建一个空的位置编码矩阵
        position_encoding = np.zeros((max_len, d_model))
        
        # 计算位置编码的每个维度
        for pos in range(max_len):
            for i in range(0, d_model, 2):
                position_encoding[pos, i] = np.sin(pos / (10000 ** (2 * i / d_model)))
                if i + 1 < d_model:
                    position_encoding[pos, i + 1] = np.cos(pos / (10000 ** (2 * i / d_model)))
        
        # 将位置编码矩阵转换为张量
        position_encoding = torch.tensor(position_encoding, dtype=torch.float32)
        return position_encoding
    
    # 示例:生成一个长度为50,维度为128的位置编码矩阵
    max_len = 50
    d_model = 128
    position_encoding = sinusoidal_position_encoding(max_len, d_model)
    

2.2 可学习位置编码(BERT)

  • 把位置编码当成可学习的参数
  • 缺点:没有长度的外推性(长度是固定死的)
    self.position_embedding = nn.Embedding(max_len, d_model)
     

三、相对位置编码

3.0 相对位置编码如何实现

  • 绝对位置编码只在输入时添加,相对位置编码在每一层中根据键和查询之间的偏移量进行计算
  • 相对位置编码通常会进行截断处理(需要有限个)

3.1 Transformer-XL相对位置编码

3.2 T5相对位置编码

  • 认为输入(x)和位置编码(p)是可以解耦的,即删除了x*p 的项
    【即 Attention矩阵 + 偏置项 

3.3 RoPE 旋转位置编码

  • 结合绝对和相对位置编码优点
    • 绝对位置编码:简单,但是不能扩展、不能表示相对位置
    • 相对位置编码:关注相对距离,捕捉相对关系,但是使模型架构复杂化
    • RoPE:用绝对位置编码的方式实现相对位置编码,简单高效
    • 原理:利用三角函数(sin,cos)的特性,将R(i)*R(j)^T → R(i-j)

      计算:
  • 代码实现(参考上面公式):  
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    import math
    
    
    def sinusoidal_position_embedding(batch_size, num_head, max_len, output_dim, device):
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(-1)
    
        # (output_dim//2)
        ids = torch.arange(0, output_dim // 2, dtype=torch.float)  
        theta = torch.pow(10000, -2 * ids / output_dim)
    
        embeddings = position * theta  # shape: (max_len, output_dim//2)
        embeddings = torch.stack([torch.sin(embeddings), torch.cos(embeddings)], dim=-1) # shape: (max_len, output_dim//2, 2)
        embeddings = embeddings.repeat((batch_size, nums_head, *([1] * len(embeddings.shape))))  # shape: (batch_size, nums_head, max_len, output_dim//2, 2)
    
        # (bs, head, max_len, output_dim)
        embeddings = embeddings.reshape(batch_size, nums_head, max_len, output_dim)
        embeddings = embeddings.to(device)
        return embeddings
    
    
    def RoPE(q, k):
        # q,k: (bs, head, max_len, output_dim)
        batch_size, num_head, max_len, output_dim = q.shape
    
        # (bs, head, max_len, output_dim)
        pos_emb = sinusoidal_position_embedding(batch_size, nums_head, max_len, output_dim, q.device)
    
        # cos_pos,sin_pos: (bs, head, max_len, output_dim)
        cos_pos = pos_emb[...,  1::2].repeat_interleave(2, dim=-1)  # 将奇数列信息抽取出来也就是cos 拿出来并复制
        sin_pos = pos_emb[..., ::2].repeat_interleave(2, dim=-1)  # 将偶数列信息抽取出来也就是sin 拿出来并复制
    
        # q,k: (bs, head, max_len, output_dim)
        q2 = torch.stack([-q[..., 1::2], q[..., ::2]], dim=-1)
        q2 = q2.reshape(q.shape)  # reshape后就是正负交替了
    
        # 更新qw, *对应位置相乘
        q = q * cos_pos + q2 * sin_pos
    
        k2 = torch.stack([-k[..., 1::2], k[..., ::2]], dim=-1)
        k2 = k2.reshape(k.shape)
        # 更新kw, *对应位置相乘
        k = k * cos_pos + k2 * sin_pos
    
        return q, k

3.4 ALiBi (Attention with Linear Biases)

  • 在注意力计算公式上,引入惩罚因子(相对距离成正比例关系)来调整注意力分数
  • 用来增强Transformer模型的长度外推能力

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐