2024年大模型面试准备(四):大模型面试必会的位置编码(绝对位置编码sinusoidal,旋转位置编码RoPE,以及相对位置编码ALiBi)

本文主要是介绍2024年大模型面试准备(四):大模型面试必会的位置编码(绝对位置编码sinusoidal,旋转位置编码RoPE,以及相对位置编码ALiBi),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。


合集在这里:《大模型面试宝典》(2024版) 正式发布!


Transformer 模型在处理序列数据时,其自注意力机制使得模型能够全局地捕捉不同元素之间的依赖关系,但这样做的代价是丧失了序列中的元素顺序信息。由于自注意力机制并不考虑元素在序列中的位置,所以在输入序列的任何置换下都是不变的,这就意味着模型无法区分序列中元素的相对位置。在许多自然语言处理任务中,词语之间的顺序是至关重要的,所以需要一种方法来让模型捕获这一信息。

因此在送入编码器端建模其上下文语义之前,一个非常重要的操作是 在词嵌入中加入位置编码(Positional Encoding) 这一特征。

具体来说,序列中每一个单词所在的位置都对应一个向量。这一向量会与单词表示对应相加并送入到后续模块中做进一步处理。在训练的过程当中,模型会自动地学习到如何利用这部分位置信息。

常见的位置编码主要有绝对位置编码(sinusoidal),旋转位置编码(RoPE),以及相对位置编码ALiBi

1、绝对位置编码sinusoidal

绝对位置编码是直接将序列中每个位置的信息编码进模型的,从而使模型能够了解每个元素在序列中的具体位置。原始Transformer提出时采用了sinusoidal位置编码,通过使用不同频率的正弦和余弦的函数,使得模型捕获位置之间的复杂关系,且这些编码与序列中每个位置的绝对值有关。sinusoidal位置编码公式如下:

在这里插入图片描述
在这里插入图片描述

原始 Transformer 的位置编码虽然是基于绝对位置的,但其数学结构使其能够捕获一些相对位置信息。使用正弦和余弦函数的组合为每个位置创建编码,波长呈几何级数排列,意味着每个位置的编码都是独特的。同时,正弦和余弦函数的周期性特性确保了不同位置之间的编码关系是连续且平滑的。

比如:

  • 对于相邻位置,位置编码的差异较小,与两者之间的距离成正比。

  • 对于相隔较远的位置,位置编码的差异较大,与两者之间的距离也成正比。

这种连续和平滑的关系允许模型学习位置之间的相对关系,而不仅仅是各自的绝对位置。考虑两个位置和,由于正弦和余弦函数的性质,位置编码的差值将与和之间的差值有关。这意味着通过比较不同位置编码之间的差值,模型可以推断出它们之间的相对位置。

总结来说,通过上面这种方式计算位置编码有这样几个好处:

  • 首先,正余弦函数的范围是在 [-1,+1],导出的位置编码与原词嵌入相加,不会使得结果偏离过远而破坏原有单词的语义信息。

  • 其次,依据三角函数的基本性质,可以得知第 pos + k 个位置的编码是第 pos 个位置的编码的线性组合,这就意味着位置编码中蕴含着单词之间的距离信息。

使用 Pytorch 实现的位置编码参考代码如下:

class PositionalEncoder(nn.Module):def __init__(self, d_model, max_seq_len = 80):super().__init__()self.d_model = d_model# 根据 pos 和 i 创建一个常量 PE 矩阵pe = torch.zeros(max_seq_len, d_model)for pos in range(max_seq_len):for i in range(0, d_model, 2):pe[pos, i] = math.sin(pos / (10000 ** ((2 * i)/d_model)))pe[pos, i + 1] = math.cos(pos / (10000 ** ((2 * (i + 1))/d_model)))pe = pe.unsqueeze(0)self.register_buffer('pe', pe)def forward(self, x):# 使得单词嵌入表示相对大一些x = x * math.sqrt(self.d_model)# 增加位置常量到单词嵌入表示中seq_len = x.size(1)x = x + Variable(self.pe[:,:seq_len], requires_grad=False).cuda()return x

另一份实现和可视化代码如下:

