1.2.llm_intro

LLM概述

PLM(pretrained language models),即bert等

LLM简史

LLM列表(持续更新中)

  • 百亿:除了LLaMA(最大650亿)和NLLB(最大545亿),大多数在100亿-200亿之间,通常需要数百甚至上千个GPU或TPU。

  • 千亿:OPT、OPT-IML、BLOOM和BLOOMZ与GPT-3(175B)大致相同,GLM有1300亿,Galactica有1200亿,通常需要数千个GPU或者TPU。

ckpt?模型发布时间大小预训练数据规模硬件训练时间

Y

2019.10

11B

1万亿tokens

1024 TPU v3

-

N

2020.05

175B

3000万亿tokens

-

-

N

2020.06

600B

1万亿tokens

2048 TPU v3

4天

Y

2020.10

13B

1万亿tokens

-

-

Y

2021.04

13B

1.1TB

2048 Ascend 910

-

Y

2021.06

198B

2.6TB

-

-

N

2021.07

12B

1000万亿tokens

-

-

N

2021.07

10B

3750亿tokens

384 v100

-

N

2021.08

178B

3000亿tokens

800 GPU

-

N

2021.09

82B

3000亿tokens

1024 A100

13.4天

N

2021.09

137B

-

128 TPU v3

60小时

N

2021.10

245B

1800亿tokens

2128 GPU

-

Y

2021.10

11B

-

512 TPU v3

27小时

N

2021.12

52B

4000亿tokens

-

-

N

2021.12

175B

-

-

-

N

2021.12

280B

3000亿tokens

4096 TPU v3

920小时

N

2021.12

260B

-

-

-

N

2021.12

1200B

2800亿tokens

1024 TPU v4

574小时

N

2022.01

137B

7680亿tokens

1024 TPU v3

57.5天

N

2022.01

530B

2700亿tokens

4480 80G A100

-

N

2022.02

41B

9670亿tokens

-

-

N

2022.03

175B

-

-

-

N

2022.03

70B

1.4万亿tokens

-

-

Y

2022.03

16B

5770亿tokens

-

-

Y

2022.04

20B

825GB

96 40G A100

-

Y

2022.04

11B

-

256 TPU v3

4小时

N

2022.04

540B

7800亿tokens

6144 TPU v4

-

Y

2022.05

20B

825GB

96 40G A100

-

Y

2022.05

175B

1800亿tokens

992 80G A100

-

Y

2022.07

54.5B

-

-

-

N

2022.08

20B

1.3万亿tokens

128 A100

120天

N

2022.09

70B

64 TPU v3

-

-

N

2022.09

10B

3000亿tokens

128 A100 40G

24天

N

2022.10

540B

-

512 TPU v4

5天

N

2022.10

540B

-

512 TPU v4

37小时

N

2022.10

540B

-

-

-

Y

2022.10

130B

4000亿tokens

768 40G A100

60天

Y

2022.10

11B

-

-

-

Y

2022.11

176B

3660亿tokens

384 80G A100

105天

Y

2022.11

13B

-

-

-

Y

2022.11

120B

1060亿tokens

-

-

Y

2022.11

176B

-

-

-

Y

2022.12

175B

-

128 40G A100

-

Y

2023.02

65B

1.4万亿tokens

2048 80G A100

21天

N

2023.03

-

-

-

-

Y

2022.09

13B

8500亿tokens

1536 Ascend 910

60天

N

2023.03

1085B

3290亿tokens

512 Ascend 910

100天

Y

2023.04

12B

3000亿tokens

256 40G A100

-

可以直接把对应的md丢给gpt,叫它导出一个excel,然后就可以自定义排序或者画散点图看了

LLM数据集

llm中文数据集:https://juejin.cn/post/7238921093553438779

  • Books:

    • BookCorpus:超过11000本电子书,用于GPT和GPT-2。

    • Gutenberg:超过70000本文学作品,包括小说、散文、诗歌、戏剧、历史、科学、哲学和其他公共领域,用于MT-NLG和LLaMA。

    • Books1和Books2:比BookCorpus大得多,但未公开,用于GPT-3。

  • CommonCrawl:最大的开源网络爬虫数据库之一,百万亿字节,有大量噪音和低质信息,需要过滤,有如下4个子集:

    • C4:包括en(806G,训练T5、LaMDA、Gopher、UL2)、en.noclean(6T)、realnewslike(36G)、webtextlike(17G)、multilingual(38T,训练mT5)。

    • CC-Stories:31G,内容以故事的形式展示

    • CC-News:76G

    • RealNews:120G

  • Reddit Links:Reddit上的帖子,高赞通常比较有用,可以拿来创建高质量数据集。

    • WebText:由Reddit上的高赞链接组成,未公开,对应的开源版是OpenWebText

    • Pushshift.io:实时更新的数据集,包括Reddit自创建以来的历史数据,有数据存储,也有实用工具,供用户搜索、总结和统计分析。

  • Wikipedia:大部分文章使用写作风格,并支持引用,英语版本用于大多数LLM,如GPT-3、LaMDA、LLaMA,还有多语言版。

  • Code:包括开源许可证的公共代码库(如github)和与代码相关的问答平台(如StackOverflow),Google公开了BigQuery数据集,CodeGen用的BIGQUERY是其的一个子集。

  • 其他:

    • The Pile有800G,包括书籍、网站、代码、科学论文和社交媒体平台,有22个子集,用于GPT-J(6B)、CodeGen(16B)、Megatron-Turing NLG(530B)。

    • ROOTS由各种小数据集组成,共1.6T,包括59种语言(自然语言和编程语言),用于BLOOM。

LLM开源库

一些开源的小模型:从零训练的 1B 以下小模型汇总

一些综述

大模型面试八股

大模型八股答案(一)——基础知识

大模型八股答案(二)——训练框架

扩展法则(scaling law)

openai的扩展法则

2020年,openai的Scaling laws for neural language models通过拟合模型在不同数据大小(2000w到230亿个token)、不同的模型大小(7.68亿到15亿个非嵌入参数)的性能,提出了在计算预算cc的条件下,LL是用nats表示的交叉熵损失,模型性能与模型规模NN数据集规模DD以及训练计算量CC间存在如下幂律关系:

L(N)=(NcN)αN,αN0.076,Nc8.8×1013L(N)=(\frac{N_c}{N})^{\alpha _N}, {\alpha}_N\sim 0.076,N_c\sim 8.8\times 10^{13}

L(D)=(DcD)αD,αD0.05,Nc5.4×1013L(D)=(\frac{D_c}{D})^{\alpha _D}, {\alpha}_D\sim 0.05,N_c\sim 5.4\times 10^{13}

L(C)=(CcC)αC,αC0.05,Cc3.1×108L(C)=(\frac{C_c}{C})^{\alpha _C}, {\alpha}_C\sim 0.05,C_c\sim 3.1\times 10^{8}

其中,NcN_c表示非嵌入参数数量,DcD_c表示训练token数量,CcC_c表示FP-days。

Go Wider Instead of Deeper说了,transformer效果的提升不在于计算量的变大,而应该在于通过提升模型的hidden dim来增加模型参数量

Chinchilla扩展法则

DeepMind在Training compute-optimal large language models中提出了Chichilla扩展法则来指导LLM最优计算量的训练。通过变化更大范围的模型大小(7000w到160亿参数)和数据大小(50亿到5000亿个token)进行实验,拟合了如下的扩展法则:

L(N,D)=E+ANα+BDβL(N, D)=E+\frac{A}{N^\alpha}+\frac{B}{D^\beta}

其中E=1.69,A=406.4,B=410.7,α=0.34,β=0.28E=1.69,A=406.4,B=410.7,\alpha = 0.34, \beta =0.28,通过在约束条件C6NDC\approx 6ND下优化损失L(N,D)L(N,D),将计算预算最优地分配给模型大小和数据大小的方法:

