AI 模型中 的 Slot、Compact、Permute 等操作到底是什么意思?
在 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
在量化场景中,pack 和 unpack 非常常见。
例如 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 相关代码,会清晰很多。
更多推荐


所有评论(0)