import math
import torch
import torch.nn as nn
import numpy as npclass PositionalEncoding(nn.Module):def __init__(self, d_model: int, dropout_prob: float, max_len: int = 5000):super().__init__()self.dropout = nn.Dropout(dropout_prob)encodings = self.get_positional_encoding(d_model, max_len)self.register_buffer('positional_encodings', encodings, False)@staticmethoddef get_positional_encoding(d_model: int, max_len: int):position = torch.arange(0, max_len, dtype=torch.float32).unsqueeze(1)two_i = torch.arange(0, d_model, 2, dtype=torch.float32)div_term = torch.exp(two_i * -(math.log(10000.0) / d_model))encodings = torch.zeros(max_len, d_model)encodings[:, 0::2] = torch.sin(position * div_term)encodings[:, 1::2] = torch.cos(position * div_term)return encodings.unsqueeze(0).requires_grad_(False)def forward(self, x: torch.Tensor):pe = self.positional_encodings[:x.shape[1]].detach().requires_grad_(False)return self.dropout(x + pe)def _test_positional_encoding():import matplotlib.pyplot as pltplt.figure(figsize=(15, 5))pe = PositionalEncoding.get_positional_encoding(20, 100)print(pe.shape)plt.plot(np.arange(100), pe[:, 0, 4:8].numpy())plt.legend(["dim %d" % p for p in [4, 5, 6, 7]])plt.title("Positional encoding")plt.show()if __name__ == '__main__':_test_positional_encoding()

可以看到不同维度沿着序列方向的位置编码变化如下图所示:

图片

2、旋转位置编码RoPE

sinusoidal位置编码对相对位置关系的表示还是比较间接的,那有没有办法更直接的表示相对位置关系呢?那肯定是有的,而且有许多不同的方法,旋转位置编码(Rotary Position Embedding,RoPE)是一种用绝对位置编码来表征相对位置编码的方法,并被用在了很多大语言模型的设计中,很多成功的LLM,例如LLAMA系列、GLM、百川、通义千问等,都使用了RoPE。

RoPE 借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。

在这里插入图片描述

图片

本文主要介绍思想,具体推导感兴趣的可以看苏剑林老师的博客或者论文:RoFormer: Enhanced Transformer with Rotary Position Embedding

有了这一形式后,具体实现有两种方式:

  • 转到复数域,对两个向量进行旋转,再转回实数域

  • 由于上述矩阵 Rn 具有稀疏性,因此可以使用逐位相乘 ⊗ 操作进一步加快计算速度,直接在实数域通过向量和正余弦函数的乘法进行运算,也就是下面这个公式:
    图片

LLaMA的代码实现就是采用了第一种形式,如下:

def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0):freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))t = torch.arange(end, device=freqs.device)  # type: ignorefreqs = torch.outer(t, freqs).float()  # type: ignorefreqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64return freqs_cisdef reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):ndim = x.ndimassert 0 <= 1 < ndimassert 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)]return freqs_cis.view(*shape)def apply_rotary_emb(xq: torch.Tensor,xk: torch.Tensor,freqs_cis: torch.Tensor,
) -> Tuple[torch.Tensor, torch.Tensor]:xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))freqs_cis = reshape_for_broadcast(freqs_cis, xq_)xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)return xq_out.type_as(xq), xk_out.type_as(xk)

第二种方式的实现会更加易懂一点,就是把前面那个公式中的四个向量凑出来,然后照着公式算一下就可以了,示例代码如下:

import torch
import mathdef rotary_position_embedding(q, k):"""Rotary Position Embedding (RoPE) for queries and keys.Args:q: tensor for queries of shape (batch_size, num_heads, seq_len, dim)k: tensor for keys of shape (batch_size, num_heads, seq_len, dim)Returns:Rotated queries and keys"""batch_size, num_heads, seq_len, dim = q.size()# Begin of sinusoidal_position_embedding contentposition = torch.arange(seq_len, dtype=torch.float).unsqueeze(-1).to(q.device)div_term = torch.exp(torch.arange(0, dim, 2, dtype=torch.float) * -(math.log(10000.0) / dim)).to(q.device)pos_emb = position * div_termpos_emb = torch.stack([torch.sin(pos_emb), torch.cos(pos_emb)], dim=-1).flatten(-2, -1)pos_emb = pos_emb.unsqueeze(0).unsqueeze(1)pos_emb = pos_emb.expand(batch_size, num_heads, -1, -1)# End of sinusoidal_position_embedding content# Extract and duplicate cosine and sine embeddingscos_emb = pos_emb[..., 1::2].repeat_interleave(2, dim=-1)sin_emb = pos_emb[..., ::2].repeat_interleave(2, dim=-1)# Create alternate versions of q and kq_alternate = torch.stack([-q[..., 1::2], q[..., ::2]], dim=-1).reshape(q.size())k_alternate = torch.stack([-k[..., 1::2], k[..., ::2]], dim=-1).reshape(k.size())# Rotate queries and keysq_rotated = q * cos_emb + q_alternate * sin_embk_rotated = k * cos_emb + k_alternate * sin_embreturn q_rotated, k_rotated

相对位置编码AliBi

