提高大模型计算速度除了使用推理加速的技术,让模型“算得更快”,还可以使用模型压缩的技术,让模型“算得更少”。本文参照https://zhuanlan.zhihu.com/p/667455383这篇博客分享的内容对模型压缩技术进行一个初步的介绍。

模型压缩技术分类

模型推理阶段的显存分配

在推理阶段主要有三部分数据会放到显存里

一个KV Cache的计算过程

以Qwen-72B为例,忽略模型GQA的设置,以朴素的MHA方式计算。

模型参数名 模型层数 注意力头数 注意力头向量维度
大小 80层 每层64个头 每个头128维
针对单个token,缓存的 $k,v$ 数据总量为:

$$num_{kv} = 2 * l * n_h = 2 \times80 \times64 = 10240$$

其中,2表示1个 $k$ 和1个 $v$ 。也就是说一个token就需要缓存10240个 $k,v$ 。这些 $k,v$ 如果按照FP32进行计算存储,每个参数占4个字节,那么一个token的参数占用为:

$$token\_mem_{kv} = 2 * num_{kv} * d_{h} = 4 \times 10240 \times 128= 5.24(MB)$$

这些 $k,v$ 如果按照更广泛使用的半精度(bf16)参数进行计算存储,每个参数占2个字节,那么一个token的参数占用为:

$$token\_mem_{kv} = 2 * num_{kv} * d_{h} = 2 \times 10240 \times 128= 2.62(MB)$$

这样也就确定了一个token计算需要的缓存的 $k,v$ 数量和存储量。那么对于一个实际的推理场景,还要考虑批量batch(B)和序列长度sequence length(S)两个维度。以下面的单条文本推理和并发推理场景为例:

单条短文本场景

参数设置 参数精度 batch大小 序列长度
参数大小 bf16 1 2048

此时KV Cache的大小计算:

$$mem_{kv} =token\_mem_{kv} * B * S = 2.62(MB) \times 1 \times 2048 = 5.366GB$$

并发长文本场景

参数设置 参数精度 batch大小 序列长度
参数大小 bf16 32 4096

此时KV Cache的大小计算:

$$mem_{kv} = token\_mem_{kv} * B * S =  2.62(MB) \times 32 \times 4096 = 343.4GB$$

除了KV Cache需要占用显存之外,模型参数也需要占用存储,推理阶段模型参数占用的存储空间是固定的。假设模型参数量为 $\Phi$ ,以bf16半精度做推理,则参数量约为 $2\Phi$ (字节)。以qwen-72B为例,参数占用存储空间约为:

$$mem_p = 2 * \Phi  = 2 \times 72 = 144G$$

重新审视上述两个场景的现存分配:

补充:在实际推理过程中,如何选择batch大小是根据实际测试而来的,尽可能在单卡装下完整模型参数和KV Cache,这时候卡内带宽很高,性能更出众。

减少KV Cache的优化方法

量化(Quantization)

量化(Quantization)是指使用精度更低的单位来表示模型的权重或中间层变量,以节省空间和加速模型推理速度的方法。

目前Weight and Activation的Weight 8bit Activition 8bit(W8A8)与FP16水平相当,而Weight Only的Weight 4bit Activition 16bit(W4A16)也与FP16相差无几了。

量化的粒度

LLM.int8()

在进行整数量化时,先将原始 $float$ 矩阵 $W$ 除以整数 $INT-N$ 能表示的最大值得到缩放因子 $S$ ,进行缩放,得到量化后的 $int$ 矩阵 $W_{int}$ 。在推理时,首先使用 $W_{int}$ 进行推理,然后再根据 $S$ 放缩回 $float$ 结果。这种方式很简单直接,推理精度下降也相对比较明显。

根据LLM.int8()的分析:

LLM.int8()量化过程

具体而言,就是通过离群(outlier)检测,把输入 $X$ 中包含异常值的列挑出来直接做16位的矩阵乘法,剩下的使用int8乘法,最后把它们累加起来。

GPTQ

