如何增长LLM推理token,从直觉到数学

本文聚焦大模型输入token长度增长技术。先阐述增长token长度的意义及外推性问题,接着从直觉和数学角度探讨解决方法,介绍了transformer原理与位置编码,还分析了HFWA、NTK - RoPE等技术,旨在让模型在长上下文长度下更好外推,提升性能。

背景:

最近大模型输入上文长度增长技术点的研究很火。为何要增长token长度,为何大家如此热衷于增长输入token的长度呢?其实你如果是大模型比价频繁的使用者,这个问题应该不难回答。增长了输入token的长度,那需要多次出入才能得到最终解,得到多个结果需要自己拼接得到最好答案的问题,可以变成一把梭哈直接输出结果。因为上下文长度不够导致对话时候忘记前面讲什么问题、因为背景知识不够需要向量知识库补上下文数据问题、因为允许输入上下文限制导致只能生成代码片段不能生成项目代码,上面这些畏难而退都会因为可输入上下文的增长得到一定程度缓解。
是否可能训练时候短输入推理时候长输入呢?如果解决外推性可以在一定扩展长度范围内可行。外推性是指大模型在训练时和预测时的输入长度不一致,导致模型的泛化能力下降的问题。例如,如果一个模型在训练时只使用了 512 个 token 的文本,那么在预测时如果输入超过 512 个 token,模型可能无法正确处理。这就限制了大模型在处理长文本或多轮对话等任务时的效果。

直觉角度如何解:

1.模型抽局部特征+全局特征融合,局部特征抽取能力强,增加长度无非就是增加特征,全局特征融合能力强可以把增长特征较好融合
2.模型全局视野很宽,在训练时候只用了部分视野;实际推理时候可以把全部视野全用上,来达到比训练时token长能力
3.模型有超宽的分辨率范围,可以根据长度来调整分辨率范围,输入token变长可以自动调整模型分辨率让模型达到最优的视野关注力
4.token有规律,长度的增加信息特征是有简单章法可循(必须随着长度线性增长),那么token增长只需要做一次信息转换就解决信息偏差问题
5.token之间关联性较弱可以近似无关联,那么我们就可以分布的求每部分的信息,然后把每部分特征concat就好了

从数学角度看问题:

transformer原理简介

image.png
可以把transformer看成是对信息的特征抽取、匹配、赋权的一个过程。输入的embbeding信息经过query算子对信息压缩抽取特征把需要信息变成查询高纬语义(可理解为是对输入信息做了simihash或者lhs),输入embbeding信息经过key算子处理把信息做表征(相当于是把特征入库变成信息唯一key表示),赋权相当于是计算key和query之间特征相似权重。这其实就是一个信息检索过程建模,query算子、key算子、赋权算子全部是需要求解的参数,也就是说transformer相当于是对检索这个流程进行建模,而不是我们一般检索过程流程确定只是求解每个部件参数。所以transformer其实学习到的是如何对信息进行构建query、key表征、赋权;还有一个很巧妙的地方在于tranformer是self信息处理,这样就保证了学习过程可以无需人工标注一堆数据。但是为什么self自信息学习可以让transformer学习到信息query、表征、赋权这一套信息流程,能够外推到任何的信息处理流程。这里面其实有做一个假设:1.信息的近场效应 2.建模的是信息抽取过程,query、key、赋权算子是会经历任何数据,并且算子是有记忆型;所以学习是self自信息但是适用任何没见过信息和非对称输入信息处理。
上面表述估计还是不够清晰,但抓住重点就是transformer之所以能够行知有效,根本在于这个架构看似简单但其实是对信息处理过程建模。模型学习的是通用信息处理过程的流程步骤,把信息抽取的各模块参数、流程一并的建模了;求解过程就是对整个系统的调优求解。所以trnasformer看似简单但是威力巨大。

位置编码说起

但是信息往往是一个序列,也就是说在一段信息之间是有时空关系的。前一段的信息会对后一段的信息有影响,越靠近自己的信息可能对自己影响越大,离得越远的信息对自己影响越小。那么该如何用数学方法来表示这种特性呢,可以分两块来看:
1.如何在序列上表示重要性值,这个其实学过信号处理的同学应该都知道怎么做,无非就是三角函数、傅立叶函数生成波形就好
2.如何随着距离远近做重要性衰减,这学过信号处理的同学也很清楚怎么做,就是搞一个衰减载波函数和波函数相乘就行
序列上表示信号示例:
image.png

import matplotlib.pyplot as plt
import numpy as np

frequency = 1  # Frequency of the rectangular waveform
amplitude = 1  # Amplitude of the rectangular waveform
duty_cycle = 0.5  # Duty cycle of the rectangular waveform (50% for a symmetric waveform)

t = np.linspace(0, 1, 500)  # Time array
waveform =  amplitude *(np.sin(2 * np.pi * frequency * (-t)) + 
                        1/3 * np.sin(6 * np.pi * frequency * t) +
                        1/5 * np.sin(10 * np.pi * frequency * t)+
                        1/7 * np.sin(11 * np.pi * frequency * t)+
                        1/9 * np.sin(15 * np.pi * frequency * t)+
                        1/13 * np.sin(20 * np.pi * frequency * t))

plt.plot(t, waveform)
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.title('Rectangular Waveform Approximation')
plt.grid(True)
plt.show()

信号衰减函数示例:
image.png

