LLaMA中ROPE位置编码实现源码解析

1、Attention中q,经下式,生成新的q。m为句长length,d为embedding_dim/head
θ i = 1 1000 0 2 i d \theta_i=\frac{1}{10000^\frac{2i}{d}} θi=10000d2i1

2、LLaMA中RoPE源码

python 复制代码
import torch

def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
    '''
    计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
    :param dim: q,k,v的最后一维,一般为emb_dim/head_num
    :param end: 句长length
    :param constant: 这里指10000
    :return:
    复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
    '''
    # freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
    # 形式化为 [theta_0, theta_1, ..., theta_d/2]
    freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]

    # 计算m
    t = torch.arange(end, device=freqs.device)  # [length]
    # 计算m*theta
    freqs = torch.outer(t, freqs).float()  # [length, d]
    # freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_d/2],其中 m=0,1,...,length-1

    # 计算cos(m*theta)+j*sin(m*theta)
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64
    # freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0),  cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_d/2-1)+j*sin(m*theta_d/2-1)]
    # 其中j为虚数单位, m=0,1,...,length-1
    return freqs_cis # [length, d]

def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
    ndim = x.ndim
    assert 0 <= 1 < ndim
    assert freqs_cis.shape == (x.shape[1], x.shape[-1])
    shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
    return freqs_cis.view(*shape) # [1, length, 1, d/2]

def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
    # 先将xq维度变为[bs, length, head,  d/2, 2], 利用torch.view_as_complex转变为复数
    # xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
    xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
    # 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
    xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))

    freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
    # 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
    # (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
    # 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
    # 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
    # 最后经flatten函数将维度拉平,即[bs, length, head, d]
    # 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
    # 即为新生成的q

    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
    return xq_out.type_as(xq), xk_out.type_as(xk)

if __name__=='__main__':
    # (bs, length, head, d)
    q = torch.randn((2, 10, 12, 32))  # q=[q0, q1, .., qd-1]
    k = torch.randn((2, 10, 12, 32))
    v = torch.randn((2, 10, 12, 32))
    freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
    # print(freqs_cis.detach().numpy())
    
    q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
    print()
相关推荐
勤劳的进取家9 分钟前
论文阅读:Do As I Can, Not As I Say: Grounding Language in Robotic Affordances
论文阅读·人工智能·机器学习·语言模型·自然语言处理
THMAIL12 分钟前
大模型0基础开发入门与实践:第8章 “大力出奇迹”的哲学:大语言模型的核心技术揭秘
人工智能·语言模型·自然语言处理
这张生成的图像能检测吗31 分钟前
(论文速读)RandAR:突破传统限制的随机顺序图像自回归生成模型
图像处理·人工智能·机器学习·计算机视觉·生成模型·自回归模型
智驱力人工智能1 小时前
智慧工厂烟雾检测:全场景覆盖与精准防控
人工智能·算法·安全·智慧城市·烟雾检测·明火检测·安全生产
山烛9 小时前
矿物分类系统开发笔记(一):数据预处理
人工智能·python·机器学习·矿物分类
拾零吖9 小时前
吴恩达 Machine Learning(Class 3)
人工智能·机器学习
admiraldeworm9 小时前
Spring Boot + Spring AI 最小可运行 Demo
java·人工智能·ai
算法_小学生10 小时前
长短期记忆网络(LSTM)
人工智能·rnn·lstm
Virgil13910 小时前
【TrOCR】模型预训练权重各个文件解读
人工智能·pytorch·计算机视觉·自然语言处理·ocr·transformer