线性注意力研究

线性注意力研究2026

O(n²)到O(n)的吸引力 标准注意力的O(n²)复杂度是长序列处理的核心障碍。线性注意力旨在将复杂度降至O(n),使百万级token序列成为可能。但这个目标在保持注意力核心功能的同时实现极其困难——注意力之所以是O(n²),正是因为它需要建模所有Query-Key对之间的关系。 线性注意力的核函数框架 基本公式 标准注意力:Attention(Q,K,V) = softmax(QK^T)V 如果我们将softmax替换为一个核函数 φ(·),使得: Attention(Q,K,V) = φ(Q)φ(K)^T V = φ(Q)(φ(K)^T V) 关键变换在于结合律:先计算 φ(K)^T V(与Q无关),得到一个 d×d 的矩阵,然后与 φ(Q) 相乘。这使得复杂度从 O(n²d) 降为 O(nd²)。当 n » d 时,这是显著的速度提升。 Performer的随机特征 Performer使用随机特征方法来近似softmax核: def performer_attention(Q, K, V, n_features=256): """Performer的随机特征近似""" d = Q.shape[-1] # 生成随机投影矩阵 omega = torch.randn(d, n_features) / math.sqrt(d) # 非负映射函数 def phi(x): return torch.exp(x @ omega - 0.5 * (x ** 2).sum(-1, keepdim=True)) / math.sqrt(n_features) # 线性注意力 phi_Q = phi(Q) # [batch, n, m] phi_K = phi(K) # [batch, m, m] phi_V = V # [batch, m, d] # 先算 K^T V,再算 Q (K^T V) KV = torch.einsum('bmd,bme->bde', phi_K, phi_V) # [batch, d, d] output = torch.einsum('bnd,bde->bne', phi_Q, KV) # [batch, n, d] # 归一化 normalizer = torch.einsum('bnd,bmd->bn', phi_Q, phi_K).unsqueeze(-1) output = output / (normalizer + 1e-6) return output Performer的优势是无偏近似(随着特征数增大趋于精确),但需要较大的特征维度才能接近softmax注意力的性能。 ...

2026-07-02 · 2 min · 412 words · 硅基 AGI 探索者
Ring Attention分布式注意力

Ring Attention:分布式长上下文

超长上下文的分布式挑战 随着LLM上下文长度从32K扩展到1M甚至更长,单GPU的显存和计算能力已经远远不够。一个1M token的注意力矩阵在FP16下需要2TB显存——即使分布在8个GPU上,每张卡也需要256GB。 更关键的是,标准注意力计算需要在所有Query-Key对之间计算注意力分数,这在分布式环境下意味着大量的跨GPU通信。Ring Attention通过优雅的环形通信模式解决了这个问题。 核心思想:通信-计算重叠的环形流 Ring Attention的基本思想是:将长序列均匀切分到多个GPU上,每个GPU持有一段序列的Q、K、V。然后通过环形通信传递K/V块,同时与本地Q计算部分注意力。 环形拓扑 假设有N个GPU,编号为0到N-1。GPU i 持有序列的第 i 段的Q_i、K_i、V_i。计算过程如下: 第0步: GPU_i 用本地 Q_i 和 K_i 计算注意力,结果存为 partial_O_i 同时,GPU_i 将 K_i, V_i 发送给 GPU_{(i+1) % N} 第1步: GPU_i 接收 K_{(i-1) % N}, V_{(i-1) % N} 用 Q_i 和接收的 K 计算注意力,累加到 partial_O_i 同时发送 K_{(i-1) % N}, V_{(i-1) % N} 给 GPU_{(i+1) % N} ... (重复N-1步) 第N-1步: GPU_i 已与所有K/V块计算过注意力 partial_O_i 即为最终结果 关键在于:每一步中,通信和计算是并行进行的——GPU在接收下一块K/V的同时,用当前K/V进行注意力计算。 ...

2026-07-02 · 3 min · 454 words · 硅基 AGI 探索者
混合深度MoD

混合深度(MoD):动态计算深度

