Transformer推理优化:从KV Cache到投机解码的工程实践
一、Transformer推理的内存墙
1.1 自回归生成的计算特性
Transformer 在训练时采用并行计算,但在推理时采用自回归生成:
训练阶段(并行):
Input: [The, cat, sat, on, the, mat]
↓ ↓ ↓ ↓ ↓ ↓
Output: [cat, sat, on, the, mat, .]
一次前向传播计算所有位置
时间复杂度:O(1) 步
推理阶段(自回归):
Step 1: Input: [The] → Output: cat
Step 2: Input: [The, cat] → Output: sat
Step 3: Input: [The, cat, sat] → Output: on
...
必须逐token生成
时间复杂度:O(N) 步
内存访问模式分析:
每次生成新token时:
1. 加载模型权重(GB级)
2. 计算当前token的Q, K, V
3. 与所有历史token的K, V计算注意力
4. 生成下一个token
问题:
- 权重加载:每次推理都要读取全部参数
- 历史计算:与所有历史token重复计算注意力
- 内存瓶颈:KV缓存随序列长度线性增长
1.2 内存墙的具体表现
LLaMA-2 70B 推理内存分析:
模型配置:
- 参数量:70B
- 隐藏维度:8192
- 层数:80
- 注意力头数:64
- 每头维度:128
内存占用(FP16):
1. 模型权重:
70B × 2 bytes = 140 GB
2. KV Cache(序列长度 4096):
每层:2 (K+V) × 4096 × 8192 × 2 bytes = 134 MB
总共:80 × 134 MB = 10.7 GB
3. 激活值:
约 2-5 GB(取决于batch size)
总计:~155 GB
单卡 A100 (80GB):无法放下
需要:模型并行(2卡)+ 流水线并行
内存墙公式:
总内存 = 模型权重 + KV Cache + 激活值
其中:
KV Cache = 2 × num_layers × seq_len × hidden_dim × bytes_per_param
关键洞察:
- 模型权重:固定开销
- KV Cache:随序列长度线性增长
- 长序列(>8K)时,KV Cache 成为瓶颈
二、KV Cache:注意力计算的缓存革命
2.1 KV Cache的核心思想
观察:在自回归生成中,历史token的Key和Value是固定的。
洞察:缓存历史token的K和V,避免重复计算。
无KV Cache:
Step 1: Q1 × [K1] → Attention1
Step 2: Q2 × [K1, K2] → Attention2
Step 3: Q3 × [K1, K2, K3] → Attention3
...
每次都要重新计算 K1, K2, ...
有KV Cache:
Step 1: Q1 × [K1] → Attention1, 缓存 K1
Step 2: Q2 × [K1, K2] → Attention2, 缓存 K2
Step 3: Q3 × [K1, K2, K3] → Attention3, 缓存 K3
...
只需计算当前token的K和V
2.2 KV Cache的实现
import torch
import torch.nn as nn
from typing import Optional, Tuple
class OptimizedAttention(nn.Module):
"""
带KV Cache优化的多头注意力
"""
def __init__(self, hidden_dim: int, num_heads: int):
super().__init__()
self.hidden_dim = hidden_dim
self.num_heads = num_heads
self.head_dim = hidden_dim // num_heads
self.q_proj = nn.Linear(hidden_dim, hidden_dim)
self.k_proj = nn.Linear(hidden_dim, hidden_dim)
self.v_proj = nn.Linear(hidden_dim, hidden_dim)
self.o_proj = nn.Linear(hidden_dim, hidden_dim)
def forward(
self,
hidden_states: torch.Tensor,
past_key_value: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
use_cache: bool = True
) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
"""
Args:
hidden_states: [batch, seq_len, hidden_dim]
past_key_value: (past_key, past_value) from previous steps
use_cache: whether to return present_key_value
Returns:
output: [batch, seq_len, hidden_dim]
present_key_value: (key, value) for caching
"""
batch_size, seq_len, _ = hidden_states.shape
# 计算 Q, K, V
query = self.q_proj(hidden_states)
key = self.k_proj(hidden_states)
value = self.v_proj(hidden_states)
# reshape 为多头: [batch, num_heads, seq_len, head_dim]
query = query.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
key = key.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
value = value.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
# 合并历史KV Cache
if past_key_value is not None:
past_key, past_value = past_key_value
key = torch.cat([past_key, key], dim=2) # 在seq_len维度拼接
value = torch.cat([past_value, value], dim=2)
# 保存当前KV用于下次迭代
present_key_value = (key, value) if use_cache else None
# 计算注意力: [batch, num_heads, seq_len, seq_len]
attn_weights = torch.matmul(query, key.transpose(-2, -1)) / (self.head_dim ** 0.5)
attn_weights = torch.softmax(attn_weights, dim=-1)
# 应用注意力到value
attn_output = torch.matmul(attn_weights, value) # [batch, num_heads, seq_len, head_dim]
# reshape 回来
attn_output = attn_output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.hidden_dim)
# 输出投影
output = self.o_proj(attn_output)
return output, present_key_value
class KVCacheManager:
"""
KV Cache 管理器
支持动态扩容和内存优化
"""
def __init__(self, num_layers: int, num_heads: int, head_dim: int, max_batch_size: int):
self.num_layers = num_layers
self.num_heads = num_heads
self.head_dim = head_dim
self.max_batch_size = max_batch_size
# 预分配KV Cache
self.k_cache = []
self.v_cache = []
self.seq_len = 0
for _ in range(num_layers):
# [max_batch, num_heads, max_seq_len, head_dim]
self.k_cache.append(None)
self.v_cache.append(None)
def allocate(self, max_seq_len: int, dtype: torch.dtype, device: torch.device):
"""预分配KV Cache内存"""
for i in range(self.num_layers):
self.k_cache[i] = torch.zeros(
self.max_batch_size, self.num_heads, max_seq_len, self.head_dim,
dtype=dtype, device=device
)
self.v_cache[i] = torch.zeros(
self.max_batch_size, self.num_heads, max_seq_len, self.head_dim,
dtype=dtype, device=device
)
def get_cache(self, layer_idx: int) -> Tuple[torch.Tensor, torch.Tensor]:
"""获取指定层的KV Cache"""
return self.k_cache[layer_idx], self.v_cache[layer_idx]
def update_cache(
self,
layer_idx: int,
new_k: torch.Tensor,
new_v: torch.Tensor,
position: int
):
"""更新KV Cache"""
batch_size = new_k.shape[0]
seq_len = new_k.shape[2]
# 写入新计算的K和V
self.k_cache[layer_idx][:batch_size, :, position:position+seq_len, :] = new_k
self.v_cache[layer_idx][:batch_size, :, position:position+seq_len, :] = new_v
def get_past_kv(self, layer_idx: int, batch_size: int, seq_len: int) -> Tuple[torch.Tensor, torch.Tensor]:
"""获取历史的K和V"""
return (
self.k_cache[layer_idx][:batch_size, :, :seq_len, :],
self.v_cache[layer_idx][:batch_size, :, :seq_len, :]
)
2.3 KV Cache的压缩技术
Multi-Query Attention (MQA):
class MultiQueryAttention(nn.Module):
"""
Multi-Query Attention: 所有头共享同一个K和V
减少KV Cache内存占用 num_heads 倍
"""
def __init__(self, hidden_dim: int, num_heads: int):
super().__init__()
self.hidden_dim = hidden_dim
self.num_heads = num_heads
self.head_dim = hidden_dim // num_heads
self.q_proj = nn.Linear(hidden_dim, hidden_dim)
# K和V只有一个头
self.k_proj = nn.Linear(hidden_dim, self.head_dim)
self.v_proj = nn.Linear(hidden_dim, self.head_dim)
self.o_proj = nn.Linear(hidden_dim, hidden_dim)
def forward(self, hidden_states, past_kv=None):
batch_size, seq_len, _ = hidden_states.shape
query = self.q_proj(hidden_states)
key = self.k_proj(hidden_states) # [batch, seq_len, head_dim]
value = self.v_proj(hidden_states) # [batch, seq_len, head_dim]
# Q reshape为多头
query = query.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
# K和V扩展为多头(广播)
key = key.unsqueeze(1) # [batch, 1, seq_len, head_dim]
value = value.unsqueeze(1) # [batch, 1, seq_len, head_dim]
# 注意力计算(K和V自动广播到所有头)
attn = torch.matmul(query, key.transpose(-2, -1)) / (self.head_dim ** 0.5)
attn = torch.softmax(attn, dim=-1)
output = torch.matmul(attn, value)
output = output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.hidden_dim)
return self.o_proj(output)
# 内存节省:
# 标准MHA: 2 × num_heads × seq_len × head_dim
# MQA: 2 × 1 × seq_len × head_dim
# 节省: num_heads 倍(如32倍)
Grouped-Query Attention (GQA):
class GroupedQueryAttention(nn.Module):
"""
Grouped-Query Attention: 中间方案
将num_heads个头分成num_groups组,每组共享K和V
"""
def __init__(self, hidden_dim: int, num_heads: int, num_groups: int):
super().__init__()
self.hidden_dim = hidden_dim
self.num_heads = num_heads
self.num_groups = num_groups
self.heads_per_group = num_heads // num_groups
self.head_dim = hidden_dim // num_heads
self.q_proj = nn.Linear(hidden_dim, hidden_dim)
self.k_proj = nn.Linear(hidden_dim, num_groups * self.head_dim)
self.v_proj = nn.Linear(hidden_dim, num_groups * self.head_dim)
self.o_proj = nn.Linear(hidden_dim, hidden_dim)
def forward(self, hidden_states, past_kv=None):
batch_size, seq_len, _ = hidden_states.shape
query = self.q_proj(hidden_states)
key = self.k_proj(hidden_states)
value = self.v_proj(hidden_states)
# Q: [batch, num_heads, seq_len, head_dim]
query = query.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
# K, V: [batch, num_groups, seq_len, head_dim]
key = key.view(batch_size, seq_len, self.num_groups, self.head_dim).transpose(1, 2)
value = value.view(batch_size, seq_len, self.num_groups, self.head_dim).transpose(1, 2)
# 将K和V扩展到num_heads(每组内相同)
key = key.repeat_interleave(self.heads_per_group, dim=1)
value = value.repeat_interleave(self.heads_per_group, dim=1)
# 标准注意力计算
attn = torch.matmul(query, key.transpose(-2, -1)) / (self.head_dim ** 0.5)
attn = torch.softmax(attn, dim=-1)
output = torch.matmul(attn, value)
output = output.transpose(1, 2).contiguous().view(batch_size, seq_len, self.hidden_dim)
return self.o_proj(output)
# 内存节省:num_heads / num_groups 倍
# 如 num_heads=32, num_groups=4, 节省 8 倍
三、量化:降低精度提升效率
3.1 量化原理
INT8 量化:
class QuantizedLinear(nn.Module):
"""
INT8 量化线性层
"""
def __init__(self, in_features: int, out_features: int):
super().__init__()
self.in_features = in_features
self.out_features = out_features
# 存储INT8权重
self.register_buffer('weight_int8', torch.randint(-128, 127, (out_features, in_features), dtype=torch.int8))
self.register_buffer('weight_scale', torch.ones(out_features))
self.register_buffer('weight_zero_point', torch.zeros(out_features))
def quantize_weight(self, weight_fp16: torch.Tensor):
"""将FP16权重量化到INT8"""
# 计算每行的scale和zero_point
w_min = weight_fp16.min(dim=1, keepdim=True)[0]
w_max = weight_fp16.max(dim=1, keepdim=True)[0]
scale = (w_max - w_min) / 255.0
zero_point = -w_min / scale
# 量化
weight_int8 = torch.round(weight_fp16 / scale + zero_point).clamp(-128, 127).to(torch.int8)
self.weight_int8.copy_(weight_int8)
self.weight_scale.copy_(scale.squeeze())
self.weight_zero_point.copy_(zero_point.squeeze())
def forward(self, x: torch.Tensor) -> torch.Tensor:
"""INT8矩阵乘法 + 反量化"""
# 将输入量化为INT8(简化版,实际使用更复杂的校准)
x_scale = x.abs().max() / 127.0
x_int8 = (x / x_scale).round().clamp(-128, 127).to(torch.int8)
# INT8矩阵乘法
# 使用 torch._int_mm (A100/H100) 或模拟
y_int32 = torch.matmul(x_int8.to(torch.int32), self.weight_int8.to(torch.int32).t())
# 反量化
y = y_int32.float() * x_scale * self.weight_scale.unsqueeze(0)
return y
# 内存节省:2x (FP16 -> INT8)
# 计算加速:取决于硬件支持
GPTQ 量化(4-bit):
"""
GPTQ: 逐层量化,最小化精度损失
核心思想:
1. 逐层处理,而非全局量化
2. 使用OBS(Optimal Brain Surgeon)确定最优量化顺序
3. 量化后更新未量化权重以补偿误差
实现复杂,通常使用现成的库:
- AutoGPTQ
- llama.cpp
- vLLM
"""
# 使用示例(概念性)
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("llama-2-7b")
# GPTQ量化到4-bit
# 内存:7B × 0.5 bytes = 3.5 GB
# 对比FP16:7B × 2 bytes = 14 GB
# 节省:4x
3.2 量化方案对比
| 方案 | 精度 | 内存节省 | 速度提升 | 适用场景 |
|---|---|---|---|---|
| FP16 | 16-bit | 2x vs FP32 | 1-2x | 通用 |
| INT8 | 8-bit | 4x vs FP32 | 2-3x | 推理 |
| INT4 (GPTQ) | 4-bit | 8x vs FP32 | 2-4x | 边缘部署 |
| AWQ | 4-bit | 8x vs FP32 | 3-4x | 高质量推理 |
四、投机解码:用速度换速度
4.1 核心思想
观察:小模型生成token的速度远快于大模型。
洞察:用小模型"猜测"多个token,大模型并行验证。
标准解码:
大模型: T1 → T2 → T3 → T4 → T5
↓ ↓ ↓ ↓ ↓
100ms 100ms 100ms 100ms 100ms = 500ms
投机解码:
小模型: T1 → T2 → T3 → T4 → T5 (快速猜测)
↓ ↓ ↓ ↓ ↓
10ms 10ms 10ms 10ms 10ms
大模型: 并行验证 [T1, T2, T3, T4, T5]
↓
120ms (一次前向)
结果:接受3个,拒绝2个
实际:120ms + 20ms = 140ms (生成3个token)
等效速度:3.5x 加速
4.2 投机解码算法
class SpeculativeDecoder:
"""
投机解码实现
"""
def __init__(
self,
target_model, # 大模型
draft_model, # 小模型(draft model)
gamma: int = 5 # 每次猜测的token数
):
self.target_model = target_model
self.draft_model = draft_model
self.gamma = gamma
def generate(self, input_ids: torch.Tensor, max_new_tokens: int) -> torch.Tensor:
"""
投机解码生成
"""
generated = input_ids.clone()
while generated.shape[1] < input_ids.shape[1] + max_new_tokens:
# Step 1: Draft model 快速生成 gamma 个token
draft_tokens = self._draft_generate(generated, self.gamma)
# Step 2: Target model 并行验证
accepted, new_token = self._verify_tokens(generated, draft_tokens)
# Step 3: 添加接受的token
generated = torch.cat([generated, accepted], dim=1)
# Step 4: 如果全部接受,添加target model的新token
if accepted.shape[1] == draft_tokens.shape[1]:
generated = torch.cat([generated, new_token], dim=1)
print(f"接受 {accepted.shape[1]}/{draft_tokens.shape[1]} 个猜测token")
return generated
def _draft_generate(self, prefix: torch.Tensor, num_tokens: int) -> torch.Tensor:
"""Draft model 快速生成"""
draft_output = self.draft_model.generate(
prefix,
max_new_tokens=num_tokens,
do_sample=False # greedy for speed
)
return draft_output[:, prefix.shape[1]:]
def _verify_tokens(
self,
prefix: torch.Tensor,
draft_tokens: torch.Tensor
) -> Tuple[torch.Tensor, torch.Tensor]:
"""
Target model 验证猜测的token
返回:
- accepted_tokens: 接受的token
- new_token: 如果全部接受,target model的下一个token
"""
# 构造输入:prefix + 所有draft tokens
input_ids = torch.cat([prefix, draft_tokens], dim=1)
# Target model 一次前向
with torch.no_grad():
logits = self.target_model(input_ids).logits
# 逐个验证
accepted = []
prefix_len = prefix.shape[1]
for i in range(draft_tokens.shape[1]):
# Target model 对位置 prefix_len + i 的预测
target_logits = logits[:, prefix_len + i - 1, :]
target_token = target_logits.argmax(dim=-1)
# Draft model 的猜测
draft_token = draft_tokens[:, i]
# 比较
if target_token == draft_token:
accepted.append(draft_token)
else:
# 拒绝,返回已接受的 + target的预测
accepted_tensor = torch.tensor(accepted).unsqueeze(0)
return accepted_tensor, target_token.unsqueeze(0)
# 全部接受,返回draft tokens + target的下一个token
next_token_logits = logits[:, -1, :]
next_token = next_token_logits.argmax(dim=-1)
return draft_tokens, next_token.unsqueeze(0)
4.3 改进方案
Medusa(多头解码):
"""
Medusa: 不依赖draft model,而是给原模型增加多个预测头
原模型输出:
- 原始LM head: 预测下一个token
Medusa增加:
- Head 1: 预测下下个token
- Head 2: 预测下下下个token
- ...
训练时:
- 冻结原模型
- 只训练新增的Medusa heads
推理时:
- 一次前向,得到多个位置的预测
- 树形验证,最大化接受率
"""
class MedusaModel(nn.Module):
"""
Medusa多头解码(概念性实现)
"""
def __init__(self, base_model, num_heads: int = 4):
super().__init__()
self.base_model = base_model
self.num_heads = num_heads
# Medusa heads: 预测未来多个token
hidden_size = base_model.config.hidden_size
vocab_size = base_model.config.vocab_size
self.medusa_heads = nn.ModuleList([
nn.Linear(hidden_size, vocab_size, bias=False)
for _ in range(num_heads)
])
def forward(self, input_ids):
# 基础模型前向
outputs = self.base_model(input_ids, output_hidden_states=True)
hidden_states = outputs.hidden_states[-1] # [batch, seq_len, hidden]
# 原始预测
base_logits = outputs.logits
# Medusa预测(基于最后一个位置的隐藏状态)
last_hidden = hidden_states[:, -1, :] # [batch, hidden]
medusa_logits = []
for head in self.medusa_heads:
logits = head(last_hidden) # [batch, vocab]
medusa_logits.append(logits)
return {
'base_logits': base_logits,
'medusa_logits': medusa_logits # 预测未来1, 2, 3, 4个token
}
五、系统级优化
5.1 连续批处理(Continuous Batching)
class ContinuousBatchingScheduler:
"""
连续批处理调度器
传统静态批处理:
- 等所有请求到齐才开始
- 快的请求等慢的请求
连续批处理:
- 请求随时加入批次
- 完成的请求随时退出
- 最大化GPU利用率
"""
def __init__(self, max_batch_size: int = 16):
self.max_batch_size = max_batch_size
self.active_requests = []
def step(self):
"""执行一步推理"""
# 1. 收集活跃请求
batch_inputs = []
positions = []
for req in self.active_requests:
if not req.is_finished():
batch_inputs.append(req.get_next_input())
positions.append(req.current_position)
if not batch_inputs:
return
# 2. 动态padding到相同长度
max_len = max(len(inp) for inp in batch_inputs)
padded_inputs = [self._pad(inp, max_len) for inp in batch_inputs]
# 3. 批量推理
batch_tensor = torch.stack(padded_inputs)
outputs = self.model(batch_tensor, position_ids=positions)
# 4. 分发结果
for i, req in enumerate(self.active_requests):
if not req.is_finished():
req.add_token(outputs[i])
# 5. 新请求加入(如果有空位)
while len(self.active_requests) < self.max_batch_size:
new_req = self.request_queue.get_nowait()
if new_req:
self.active_requests.append(new_req)
else:
break
def _pad(self, input_ids: list, target_len: int) -> torch.Tensor:
"""padding到目标长度"""
if len(input_ids) >= target_len:
return torch.tensor(input_ids)
padding = [self.pad_token_id] * (target_len - len(input_ids))
return torch.tensor(input_ids + padding)
5.2 PagedAttention(vLLM)
"""
PagedAttention: 借鉴OS虚拟内存管理KV Cache
核心思想:
- 将KV Cache分页管理
- 非连续的物理存储
- 按需分配,减少内存碎片
类比:
OS虚拟内存:虚拟地址 → 页表 → 物理页
PagedAttention:逻辑KV → 块表 → 物理块
"""
class PagedAttention:
"""
PagedAttention 概念实现
"""
def __init__(self, block_size: int = 16, num_blocks: int = 1000):
self.block_size = block_size
self.num_blocks = num_blocks
# 空闲块列表
self.free_blocks = list(range(num_blocks))
# 每个序列的块表: seq_id -> [block_ids]
self.block_tables = {}
def allocate(self, seq_id: str, num_tokens: int):
"""为序列分配KV Cache块"""
num_blocks_needed = (num_tokens + self.block_size - 1) // self.block_size
if len(self.free_blocks) < num_blocks_needed:
raise MemoryError("No free blocks available")
# 分配块
allocated_blocks = self.free_blocks[:num_blocks_needed]
self.free_blocks = self.free_blocks[num_blocks_needed:]
self.block_tables[seq_id] = allocated_blocks
return allocated_blocks
def get_kv_cache(self, seq_id: str, position: int):
"""获取指定位置的KV Cache"""
block_table = self.block_tables[seq_id]
block_idx = position // self.block_size
offset = position % self.block_size
physical_block = block_table[block_idx]
# 从物理块读取KV
return self.kv_cache[physical_block, offset]
def fork(self, parent_seq_id: str, child_seq_id: str):
"""
复制序列(用于beam search)
写时复制(Copy-on-Write):
- 共享相同的物理块
- 只在写入时复制
"""
self.block_tables[child_seq_id] = self.block_tables[parent_seq_id].copy()
def free(self, seq_id: str):
"""释放序列的KV Cache"""
if seq_id in self.block_tables:
blocks = self.block_tables[seq_id]
self.free_blocks.extend(blocks)
del self.block_tables[seq_id]
# 内存节省效果:
# 传统:连续分配,存在大量碎片
# PagedAttention:按需分配,减少碎片
# 典型提升:2-4x 吞吐量
六、优化策略总结
6.1 优化技术对比
| 技术 | 优化目标 | 复杂度 | 效果 |
|---|---|---|---|
| KV Cache | 减少重复计算 | 低 | 2-3x 加速 |
| MQA/GQA | 减少内存占用 | 低 | 4-32x 内存节省 |
| INT8量化 | 减少内存+加速 | 中 | 2x 内存,2-3x 加速 |
| GPTQ 4-bit | 极致压缩 | 高 | 4x 内存 |
| 投机解码 | 减少解码步数 | 高 | 2-3x 加速 |
| Continuous Batching | 提高吞吐 | 中 | 10-20x 吞吐 |
| PagedAttention | 减少内存碎片 | 高 | 2-4x 吞吐 |
6.2 实际部署建议
场景1:高吞吐在线服务
├── Continuous Batching
├── PagedAttention (vLLM)
├── INT8 量化
└── 预期:10-20x 吞吐提升
场景2:边缘设备部署
├── GPTQ 4-bit 量化
├── MQA/GQA
├── 模型蒸馏
└── 预期:10x 模型缩小
场景3:最低延迟
├── 投机解码
├── TensorRT / ONNX Runtime
├── 专用硬件(TPU/Groq)
└── 预期:2-3x 延迟降低
场景4:长上下文(>32K)
├── Ring Attention
├── 稀疏注意力
├── 滑动窗口KV Cache
└── 预期:支持 100K+ 上下文
结语
Transformer 推理优化是一个系统工程,涉及算法、系统和硬件多个层面。从 KV Cache 的缓存优化,到量化的精度-效率权衡,再到投机解码的速度换速度,每种技术都在解决"内存墙"这一核心瓶颈。
核心洞见:
- 内存是瓶颈:计算不再是瓶颈,内存带宽和容量才是
- 批处理是关键:充分利用 GPU 并行性
- 精度可权衡:INT8/INT4 量化在大多数场景下可接受
- 系统优化同样重要:Continuous Batching、PagedAttention 带来数量级提升
随着模型规模持续增长(GPT-4 估计 1.8T 参数),推理优化将成为 AI 工程的核心竞争力。理解这些优化技术,不仅是掌握工具,更是理解大规模模型服务的工程本质。
参考资源
经典论文:
- Vaswani, A., et al. (2017). "Attention Is All You Need". NeurIPS.
- Frantar, E., et al. (2022). "GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers". ICLR.
- Leviathan, Y., et al. (2022). "Fast Inference from Transformers via Speculative Decoding". ICML.
- Kwon, W., et al. (2023). "Efficient Memory Management for Large Language Model Serving with PagedAttention". SOSP.
工程资源: 5. vLLM: https://github.com/vllm-project/vllm 6. TensorRT-LLM: https://github.com/NVIDIA/TensorRT-LLM 7. llama.cpp: https://github.com/ggerganov/llama.cpp 8. Text Generation Inference: https://github.com/huggingface/text-generation-inference
优化指南: 9. 《Efficient Transformers: A Survey》 10. NVIDIA TensorRT 优化指南:https://docs.nvidia.com/deeplearning/tensorrt/
创建时间:2026年04月11日
更新时间:2026年04月11日