GPTQ方法是对原始的OBQ(Optimal Brain Quantization)方法的改进。

OBQ方法是最早源于LeCun的OBD算法(Optimal Brain Damage),到后来的OBS(Optimal Brain Surgeon),再到2022年的OBC(Optiaml Brain Compression)方法一路流传下来的模型压缩方法。

具体而言,OBQ方法通过在量化过程中保留对损失函数影响最小的权重,来补偿因量化引起的精度损失。该方法将压缩问题转化为了“在一已知要把 $w_{ij}$ 变为 $Quant(w_{ij})$ 的前提下,如何变化 $W_i$ 的其他值使loss的变化最小”。此时,整个量化过程如下:

$$w_q = \mathrm{argmin}_{w_{q}} \frac{(quant(w_q)-w_q)^2}{[\mathbf{H}^{-1}]_{qq}}$$

$$\delta_F = - \frac{w_q-quant(w_q)}{[\mathbf{H}^{-1}]_{qq}} · [\mathbf{H}^{-1}]_{:,q}$$

$$\mathbf{H}^{-1} = (\mathbf{H}^{-1} - \frac{1}{[ \mathbf{H}^{-1}]_{qq}} \mathbf{H}^{-1}_{:,q} H^{-1}_{q,:})$$

重复这三个步骤直到全部矩阵都被量化。其中最后一步更新 $\textbf{H}$ 涉及到矩阵乘法,复杂度较高(为 $O(d_{row}*d^3_{col})$ ),所以这个算法对大模型来说很难实现。

为了提高量化效率,GPTQ被提出来了。

GPTQ的算法伪代码
  1. 初始化量化结果 $\textbf{Q}$ 为一个零矩阵,初始化误差矩阵 $\textbf{E}$ 为一个零矩阵

  2. 对 $\textbf{H}^{-1}$ 进行Cholesky分解,得到 $\textbf{H}^{-1}$ 的逆矩阵信息

  3. 迭代处理权重列的量化

  4. 对每个列进行量化,更新Q矩阵中的对应列

  5. 计算量化误差,更新误差矩阵 $\textbf{E}$

  6. 更新权重矩阵 $\textbf{W}$ 中的权重,以减少误差

  7. 重复上述步骤,直到所有的权重列都被量化

  8. 最终,返回量化后的权重矩阵 $\textbf{Q}$

总体而言,GPTQ有以下两个优点:

在INT4精度下,GPTQ可以与FP16效果相当,而INT3下也只低了5%~10%。推理速度方面,GPTQ可以比FP16快3~5倍。

SmoothQuant

当模型规模更大时,单个token的值变化范围也较大(与LLM.int8()的观察一直,存在大量的离群特征),导致token相较weight难以量化。因此,很多量化方法都关注权重量化,在计算过程中主要就是权重参与,而输入token的激活值仍然是FP16的。但是这种只量化weight不量化Activation的想法,在矩阵计算时就需要使用FP16乘以INT8的矩阵乘法,这种计算效率是肯定比INT乘以INT8的计算效率低的。

SmoothQuant意图解决这种激活值幅度变化大难以量化,而权重幅度变化相对较小的情况,平衡两者的量化难度。SmoothQuant通过数学上等价的逐通道缩放变化,将量化的难度从激活值转移到模型权重上。具体而言,SmoothQuant引入了平滑因子 $s$ 对权重 $W$ 和激活值 $X$ 进行缩放:

$$Y = (X diag(s)^{-1}) · ((diag(s))W) = \hat{X}\hat{W}$$

SmoothQuant的缩放
SmoothQuant的计算过程

得到这样Smooth变换后的激活值和权重矩阵,可以再采用per-token或per-tensor的量化方式。

不同的量化方式

SmoothQuant不会影响模型的推理效率,因为:

根据SmoothQuant的论文显示,SmoothQuant后推理的Latency可以降低20%-40%,而且得益于需要的内存变少了,批量推理的吞吐量可以提升数倍。

AWQ

