在 AI Infra、LLM 推理系统、算子开发、KV Cache 管理、MoE 路由、量化 kernel 中,经常会看到一些词:

  • slot
  • compact
  • permute
  • gather
  • scatter
  • pack / unpack
  • pad / unpad
  • reorder

这些词本质上大多不是某个复杂算法,而是数据布局、数据搬运、数据重排、索引映射相关的底层操作。

可以先用一句话概括:

slot = 找坑位 / 物理地址;compact = 去掉空洞变紧凑;permute = 按某种顺序重排。


1. 常见术语总览

术语 直观含义 常见操作 简单例子
slot 槽位、坑位、物理位置 逻辑 token / sequence 映射到实际存储位置 slot_mapping[token_id] = physical_kv_slot
compact 压紧、去空洞 删除 padding、无效 token、finished request [A, pad, B, pad, C] -> [A, B, C]
permute 换维度 / 换顺序 tensor 维度重排,或元素按索引重排 [B, S, H, D] -> [S, B, H, D]
gather 按索引读 从大 tensor 中读取指定位置 out[i] = x[index[i]]
scatter 按索引写 把数据写入指定位置 out[index[i]] = src[i]
reshape / view 改形状 不改变底层数据,只改变 tensor 的解释方式 [2, 3, 4] -> [6, 4]
transpose 交换两个维度 permute 的特殊情况 [M, N] -> [N, M]
pack 打包 把多个小数据压成更紧凑的格式 两个 INT4 打包成一个 byte
unpack 解包 把 packed 格式还原成可计算格式 INT4 packed -> int8 / fp16
pad 补齐 为了 batch 对齐,把短序列补到同长度 [A, B] -> [A, B, pad, pad]
unpad 去 padding 只保留真实 token 根据 attention mask 提取有效 token
reorder 重排 调整 batch、token、cache 或 expert 的顺序 MoE token 按 expert 分组
fuse 融合 把多个算子合并成一个 kernel bias + gelu + matmul fusion

2. Slot:关注“写到哪个物理位置”

slot 最常见的语义是物理槽位

在 LLM 推理系统里,特别是 KV Cache 管理中,逻辑 token 并不一定连续存储在物理内存中。系统通常会维护一个映射关系:

kv_cache[slot_mapping[i]] = kv[i]

其中:

i                 表示逻辑 token 的编号
slot_mapping[i]   表示这个 token 对应的物理 KV Cache 位置
kv_cache[...]     表示真正写入的缓存位置

所以:

slot 关注的是:这个 token 的 K/V 应该写到哪个物理坑位?

典型场景:

token0 -> slot 8
token1 -> slot 9
token2 -> slot 23
token3 -> slot 24

逻辑上 token 是连续的,但物理存储可能分布在不同 page / block 中。


3. Compact:关注“去空洞,变紧凑”

compact 的核心含义是:

把有效数据提取出来,去掉无效位置,让数据连续排放。

例如 batch 中有 padding:

原始数据:
[A, pad, B, pad, C]

compact 后:
[A, B, C]

在 AI Infra 中,compact 很常见。

3.1 去 padding

不同序列长度不一样:

seq1: A B C D
seq2: E F pad pad
seq3: G pad pad pad

如果直接计算,会浪费大量算力在 pad 上。

compact 后:

[A, B, C, D, E, F, G]

然后用额外 metadata 记录每个 sequence 的边界,例如:

cu_seqlens = [0, 4, 6, 7]

这种思路在 FlashAttention、varlen attention、sequence packing 中都很常见。


3.2 推理 serving 中清理 finished request

假设一个 batch 中有些请求已经生成结束:

req0 active
req1 finished
req2 active
req3 finished
req4 active

下一轮 decode 不应该继续计算 finished request,所以需要 compact:

[req0, req2, req4]

但要注意,compact 通常不只是移动 input token,还要同步更新很多 metadata:

input_ids
position_ids
seq_lens
slot_mapping
block_tables
sampling metadata
request state