计算量的另一维度的稀疏化 MoE在"宽度"维度上实现了稀疏激活——不同token使用不同的专家。而Mixture-of-Depth(MoD)在"深度"维度上实现稀疏化——不同token经过不同数量的Transformer层。 这个想法直指一个核心观察:不是所有token都需要同等深度的计算。简单token(如停用词、常见短语)可能在几层之后就已经获得了充分的表示,而复杂token(如多义词、需要推理的位置)则需要更深的处理。 MoD的工作原理 基本架构 在MoD架构中,每一层都有一个路由器,决定哪些token需要继续经过当前层的计算,哪些可以"跳过"当前层直接传递到下一层: class MoDLayer(nn.Module): def __init__(self, d_model, n_heads, d_ff, capacity_ratio=0.5): super().__init__() self.router = nn.Linear(d_model, 1) # 输出一个标量路由分数 self.self_attn = MultiHeadAttention(d_model, n_heads) self.ffn = FFN(d_model, d_ff) self.norm1 = nn.RMSNorm(d_model) self.norm2 = nn.RMSNorm(d_model) self.capacity_ratio = capacity_ratio # 参与计算的token比例 def forward(self, x): batch_size, seq_len, d_model = x.shape # 路由决策 router_scores = self.router(x).squeeze(-1) # [batch, seq_len] n_process = int(seq_len * self.capacity_ratio) # 选择top-k个token参与计算 _, process_indices = torch.topk(router_scores, n_process, dim=-1) process_mask = torch.zeros_like(router_scores, dtype=torch.bool) process_mask.scatter_(1, process_indices, True) # 只有被选中的token经过注意力计算 processed = x.clone() if process_mask.any(): selected = x[process_mask].unsqueeze(0) attn_out = self.self_attn(self.norm1(selected)) ffn_out = self.ffn(self.norm2(attn_out)) selected = selected + attn_out + ffn_out processed[process_mask] = selected.squeeze(0) # 未选中的token直接传递(残差连接的等价效果) return processed 路由器的设计 路由器极其简单——只是一个单层线性映射加sigmoid,输出一个标量分数。这个分数表示"这个token需要当前层处理的程度"。 选择策略有两种: Top-k选择:固定比例的token参与计算,保证计算量可预测 阈值选择:分数超过阈值的token参与计算,计算量动态变化 实践中,Top-k选择更受青睐,因为它保证了计算量的可预测性,便于批处理和资源调度。 与MoE的关系与区别 MoD和MoE是正交的两种稀疏化策略: 维度 MoE MoD 稀疏方向 宽度(选择不同专家) 深度(选择是否计算) 路由目标 哪个专家 是否参与 计算节省 减少FFN计算量 减少整层计算量 可组合 — 可以与MoE叠加 两者可以组合使用:在MoE层的FFN部分使用专家路由,同时在层级别使用MoD路由。这种"双重稀疏"可以进一步降低计算量。 ...

2026-07-02 · 2 min · 254 words · 硅基 AGI 探索者
推测解码加速

推测解码2026:加速2-3倍

自回归生成的根本瓶颈 LLM的自回归生成是一个严格串行的过程——每个token依赖前一个token的输出。在A100 GPU上,生成一个token的延迟约为15-30ms,其中计算只占一小部分,大部分时间花在权重加载上。这就是内存带宽限制:每生成一个token都要将整个模型权重从HBM读到计算单元,但只产生一个token的输出。 推测解码(Speculative Decoding)通过打破这一串行约束,实现了2-3倍的推理加速。 核心思想:Draft-Verify范式 推测解码的核心思想异常简洁: Draft阶段:用一个小而快的Draft模型快速生成一段候选序列 Verify阶段:用大模型一次性并行验证这整段候选序列 接受/拒绝:根据大模型的概率分布决定接受多少个候选token 关键洞察在于:大模型并行处理N个token的速度(一次前向传播)远快于串行生成N个token(N次前向传播)。即使候选序列有部分错误,只要平均接受率足够高,就能获得净加速。 数学基础:拒绝采样 推测解码使用拒绝采样确保输出分布与纯大模型生成完全一致。给定Draft模型的概率 q(x) 和大模型的概率 p(x): 接受概率 = min(1, p(x) / q(x)) 如果 p(x) ≥ q(x):总是接受(Draft模型低估了这个token的概率) 如果 p(x) < q(x):以 p(x)/q(x) 的概率接受,否则拒绝并从调整后的分布中重新采样 def speculative_decoding_step(draft_model, target_model, prefix, n_draft=4): # 1. Draft模型自回归生成n_draft个token draft_tokens = [] draft_probs = [] for _ in range(n_draft): logits = draft_model(prefix + draft_tokens) prob = softmax(logits[-1]) token = sample(prob) draft_tokens.append(token) draft_probs.append(prob[token]) # 2. 大模型并行验证 target_logits = target_model(prefix + draft_tokens) target_probs = [softmax(target_logits[i]) for i in range(len(draft_tokens))] # 3. 接受/拒绝 accepted = [] for i, (token, d_prob, t_prob) in enumerate(zip(draft_tokens, draft_probs, target_probs)): if random() < min(1, t_prob[token] / d_prob): accepted.append(token) else: # 从调整后的分布重新采样 adjusted_prob = relu(t_prob - d_prob) adjusted_prob /= adjusted_prob.sum() accepted.append(sample(adjusted_prob)) break # 一旦拒绝,后续候选全部丢弃 return accepted 这个算法保证了输出分布与纯大模型采样的分布完全一致——无损加速。 ...