Nopt(C)=G(C6)a,Dopt(C)=G1(C6)bN_{o p t}(C)=G\left(\frac{C}{6}\right)^a, \quad D_{o p t}(C)=G^{-1}\left(\frac{C}{6}\right)^b

其中a=αα+βa=\frac{\alpha}{\alpha+\beta}b=βα+βb=\frac{\beta}{\alpha+\beta}GG是由A,B,α,βA,B,\alpha,\beta计算出的扩展系数。

随着计算预算的增加,

  • openai的扩展法则更偏向于将更大预算分给模型大小,因为其对比各模型时使用了固定的训练数据量和学习率等超参,低估了数据量的作用。每增加10倍的计算量,应该让数据集大小增加为约1.8倍,模型参数量增加为约5.5倍。即模型参数量更加的重要

  • Chinchilla扩展法则认为模型大小和数据大小要同比例增加,即aabb取值差不多。因为其在无视模型大小的前提下,发现设置与数据量差不多match的学习率能获得更好的loss。每增加10倍的计算量,应该让数据集大小增加为约3.16倍,模型参数量也增加为约3.16倍。即数据集大小和模型参数量一样重要

然而,有一些能力(如涌现)无法根据扩展法则进行预测,只有当模型达到一定规模时才会出现。

飘红的就是常见的10B模型,大概要205B的token来训练,能达到计算最优点,当然并不一定是loss最小的点,这个可以参考llama3的现象

scaling law的一些讨论

Scaling Laws 又失灵了?谷歌新研究:扩散模型不是越大越好

Bigger is not Always Better: Scaling Properties of Latent Diffusion Models

腾讯混元、北大发现Scaling law「浪涌现象」,解决学习率调参难题

Surge Phenomenon in Optimal Learning Rate and Batch Size Scaling

SIGIR24最佳论文:Scaling Laws For Dense Retrieval

中科大联合华为诺亚提出Entropy Law,揭秘大模型性能、数据压缩率以及训练损失关系

词表的scaling law

NeurIPS 2024 | 大模型的词表大小,同样适用于Scaling Law

Scaling Laws with Vocabulary: Larger Models Deserve Larger Vocabularies

https://github.com/sail-sg/scaling-with-vocab/

scaling law for precision

Scaling Laws终结,量化无用,AI大佬都在审视这篇论文

Scaling Laws for Precision

你训练的 token 越多,你需要的精度就越高。

涌现能力

涌现能力:在小型模型中不存在而在大型模型中产生的能力,当规模达到一定程度时,性能显著提升,超出随机水平(参考 Emergent Abilities of Large Language Models)。与物理学中的相变现象类似(物质从一种相(状态)转变为另一种相的过程,通常伴随着能量的吸收或释放,并且涉及不同的物理性质,例如固体、液体和气体之间的转变)。

普林斯顿DeepMind用数学证明:LLM不是随机鹦鹉!「规模越大能力越强」有理论根据

A Theory for Emergence of Complex Skills in Language Models

LLM的3种典型涌现能力及其对应代表模型:

上下文学习(in-context learning)

GPT-3(Language models are few-shot learners)提出,只要提供一个自然语言指令和/或几个任务演示,语言模型就能通过完成输入文本的词序列的方式来为测试实例生成预期输出,不用额外的梯度更新。

  • ICL能力小模型不具备:1750亿的GPT-3有ICL能力,但GPT-1和GPT-2无此能力。

  • ICL能力取决于具体下游任务:130亿的GPT-3能在算术任务上有ICL,但1750亿的GPT-3在波斯语QA上无能为力。

指令遵循(instruction following)

使用自然语言描述的混合多任务数据集进行微调(指令微调),LLM在未见过的以指令形式描述的任务上表现出色,具有更好的泛化能力。例如Multitask prompted training enables zero-shot task generalizationTraining language models to follow instructions with human feedbackFinetuned language models are zero-shot learners

Finetuned language models are zero-shot learners的实验中,当模型大小达到680亿时,经过指定微调的LaMDA-PT开始在未见过的任务上显著优于未微调的模型,而80亿或更小的模型则没有这个现象。

Scaling instruction-finetuned language models的实验中,PaLM至少在620亿参数上才能在4个评估基准的各种任务上表现良好。

精准0误差,输入价格打骨折!OpenAI官宣API支持结构化输出,JSON准确率100%

逐步推理(multi-step reasoning)

对于涉及多个推理步骤的复杂任务(如数学),可以使用思维链(Chain-of-Thought, CoT)提示策略(Chain of thought prompting elicits reasoning in large language models),让LLM通过利用中间推理步骤的提示机制来解决这类任务。

Chain of thought prompting elicits reasoning in large language models发现,CoT在模型大于600亿的PaLM和LaMBDA变体中能够提升在算术推理基准任务的效果,而当模型大于1000亿时,相比标准提示的优势更明显。

How does GPT Obtain its Ability? Tracing Emergent Abilities of Language Models to their Sources

LLM关键点

如何让LLM能够通用有能力

扩展

更大的模型、数据规模和更多的训练计算,但计算预算是有限的,可以用扩展法更高效地分配计算资源,如Chinchilla在相同计算预算下增加训练token数,优于更大模型规模的Gopher,同时需要数据清理。

训练

能力引导

当LLM执行某些特定任务时,可能不会显式地展示出其通用求解器的能力,设计合适的任务指令或具体的ICL策略可以激发这种能力,例如

  • 通过包含中间推理步骤的CoT提示

  • 使用自然语言表达的任务描述,对LLM进行指令微调

对齐微调

由于预训练语料库包括高质量和低质量的数据,LLM可能生成有毒、偏见甚至有害的内容,要让LLM和人类价值观保持一致,如有用性、诚实性和无害性。RLHF相关工作如Training language models to follow instructions with human feedbackDeep reinforcement learning from human preferences能够产生高质量、无害的回答(例如拒绝回答侮辱性问题)。

工具操作

LLM本质是基于海量文本语料库进行文本生成训练的,对于不适合以文本形式表达的任务表现不佳(如数字计算),且其能力受限于预训练数据,无法获取最新信息。可以利用外部工具:

数据收集

数据获取

  • 通用文本数据:

    • 网页:例如CommonCrawl,同时需要过滤和处理以提高质量

    • 对话文本:公共对话数据如PushShift.io,对于在线社交媒体的对话数据,可以转换成树形结构,每句话与回应其的话相连。多方的对话树可以划分为预训练语料库中的多个子对话。过度引入对话数据可能会有潜在风险(OPT: open pre-trained transformer language models):陈述性指令和直接疑问句被错误地认为是对话的开始,导致指令的有效性下降。

    • 书籍:更正式的长文本,利于学习语言知识建模长期依赖关系生成叙述性和连贯的文本

  • 专用文本数据:

    • 多语言文本:BLOOM的预训练语料中包括了46种语言,PaLM包含了122种

    • 科学文本:如arxiv论文、科学教材、数学 网页等,通常需要特定的标记化和预处理。

    • 代码:一是编程问答社区,二是开源代码仅为。对应长距离依赖和准确的执行逻辑,可能是复杂推理能力的来源。将推理任务格式化为代码形式还能帮LLM生成更准确的结果(如Language models of code are few-shot commonsense learnersAutoformalization with large language models

数据预处理

  • 质量过滤:有一些基于分类器的方法,例如维基百科的数据为正样本,负采样其他数据训练二分类器,但这种方法会删除方言、口语和社会语言的高质量文本,可能导致有偏、减少多样性。还有启发式的方法,主要包括:

    • 基于语言的过滤:如果该llm主要用于某种语言,可以把其他语言删了

    • 基于度量的过滤:利用生成文本的评估度量(如perplexity)来检测和删除不自然的句子

    • 基于统计的过滤:如标点符号分布符号和单词比例句子长度

    • 基于关键词的过滤:删除噪声或无用元素,如HTML标签超链接模板攻击性词语等。

  • 去重:Scaling laws and interpretability of learning from repeated data中发现重复数据会降低多样性,可能导致训练不稳定。下面3个级的去重都很有用

    • 句子级:删掉包含重复单词和短语的句子,因为可能在语言建模中引入重复模式The curious case of neural text degeneration)(后面的章节会讲)

    • 文档级:通过文档间的表层特征(如n-gram或单词重合率)来删掉重复文档

    • 数据集级:训练集中删掉测试集可能出现的重复文本,防止训练集和评估集间的重叠

  • 隐私去除:删掉可识别个人信息(PII),如基于关键词(姓名、地址、电话号码)识别。另外,Deduplicating Training Data Mitigates Privacy Risks in Language Models发现LLM在隐私攻击下的脆弱性可能归因于预训练语料中存在重复PII数据

  • 分词:可以直接利用已有分词器,也可以使用专门为预训练语料库设计的分词器,如SentencePiece,而且BPE(byte pair encoding)能确保分词后的信息不会丢失,但其中的如NFKC(Unicode normalization forms)的归一化技术可能会降低分词的性能