4. Permute:关注“换顺序 / 换维度”

permute 的核心含义是:

按照某个规则重新排列 tensor 的维度或元素顺序。

例如 attention 中经常会有:

hidden: [B, S, hidden_dim]

经过 QKV projection 后:

qkv: [B, S, 3, num_heads, head_dim]

为了方便 kernel 计算,可能会调整成:

[3, B, num_heads, S, head_dim]

或者:

[B, num_heads, S, head_dim]

这就是典型的 permute

在 PyTorch 中:

import torch

x = torch.randn(2, 3, 4)

# 原始 shape: [2, 3, 4]
y = x.permute(1, 0, 2)

# 新 shape: [3, 2, 4]
print(y.shape)

5. Gather 和 Scatter:一个按索引读,一个按索引写

这两个词经常成对出现。

5.1 Gather:按索引读取

out[i] = x[index[i]]

意思是:

根据 index 中给定的位置,从 x 中取数据。

例如:

x     = [10, 20, 30, 40, 50]
index = [3, 0, 2]

gather 后:
out = [40, 10, 30]

5.2 Scatter:按索引写入

out[index[i]] = src[i]

意思是:

把 src 中的数据写入到 index 指定的位置。

例如:

src   = [100, 200, 300]
index = [2, 0, 4]

scatter 到 out 后:
out[2] = 100
out[0] = 200
out[4] = 300

6. KV Cache 写入:Slot + Scatter

LLM decode 阶段,每生成一个 token,都会产生新的 K/V。

这些 K/V 要写入 KV Cache,但写入位置并不一定是连续的,而是由 slot_mapping 决定。

逻辑上类似:

for i in range(num_tokens):
    kv_cache[slot_mapping[i]] = kv[i]

这里可以这样理解:

slot_mapping 负责告诉你写到哪里
scatter 负责把数据写进去

因此 KV Cache 写入本质上经常是:

slot mapping + scatter write

7. MoE 路由:Permute + Compact + Grouped GEMM + Unpermute

MoE,也就是 Mixture of Experts,中每个 token 会被路由到不同 expert。

假设:

token0 -> expert2
token1 -> expert0
token2 -> expert2
token3 -> expert1

原始 token 顺序是:

[token0, token1, token2, token3]

为了让每个 expert 的 token 连续存放,通常会重排成:

[expert0: token1] [expert1: token3] [expert2: token0, token2]

这个过程通常包含:

1. 根据 expert id 对 token 排序
2. compact 成每个 expert 的连续 token block
3. 对每个 expert 做 grouped GEMM
4. 最后 unpermute 回原始 token 顺序

整体流程:

原始 token
   ↓
permute / reorder by expert
   ↓
compact by expert
   ↓
grouped GEMM
   ↓
unpermute back
   ↓
恢复原始 token 顺序

所以在 MoE kernel 中,经常会看到:

permute
sort
expert offset
token offset
unpermute

这些都和 token 路由、分组计算、恢复顺序有关。


8. Quantization 中的 Pack / Unpack

在量化场景中,packunpack 非常常见。

例如 INT4 权重中,一个数只占 4 bit,而一个 byte 有 8 bit,所以可以把两个 INT4 打包到一个 byte 中:

w0: 4 bit
w1: 4 bit

packed byte = [w1 | w0]

代码上类似:

packed = (w1 << 4) | w0

计算时再解包:

w0 = packed & 0xF
w1 = (packed >> 4) & 0xF

所以量化 kernel 中常见流程是:

load packed weight
   ↓
unpack INT4 / INT8
   ↓
dequantize with scale / zero_point
   ↓
MMA / GEMM
   ↓
requantize or cast output

可以简单理解为:

pack   = 为了省显存 / 带宽,把数据压紧
unpack = 为了计算,把压紧的数据还原

9. Pad / Unpad:补齐和去补齐

在 batch 计算中,为了让不同长度的序列组成一个规整 tensor,经常需要 padding。

例如:

seq1: A B C D
seq2: E F
seq3: G