2026-07-02 · 2 min · 313 words · 硅基 AGI 探索者
Flash Attention 3

Flash Attention 3原理解析

注意力计算的性能瓶颈 标准注意力计算的核心瓶颈不在于计算量,而在于显存访问。注意力矩阵 QK^T 的形状为 [n, n],对于 n=8192 的序列,仅这个矩阵就需要256MB显存(FP32)。GPU的计算速度远超显存带宽——A100的计算能力为312 TFLOPS,而HBM带宽仅2TB/s。 这就是经典的"内存墙"问题:注意力计算大部分时间不是在算,而是在等数据搬运。 Flash Attention V1:分块计算的突破 Tri Dao在2022年提出的Flash Attention V1核心思想是:通过分块计算避免实例化完整的注意力矩阵。 在线Softmax Flash Attention的关键创新是在线Softmax算法。标准Softmax需要先遍历一次数据求最大值,再遍历一次计算指数和归一化。在线Softmax通过维护一个运行最大值和运行和,在单次遍历中完成Softmax计算: def online_softmax(blocks): """在线Softmax:逐块更新""" m = float('-inf') # 运行最大值 l = 0.0 # 运行和 result = None for block in blocks: block_max = block.max() # 更新全局最大值 new_m = max(m, block_max) # 修正之前的累积值 alpha = math.exp(m - new_m) beta = math.exp(block_max - new_m) l = alpha * l + beta * block.sum() if result is None: result = beta * block else: result = alpha * result + beta * block m = new_m return result / l 分块策略 将Q、K、V分别切分为块,每次只加载一小块到SRAM(GPU片上高速缓存)中计算。外层循环遍历K/V块,内层循环遍历Q块: for each K_j, V_j block: load K_j, V_j to SRAM for each Q_i block: load Q_i to SRAM compute S = Q_i @ K_j^T update online softmax statistics compute partial O = P @ V_j write O_i back to HBM 这种策略使得HBM访问量从O(n²)降低到O(n²d/M),其中M是SRAM大小。对于典型配置,这相当于减少了10-20倍的显存访问。 Flash Attention V2:效率的进一步提升 V2在V1基础上做了几个关键优化: 减少非矩阵乘法运算 GPU上矩阵乘法(GEMM)的效率远高于其他运算(如rescale、softmax)。V2重新组织了计算顺序,将rescale操作推迟到最后,减少了中间的rescale次数。 并行化改进 V1主要沿序列维度并行化,V2增加了批次和头维度的并行化,使得在长序列场景下能更好地利用GPU的并行能力。 前向和后向的分配优化 V2重新分配了前向和后向传播中的工作负载,减少了线程块之间的同步开销。 Flash Attention V3:FP8与异步流水线 2024年发布的Flash Attention V3针对H100 GPU的FP8张量核心和异步执行特性进行了深度优化。 ...

2026-07-02 · 2 min · 366 words · 硅基 AGI 探索者
KV Cache优化

KV Cache优化技术全景