预训练语料的重要性

  • 混合来源:不同领域和场景的数据能让LLM有更强大的泛化能力。需要仔细设置数据分布,Gopher对数据分布消融,发现增加书籍数据可以提升捕捉长期依赖的能力,增加c4数据集比例可以提升其在c4验证集上的效果,但单独训练过多的某个领域数据会影响LLM在其他领域的泛化能力。

  • 数据量:模型性能方面,数据大小也能看到与模型大小类似的扩展法则。LLaMA发现,用更多数据训练更长时间,较小的模型也能实现良好性能。

  • 数据质量:Gopher、GLaM和T5都发现,在清理后的数据上训练能提升llm效果。数据的重复可能导致『双下降现象』(Scaling laws and interpretability of learning from repeated dataDeep double descent: Where bigger models and more data hurt),甚至会导致训练不稳定。此外,Scaling laws and interpretability of learning from repeated data还发现,重复数据会降低LLM从上下文复制的能力,从而影响ICL中的泛化能力

注:双下降指的是随着模型复杂性的增加,可能loss先下降,然后再升高,最后又下降

  • 当模型的复杂性低于数据的复杂性时,增加模型的复杂性可以帮助减少训练误差。

  • 当模型的复杂性超过数据的复杂性时,增加模型的复杂性反而可能导致训练误差增加。这是因为模型开始过拟合数据,捕获数据中的噪声而非实际的模式。

  • 当模型的复杂性远大于数据的复杂性时,训练误差可能再次开始减少。这是因为模型有足够的能力来对数据的噪声进行平滑,同时仍然能够捕获数据的实际模式。

LLM模型架构

MoE原理

MoE模型的前世今生

MoE 系列论文解读:Gshard、FastMoE、Tutel、MegaBlocks 等

CMU开源GRIFFIN:一种新颖的无需训练的MoE方法,提高大模型的生成效率!

Prompt-prompted Mixture of Experts for Efficient LLM Generation

From Sparse to Soft Mixtures of Experts: softmoe

MoE的核心问题是一个如何把token分配给哪个专家离散优化问题,有如下离散+稀疏的分配方法,都需要辅助loss平衡每个专家的负载,以减少drop tokens:

  • 线性规划

  • 强化学习

  • 人为固定规则

  • 最优运输方法

  • 贪心topk token-choose-expert

  • 贪心topk expert-choose-token

在softmoe中,假设N个token,S个slot,E个expert

代码:

https://github.com/google-research/vmoe/blob/main/vmoe/projects/soft_moe/router.py#L97https://github.com/google-research/vmoe/blob/main/vmoe/moe.py#L128

算法、系统和应用,三个视角全面读懂混合专家(MoE)

A Survey on Mixture of Experts

从ACL 2024录用论文看混合专家模型(MoE)最新研究进展

DeepSeekMOE

DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models

https://github.com/deepseek-ai/DeepSeek-MoE

动机:

  • 专家不够分化:以往的MoE模型专家数量很少,假如模型的知识涉及的领域很多,平均一个专家要包含很多领域的知识,即不够

  • 专家有冗余:假设每个token只能选一个专家,又假设每个token都需要常识知识,结果就是不论选哪个专家,这个专家的参数里都有常识知识,因此有冗余了——最好的情况是有个专家专门负责提供常识知识,所有 token 都会用一下这个专家。

解法:

  • 增加专家数量:专家是个FFN,假设两个矩阵是dhdhhdhd,如果将它拆成2个专家,就是拆成2个dh/2dh/2h/2dh/2*d,假设原来一个token选top-1专家,现在就是选top-2专家,拆前拆后的计算量和参数量没变,好处就是排列组合多样性更多了,选择也更灵活了。

  • 增设共享专家:有的专家是必选的,除此以外,每个token按照自己的喜好,再来选top-k。比如有64个专家,那么第一个专家是所有token都要选的,除此以外,每个token还从剩下的63个里选择自己的top-1,其实就是top-2。

Dynamic MoE

Harder Tasks Need More Experts: Dynamic Routing in MoE Models

https://github.com/ZhenweiAn/Dynamic_MoE

XMoE

是上面两种方法的并集

XMoE: Sparse Models with Fine-grained and Adaptive Expert Selection

https://github.com/ysngki/XMoE

HyperMoE

HyperMoE: Towards Better Mixture of Experts via Transferring Among Experts

https://github.com/Bumble666/Hyper_MoE

Expert Pruning

Not All Experts are Equal: Efficient Expert Pruning and Skipping for Mixture-of-Experts Large Language Models

https://github.com/Lucky-Lance/Expert_Sparsity

MixLoRA

Multimodal Instruction Tuning with Conditional Mixture of LoRA

ESFT

Let the Expert Stick to His Last: Expert-Specialized Fine-Tuning for Sparse Architectural Large Language Models

多模态MoE

混合专家更有主见了,能感知多模态分情况行事,Meta提出模态感知型专家混合

Chameleon: Mixed-modal early-fusion foundation models单一Transformer架构,可以根据下一个token的预测目标,对由离散图像和文本token组成的混合模态序列进行建模,从而在不同模态之间进行无缝推理和生成。然而对于Chameleon这样各种模态会在模型训练的早期混合起来的模型,想要拓展它的能力,需要投入大量算力。

MoMa: Efficient Early-Fusion Pre-training with Mixture of Modality-Aware Experts使用路由式稀疏架构(routed sparse architecture)

HMOE

(toread)

优化传统MoE结构,腾讯混元团队提出专家差异化新思路

HMoE: Heterogeneous Mixture of Experts for Language Modeling

在 HMoE 中,每个专家的大小不再相同,从而赋予了每个专家不同的表达能力。这种差异化设计使得路由可以根据专家的实际能力动态分配不同难度的 token,有效解决了专家专业化程度不足的问题。

OLMoE

(toread)

OLMoE: Open Mixture-of-Experts Language Models

https://huggingface.co/allenai/OLMoE-1B-7B-0924

https://github.com/allenai/OLMoE

元象MOE

中国最大开源MoE模型,255B参数无条件免费商用,元象发布

XVERSE-MoE-A36B,该模型总参数255B,激活参数36B,达到100B模型性能的「跨级」跃升。

https://github.com/xverse-ai/XVERSE-MoE-A36B

MoEUT

Jurgen、曼宁等大佬新作:MoE重塑6年前的Universal Transformer,高效升级

MoEUT: Mixture-of-Experts Universal Transformers