AWQ的核心思想:“权重并不同等重要”。AWQ观察到权重里面有0.1%~1%的权重是非常重要的权重,如果对这些权重不量化,保持FP16的精度,那么会大大减少量化误差。

为了寻找这些重要权重,AWQ做了相关的分析实验,与SmoothQuant里的经验结论一致,权重的分布相对平缓,因此依据权重分布选择重要权重是不合理的。与之相对,选择观测激活值的分布,选择对应输出比较大激活值的权重channel,认为这是一个比较重要的权重,依据此构建了一个按照激活值分布量化的算法,成为Activation-aware Weight Quantization,即激活感知权重量化算法。(这个方法有一定的局限性:保留显著权重为FP16可以提升量化后模型效果,但是这种方法并不硬件友好,会使模型效率降低。因此采用类似SmoothQuant的放缩方式进行处理,从而通过通过放大显著channel来减少其相对量化误差)

具体而言,AWQ的量化通过网格搜索找到每个channel的最佳缩放因子scale:

$$s^{*} = \mathop{\arg\min}\limits_{s} \cal{L}(s)$$

$${\cal L}(s) = | Q({\mathbf W}·diag(s))(diag(s)^{-1} · {\mathbf X}) - \mathbf W \mathbf X  |$$

其中 $s$ 时per-channel scaling的缩放因子, $s^{-1}· {\mathbf X}$ 可以被融合至前面的算子

$$s = {s_{\mathbf{X}}}^{\alpha}$$

$$\alpha^{*} = \mathop{\arg\min}\limits_{s} \cal{L}({s_{\mathbf{X}}}^{\alpha})$$

精简Attention

因为Attention的计算占据了模型推理的很大一部分计算资源,所以通过精简一些Attention计算的方法可以有效减少模型的运算量。

共享Attention参数-由MHA的思考

不同的注意力计算方式

共享Attention参数-MQA (Multi Query Attention)

在MHA中,输入分别经过 $W_Q$ 、 $W_K$ 和 $W_V$ 的变换之后,都切成了 $n$ 份( $n$ 即是头数),同时维度也从 $d_{model}$ 降到了 $d_{head}$ ,此后分别进行attention计算然后再进行拼接。

在MQA中,经过线性变换后,只对 $Q$ 进行切分,而 $K$ 、 $V$ 则直接在线性变换的时候把维度降到了 $d_{head}$ (并不进行切分),然后用切分后的 $Q$ 分别和同一份 $K$ 、 $V$ 进行attention计算,之后把结果拼接起来。

简单来说,就是MHA中,每个注意力头的 $K$ 、 $V$ 是不一样的,而MQA这里,每个注意力头的 $K$ 、 $V$ 是一样的,值是共享的。而其他步骤都和MHA一样。如此需要缓存的 $K$ 、 $V$ 值就从所有头的量变成了一个头的量。

这种方法由于共享了多个头的参数,限制了模型的表达能力,虽然能更好地支持推理加速,但是在效果上比MHA差。

共享Attention参数-GQA (Grouped Query Attention)

因为MQA对效果会有影响,但是MHA占据的缓存很多,那么GQA提出了一个折中的办法,既能减少MQA效果的损失,又相比MHA需要更少的缓存。

在GQA中, $Q$ 和MHA/MQA的做法不变,使用多套共享的 $K$ 、 $V$ ,形成多个group,同一个group内的 $Q$ 共享同一套 $K$ 、 $V$ ,不同group的 $Q$ 所用的 $K$ 、 $V$ 不同。

如此一来,MHA可以看做group为n(头数)的GQA,而MQA可以看做group为1的GQA。

共享Attention参数-从MHA得到MQA和GQA

共享Attention参数- MLA

MLA与其他注意力计算方式对比

多头潜在注意力(MLA)将潜在特征表示纳入注意力机制,从而降低计算复杂度并改善上下文表示。其核心思想是对KV进行压缩后,再送入标准的MHA算法中,用一个更短的K,V向量来进行计算,从而减少KV Cache的大小。

MLA的计算过程
  1. 计算代表KV Cache的潜在向量