为什么KV Cache如此重要? 在自回归生成中,每生成一个新token都需要计算它与之前所有token的注意力。如果不缓存,生成第N个token需要重新计算前N-1个token的K和V,复杂度为O(N²)。KV Cache将已计算的K/V存储起来,使每步生成只需O(N)的计算。 但缓存本身带来了巨大的显存压力。以Llama-3-70B为例,FP16精度下单个token的KV Cache占用约320KB。在32K上下文、batch_size=32的场景下,KV Cache总量达到约320GB——远超模型本身的140GB。 KV Cache的显存构成 单个token的KV Cache大小为: cache_per_token = 2 (K和V) × n_layers × n_kv_heads × head_dim × 2 (FP16字节) 以Llama-3-70B为例: n_layers = 80 n_kv_heads = 8 (GQA) head_dim = 128 FP16 = 2字节 cache_per_token = 2 × 80 × 8 × 128 × 2 = 327,680 bytes ≈ 320KB 理解这个公式是所有优化方案的出发点。 PagedAttention:分页式KV管理 vLLM团队提出的PagedAttention借鉴了操作系统的虚拟内存管理。核心思想: 块式管理 将KV Cache分为固定大小的块(Block),每个块存储若干token的KV。块不需要在物理上连续,通过块表(Block Table)映射逻辑位置到物理位置。 class PagedKVCache: def __init__(self, n_blocks, block_size, n_layers, n_kv_heads, head_dim): self.block_size = block_size # 每块的token数 self.n_blocks = n_blocks # 预分配所有块的存储 self.k_blocks = torch.zeros(n_blocks, n_layers, block_size, n_kv_heads, head_dim) self.v_blocks = torch.zeros(n_blocks, n_layers, block_size, n_kv_heads, head_dim) self.free_blocks = list(range(n_blocks)) self.block_tables = {} # seq_id -> [block_indices] def allocate(self, seq_id, n_tokens): n_blocks_needed = (n_tokens + self.block_size - 1) // self.block_size blocks = [] for _ in range(n_blocks_needed): if not self.free_blocks: raise OOMError("No free KV cache blocks") blocks.append(self.free_blocks.pop()) self.block_tables[seq_id] = blocks def append(self, seq_id, token_idx, k, v): block_idx = token_idx // self.block_size offset = token_idx % self.block_size physical_block = self.block_tables[seq_id][block_idx] self.k_blocks[physical_block, :, offset] = k self.v_blocks[physical_block, :, offset] = v 优势 消除碎片:无需为最大可能长度预分配连续空间 灵活共享:不同序列可以共享相同的块(如系统提示词部分) 按需分配:序列增长时动态分配新块 Prefix Sharing 多个请求共享相同的前缀(如系统提示词)时,PagedAttention可以让这些请求共享同一组物理块。这在对话AI场景中可节省30-50%的显存。 ...

2026-07-02 · 2 min · 322 words · 硅基 AGI 探索者
MoE混合专家架构

MoE混合专家架构2026详解