https://github.com/robertcsordas/moeut

MoA

无问芯穹提出混合稀疏注意力方案MoA,加速长文本生成,实现最高8倍吞吐率提升

https://github.com/thu-nics/MoA

MoA: Mixture of Sparse Attention for Automatic Large Language Model Compression

GRIN

专家模型不要专家并行!微软开源MoE新路径

GRIN: GRadient-INformed MoE

主流框架

  • 编码器-解码器架构(encoder-decoder):标准Transformer,如T5、BART,只有少数LLLM还用这种结构,如Flan-T5

  • 因果解码器架构(causual decoder):也叫decoder-only单向注意力掩码,输入和输出token通过解码器以相同方式进行处理,以GPT系列为代表,现有大部分LLM都是这种架构,如OPT、BLOOM、Gopher等。

  • 前缀解码器架构(prefix decoder):修正因果解码器的掩码机制,使其能对前缀token执行双向注意力,并且仅对生成的token执行单向注意力(和encoder-decoder类似),即Unified language model pre-training for natural language understanding and generation提出的uni-lm。What language model architecture and pretraining objective works best for zero-shot generalization?建议不从头开始预训练,而是继续训练因果编码器,然后将其转换成前缀编码器以加速收敛。例如U-PaLM从PaLM演化而来,还有GLM-130B也是这种架构。

https://github.com/microsoft/unilm

对于这3种架构,都可以用MoE进行扩展,每个输入的一小部分神经网络权重稀疏激活,如Switch Transformer和GLaM。Unified scaling laws for routed language models发现,通过增加专家数量或总参数大小,性能会有显著改进。

讨论:为什么现在的LLM都是Decoder only的架构?

https://www.zhihu.com/question/588325646/answer/2940298964

盛名一时的BERT哪去了?这个问题的答案昭示了LLM范式的转变

What happened to BERT & T5? On Transformer Encoders, PrefixLM and Denoising Objectives

去噪目标

去噪目标指的是span corruption任务的任意变体,即填充(infilling)或填空(fill in the blank)。表达方式有很多,比如span长度、随机性、sentinel token等。

  • BERT类的模型中,大部分是in-place的去噪目标,例如对mask tokens的分类head,

  • T5的做法则是通过encoder-decoder或decoder-only模型来处理数据变换,即把masked token move to the back给模型预测。

去噪目标的效果很好,可以作为常规语言建模的补充目标,但不足以单独作为目标,因为去噪有两个缺点:

  • 更少的loss exposure:在去噪目标中,只有少量token会被mask和学习,而常规语言建模则接近100%,使得每个FLOP的样本效率非常低

  • 比常规语言建模更不自然:以一种奇怪的方式重新设定输入输出格式,不太适合少样本学习

PrefixLM vs decoder-only

注:归纳偏置(inductive bias)指模型在预测未遇到的输入时,做的一些假设的集合,例如最小描述长度(奥卡姆剃刀)指的就是当构成一个假设时,试图去最小化其假设的描述长度。假设越简单,越可能为真的。

对语言模型来说,双向注意力是一种有趣的归纳偏置,相比于较小规模的场景,双向注意力在规模较大时可能就没那么重要了,或者可能对不同的任务或模态有不同的影响,例如PaliGemma就用的prefixLM(PaliGemma: A versatile 3B VLM for transfer

PrefixLM也存在缓存问题,是这类架构的一个固有缺陷

encoder-decoder的优缺点

  • 相比decoder-only的优势:endocer不受causal的限制,可以激进地试各种pooling/linear attention,因此可以offload一些不那么重要的context到encoder中,也可以让encoder更小,例如Charformer

  • 相比prefixLM的缺点:输入和目标必须分配固定的预算,例如输入预算是1024token,那么encoder就必须pad到1024,而这可能会浪费大量计算。相反,在 PrefixLM 中,输入和目标可以直接concat起来,从而可以缓解这个问题

组件配置

标准化(norm)

LN(layer norm)能缓解LLM训练不稳定的问题,其位置很重要。

此外,在emb后直接加额外的LN能提升训练稳定性,但会导致显著的性能下降(What language model to train if you have one million GPU hours?),在后来的LLM中被移除BLOOM: A 176b-parameter open-access multilingual language model)。

神经网络可能不再需要激活函数?Layer Normalization也具有非线性表达!

On the Nonlinearity of Layer Normalization

激活函数

FFN中的激活函数:

原始Transformer中

FFN(x,W1,W2,b1,b2)=max(0,xW1+b1)W2+b2\operatorname{FFN}\left(x, W_1, W_2, b_1, b_2\right)=\max \left(0, x W_1+b_1\right) W_2+b_2

T5中把bias干掉了

FFNReLU(x,W1,W2)=max(xW1,0)W2\operatorname{FFN}_{\operatorname{ReLU}}\left(x, W_1, W_2\right)=\max \left(x W_1, 0\right) W_2

然后,$\operatorname{GELU}(x)=x \Phi(x)$,同时$\operatorname{Swish}_\beta(x)=x \sigma(\beta x)$,接下来

GLU(x,W,V,b,c)=σ(xW+b)(xV+c)\operatorname{GLU}(x, W, V, b, c)=\sigma(x W+b) \otimes(x V+c) Bilinear(x,W,V,b,c)=(xW+b)(xV+c)\operatorname{Bilinear}(x, W, V, b, c)=(x W+b) \otimes(x V+c) ReGLU(x,W,V,b,c)=max(0,xW+b)(xV+c)\operatorname{ReGLU}(x, W, V, b, c)=\max (0, x W+b) \otimes(x V+c) GEGLU(x,W,V,b,c)=GELU(xW+b)(xV+c)\operatorname{GEGLU}(x, W, V, b, c)=\operatorname{GELU}(x W+b) \otimes(x V+c) SwiGLU(x,W,V,b,c,β)=Swishβ(xW+b)(xV+c)\operatorname{SwiGLU}(x, W, V, b, c, \beta)=\operatorname{Swish}_\beta(x W+b) \otimes(x V+c)

对应起来就是

FFNGLU(x,W,V,W2)=(σ(xW)xV)W2\operatorname{FFN}_{\mathrm{GLU}}\left(x, W, V, W_2\right)=(\sigma(x W) \otimes x V) W_2 FFNBilinear (x,W,V,W2)=(xWxV)W2\operatorname{FFN}_{\text {Bilinear }}\left(x, W, V, W_2\right)=(x W \otimes x V) W_2 FFNReGLU(x,W,V,W2)=(max(0,xW)xV)W2\operatorname{FFN}_{\operatorname{ReGLU}}\left(x, W, V, W_2\right)=(\max (0, x W) \otimes x V) W_2 FFNGEGLU (x,W,V,W2)=(GELU(xW)xV)W2\operatorname{FFN}_{\text {GEGLU }}\left(x, W, V, W_2\right)=(\operatorname{GELU}(x W) \otimes x V) W_2 FFNSwiGLU (x,W,V,W2)=(Swish1(xW)xV)W2\operatorname{FFN}_{\text {SwiGLU }}\left(x, W, V, W_2\right)=\left(\operatorname{Swish}_1(x W) \otimes x V\right) W_2

位置编码

Transformer的self-attention有转换不变性,故要位置编码以引入绝对或相对位置信息来建模序列。

Transformer升级之路:RoPE的底数设计原则

Base of RoPE Bounds Context Length

Decoder-only的LLM为什么需要位置编码?

HuggingFace工程师亲授:如何在Transformer中实现最好的位置编码

(toread)

注意力机制和Bias

小结

归一化位置

sublayer表示FFN或self-attention模块

方法公式

post Norm

Norm(x+Sulayerb(x))\operatorname{Norm}(\mathbf{x}+\operatorname{Sulayerb}(\mathbf{x}))