$$[c_{t}^{KV}] = W^{DKV}{\mathbf h_t}$$

其中, $c_t^{KV}$ 是在时间步t计算的键值缓存潜在向量。 $W^{DKV}$ 是一个权重矩阵,用于将隐藏状态 $\mathbf h_t$ 映射到键值缓存空间,这一步可以通过神经网络映射得到。总体而言, $c_t^{KV}$ 相对原来的 $\mathbf h_t$ 要小很多。

  1. 计算key和value的潜在向量

$$[k_{t,1}^C;k_{t,2}^C;...;k_{t,n_h}^C] = k_{t}^C = W^{UK}c_{t}^{KV}$$

$$[v_{t,1}^C;v_{t,2}^C;...;v_{t,n_h}^C] = v_{t}^C = W^{UK}c_{t}^{KV}$$

$k_t^{C}$ 是键的潜在向量,通过将 $c_{t}^{KV}$ 与权重矩阵 $W^{UK}$ 相乘得到,这一步上采样,通过潜向量特征 $c_{t}^{KV}$ 映射得到较大的 $k_t^C$ 用于后续的注意力计算。 $v_t^{C}$ 的计算同理。

  1. 计算旋转位置编码

$$k_t^{R}={RoPE}\left(W^{K R} \mathbf{h}_t\right)$$

${RoPE}$ 是一种相对位置编码方式,用于在键向量中引入位置信息。

  1. 组合潜向量 $k$ 和位置编码 $k$ 得到最终的key向量

$$k_{t, i}=\left[k_{t, i}^C ; k_t^R\right]$$

最终的键向量 $k_{t,i}$ 是通过将内容相关的键向量 $k_{t, i}^C$ 和位置编码 $k_t^R$ 连接起来得到的。

  1. 计算query的潜在向量

$$c_t^{Q} = W^{DQ}h_t$$

$$[q_{t,1}^{C};q_{t,2}^{C};...;q_{t,n_h}^{C}] = q_t^C=W^{UQ}c_t^Q$$

$$[q_{t,1}^{R};q_{t,2}^{R};...;q_{t,n_h}^{R}] = q_t^R={RoPE}({W^{QR}c_t^Q})$$

$$q_{t,i}=[q_{t,i}^C;q_{t,i}^R]$$

与 $k$ 向量的计算类似,通过潜在向量计算得到后续MHA计算的查询向量 $q$ 。

  1. 注意力计算

最终的注意力输出 $u_t$ 是通过query  $\left(q_{t, i}\right)$ ,key $\left(k_{j, i}\right)$ 和value $\left(v_{j, i}^C\right)$ 结合起来计算得到的:

$$o_{t,i} = \sum_{j=1}^{t} {Softmax}_j(\frac{\mathbf{q}_{t,i}^T \mathbf{k}_{j,i}}{\sqrt{d_h+d_h^R}})\mathbf{v}_{j,i}^C$$

$$\mathbf{u}_t = W^o[\mathbf{o}_{t,1};\mathbf{o}_{t,2}; ...;\mathbf{o}_{t,n_h}]$$

$\mathbf{o}_{t, i}$ 是第 $i$ 个注意力头的输出。

通过上述的计算过程可以看到MLA是如何在推理时减少KV Cache的,实际上就是使用了降维的方法,把 $k,v$ 降维到一个隐空间中,然后在推理时只缓存 $c_t^{KV}$ 即可。这个 $c_t^{KV}$ 会在后面使用 $W^{UK},W^{UV}$ 升维,之后的计算与MHA是一致的。实际上,MLA计算时并不需要显式的计算出 $k_{t,i},v_{t,i}$ ,因为降维矩阵 $W^{UK}$ 和 $W^{UV}$ 可以被 $W^{UQ}$ 和 $W^{O}$ 通过预先计算的方式吸收。以不带位置编码时的 $q_t^Tk_t$ 为例:

$$q_t^Tk_t = (W^{UQ}c_t^Q)^TW^{UK}c_t^{KV} = c_t^Q(W^{UQ})^TW^{UK}c_t^{KV}=c_t^{Q}Wc_t^{KV}$$