受到 T5 Bias 的启发,Press 等人提出了 ALiBi 算法,是一种预定义的相对位置编码。与传统方法不同,ALiBi 不向单词embedding中添加位置embedding,而是根据token之间的距离给 attention score 加上一个预设好的偏置矩阵,比如 和 相对位置差 1 就加上一个 -1 的偏置,两个 token 距离越远这个负数就越大,代表他们的相互贡献越低。由于注意力机制一般会有多个head,这里针对每一个head会乘上一个预设好的斜率项(Slope)。

在这里插入图片描述

图片

ALiBi 对最近性具有归纳偏差,它对远程查询-键对之间的注意力分数进行惩罚,随着键和查询之间的距离增加,惩罚增加。不同的注意头以不同的速率增加其惩罚,这取决于斜率幅度。实验证明这组斜率参数适用于各种文本领域和模型尺寸,不需要在新的数据和架构上调整斜率值。

因此ALiBi方法不需要对原始网络进行改动,允许在较短的输入序列上训练模型,同时在推理时能够有效地外推到较长的序列,从而实现了更高的效率和性能。

下面给出一份实验代码,大家可以自己跑一跑感觉一下:

import math
import torch
from torch import nndef get_slopes(n_heads: int):n = 2 ** math.floor(math.log2(n_heads))m_0 = 2.0 ** (-8.0 / n)m = torch.pow(m_0, torch.arange(1, 1 + n))if n < n_heads:m_hat_0 = 2.0 ** (-4.0 / n)m_hat = torch.pow(m_hat_0, torch.arange(1, 1 + 2 * (n_heads - n), 2))m = torch.cat([m, m_hat])return m@torch.no_grad()
def get_alibi_biases(n_heads: int, mask: torch.Tensor):m = get_slopes(n_heads).to(mask.device)seq_len = mask.size(0)distance = torch.tril(torch.arange(0, -seq_len, -1).view(-1, 1).expand(seq_len, seq_len))print(distance)return distance[:, :, None] * m[None, None, :]seq_len = 10
n_heads = 8m = get_slopes(n_heads)
print(m)alibi_biases = torch.zeros(seq_len,seq_len)
for j in range(1,seq_len):for i in range(j, seq_len):alibi_biases[i, i - j] = -j
print(alibi_biases)print(alibi_biases[:, :, None].shape, m[None, None, :].shape)alibi_biases[:, :, None] * m[None, None, :]

代码打印出的结果如下:

图片

可以看到上面打印出来的第一行就是给不同head的系数 ,第二行矩阵就是基于两个 token 之间距离计算的偏置矩阵。

技术交流群

前沿技术资讯、算法交流、求职内推、算法竞赛、面试交流(校招、社招、实习)等、与 10000+来自港科大、北大、清华、中科院、CMU、腾讯、百度等名校名企开发者互动交流~

我们建了算法岗技术与面试交流群, 想要进交流群、需要源码&资料、提升技术的同学,可以直接加微信号:mlc2040。加的时候备注一下:研究方向 +学校/公司+CSDN,即可。然后就可以拉你进群了。

方式①、微信搜索公众号:机器学习社区,后台回复:加群
方式②、添加微信号:mlc2040,备注:技术交流

用通俗易懂方式讲解系列

  • 《大模型面试宝典》(2024版) 正式发布!
  • 《大模型实战宝典》(2024版)正式发布!
  • 2024年大模型面试准备(一):LLM主流结构和训练目标、构建流程
  • 2024年大模型面试准备(二):LLM容易被忽略的Tokenizer与Embedding
  • 2024年大模型面试准备(三):聊一聊大模型的幻觉问题

参考文献:

[1] Touvron H, Lavril T, Izacard G, et al. Llama: Open and efficient foundation language models[J]. arXiv preprint arXiv:2302.13971, 2023.
[2] Raffel C, Shazeer N, Roberts A, et al. Exploring the limits of transfer learning with a unified text-to-text transformer[J/OL]. Journal of Machine Learning Research, 2020, 21(140):1-67. http://jmlr.org/papers/v21/20-074.html.
[3] Press O, Smith N A, Lewis M. Train short, test long: Attention with linear biases enables input length extrapolation[J]. arXiv preprint arXiv:2108.12409, 2021.
[4] Sun Y, Dong L, Patra B, et al. A length-extrapolatable transformer[J]. arXiv preprint arXiv:2212.10554, 2022.
[5] Chen S, Wong S, Chen L, et al. Extending context window of large language models via positional interpolation[J]. arXiv preprint arXiv:2306.15595, 2023.

这篇关于2024年大模型面试准备(四):大模型面试必会的位置编码(绝对位置编码sinusoidal,旋转位置编码RoPE,以及相对位置编码ALiBi)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/850430

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费