pre Norm

x+Sublayer(Norm(x))\mathbf{x}+\operatorname{Sublayer}(\operatorname{Norm}(\mathbf{x}))

Sandwich Norm

x+Norm(Sublayer(Norm(x)))\mathbf{x}+\operatorname{Norm}(\operatorname{Sublayer}(\operatorname{Norm}(\mathbf{x})))

归一化方法

方法公式

Layer Norm

xμσγ+β,μ=1di=1dxi,σ=1di=1d(xiμ)2\frac{\mathrm{x}-\mu}{\sqrt{\sigma}} \cdot \gamma+\beta, \quad \mu=\frac{1}{d} \sum_{i=1}^d x_i, \quad \sigma=\sqrt{\frac{1}{d} \sum_{i=1}^d(x_i-\mu)^2}

RMSNorm

xRMS(x)γ,RMS(x)=1di=1dxi2\frac{\mathrm{x}}{\operatorname{RMS}(\mathrm{x})} \cdot \gamma, \quad \operatorname{RMS}(\mathbf{x})=\sqrt{\frac{1}{d} \sum_{i=1}^d x_i^2}

Deep Norm

LayerNorm(αx+Sublayer(x))LayerNorm (\alpha \cdot \mathbf{x}+\operatorname{Sublayer}(\mathbf{x}))

激活函数

方法公式

ReLU

ReLU(x)=max(x,0)\operatorname{ReLU}(\mathbf{x})=\max (\mathbf{x}, \mathbf{0})

GeLU

GeLU(x)=0.5x[1+erf(x/2)],erf(x)=2π0xet2dt\operatorname{GeLU}(\mathbf{x})=0.5 \mathrm{x} \otimes[1+\operatorname{erf}(\mathbf{x} / \sqrt{2})], \quad \operatorname{erf}(x)=\frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} d t

Swish

Swish(x)=xsigmoid(x)\operatorname{Swish}(\mathbf{x})=\mathbf{x} \otimes \operatorname{sigmoid}(\mathbf{x})

SwiGLU

SwiGLU(x1,x2)=Swish(x1)x2\operatorname{SwiGLU}\left(\mathbf{x}_1, \mathbf{x}_2\right)=\operatorname{Swish}\left(\mathbf{x}_1\right) \otimes \mathbf{x}_2

GeGLU

GeGLU(x1,x2)=GeLU(x1)x2\operatorname{GeGLU}\left(\mathbf{x}_1, \mathbf{x}_2\right)=\operatorname{GeLU}\left(\mathbf{x}_1\right) \otimes \mathbf{x}_2

位置嵌入

  • AijA_{ij}q和k之间注意力分数

  • rijr_{i-j}:基于q和k之间偏移的可学习标量

  • Rθ,ij\mathbf{R}_{\theta, i-j}:旋转角度为tθt\cdot \theta的旋转矩阵

方法公式

绝对位置编码

xi=xi+pi\mathbf{x}_i=\mathbf{x}_i+\mathbf{p}_i

相对位置编码

Aij=WqxixjTWkT+rijA_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{x}_j^T \mathbf{W}_k^T+r_{i-j}

RoPE

Aij=WqxiRθ,ijxjTWkTA_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{R}_{\theta, i-j} \mathbf{x}_j^T \mathbf{W}_k^T

Alibi

Aij=WqxiRθ,ijxjTWkTAij=WqxixjTWkTm(ij)A_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{R}_{\theta, i-j} \mathbf{x}_j^T \mathbf{W}_k^T A_{i j}=\mathbf{W}_q \mathbf{x}_i \mathbf{x}_j^T \mathbf{W}_k^T-m(i-j)

预训练任务

语言建模

语言建模是仅解码器LLM的常见目标,给定token序列x={x1,,xn}\mathbf{x}=\left\{x_1, \ldots, x_n\right\},旨在基于序列中前面的token,自回归地预估目标token:

LLM(x)=i=1nlogP(xix<i)\mathcal{L}_{L M}(\mathbf{x})=\sum_{i=1}^n \log P\left(x_i \mid x_{<i}\right)

对应到代码里:

hidden_states = outputs[0]
logits = self.lm_head(hidden_states)

# gemma系列模型会做soft-cap
cap = self.config.logits_soft_cap
logits = nn.functional.tanh(logits / cap) * cap

logits = logits.float()
loss = None
if labels is not None:
    # Shift so that tokens < n predict n
    ## 假设句子长度为4,词表有3个词,
    ## logits: [ [0.1, 0.2, 0.7], [0.3, 0.4, 0.3], [0.5, 0.2, 0.3], [0.6, 0.1, 0.3] ]
    ## labels: [0, 2, 1, 0]
    ## shift_logits: [ [0.1, 0.2, 0.7], [0.3, 0.4, 0.3], [0.5, 0.2, 0.3]
    shift_logits = logits[..., :-1, :].contiguous()
    ## shift_labels: [2, 1, 0]
    shift_labels = labels[..., 1:].contiguous()
    # Flatten the tokens
    loss_fct = CrossEntropyLoss()
    # [bs, seq_len - 1, vocab_size] 变为 [(bs * (seq_len - 1)), vocab_size]
    shift_logits = shift_logits.view(-1, self.config.vocab_size)
    # [bs, seq_len - 1] 变为 [(bs * (seq_len - 1))]
    shift_labels = shift_labels.view(-1)
    # Enable model parallelism
    shift_labels = shift_labels.to(shift_logits.device)
    loss = loss_fct(shift_logits, shift_labels)

前缀解码器架构使用的是前缀语言建模任务,其loss不涉及对前缀内token的预测,故预训练时涉及的序列中token较少,故当预训练token数相同时,前缀语言模型的性能往往略低于传统语言模型任务。

另外,自回归的loss:

  • 训练时:是可以并行的,因为每个位置的label是已知的,可以并行算,

  • 预测时:是串行的,因为得预测完了第t个词,才能去预测第t+1个词。

去噪自编码

DAE是BERT待模型的常见任务,即MLM(masked language model),输入x\x~\mathbf{x}_{\backslash \tilde{\mathbf{x}}}是一些有随机替换区间的损坏文本,目标是恢复被替换的token x~\tilde{\mathbf{x}}

LDAE(x)=logP(x~x\x~)\mathcal{L}_{D A E}(\mathbf{x})=\log P\left(\tilde{\mathbf{x}} \mid \mathbf{x}_{\backslash \tilde{\mathbf{x}}}\right)

在T5和GLM-130B中使用,自回归地恢复替换区间

其他任务

multi-token prediction,一次预估未来的k个词

Better & Faster Large Language Models via Multi-token Prediction

新的模型结构

长上下文的问题

长序列(Long Context)大模型笔记

LLM长上下文的问题

以中文为例,大部分模型每个token对应的中文字数都>1.5个字,所以200k的token就对应30w字的上下文

对长文本的几个要求:

  • 在文本比较长的时候,还能保证通顺,ppl要足够低

  • 能attention到前面提过的细节,不能自我矛盾

注意:如果训练时是2k长度的语料,而推理设定8k窗口,那么PPL会急剧上升,因为

  • RoPE不能很好地处理没有训练过的位置编码

  • 推理时注意力机制所处理的token数量远超训练时的数量,导致注意力机制的崩坏

两阶段训练方式

  • 直接输入连续长文本(如书籍)

  • 多个中等文本拼接,再通过attention mask来限制各段文本之间注意力,让它们可以在各自的位置上各训各的,互不干扰。甚至实际上即使不做attention mask,效果也挺好。