可以看到,并不需要计算出 $W^{UK}$ ,可以把 $W^{UK}$ 吸收进 $W^{UQ}$ ,这样就避免了重复计算,并且可以让缓存的 $c_t^{KV}$ 直接参与计算,而不需要显式计算出 $k$ 。如此MLA在减少KV Cache的同时保留了KV Cache本身减少重复计算的功能。(实际操作时, $q$ 的输入也改为了低秩投影形式,这与减少KV Cache无关,主要是为了减少训练期间参数量和相应的梯度所占的显存)

但是这种吸收无法直接应用 ${RoPE}$ 编码:

$$q_tk_i^T = (x_tW_qR_t)(c_iW_kR_i)^T = x_t(W_qR_{t-i}W_k^T)c_i^T$$

此时, $W_qR_{t-i}W_k^T$ 与位置差 $t-i$ 相关,就无法合并为一个固定的投影矩阵了。

因此,MLA将 $QK$ 的位置信息部分和内容信息部分解耦开了,专门生成多头的 $q_t^R$ 和共享的 $k_t^R$ (共享的 $k_t^R$ 指的是每个头的 $k$ 都用这同一个 $k_t^R$ )。然后再通过拼接的方式构造完整的 $Q$ 和 $K$ :

$$q_{t,i}^Tk_{j,i} = [c_t^Q(W^{UQ})^T,(q_t^R)^T]\begin{bmatrix}    W^{UK}c_t^{KV} \    k_t^R \end{bmatrix}$$

$$[c_t^Q(W^{UQ})^T,(q_t^R)^T]\begin{bmatrix}    W^{UK}c_t^{KV} \    k_t^R \end{bmatrix} = c_t^Q(W^{UQ})^TW^{UK}c_t^{KV} +(q_t^R)^Tk_t^R$$

在此设计下,MLA既减少了KV Cache,也保住了 ${RoPE}$ 的应用,同时还确保了没有重复计算。MLA节约了大量缓存并且性能很好,这种提升可以理解为虽然MLA增大了计算了,但是KV Cache的减少降低了显存和带宽的压力,在token的生成阶段,主要的速度瓶颈是带宽瓶颈和显存瓶颈,因此使用MLA可以明显提高生成的速度。

稀疏Attention-由self-attention的思考

self-attention

对self-attention而言,需要对序列中的任意两个向量都需要计算相关度。上图的左子图显示了注意力矩阵,右子图显示了关联性,这意味着每个元素都跟序列内所有元素有关联。如果想要节省显存,加速计算,一个思路就是减少相关度计算,即认为每个元素只与序列中的一部分元素相关,这便是稀疏Attention的基本原理。

稀疏Attention-Atrous Self Attention

Atrous self-attention

Atrous Self Attention受“膨胀卷积”(Atrous Convolution)的启发,对相关性进行了约束,强行要求每个元素只跟它相对距离为 $k, 2k, 3k,...$ 的元素关联,其中 $k \gt 1$ 是预先设定的超参数。从上左子图的注意力矩阵看,就是强行要求相对距离不是 $k$ 的倍数的位置的注意力为0(图中白色代表0)。

在这种方法下,实际每个元素都只跟大约 $\frac{n}{k}$ 个元素算相关性,这样运行效率和显存占用都变成了 $O(n^2/k)$ ,也就是说能直接降低到原来的 $\frac{1}{k}$ 。

稀疏Attention-Local Self Attention

Local self-attention

在计算机视觉领域,自注意力机制一直被统称为“Non Local”,与之相对的Local Self Attention就是放弃了全局的元素关联,重新引入局部关联。在实际处理上,就是约束每个元素只与前后 $k$ 个元素以及自身有关联。从上左子图的注意力矩阵来看,就是相对距离超过 $k$ 的注意力都直接设为0。实际而言,Local Self Attention和普通卷积很像,都保留了 $2k+1$ 大小的窗口,然后在窗口内进行一些运算。区别只是普通卷积是把窗口展平然后接一个全连接层得到输出,现在是窗口内通过注意力来加权平均得到输出。