import numpy as np
import matplotlib.pyplot as plt

# 生成时间序列
t = np.linspace(0, 10, 1000)

# 生成信号震荡衰减函数(例如,正弦函数衰减)
frequency = 3  # 频率
amplitude = 0.3 # 振幅
decay_rate = 0.6  # 衰减率
signal = amplitude  *(np.sin(2 * np.pi * frequency*t *np.log( decay_rate*t))+frequency)* np.exp( -decay_rate *t)

# 绘制图形
plt.figure(figsize=(10, 6))
plt.plot(t, signal, label='signal')
plt.xlabel('time')
plt.ylabel('amplitude')
plt.title('signal')
plt.legend()
plt.grid(True)
plt.show()

现在有了表示信息序列值的方法,接下来的事就是如何把这个信息和序列表示关联起来,让信息的表征具备序列特性而不是和序列无关的。最直接想到的方法就是把信息的向量表示矩阵和序列算子点乘就行了。然而transformer的实现时候有点违反直觉,他们选了位置embbeding和信息embbeding用concat方式来融合。位置embbeding他们选择了用三角函数Sinusoidal位置编码来实现。
image.png
KaTeX parse error: {equation} can be used only in display mode.
其中pk,2i,pk,2i+1分别是位置k的编码向量的第2i,2i+1个分量,d是位置向量的维度。
为什么transformer这么设计也能够起到考量信号序列差异的作用的,我们可以参考苏神这篇文章Transformer升级之路:1、Sinusoidal位置编码追根溯源 - 科学空间|Scientific Spaces来看。
把序列差异建模为以下数学描述:
输入:xm,xn分别表示第m,n个输入,不失一般性,设f是标量函数。像Transformer这样的纯Attention模型,它是全对称的,即对于任意的m,n都有
KaTeX parse error: {equation} can be used only in display mode.
这就是我们说Transformer无法识别位置的原因——全对称性,简单来说就是函数天然满足恒等式f(x,y)=f(y,x),以至于我们无法从结果上区分输入是[x,y]还是[y,x]。
要打破这种对称性,比如在每个位置上都加上一个不同的编码向量:
KaTeX parse error: {equation} can be used only in display mode.
只要每个位置的编码向量不同,那么这种全对称性就被打破了,即可以用f̃ 代替f来处理有序的输入。
只考虑m,n这两个位置上的位置编码,将它视为扰动项,泰勒展开到二阶:
KaTeX parse error: {equation} can be used only in display mode.
可以看到,第1项跟位置无关,第2到5项都只依赖于单一位置,所以它们是纯粹的绝对位置信息,第6项是第一个同时包含pm,pn的交互项,我们将它记为 p m ⊤ H p n \boldsymbol{p}_m^{\top} \boldsymbol{\mathcal{H}} \boldsymbol{p}_n pmHpn,希望它能表达一定的相对位置信息。
假设 H = I \boldsymbol{\mathcal{H}}=\boldsymbol{I} H=I是单位矩阵,此时 p m ⊤ H p n = p m ⊤ p n = ⟨ p m , p n ⟩ \boldsymbol{p}_m^{\top} \boldsymbol{\mathcal{H}} \boldsymbol{p}_n = \boldsymbol{p}_m^{\top} \boldsymbol{p}_n = \langle\boldsymbol{p}_m, \boldsymbol{p}_n\rangle pmHpn=pm

### LLM 自定义 Token 的实现方法及配置 在大型语言模型 (LLM) 开发过程中,自定义 token 是一种常见的需求,尤其是在特定领域或应用场景下需要扩展默认词表的情况。以下是关于如何在 LLM 中实现自定义 token 的详细说明。 #### 1. 扩展 Vocabulary 为了支持新的 token,通常需要扩展模型的 vocabulary。这可以通过修改 tokenizer 配置文件来完成。大多数预训练模型都提供了基于 SentencePiece 或 BPE 的分词器,这些工具允许动态调整词汇表大小。 ```python from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("path/to/model") new_tokens = ["<custom_token_1>", "<custom_token_2>"] num_added_toks = tokenizer.add_tokens(new_tokens) print(f"Added {num_added_toks} tokens.") model.resize_token_embeddings(len(tokenizer)) # 调整嵌入层尺寸以适应新增加的token[^1] ``` 上述代码片段展示了如何向现有的 tokenizer 添加新 token 并更新模型的 embedding 层维度。 #### 2. 数据准备与 Fine-tuning 当引入自定义 token 后,需重新整理训练数据并进行 fine-tune 来让模型学习到这些新 token 的语义表示。可以利用开源的数据集作为起点,比如 `alpaca_gpt4_data_zh.json` 提供了中文领域的高质量对话样本[^3]。 对于具体任务而言,可能还需要额外标注一些特殊标记以便于区分不同类型的输入序列: ```json { "instruction": "请解释一下这个概念。", "input": "<custom_token_1>", "output": "这是用户定义的一个专有名词..." } ``` 通过这种方式构造出适合当前项目的微调数据集合之后就可以启动训练流程了。 #### 3. 测试阶段验证效果 最后,在部署之前应该充分测试带有自定义 token 的交互过程是否正常工作以及生成质量是否有明显提升或者退化现象发生 。如果发现某些情况下表现不佳,则考虑进一步优化超参数设置或者是收集更多针对性强的相关实例来进行迭代改进。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值