第2章:新型架构探索 (New Architectures)#
本章定位:打破 Transformer 的垄断。我们将深入 DeepSeek 和 Mixtral 及其背后的 MoE (混合专家) 技术,并探索挑战 Attention 机制的 SSM (Mamba) 架构。这也是 DeepSeek-V3 能在极低成本下训练出来的核心秘密。
目录#
1. 混合专家模型 (MoE) 深度解析#
1.1 稀疏激活:从 Dense 到 Sparse#
传统 Transformer 是 Dense (稠密) 的:每个 Token 都要经过模型的所有参数计算。 MoE 是 Sparse (稀疏) 的:
- 模型包含 $N$ 个专家(Experts,通常是 FFN 层)。
- 每个 Token 只激活其中的 $k$ 个专家(例如 8 个专家里选 2 个)。
收益:
- 训练/推理成本:只取决于激活专家的参数量(Active Params)。
- 模型容量:取决于总参数量(Total Params)。
- 结论:用极低的计算量(如 7B 级别)享受到极大模型(如 50B 级别)的知识容量。
1.2 核心组件:Router (Gate) 原理#
Router 决定每个 Token 去哪个专家。最常用的是 Top-K Gating。
$$ h(x) = \text{Softmax}(x \cdot W_g) $$ $$ \text{Gate}(x) = \text{TopK}(h(x), k) $$
Token $x$ 最终的输出是选定专家的加权和: $$ y = \sum_{i \in \text{TopK}} h(x)_i \cdot E_i(x) $$
1.3 负载均衡与辅助损失 (Aux Loss)#
问题:Router 可能会“偷懒”,把所有 Token 都发给同一个专家(导致该专家过载,其他专家闲置)。这叫 Router Collapse。
解决方案:引入辅助损失 (Auxiliary Loss) 惩罚负载不均。 $$ \mathcal{L}{aux} = \alpha \cdot N \cdot \sum{i=1}^N f_i \cdot P_i $$
- $f_i$: 分配给专家 $i$ 的 Token 比例。
- $P_i$: 专家 $i$ 被选中的平均概率。
- 目标是让每个专家处理的数据量尽量均匀。
1.4 实战:手写一个 MoE Layer#
import torch
import torch.nn as nn
import torch.nn.functional as F
class MoELayer(nn.Module):
def __init__(self, hidden_dim, num_experts, top_k):
super().__init__()
self.num_experts = num_experts
self.top_k = top_k
# 1. 门控网络 (Router)
self.gate = nn.Linear(hidden_dim, num_experts)
# 2. 专家网络 (这里用简单的 Linear 模拟 MLP)
self.experts = nn.ModuleList([
nn.Linear(hidden_dim, hidden_dim) for _ in range(num_experts)
])
def forward(self, x):
# x: [batch, seq, dim]
batch, seq, dim = x.shape
x_flat = x.view(-1, dim)
# 1. 计算路由概率
logits = self.gate(x_flat) # [total_tokens, num_experts]
probs = F.softmax(logits, dim=-1)
# 2. 选出 Top-K 专家
# indices: [total_tokens, top_k] (专家的 ID)
# weights: [total_tokens, top_k] (路由权重)
weights, indices = torch.topk(probs, self.top_k, dim=-1)
# 归一化权重 (让选中的 k 个权重之和为 1)
weights = weights / weights.sum(dim=-1, keepdim=True)
# 3. 专家计算 (这里用循环模拟,实际用 CUDA Kernel 优化)
final_output = torch.zeros_like(x_flat)
for i in range(self.num_experts):
# 找到分配给专家 i 的 token
# mask: [total_tokens, top_k]
mask = (indices == i)
# batch_idx, k_idx: 哪些 token 的第几个选择是专家 i
batch_idx, k_idx = torch.where(mask)
if len(batch_idx) == 0:
continue
# 提取输入
expert_input = x_flat[batch_idx]
# 专家前向传播
expert_output = self.experts[i](expert_input)
# 加权累加回输出
# weights[batch_idx, k_idx]: 对应的路由权重
scale = weights[batch_idx, k_idx].unsqueeze(-1)
final_output.index_add_(0, batch_idx, expert_output * scale)
return final_output.view(batch, seq, dim)
# 测试
moe = MoELayer(hidden_dim=128, num_experts=8, top_k=2)
x = torch.randn(2, 10, 128)
out = moe(x)
print(f"Input: {x.shape}, Output: {out.shape}")2. DeepSeek-V3 核心:MLA (Multi-Head Latent Attention)#
核心价值:DeepSeek-V3 相比传统 Llama 架构,节省了 98.4% 的 KV Cache 显存。这是它能由极其“廉价”的成本提供高性能服务的关键。
2.1 KV Cache 的显存瓶颈#
在传统 MHA (Multi-Head Attention) 中,每个 Token 都需要存储完整的 K 和 V 矩阵: $$ \text{Cache} = 2 \times \text{Layers} \times \text{Heads} \times \text{HeadDim} $$ 对于一个 70B 模型,128k 上下文,仅 KV Cache 就要占用 100GB+ 显存!这导致必须堆显卡。
2.2 MLA 原理:低秩压缩#
MLA 认为 K 和 V 矩阵存在大量冗余(Low Rank)。它不直接存储 K 和 V,而是存储一个压缩的潜在向量 (Latent Vector) $C_{KV}$。
公式推导:
- 压缩 (Down-projection): $$ C_{KV} = X \cdot W_{Down} $$ $C_{KV}$ 的维度 $d_c$ (如 512) 远小于原始 KV 维度 (如 128头 $\times$ 128维 = 16384)。
- 存储: KV Cache 只存 $C_{KV}$。
- 解压 (Up-projection): 推理计算 Attention 时,临时恢复成 K 和 V: $$ K = C_{KV} \cdot W_{UpK} $$ $$ V = C_{KV} \cdot W_{UpV} $$
2.3 显存节省计算案例#
以 DeepSeek-V3 配置为例:
- Heads = 128, HeadDim = 128
- MHA 存储维度 = $128 \times 128 = 16384$
- MLA 压缩维度 $d_c = 512$
$$ \text{压缩比} = \frac{512}{16384} \approx 3% $$
结论:MLA 只需要传统 MHA 3% 的显存。这使得单机可以跑超长上下文,或者支持极大并发 (Batch Size)。
3. 状态空间模型 (SSM) 与 Mamba#
3.1 线性复杂度:O(N) vs O(N^2)#
- Transformer: Attention 机制需要两两计算相似度,复杂度是序列长度的平方 $O(N^2)$。长文训练极慢。
- RNN: 只能看上一步,无法并行训练。
- Mamba (SSM): 结合了 RNN 的推理效率 (O(1)) 和 Transformer 的并行训练能力。
3.2 选择性机制 (Selection Mechanism)#
Mamba 的核心创新是选择性地遗忘和记忆。 它引入了随输入 $x_t$ 变化的参数 $\Delta, B, C$,让模型能根据当前内容动态决定:
- 这是一个重要的 Token -> 记入状态。
- 这是一个噪音 Token -> 忽略/遗忘。
3.3 Mamba 代码实现#
import torch
import torch.nn as nn
class MambaBlock(nn.Module):
def __init__(self, d_model, d_state=16):
super().__init__()
# 1. 线性投影
self.in_proj = nn.Linear(d_model, d_model * 2)
self.x_proj = nn.Linear(d_model, d_model + d_state * 2) # 生成 delta, B, C
# 2. SSM 参数 (A 是固定的/缓慢变化的)
self.A_log = nn.Parameter(torch.log(torch.arange(1, d_state + 1, dtype=torch.float32)))
def forward(self, x):
# 简化版前向传播 (非并行优化的 Scan 实现)
batch, seq, dim = x.shape
states = torch.zeros(batch, dim, self.d_state).to(x.device)
outputs = []
for t in range(seq):
xt = x[:, t, :]
# 动态计算参数 (Selective Scan)
# 这里省略了复杂的离散化 (Discretization) 步骤
# h_t = A * h_{t-1} + B * x_t
# y_t = C * h_t
# ... (完整实现需 CUDA Kernel)
pass
return x # Placeholder(注:真实 Mamba 训练依赖 Triton 编写的 Parallel Scan Kernel,Python 循环无法训练)
本章小结#
- MoE (DeepSeek/Mixtral):通过稀疏激活解决了参数量与计算量的矛盾。核心是 Router 和 Load Balancing。
- MLA (DeepSeek-V3):通过低秩压缩解决了KV Cache 显存瓶颈,是长文本推理的神器。
- SSM (Mamba):通过线性复杂度挑战了 Transformer 的统治地位,特别适合超长序列 (如基因组、长视频)。
掌握了这些,你就看懂了当前 LLM 架构演进的主战场。