在这种方法下,实际每个元素都只跟 $2k+1$ 个元素算相关性,这样一来理想情况下运行效率和显存占用都变成了 $O((2k+1)n) \backsim O(kn)$ ,也就是说随着 $n$ 而线性增长,不过这个方法牺牲了长程关联性。

稀疏Attention-Sparse Self Attention

Sparse self-attention

Sparse Self Attention是对Local Self Attention和Atrous Self Attention的交替使用,两者累积起来,理论上也是能学习到全局关联性的,同时还节省了显存。从上左子图的注意力矩阵来看,就是除了相对距离不超过 $k$ 的、相对距离为 $k, 2k, 3k,...$ 的注意力都直接设为0。如此一来,Attention就具有“局部紧密相关和远程稀疏相关”的特性。

稀疏Attention-Longformer

不同注意力计算方式下的注意力矩阵

Longformer针对上图(a)的经典self attention进行改进,提出了Sliding Window Attention(滑窗机制,图b,类似Local Attention)、Dilated Sliding Window(空洞滑窗机制,图c)和Global+sliding window(融合全局信息的滑窗机制,图d)。

稀疏Attention-StreamingLLM

不同注意力范围的注意力矩阵

根据StreamLLM的实验分析,对于上图(b)的Window Attention而言,其会缓存最近的 $L$ 个token的KV,但是一旦开头的token的KV被驱逐出Cache,模型推理的表现就会急剧下降。为解决这个问题的一个优化是图(c)的重算方法,让Window Attention重新计算,从每个新token的 $L$ 最近token中重建KV Cache。虽然这个方法在长文本上表现良好,但是由于上下文重新计算中的二次注意力计算,导致时间复杂度为 $O(TL^2)$ ,计算速度相当慢。

经过进一步的分析,发现了如下现象:

注意力热力图

基于上图对于Attention的观察,StreamingLLM提出了“attention sink”的概念来解释了Window Attention失败的原因:输入给LLM推理开头的几个initial tokens是非常特殊的,类似水池的排水口,吞噬了大量的attention。同时intial tokens与被预测token的距离如何,语义信息是什么都不重要,重要的只是它的绝对位置。也就是说前几个位置上的token不管是啥,对维持LLM推理的稳定性都很关键。

补充:attention sink出现的原因(一种解释)

在Attention机制中,Softmax的输出代表了key/query的匹配程度的概率。如果softmax在某个位置的值非常大,那么在反向传播时,这个位置的权重就会大幅度地更新。但是有时候attention并不确定哪个位置更值得关注,不过因为softmax需要所有位置的值的和为1,因此必须给某些位置较大的权重,这就可能导致错误的权重更新,这个错误在后续的过程中也很难被纠正。

对此,Evan Miller发表了一篇博客《Attention Is Off by One》,在博客中他解释了这个softmax带来的问题,并提出了一个改进softmax的方法:通过给softmax的分母加1,让所有位置值可以加和不为1,从而给予Attention可以不对任何位置“表态”的权利。

$$(softmax_1(x))_i = \frac{exp(x_i)}{1+\sum_jexp(x_j)}$$

StreamingLLM在这个观点的基础上进一步认为,模型倾向于将不必要的注意力值转嫁给特定的token,而这些token就是初始token。

基于上述的观察研究,StreamingLLM设计了Window Attention的改进版,其在当前滑动窗口方法基础上,重新引入了一些初始token的kv在注意力计算中使用。由此,StreamingLLM中的KV缓存可以分为两个部分:

StreamingLLM的计算示例

此外,还是用了一些小改动来给attention注入位置信息,从而使得StreamingLLM可以无缝地融入任何使用相对位置编码的自回归语言模型,如RoPE和ALiBi。通过上述办法,StreamingLLM不需要做训练,只用把初始token设置为4就可以获得不错的长输入下的推理表现。