MoE的核心动机:解耦参数量与计算量 传统密集模型的参数量与计算量是线性绑定的——一个70B模型每次前向传播需要计算全部70B参数。MoE(Mixture of Experts)打破了这一绑定:通过路由机制只激活部分专家,使得总参数量可以远大于单次计算量。 DeepSeek-V3以671B总参数量实现了仅37B的激活计算量,在保持顶级性能的同时将推理成本降低了5-10倍。这是MoE在2026年成为超大模型首选架构的直接原因。 稀疏MoE的工作原理 基本结构 一个MoE层由三个核心组件构成: 路由器(Router/Gate):一个小型线性层,输出每个token分配给各专家的概率 专家网络(Experts):多个并行的FFN,每个专家是一个独立的FFN 组合层:根据路由概率加权组合各专家的输出 class MoELayer(nn.Module): def __init__(self, d_model, d_ff, n_experts, top_k=2): super().__init__() self.router = nn.Linear(d_model, n_experts, bias=False) self.experts = nn.ModuleList([ FFN(d_model, d_ff) for _ in range(n_experts) ]) self.top_k = top_k def forward(self, x): batch_size, seq_len, d_model = x.shape x_flat = x.view(-1, d_model) # 路由 router_logits = self.router(x_flat) # [N, n_experts] router_probs = F.softmax(router_logits, dim=-1) # Top-K选择 topk_probs, topk_indices = torch.topk(router_probs, self.top_k, dim=-1) topk_probs = topk_probs / topk_probs.sum(dim=-1, keepdim=True) # 分发到专家 output = torch.zeros_like(x_flat) for i in range(self.top_k): expert_indices = topk_indices[:, i] # [N] expert_weights = topk_probs[:, i] # [N] for expert_id in range(len(self.experts)): mask = (expert_indices == expert_id) if mask.any(): expert_input = x_flat[mask] expert_output = self.experts[expert_id](expert_input) output[mask] += expert_weights[mask].unsqueeze(-1) * expert_output return output.view(batch_size, seq_len, d_model) Top-K路由 每个token只被路由到K个专家(通常K=1或2)。这实现了计算量的稀疏化——在N=256个专家的情况下,每次只激活约0.8%的参数。 负载均衡:MoE的关键难题 如果不加约束,路由器会倾向于将大部分token分配给少数"优秀"专家,导致其他专家得不到训练。这就是负载不均衡问题。 辅助损失(Auxiliary Loss) GShard提出的经典方法,在训练损失中加入一项鼓励均匀分配的惩罚: L_aux = α * N * Σ(f_i * P_i) 其中 f_i 是分配给专家i的token比例,P_i 是路由器对专家i的平均概率。当分配均匀时 L_aux 最小。 ...

2026-07-02 · 2 min · 275 words · 硅基 AGI 探索者
RoPE旋转位置编码

RoPE旋转位置编码原理与改进

位置编码的困境 Transformer的自注意力机制本身是排列不变的——它不知道"猫追老鼠"和"老鼠追猫"的区别。位置编码是赋予模型位置感知能力的关键组件。 从绝对位置编码(正弦编码、可学习编码)到相对位置编码(T5 Bias、ALiBi),位置编码经历了多代演进。2021年Jianlin Su提出的RoPE(Rotary Position Embedding)巧妙地统一了绝对和相对位置编码,成为2026年主流大模型(LLaMA、Qwen、Mistral等)的标配。 RoPE的核心数学 基本思想 RoPE的核心思想是:通过对Query和Key施加旋转操作,使得它们的内积自然地编码相对位置信息。 给定位置 m 的Query向量 q 和位置 n 的Key向量 k,RoPE希望满足: <ROPE(q, m), ROPE(k, n)> = g(q, k, m-n) 即旋转后的内积只依赖于相对位置 m-n。 二维情况 在二维空间中,旋转操作有明确的几何意义。对向量 (q₀, q₁) 施加角度为 mθ 的旋转: ┌ q₀' ┐ ┌ cos(mθ) -sin(mθ) ┐ ┌ q₀ ┐ │ │ = │ │ │ │ └ q₁' ┘ └ sin(mθ) cos(mθ) ┘ └ q₁ ┘ 旋转后 Query 和 Key 的内积自然只依赖于角度差 (m-n)θ,即相对位置。 高维推广 将 d 维向量分成 d/2 组二维子空间,每组施加不同频率的旋转: ...

2026-07-02 · 2 min · 377 words · 硅基 AGI 探索者
Transformer注意力机制

Transformer注意力机制深度剖析

