-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: add attention: 1. score function: additive, location_sensitive, scaled_dot_product; 2. self-attention: MultiHeadAttention #3
Conversation
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
…tention dir and readme Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
Signed-off-by: weedge <[email protected]>
longer context lengththe best ways for extending a pretrained model to longer context length: |
大语言模型内存要求 LLM memory requirement实际上,影响 GPU 大型语言模型(LLM)内存需求的两个主要因素是模型权重和 KV 缓存。 模型权重 Model weights内存被模型参数所占用。举例来说,一个包含 70 亿个参数的模型(比如 Llama 2 7B),以 16 位精度(FP16 或 BF16)加载,大约需要 70 亿 * sizeof(FP16) ~= 14 GB 的内存。 Key-Value (KV) cachingNote 内存被自注意力张量的缓存所占用,以避免重复计算,加快forward推理速度(训练和inference), 一般训练的时候可以不用缓存(本身训练NN 反向传播参数量占很大(3/4)一部分内存),主要是serving时,对inference的优化 KV(键值)缓存是decoder阶段常见的一种优化技术。在decoder阶段,每个时间步生成一个token,但每个token都依赖于之前所有token的KV张量(包括预填充时计算的输入token的KV张量,以及直到当前时间步计算的任何新KV张量)。 为了避免在每个时间步重新计算所有这些张量的值,可以将它们缓存到GPU内存中。在每次迭代中,当新的元素被计算出来时,它们被简单地添加到正在运行的缓存中,以便在下一次迭代中使用。在某些实现中,模型的每一层都有一个KV缓存。 如果我们可以只输入最近的token,然后从那里预测下一个token,那就更好了。然而,我们需要整个上下文的 K 和 V 值来完成注意力计算。幸运的是,由于句子中的每个单词只能关注句子中的前一个单词,因此 N-1 个token的 K 和 V 值在每次后续计算中都完全相同。这意味着您可以存储 K 和 V 的值,仅计算新添加的标记的新 K 和 V,然后将它们与之前存储的 K 和 V 连接起来以获得相同的完整 K 和 V 向量。 通过使用KV缓存,可以避免重复计算先前时间步骤中生成的中间状态,提高了decoder阶段的效率。这样做可以减少计算成本,加快推理速度,并有效利用GPU的内存和计算资源。这极大地加快了自回归生成的速度,尤其是在较大的模型尺寸下,但有一个问题——现在你的瓶颈是内存(memory bound)而不是计算(computer bound)。 内存计算:在批处理中,批处理中每个请求的 KV 缓存仍然需要单独分配,并且可能具有较大的内存占用。下面的公式描述了适用于今天大多数常见LLM架构的KV缓存大小。 每个标记的KV缓存大小(以字节为单位)= 2 * (层数) * (头数 * 头尺寸) * 字节精度 Size of KV cache per token in bytes = 2 * (num_layers) * (num_heads * dim_head) * precision_in_bytes 第一个因子2代表K和V矩阵。通常,(头数 * 头尺寸)的值与transformer的隐藏大小(或模型的维度,d_model)相同。这些模型属性通常可以在模型卡片或关联的配置文件中找到。 这个内存大小适用于批量输入序列中的每个标记。假设半精度,KV缓存的总大小由下面的公式给出。 KV缓存的总大小(以字节为单位)= (批量大小) * (序列长度) * 2 * (层数) * (隐藏大小) * sizeof(FP16) Total size of KV cache in bytes = (batch_size) * (sequence_length) * 2 * (num_layers) * (hidden_size) * sizeof(FP16) 例如,使用 16 位精度的 Llama 2 7B 模型和批量大小为 1,KV 缓存的大小将是 1 * 4096 * 2 * 32 * 4096 * 2 字节,约为 2 GB。 更好模型性能 VS KV 缓存的优化(更少的kv缓存)回顾下原始论文中的MHA方法的作用: 有效管理这个KV缓存是一个具有挑战性的任务。随着批处理大小和序列长度线性增长,内存需求会迅速扩大,对于参数量比较大的模型,kv cache成为瓶颈, 而且训练推理成本高。因此,它限制了可以提供的吞吐量,并对长上下文输入提出了挑战。在这种背景下,为了改进MHA K/V cache, 针对原始Transformer使用 Multi-Head Attention (MHA) 多头注意力 提出了不同的优化方法, 按自己的理解归为两类:
这里主要介绍针对MHA模型结构优化。 Multi-Query Attention 多查询注意力 (MQA)
注: 过渡方案 Grouped-Query Attention 分组查询注意力 (GQA)
这种新的训练方法可以在使用少量原始训练计算资源的情况下,将最初采用多头注意力(MHA)训练的模型进行“上训练”(uptraining),转换为采用组查询注意力(GQA)。这种方法可以使模型在保持接近多头注意力(MHA)的质量的同时,保持更接近多查询注意力(MQA)的计算效率。Llama 2 70B就是一个采用组查询注意力(GQA)的模型的例子。 像多查询注意力(MQA)和组查询注意力(GQA)这样的优化方法有助于通过减少存储的键和值头的数量来减少键值(KV)缓存所需的内存。但在如何管理这种KV缓存方面可能仍存在一些低效性。 注: 折中方案,常使用在参数量大的模型上。 Multi-Head Latent Attention 多头潜在注意力 (MLA)
表中展示了不同注意机制之间每个令牌的 KV 缓存的比较。 MLA只需要少量的KV缓存,相当于GQA只有2.25组,但可以实现比MHA更强的性能。 |
attention
attention Alignment score function:
Additive attention
原始论文中应用在NMT任务seq2seq模型的decoder中
Neural Machine Translation by Jointly Learning to Align and Translate(RNN(LSTM) Additive Attention(Bahdanau Attention) in NMT)
Multiplicative(Dot-Product) attention
原始论文中应用在NMT任务seq2seq模型的decoder中
Effective Approaches to Attention-based Neural Machine Translation(RNN(LSTM) (global/local)multiplicative attention(Luong Attention))
将attention model分成global 和 local attention, 两者计算差不多,local attention 通过滑动窗口计算
Scaled Dot-Product Attention
❤Attention Is All You Need❤ (Transformer,based solely on attention mechanisms, dispensing with recurrence and convolutions entirely. self attention(Scaled Dot-Product Attention(SDPA), Multi-Head Attention))
原始论文中应用在NMT任务seq2seq模型的encoder-decoder中
Multi-Head Attention
self-attention
在深度学习中,经常使用卷积神经网络(CNN)或循环神经网络(RNN)对序列进行编码。 想象一下,有了注意力机制之后,我们将词元序列输入注意力池化中, 以便同一组词元同时充当查询、键和值。 具体来说,每个查询都会关注所有的键-值对并生成一个注意力输出。 由于查询、键和值来自同一组输入,因此被称为 自注意力(self-attention) 也被称为内部注意力(intra-attention)
positional-encoding
在处理token序列时,循环神经网络是逐个的重复地处理token, 而自注意力则因为并行计算而放弃了顺序操作。 为了使用序列的顺序信息,通过在输入表示中添加 位置编码(positional encoding)来注入绝对的或相对的位置信息。 位置编码可以通过学习得到也可以直接固定得到。
seq2seq with attention (rnn attention, cnn attention, self-attention(all))
rnn vs cnn vs self-attention
summary
Transformer
❤Attention Is All You Need❤ (Transformer,based solely on attention mechanisms, dispensing with recurrence and convolutions entirely. self attention(Scaled Dot-Product Attention(SDPA), Multi-Head Attention))
self-attention
Transformer 以三种不同的方式使用多头注意力:
Encoder self-attention: 编码器包含自注意力层。在自注意力层中,所有键、值和查询都来自同一位置,在本例中是编码器中前一层的输出。编码器中的每个位置可以关注编码器上一层中的所有位置.
MaskedDecoder self-attention: 类似地,解码器中的自注意力层允许解码器中的每个位置关注解码器中直到并包括该位置的所有位置。我们需要防止解码器中的左向信息流以保留自回归属性。我们通过屏蔽(设置为 -∞) softmax 输入中对应于非法连接的所有值。
positional-encoding
原始论文中使用基于正弦函数和余弦函数的固定位置编码
更多细节见:https://github.com/weedge/doraemon-nb/blob/main/AnnotatedTransformer.ipynb