pad 后:

seq1: A B C D
seq2: E F pad pad
seq3: G pad pad pad

但是 attention 计算时,如果把 pad 也算进去,就会浪费算力。

因此高性能 attention 通常会 unpad:

[A, B, C, D, E, F, G]

然后使用额外的 offset 信息记录边界:

cu_seqlens = [0, 4, 6, 7]

这里:

pad   = 补齐,方便组成 batch
unpad = 去掉 padding,避免无效计算

10. Reshape / View / Transpose / Permute 的区别

这几个词很容易混。

操作 是否改变数据顺序 主要作用
reshape 通常不改变底层数据,只改变形状解释 改 shape
view 类似 reshape,但对连续性要求更严格 改 tensor 视图
transpose 交换两个维度 二维或高维维度交换
permute 任意维度重排 更通用的 transpose
contiguous 重新整理内存,让数据物理连续 可能触发实际拷贝

例如:

x = torch.randn(2, 3, 4)

# 交换第 0 维和第 1 维
y = x.transpose(0, 1)

# 任意重排维度
z = x.permute(2, 0, 1)

print(y.shape)  # [3, 2, 4]
print(z.shape)  # [4, 2, 3]

需要注意:

y = x.permute(2, 0, 1)

很多时候只是改变 stride,不一定真的搬数据。

但如果后续调用:

y = y.contiguous()

就可能触发真实的数据重排和拷贝。


11. 几个典型 AI Infra 场景总结

11.1 LLM Decode 阶段

input token
   ↓
compute QKV
   ↓
根据 slot_mapping 写入 KV Cache
   ↓
attention 读取历史 KV
   ↓
sampling
   ↓
更新 request state

相关操作:

slot
scatter
gather
reorder
compact

11.2 FlashAttention / Varlen Attention

原始 padded batch
   ↓
unpad / compact
   ↓
varlen attention
   ↓
pad back / scatter back

相关操作:

pad
unpad
compact
cu_seqlens
gather
scatter

11.3 MoE 推理

token hidden states
   ↓
router 得到 expert id
   ↓
按 expert 重排 token
   ↓
每个 expert 做 grouped GEMM
   ↓
结果恢复原始 token 顺序

相关操作:

permute
sort
compact
grouped GEMM
unpermute
scatter

11.4 量化 GEMM

packed INT4 / INT8 weight
   ↓
load
   ↓
unpack
   ↓
dequantize
   ↓
MMA / GEMM
   ↓
requantize / cast

相关操作:

pack
unpack
dequantize
requantize
layout transform

12. 一句话速记

最后可以用下面这张表快速记忆:

看到的词 可以先理解成
slot 我要写到哪个物理坑位
mapping 逻辑 ID 到物理 ID 的映射表
compact 把有效数据挤到一起,去掉洞
permute 换顺序 / 换维度
gather 按 index 读
scatter 按 index 写
pack 压成更紧凑的数据格式
unpack 从紧凑格式还原
pad 补齐
unpad 去掉补齐
reorder 重排 batch / token / cache 顺序
fuse 多个算子合成一个 kernel

13. 核心区别

最重要的是区分这几个:

slot    关注“地址”
compact 关注“去空洞”
permute 关注“换顺序”
gather  关注“按索引读”
scatter 关注“按索引写”
pack    关注“压缩布局”

也就是说:

  • slot 更偏向 存储位置管理

  • compact 更偏向 有效数据压缩

  • permute 更偏向 顺序或维度重排

  • gather/scatter 更偏向 按索引读写

  • pack/unpack 更偏向 低 bit 数据布局转换

这些词看起来很零散,但在 LLM 推理、MoE、KV Cache、FlashAttention、量化 kernel 中,本质上都是围绕一个问题:

如何把数据以更适合 GPU 计算的方式组织起来?

理解这些底层操作之后,再看 vLLM、TensorRT-LLM、FlashAttention、MoE kernel、量化 GEMM 相关代码,会清晰很多。

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