如果解除不训练模型的限制,通过Pre-training LLMs with attention sinks可以获得更好的表现。作者提出了两种方法:

投机采样

投机采样的核心思想:并非所有token的生成都很难,前面几个token的生成相对比较容易,可以使用小模型代劳,从而让小模型先生成一部分token再由大模型验证。

投机采样的特点:投机采样并不会改变模型结构,而是通过让decoding阶段可以并发提高计算效率。

投机采样的流程(假设有一个和大模型近似的小模型):

这个投机采样的算法流程虽然看起来像是一个近似算法,但是它实际上是数学完备的,可以保证最终输出的结果和直接使用大模型推理的结果严格一致。本质上来说投机采样是利用了大模型推理n个token需要推理n次,而验证结果只需要推理1次的思想。

一种理解方式:投机采样采用了一个原始目标模型和一个比原始模型小的多的近似模型,近似模型用于进行自回归串行采样,而原始目标模型用于评估采样结果。在解码过程中,某些token的解码相对容易,可以交给小模型处理,而有些token的解码很困难,交给大模型处理。这里的小模型可以采用与原始模型相同的结构,但参数更少,从而让计算量更小,而且减少了内存访问的需求。

参考笔记

LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale论文解读https://fancyerii.github.io/2024/01/16/int8/

模型量化 Quantization https://banxian-w.com/article/2024/9/11/2772.html#4.2%20GPTQ%20-%204%20%E4%BD%8D%E9%9D%9E%E5%AF%B9%E7%A7%B0%20PTQ

GPTQ: 模型量化,穷鬼救星 https://zhuanlan.zhihu.com/p/616969812

大模型量化技术原理-LLM.int8()、GPTQ https://blog.csdn.net/scgaliguodong123_/article/details/136176382

LLM(十一):大语言模型的模型量化(INT8/INT4)技术 https://zhuanlan.zhihu.com/p/627436535

大语言模型推理加速技术:模型压缩篇 https://zhuanlan.zhihu.com/p/667455383

大语言模型量化相关技术 https://zhuanlan.zhihu.com/p/664054739

理解Attention:从起源到MHA,MQA和GQA https://zhuanlan.zhihu.com/p/686149289

Attention进阶史(MHA,MQA,GQA,MLA)https://www.gnn.club/?p=2729

为节约而生:从标准Attention到稀疏Attention https://mp.weixin.qq.com/s?__biz=MzIwMTc4ODE0Mw==&mid=2247498604&idx=1&sn=178bcb8827162a58a04d4ac131d03408&chksm=96ea24eca19dadfa27b5bedb58ddd0d6924d4b9e410bb523636e1a7834dd0f5cdb5ec7a2e45b&mpshare=1&scene=1&srcid=1211xlsVVTWl8oBM0HEjlwk6&sharer_sharetime=1607702340523&sharer_shareid=6de0f8e01e8c0625eda8ab4e997af088&key=ec5faba1391b624a81f012ed8c2d4d2434a6abbc0262b3172078a063493c8bf9482ca39875577a46da3b18bb8d4b315fc95b59b1d88414ef92efc739e62158b8f0392dec87c4a8d6d42f8512e548cb6aa9d9cd2f722275a30a40711f6aa8d0c170cd2d5c320dfaeb89575fca886e972106a20736944c8da7cb0e321515d86f91&ascene=1&uin=MjAwMzE0NjU0NQ%3D%3D&devicetype=Windows+10+x64&version=62090070&lang=zh_CN&exportkey=AUNZm11axeAFWi9%2BGO9u4lk%3D&pass_ticket=4YK02S64Ga8SiOQnwW2CZhb8lPVQDw9ZQhTUlcfnYY5e6IvbQAiTI%2FVap96j5Xy9&wx_header=0

一文看懂什么是Longformer https://zhuanlan.zhihu.com/p/405317918

LLM推理技术之StreamingLLM:如何拥有无限生成能力 https://zhuanlan.zhihu.com/p/659875511

缓存与效果的极限拉扯:从MHA、MQA、GQA到MLA https://kexue.fm/archives/10091