如果简单地增加长度,例如从4k变到32k,长度增加8倍,为了加速计算需要缓存中间结果(如QK的结果是s2s^2的空间复杂度),所以显存会扩大82=648^2=64倍。一般的做法是2阶段:

  • 第一阶段:用2k或者4k训练一个基础模型,让模型学好文本内容短位置关系

  • 第二阶段:用比第一阶段小的数据量优化模型在长上下文的效果,具体做法见下节

针对位置编码的插值类方法

线性插值

Extending Context Window of Large Language Models via Positional Interpolation

NTK-Aware Interpolation

NTK-by-parts

Dynamically NTK Scaled RoPE

针对attention score的缩放方法

YaRN

logn

lossless long context

专访月之暗面杨植麟:lossless long context is everything

外推问题

语言模型窗口外推技术综述

longRoPE

LongRoPE:超越极限,将大模型上下文窗口扩展超过200万tokens

CoPE

解决Transformer根本缺陷,CoPE论文爆火:所有大模型都能获得巨大改进

Contextual Position Encoding: Learning to Count What’s Important

DAPE

NeurIPS 2024 | Transformer长度外推,全新位置编码DAPE大幅提升模型性能

DAPE: Data-Adaptive Positional Encoding for Length Extrapolation

https://github.com/chuanyang-Zheng/DAPE

retrieval head

Retrieval Head Mechanistically Explains Long-Context Factuality

SSM

挑战Transformer的Mamba是什么来头?作者博士论文理清SSM进化路径

Pretraining Without Attention

预训练无需注意力,扩展到4096个token不成问题,与BERT相当

Diffusion Models Without Attention

丢掉注意力的扩散模型:Mamba带火的SSM被苹果、康奈尔盯上了

一文看懂Mamba,Transformer最强竞争者

Long Range Language Modeling via Gated State Spaces 认为 Transformer 和 SSM 完全可以互补。

选择性状态空间模型(selective state space model)是Mamba论文作者Albert Gu此前主导研发的S4架构(Structured State Spaces for Sequence Modeling)的一个简单泛化。

https://stacks.stanford.edu/file/druid:mb976vf9362/gu_dissertation-augmented.pdf

序列模型在训练和推理时的侧重点:

  • 训练时:在整个list上计算loss,需要优化forward的耗时

  • 推理时:一次输入一个时间步,需要高效地顺序处理

SSM原理

输入u(t)Ru(t) \in \mathbb{R},输出是y(t)Ry(t) \in \mathbb{R},引入状态x(t)RNx(t) \in \mathbb{R}^N,目标是学习映射u(t)y(t)u(t) \mapsto y(t)

x(t)=Ax(t)+Bu(t)y(t)=Cx(t)+Du(t)\begin{aligned} x^{\prime}(t) & =\boldsymbol{A} x(t)+\boldsymbol{B} u(t) \\ y(t) & =\boldsymbol{C} x(t)+\boldsymbol{D} u(t) \end{aligned}

结合维基百科的图,方便理解

各变量含义如下(看起来和RNN很像):

  • ARN×N\boldsymbol{A}\in \mathbb{R}^{N\times N}:状态矩阵

  • BRN×N\boldsymbol{B}\in \mathbb{R}^{N\times N}:输入矩阵

  • CRN×N\boldsymbol{C}\in \mathbb{R}^{N\times N}:输出矩阵

  • DRN×N\boldsymbol{D}\in \mathbb{R}^{N\times N}:feedforward矩阵或者feedthrough矩阵

  • x(t):=ddtx(t)x^{\prime}(t):=\frac{d}{d t} \mathbf{x}(t)x(t)x(t)关于tt的导数,所以图里有一个积分\int操作把它变回x(t)x(t)

假设序列长度为LL,那么

  • 时间复杂度:

    • SSM:O(N2L)O(N^2L),因为Ax(t)\boldsymbol{A} x(t)N×NN\times NN×1N\times 1的矩阵乘法,复杂度是N2N^2

    • RNN:O(N2L)O(N^2L),和SSM类似

    • CNN:O(kLM2)O(kLM^2),假设kk个卷积核,每个卷积核M×MM\times M,一般MNM \ll N

  • 空间复杂度:

    • SSM:O(N2+NL)O(N^2+NL),因为中间状态x(t)RNx(t) \in \mathbb{R}^N是需要额外存储

    • RNN:O(N2)O(N^2),所有时间步共享权重,不需要像SSM专门为每个时间步存一个状态x(t)x(t)

    • CNN:kM2kM^2

所以传统SSM的时空复杂度都很高,作者提出了S4(structured state space model)

====>hippo的假设会让模型更关注宽波,对于很窄的毛刺信号效果不好,所以对大海捞针任务效果并不好

Mamba

Mamba: Linear-Time Sequence Modeling with Selective State Spaces

https://huggingface.co/state-spaces

https://github.com/havenhq/mamba-chat

MODELING SEQUENCES WITH STRUCTURED STATE SPACES

Mamba2

再战Transformer!原作者带队的Mamba 2来了,新架构训练效率大幅提升

Transformers are SSMs: Generalized Models and Efficient Algorithms Through Structured State Space Duality

https://github.com/state-spaces/mamba

Mamba+Transformer

Mamba真比Transformer更优吗?Mamba原作者:两个都要!混合架构才是最优解

An Empirical Study of Mamba-based Language Models

Block-State Transformer

Block-State Transformer

Jamba

Mamba做大做强!混合Transformer,打败Transformer

https://huggingface.co/ai21labs/Jamba-v0.1

让mamba做短程头,让transformer做长程头

Hawk & Griffin

RNN效率媲美Transformer,谷歌新架构两连发:同等规模强于Mamba

Griffin: Mixing Gated Linear Recurrences with Local Attention for Efficient Language Models

简介

global attention在infer阶段的效率和序列长度成二次关系,而且序列长度与KV cache呈线性增长关系。Fast Transformer Decoding: One Write-Head is All You Need提出的multi-query attention(MQA)可以通过一个constant factor减小cache size,部分缓解这个问题,但cache还是与序列长度线性相关。

循环模型能够将整个序列压缩到一个fixed-size的hidden state,并通过迭代进行更新。但要想取代transformer,rnn不仅需要在效果上可比,还要相似的硬件效率,相关工作如下:

