Transformer的优化
本文总结 Transformer 和 attention 机制相关的 trick。留下学习痕迹。
Multi Query Attention (MQA)#
早在 2019 年就被提出,但最近才被重视。
相比 Multi Head Attention,MQA 让多头注意力层的各个 head 共享同一份 Key 和 Value 参数(Query 不参与共享,各 head 独立)。如此,以不太多的精度代价,可减少参数量,提升推理速度。
目前 PyTorch 没有 MQA 的原生实现,下文的 GQA 也是。若不使用这些 trick,使用原生的
F.scaled_dot_product_attention
能够享受速度加成。这个仓库 使用纯 Python 的方式实现了 MQA 和 GQA。据作者实验,当
较小时 GQA 仍然比 PyTorch 原生 MHA 更快。 这个视频 讲述了LLaMA2 模型中用到的技巧,包括 MQA 和 KV Cache。可以参考。
Grouped Query Attention (GQA)#
MQA 的做法也许太极端——所有 head 只共享一份 Key 和 Value 势必会影响模型效果。
GQA 作为折中方案,实现方法非常直接。将 head 分为
很明显,当
Attention with Linear Bias(ALiBi)#
为了让 transformer 模型知道输入序列的顺序关系,需要对输入序列添加 Position Embedding。
而 ALiBi 去掉了 Position Embedding 步骤,转而在计算 Query × Key 值时添加一个偏置常量来注入位置信息。实验证明,这样的修改可以让模型训练长度小于推理长度时也能获得良好推理效果。
具体实现的话,部分代码如下(参考)。
首先要获得 bias。这个 bias 要加到 Query × Key 结果中,充当位置信息。
def get_relative_positions(seq_len: int) -> torch.tensor:
x = torch.arange(seq_len)[None, :]
y = torch.arange(seq_len)[:, None]
return x - y
这个函数会返回类似以下的矩阵:
tensor([[ 0, 1, 2, 3, 4],
[-1, 0, 1, 2, 3],
[-2, -1, 0, 1, 2],
[-3, -2, -1, 0, 1],
[-4, -3, -2, -1, 0]])
针对不同的 head,有着不同的 bias 权重大小。
def get_alibi_slope(num_heads):
x = (2 ** 8) ** (1 / num_heads)
return (
torch.tensor([1 / x ** (i + 1) for i in range(num_heads)])
.unsqueeze(-1)
.unsqueeze(-1)
)
如此,就能获得 [head, seq_len, seq_len]
大小的 bias 了:
alibi = (
get_relative_positions(seq_len) * get_relative_positions(seq_len)
).unsqueeze(0)
为了让运算更快,可以用上 PyTorch 原生的 F.scaled_dot_product_attention
(参考)。
context_layer = F.scaled_dot_product_attention(
query_layer, key_layer, value_layer, attn_mask=alibi, dropout_p=0.0
)
参考来源#
- 何枝,“【LLM 加速技巧】Muti Query Attention 和 Attention with Linear Bias(附源码)”,https://zhuanlan.zhihu.com/p/634236135?utm_id=0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了