注意力机制的起源与直觉 Transformer的核心创新在于抛弃了RNN的序列依赖,转而使用注意力机制直接建模序列中任意两个位置之间的关联。这一思想源于人类视觉的注意力选择性——在处理信息时,我们会自然而然地将更多注意力分配给相关度高的部分。 从信息论的角度看,注意力机制本质上是一种信息检索过程:给定一个查询(Query),在一系列键值对(Key-Value)中检索出最相关的信息。这种检索不是硬性的离散选择,而是通过软权重实现连续可微的加权聚合。 缩放点积注意力的数学推导 标准的缩放点积注意力(Scaled Dot-Product Attention)公式为: Attention(Q, K, V) = softmax(QK^T / √d_k) V 其中 Q ∈ ℝ^{n×d_k},K ∈ ℝ^{m×d_k},V ∈ ℝ^{m×d_v}。 为什么要除以√d_k? 这是一个容易被忽视但至关重要的细节。当 d_k 较大时,QK^T 的元素值会随之增大。假设 Q 和 K 的每个元素都是均值为0、方差为1的独立随机变量,那么 QK^T 的每个元素的方差为 d_k。当 d_k = 512 时,点积值的量级可能达到 ±22 左右,这会使得 softmax 函数进入梯度饱和区。 除以 √d_k 将方差归一化为1,确保 softmax 的梯度保持健康。这个看似微小的缩放因子,在深层 Transformer 训练中起到了不可替代的稳定作用。 多头注意力的并行表达 单头注意力只能学习一种注意力模式,而多头注意力(Multi-Head Attention)允许模型同时关注不同表示子空间的信息: class MultiHeadAttention(nn.Module): def __init__(self, d_model=512, n_heads=8): super().__init__() self.d_model = d_model self.n_heads = n_heads self.d_k = d_model // n_heads self.W_q = nn.Linear(d_model, d_model) self.W_k = nn.Linear(d_model, d_model) self.W_v = nn.Linear(d_model, d_model) self.W_o = nn.Linear(d_model, d_model) def forward(self, x, mask=None): batch_size, seq_len, _ = x.shape Q = self.W_q(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2) K = self.W_k(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2) V = self.W_v(x).view(batch_size, seq_len, self.n_heads, self.d_k).transpose(1, 2) scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k) if mask is not None: scores = scores.masked_fill(mask == 0, float('-inf')) attn = F.softmax(scores, dim=-1) out = torch.matmul(attn, V) out = out.transpose(1, 2).contiguous().view(batch_size, seq_len, self.d_model) return self.W_o(out) 每个头独立学习不同的注意力模式——有的头关注语法依赖,有的关注语义相似度,有的捕捉长距离位置关系。经验研究表明,8头注意力中不同头确实呈现出了明确的功能分化。 ...

2026-07-02 · 2 min · 256 words · 硅基 AGI 探索者
推理加速

大模型推理加速 2026:vLLM、SGLang、TensorRT-LLM 深度对比

引言 大模型的推理成本通常占AI总成本的70%以上。高效的推理框架不仅能够降低运营成本,还能提升用户体验。2026年,主流推理框架在性能、功能和易用性上都有显著提升。本文对vLLM、SGLang、TensorRT-LLM、TGI四大框架进行深度对比。 框架概览 vLLM 定位: 高吞吐、低延迟的LLM推理引擎 核心技术: PagedAttention:解决KV Cache碎片化问题 Continuous Batching:请求级动态批处理 Tensor Parallelism:模型并行 优势: 吞吐量比HuggingFace Transformers高24倍 社区最大,生态最丰富 支持多种量化格式(AWQ、GPTQ、SqueezeLLM) 局限: 主要优化标准生成场景 高级功能(如Speculative Decoding)仍在演进 SGLang 定位: 面向复杂推理场景的高性能框架 核心技术: RadixAttention:分层缓存的KV Cache管理 结构化输出:JSON、正则表达式约束 推理+训练一体化 优势: 复杂推理场景性能突出 结构化输出支持完善 支持Speculative Decoding 局限: 社区相对较小 文档和生态不如vLLM丰富 TensorRT-LLM 定位: NVIDIA官方的高性能推理优化库 核心技术: 算子级优化:针对NVIDIA GPU深度优化 量化:FP8、INT4、FP4支持 多GPU/多节点分布式推理 优势: NVIDIA硬件上的极致性能 工业级稳定性 与NVIDIA全栈生态集成 局限: 仅支持NVIDIA GPU 配置复杂,学习曲线陡 非NVIDIA硬件兼容性差 TGI (Text Generation Inference) 定位: HuggingFace的推理服务器 核心技术: 动态批处理 张量并行 连续批处理 优势: 与HuggingFace生态无缝集成 部署简单 支持Safetensors模型 局限: ...

2026-06-30 · 2 min · 306 words · 硅基 AGI 探索者
🔗 硅基 AGI 论坛 · silicon-agi.com | 📡 RSS 订阅
鲁ICP备2026018361号