本文提出了新的RG-LRU层,一种新的gated linear recurrent layer,并基于此提出了将MLP和RG-LRU结合的Hawk,还有将MLP和RG-LRU与local attention混合的Griffin。

  • 对于最多超过7B的模型,Hawk和Griffin发现了held-out loss训练FLOPS间的power law scaling(上图左边)

  • Hawk-3B比Mamba-3B在下游任务上要好,而训练的token数只有mamba的一半;Griffin-7B和14B与Llama-2效果相当,而训练数据只有其1/7

  • 训练在TPU-v3上完成,用JAX中的Pallas实现了RG-LRU(Real-Gated Linear Recurrent Unit)层的内核(https://jax.readthedocs.io/en/latest/pallas/index.html),减小内存transfer

  • infer阶段比MQA的吞吐高很多(上图右边),而且对长序列有更低的latency

  • 训练时在长序列上比transformer更好,而且能够高效地学习复制和检索的任务。但如果没有finetune,直接对比pretrain的效果,transformer会更好

网络结构

包括三大类组件:

  • residual block:

  • MLP block:

  • temporal-mixing block

Residual Block

受pre-norm transformer的启发,用的RMSNorm

MLP block

参考Language modeling with gated convolutional networks(类似star两个W直接element-wise product),采用了gated MLP,即如下两个linear的结果(输入维度DD,输出维度都是MD,M=3MD,M=3)进行element-wise product(类似GeGLU(Glu variants improve transformer)),再过一个linear

  • 直接过一个linear,但没有激活

  • linear后加一个GeLU激活(实际用的nn.functional.gelu(input, approximate="tanh")

看recurrentGemma-2b的config,发现总共有26个block,一个block依次包括:

  • rg-lru或者MQA,每个block里的选择方式是(rg,rg,att,rg,rg,att,rg,rg,att,...)

  • 再过一个gated MLP

  "_block_types": [
    "recurrent",
    "recurrent",
    "attention"
  ],
  "num_hidden_layers": 26,
  "attention_window_size": 2048,

Temporal-mixing block

global Multi-Query Attention(MQA)

Fast Transformer Decoding: One Write-Head is All You Need中为了加速推理,采用了MQA的方法,本文固定了head的维度为Dhead=128D_{head}=128,head的个数HH也固定,且HDhead=DHD_{head}=D,所以model的维度DD需要是128的倍数。没用绝对位置编码,用了RoPE。

local(sliding-window) MQA

Longformer: The long-document transformer提出了可以用local attention,即滑动窗口attention。让每个位置只和前面的固定个tokens去算attentioin,可以

  • 降低计算的FLOPS

  • 让KV cache的size的上界变成了window的size,从而不是序列长度的二次关系

RG-LRU

类似GSS block,也类似Mamba,输入DD,分别过一个linear得到两个分支,均是DRNND_{RNN}

两个分支的输出element-wise product一下,再过一个linear得到dd

conv1d参考torch官方doc

  • 输入:(N,Cin,Lin)\left(N, C_{i n}, L_{i n}\right)

  • 输出:(N,Cout ,Lout )\left(N, C_{\text {out }}, L_{\text {out }}\right)

其中,

Lout =Lin +2× padding  dilation ×( kernel_size 1)1 stride +1L_{\text {out }}=\left\lfloor\frac{L_{\text {in }}+2 \times \text { padding }- \text { dilation } \times(\text { kernel\_size }-1)-1}{\text { stride }}+1\right\rfloor

groups==in_channels and out_channels=K*in_channels,也叫depthwise convolution,K是depthwise乘子。即每个输入通道都有自己的卷积核,并且只作用于该通道

        ## conv1d_width = 4, 
        ## 对图像卷积来讲,padding就是让输出的shape不小于输入shape
        ## 输入是hidden_size=2560,而lru_width也是2560
        self.conv_1d = nn.Conv1d(
                    config.lru_width, # in_channels
                    config.lru_width, # out_channels
                    kernel_size=config.conv1d_width,
                    groups=config.lru_width,
                    padding=config.conv1d_width - 1,
                )
        
        ## 输入[bs, seq_len, hidden_size]
        x_branch = self.linear_x(input_states)
        ## 变成[bs, hidden_size, seq_len]
        x_branch = x_branch.transpose(1, 2)
        if use_cache:
            if cache_position.shape[0] != 1:  # prefill
                self.conv1d_state = nn.functional.pad(x_branch, 
                    (self.conv1d_width - x_branch.shape[-1] - 1, 0))
                x_branch = self.conv_1d(x_branch)[..., :seq_len]
            else:  # decoding
                conv_state = torch.cat((self.conv1d_state, x_branch), -1)
                x_branch = torch.sum(conv_state * self.conv_1d.weight[:, 0, :], dim=-1) 
                    + self.conv_1d.bias
                x_branch = x_branch.unsqueeze(-1)
                self.conv1d_state = conv_state[:, :, 1:]
        else:
            # 前面维度不变,最后一维截断到seq_len
            x_branch = self.conv_1d(x_branch)[..., :seq_len]

参考Resurrecting Recurrent Neural Networks for Long Sequences提出的LRU(Linear Recurrent Unit),并参考传统LSTM和GRU引入了gate:

rt=σ(Waxt+ba), recurrence gate it=σ(Wxxt+bx), input gate at=acrt,ht=atht1+1at2(itxt).\begin{aligned} r_t & =\sigma\left(W_a x_t+b_a\right), \quad \text { recurrence gate } \\ i_t & =\sigma\left(W_x x_t+b_x\right), \quad \text { input gate } \\ a_t & =a^{c r_t}, \\ h_t & =a_t \odot h_{t-1}+\sqrt{1-a_t^2} \odot\left(i_t \odot x_t\right) . \end{aligned}

其中,recurrent weight a=σ(Λ)a=\sigma(\Lambda)是一个对角矩阵,Λ\Lambda是一个可学习的参数。cc是一个常数8,为了计算稳定,在log-space计算acrta^{c r_t},即先算出logat\log a_t,再取exp。

logat=logacrt=logσ(Λ)crt=csoftplus(Λ)rt\log a_t=\log a^{c r_t}=\log \sigma(\Lambda)^{c r_t}=-\operatorname{csoftplus}(\Lambda) \odot r_t

(这个公式可能有点问题,感觉应该是csoftplus(Λ)rt-\operatorname{csoftplus}(-\Lambda) \odot r_t,不过Λ\Lambda是一个可学习的nn.Parameter,其实这个错误无所谓吧)

    def __init__(self, config):
        super().__init__()
        self.num_attention_heads = config.num_attention_heads
        self.block_width = config.lru_width // self.num_attention_heads

        self.recurrent_param = nn.Parameter(torch.empty([config.lru_width]))
        self.input_gate_weight = nn.Parameter(
            torch.empty([self.num_attention_heads, self.block_width, self.block_width])
        )
        self.input_gate_bias = nn.Parameter(torch.empty([self.num_attention_heads, self.block_width]))

        self.recurrent_gate_weight = nn.Parameter(
            torch.empty([self.num_attention_heads, self.block_width, self.block_width])
        )
        self.recurrent_gate_bias = nn.Parameter(torch.empty([self.num_attention_heads, self.block_width]))
        self.recurrent_states = None

    def forward(xxx):
        ## reshape成适合多头的情况
        reshape_act = activations.reshape(batch_size * seq_len, self.num_attention_heads, self.block_width)
        ## (num_attention_heads, batch_size * seq_len, block_width)
        reshape_act = reshape_act.permute(1, 0, 2)

        ## 批量矩阵乘法(baddbmm),在reshape_act和self.input_gate_weight之间进行,
        ## 并加上偏置self.input_gate_bias。这一步计算输入门的原始值。
        res = torch.baddbmm(self.input_gate_bias[:, None, :], reshape_act, self.input_gate_weight)
        input_gate = torch.sigmoid(res.transpose(0, 1).reshape(batch_size, seq_len, lru_width))

        ## 类似input_gate
        res = torch.baddbmm(self.recurrent_gate_bias[:, None, :], reshape_act, self.recurrent_gate_weight)
        recurrent_gate = torch.sigmoid(res.transpose(0, 1).reshape(batch_size, seq_len, lru_width))

        # Compute the parameter `A` of the recurrence.
        # 上面的公式
        log_recurrent_gate = -8.0 * recurrent_gate * nn.functional.softplus(self.recurrent_param)
        recurrent_gate = torch.exp(log_recurrent_gate)

还有如下几个特点:

gate特点

先复习一下LSTM:

GRU:

  • 重置门(reset gate):如果重置门关闭,会忽略掉历史信息,即历史不相干的信息不会影响未来的输出。

  • 更新门(update gate):将LSTM的输入门和遗忘门合并,用于控制历史信息对当前时刻隐层输出的影响。如果更新门接近1,会把历史信息传递下去。

  • 两个gate只和xtx_t有关,ht1h_{t-1}无关

  • input gate iti_t和LSTM类似,直接对输入xtx_t进行filter或者scale down。

  • recurrent gate rtr_t和之前的gate机制不同:

    • mamba里的selection机制和GRU的update gate类似,在之前的状态当前输入xtx_t之间进行插值(interpolate),功能类似LSTM的forget gate,能够reset状态,并遗忘之前的信息

    • 本文的recurrent gate则类似于在LRU的更新和之前的隐藏状态之间进行插值,能够有效地丢弃输入,并且保持之前历史里的所有信息。使得模型在处理不相关或重复输入(uniformative inputs)时,更能达到超指数的记忆能力,以更有效地保留有用信息(因为这个gateht1h_{t-1}无关)。

SAMBA

长文本模型近期研究工作梳理

SAMBA: Simple Hybrid State Space Models for Efficient Unlimited Context Language Modeling

Mamba in llama

(toread)

Mamba作者新作:将Llama3蒸馏成混合线性 RNN

The Mamba in the Llama: Distilling and Accelerating Hybrid Models

feedback attention memory

TransformerFAM: Feedback attention is working memory

infini-attention

Leave No Context Behind: Efficient Infinite Context Transformers with Infini-attention

【重磅】谷歌重塑Transformer:无限记忆力,无限长输入,LLM基础研究重大突破

压缩记忆整合进标准的点积注意力机制,并在单个Transformer块内同时实现了掩码局部注意力长期线性注意力机制

与transformer-xl对比:

https://github.com/mustafaaljadery/gemma-2B-10M

https://github.com/dingo-actual/infini-transformer

MEGA

Mega: Moving average equipped gated attention

https://github.com/facebookresearch/mega

标准的self-attention公式

对于序列长度=nn的输入X={x1,x2,,xn}Rn×d\boldsymbol{X}=\left\{\mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_n\right\} \in \mathbb{R}^{n \times d},输出Y={y1,y2,,yn}Rn×d\boldsymbol{Y}=\left\{\mathbf{y}_1, \mathbf{y}_2, \ldots, \mathbf{y}_n\right\} \in \mathbb{R}^{n \times d}

Y=Attn(X)=f(QKTτ(X))V\boldsymbol{Y}=\operatorname{Attn}(\boldsymbol{X})=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}\right) \boldsymbol{V}
Q=XWq+bq,K=XWk+bk,V=XWv+bv\boldsymbol{Q}=\boldsymbol{X} W_q+b_q,\boldsymbol{K}=\boldsymbol{X} W_k+b_k,\boldsymbol{V}=\boldsymbol{X} W_v+b_v

其中, Attn : Rn×dRn×d\text { Attn : } \mathbb{R}^{n \times d} \rightarrow \mathbb{R}^{n \times d}Wq,Wk,WvRd×dW_q, W_k, W_v \in \mathbb{R}^{d \times d}bq,bk,bvRdb_q, b_k, b_v \in \mathbb{R}^d,而且有两种定义方式:

对于hh个attention heads,计算A=f(QKTτ(X))Rn×n\boldsymbol{A}=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}\right) \in \mathbb{R}^{n \times n}需要的时间和空间复杂度都是O(hn2)O(hn^2)

EMA

对于输出的序列Y\boldsymbol{Y}采用Exponential Moving Average(指数滑动平均)如下

yt=αxt+(1α)yt1\mathbf{y}_t=\boldsymbol{\alpha} \odot \mathbf{x}_t+(1-\boldsymbol{\alpha}) \odot \mathbf{y}_{t-1}

其中,α(0,1)d\boldsymbol{\alpha} \in(0,1)^d表示权重衰减,\odot是element-wise product

α\boldsymbol{\alpha}越大,1α1-\boldsymbol{\alpha}越小,对历史的衰减也越快:

EMA的计算看成nn独立的卷积,可以通过**FFT(快速傅立叶变换)**来加速计算。具体。。。再看看

Damped EMA:由于输入的x是d维向量,可以引入一个因子δ(0,1)d\boldsymbol{\delta} \in(0,1)^d让EMA更鲁棒:

yt=αxt+(1αδ)yt1\mathbf{y}_t=\boldsymbol{\alpha} \odot \mathbf{x}_t+(1-\boldsymbol{\alpha} \odot \boldsymbol{\delta}) \odot \mathbf{y}_{t-1}

MEGA

EMA可以看成是一种与位置相关的归纳偏置(inductive bias),即假设当前位置与之前位置满足滑动平均的关系,而attention矩阵的计算其实并没有考虑位置信息,所以可以把二者结合一下。

其中的multi-dimensional damped EMA大致流程如下:

  • 先变成h维:先把XRn×d\boldsymbol{X} \in \mathbb{R}^{n \times d}通过矩阵β\beta映射成URn×h\boldsymbol{U}\in \mathbb{R}^{n \times h}

  • 计算EMA:然后通过EMA得到hRn×h\boldsymbol{h}\in \mathbb{R}^{n \times h}(具体ht(j)=αjut(j)+(1αjδj)ht1(j)\mathbf{h}_t^{(j)}=\boldsymbol{\alpha}_j \odot \mathbf{u}_t^{(j)}+\left(1-\boldsymbol{\alpha}_j \odot \boldsymbol{\delta}_j\right) \odot \mathbf{h}_{t-1}^{(j)}

  • 再变回d维:再通过一个矩阵η\eta变回YRn×h\boldsymbol{Y}\in \mathbb{R}^{n \times h}

然后看整个流程:

  • 先计算EMA

X=EMA(X)Rn×dZ=ϕsilu (XWz+bz)Rn×z\begin{aligned} \boldsymbol{X}^{\prime} & =\operatorname{EMA}(\boldsymbol{X}) & & \in \mathbb{R}^{n \times d} \\ \boldsymbol{Z} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_z+b_z\right) & & \in \mathbb{R}^{n \times z} \end{aligned}
  • 再基于EMA的结果计算QK,基于原始的X计算V:

Q=κqZ+μqRn×zK=κkZ+μkRn×zV=ϕsilu (XWv+bv)Rn×v\begin{array}{ll} \boldsymbol{Q}=\boldsymbol{\kappa}_q \odot \boldsymbol{Z}+\boldsymbol{\mu}_q & \in \mathbb{R}^{n \times z} \\ \boldsymbol{K}=\boldsymbol{\kappa}_k \odot \boldsymbol{Z}+\boldsymbol{\mu}_k & \in \mathbb{R}^{n \times z} \\ \boldsymbol{V}=\phi_{\text {silu }}\left(\boldsymbol{X} W_v+b_v\right) & \in \mathbb{R}^{n \times v} \end{array}
  • 计算带位置bias的attention:

O=f(QKTτ(X)+brel)VRn×v\boldsymbol{O}=f\left(\frac{\boldsymbol{Q} \boldsymbol{K}^T}{\tau(\boldsymbol{X})}+\boldsymbol{b}_{\mathrm{rel}}\right) \boldsymbol{V} \quad \in \mathbb{R}^{n \times v}
  • 通过reset gate γ\boldsymbol{\gamma}和update gate φ\boldsymbol{\varphi}计算输出

γ=ϕsilu (XWγ+bγ)Rn×vφ=ϕsigmoid (XWφ+bφ)Rn×dH^=ϕsilu (XWh+(γO)Uh+bh)Rn×dY=φH^+(1φ)XRn×d\begin{aligned} \boldsymbol{\gamma} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_\gamma+b_\gamma\right) & & \in \mathbb{R}^{n \times v} \\ \boldsymbol{\varphi} & =\phi_{\text {sigmoid }}\left(\boldsymbol{X}^{\prime} W_{\varphi}+b_{\varphi}\right) & & \in \mathbb{R}^{n \times d} \\ \hat{\boldsymbol{H}} & =\phi_{\text {silu }}\left(\boldsymbol{X}^{\prime} W_h+(\boldsymbol{\gamma} \boldsymbol{O}) U_h+b_h\right) & & \in \mathbb{R}^{n \times d} \\ \boldsymbol{Y}&=\boldsymbol{\varphi} \odot \hat{\boldsymbol{H}}+(1-\boldsymbol{\varphi}) \odot \boldsymbol{X} \quad & & \in \mathbb{R}^{n \times d} \end{aligned}