示例¶
本页收录 manifest 中的五个真实 spec,每个 spec 之后附有一张表,列出其中各处写法对应的说明。这些 spec 摘自 src/tileops/manifest/,删去了注释与部分 workload 行。
1. GemmFwdOp:type family¶
# src/tileops/manifest/spec/gemm.yaml
GemmFwdOp:
ref_api: "torch.matmul"
family: gemm
status: implemented
signature:
types:
Mat:
params: {t: Bool, R: Dim, C: Dim}
match: t
cases:
- {when: false, is: "[R, C]"}
- {when: true, is: "[C, R]"}
forall: {M: Dim, N: Dim, K: Dim, T: "DType[float16 | bfloat16]"}
params:
trans_a: {type: bool, default: false}
trans_b: {type: bool, default: true}
inputs:
a: {dtype: T, shape: "Mat[trans_a, M, K]"}
b: {dtype: T, shape: "Mat[trans_b, K, N]"}
outputs:
d: {dtype: T, shape: "[M, N]"}
workloads:
- {M: 1024, N: 1024, K: 1024, trans_a: false, trans_b: false, dtype_cases: [{T: float16}, {T: bfloat16}], label: square-1k}
- {M: 128, N: 2112, K: 7168, trans_a: false, trans_b: true, dtype_cases: [{T: bfloat16}], label: ds-v3-decode-qkv-a}
# 其余行省略
roofline:
flops: "2 * M * N * K"
表 1 GemmFwdOp 中各处写法的说明
| No. | spec 中的写法 | 说明所在 |
|---|---|---|
| 1 | types.Mat:由 trans_a、trans_b 决定 a、b 的轴顺序 |
扩展写法 2 |
| 2 | forall 声明三个轴长与一个 DType index |
写一个 spec 3 |
| 3 | trans_a、trans_b 既是构造参数,也是 Mat 的 discriminant |
写一个 spec 4 |
| 4 | workload 行给出参数与 index 的取值;第一行展开为两个 case,id 分别是 square-1k-float16 与 square-1k-bfloat16 |
写一个 spec 8 |
| 5 | roofline 只给出 flops;bytes 由签名推导,等于 (M*K + K*N + M*N) 乘以每个元素的字节数 |
写一个 spec 9 |
2. MoEPrePermuteFwdOp:ADT、let 与 generator¶
layout 参数的类型是 spec/types.yaml 中定义的 ADT MGroupedLayout,定义见扩展写法 3。
# src/tileops/manifest/spec/moe.yaml
MoEPrePermuteFwdOp:
family: moe
status: implemented
signature:
types:
LayoutMetadata:
params: {layout: MGroupedLayout, E: Dim, P: Dim}
match: layout
cases:
- {when: {contiguous: {metadata_kind: physical_psum}}, is: "[E]"}
- {when: {contiguous: {metadata_kind: per_row}}, is: "[P]"}
forall: {T: Dim, H: Dim, K: Dim, D: "DType[float16 | bfloat16]"}
params:
layout: {type: MGroupedLayout}
num_local_experts: {type: int}
inputs:
hidden_states: {dtype: D, shape: "[T, H]", contiguous: true}
local_expert_ids: {dtype: int32, shape: "[T, K]", contiguous: true, values: "topk_ids(T, K, num_local_experts)", requires: ["in_range(0, num_local_experts)"]}
let:
P: "moe.capacity(layout, T * K, num_local_experts)"
outputs:
expert_input: {dtype: D, shape: "[P, H]", contiguous: true}
layout_metadata: {dtype: int32, shape: "LayoutMetadata[layout, num_local_experts, P]", contiguous: true}
inverse_indices: {dtype: int32, shape: "[T * K]", contiguous: true}
shape_rules:
- "layout.kind == 'contiguous'"
- "num_local_experts > 0"
- "T > 0"
- "K > 0"
workloads:
- {T: 32, H: 128, K: 2, num_local_experts: 4, layout: {contiguous: {packing: tight, metadata_kind: physical_psum, alignment: 1}}, dtype_cases: [{D: float16}, {D: bfloat16}], label: "decode-t32"}
# 其余行省略
roofline:
flops: "0"
表 2 MoEPrePermuteFwdOp 中各处写法的说明
| No. | spec 中的写法 | 说明所在 |
|---|---|---|
| 1 | layout.kind == 'contiguous' 是一条定义域限制,它排除了 masked layout,因此 LayoutMetadata 不需要 masked 对应的 case |
扩展写法 2、3 |
| 2 | LayoutMetadata 按 constructor 与字段 metadata_kind 做 pattern matching |
扩展写法 2 |
| 3 | int 参数 num_local_experts 直接出现在形状中 |
写一个 spec 4 |
| 4 | let 中的 P 由 primitive moe.capacity 计算得到,并用于输出形状 |
扩展写法 4 |
| 5 | local_expert_ids 的取值由 generator topk_ids 生成,其内容由 requires 约束 |
扩展写法 7 |
| 6 | 各张量声明了 contiguous: true |
扩展写法 5 |
| 7 | workload 行中的 layout 写成 ADT 值 |
扩展写法 3 |
3. MeanPoolingFwdOp:可选输入与 metadata 张量¶
# src/tileops/manifest/spec/pool.yaml
MeanPoolingFwdOp:
family: pool
status: implemented
signature:
types:
PoolOut:
params: {p: Bool, B: Dim, NC: Dim, S: Dim, c: Dim, H: Dim, D: Dim}
match: p
cases:
- {when: true, is: "[B, NC, H, D]"}
- {when: false, is: "[B, ceil_div(S, c), H, D]"}
forall: {B: Dim, S: Dim, H: Dim, D: Dim, NS: Dim, NC: Dim, T: "DType[float16 | bfloat16 | float32]", seq_lens: "Seq[Int]"}
params:
chunk_size: {type: int}
accum_dtype: {type: torch.dtype}
inputs:
x: {dtype: T, shape: "[B, S, H, D]"}
offsets: {dtype: int32, optional: true, shape: "[NS + 1]", values: "prefix_sum(seq_lens)", requires: ["prefix_offsets(S)"]}
indices: {dtype: int32, optional: "present(offsets)", shape: "[NC, 2]", values: "chunk_indices(seq_lens, chunk_size)"}
outputs:
output: {dtype: T, shape: "PoolOut[present(offsets), B, NC, S, chunk_size, H, D]"}
shape_rules:
- "chunk_size > 0 and chunk_size % 32 == 0"
- "D <= 128 or D % 128 == 0"
- "category(accum_dtype) == 'float'"
workloads:
- {B: 1, S: 8192, H: 64, D: 128, chunk_size: 64, accum_dtype: float32, dtype_cases: [{T: float16}, {T: bfloat16}], label: uniform-8k}
- {B: 1, S: 8192, H: 64, D: 128, seq_lens: "repeat(2048, 4)", chunk_size: 64, accum_dtype: float32, some: [offsets], dtype_cases: [{T: float16}, {T: float32}], label: ragged-even}
# 其余行省略
roofline:
flops: "B * S * H * D + B * (NC if present(offsets) else ceil_div(S, chunk_size)) * H * D"
表 3 MeanPoolingFwdOp 中各处写法的说明
| No. | spec 中的写法 | 说明所在 |
|---|---|---|
| 1 | indices 声明为 optional: "present(offsets)",因此与 offsets 同时传入或同时不传 |
扩展写法 1 |
| 2 | type family PoolOut 以 present(offsets) 为 discriminant |
扩展写法 2 |
| 3 | 第一行不传 offsets,没有用到 seq_lens,因此行中不给出它;第二行通过 some: [offsets] 传入 offsets,同时给出 seq_lens,这里写成值 primitive 调用 "repeat(2048, 4)" |
扩展写法 1、写一个 spec 8 |
| 4 | NS 与 NC 由 generator 结果的 unification 求得,不在行中给出 |
扩展写法 7 |
| 5 | category(accum_dtype) == 'float' 限制累加 dtype 必须是浮点类型 |
扩展写法 9 |
| 6 | roofline 公式通过 present(offsets) 区分两种情况 |
写一个 spec 9 |
4. ReluFwdOp:任意秩与 effect¶
# src/tileops/manifest/spec/elementwise_unary_activation.yaml
ReluFwdOp:
ref_api: "torch.nn.functional.relu"
family: elementwise
status: implemented
signature:
forall: {S: Shape, T: "DType[float16 | bfloat16 | float32]"}
params:
inplace: {type: bool, default: false, kw_only: true}
inputs:
input: {dtype: T, shape: "[*S]", mutated: inplace}
outputs:
output: {dtype: T, shape: "[*S]", alias: input}
workloads:
- {S: [2048, 4096], dtype_cases: [{T: float16}, {T: bfloat16}], label: "hidden-state-prefill"}
- {S: [1, 4096], dtype_cases: [{T: bfloat16}], label: "hidden-state-decode"}
roofline:
flops: "prod(S)"
表 4 ReluFwdOp 中各处写法的说明
| No. | spec 中的写法 | 说明所在 |
|---|---|---|
| 1 | S 的 kind 是 Shape,输入与输出使用同一个形状项 [*S] |
写一个 spec 3、5 |
| 2 | mutated: inplace 与 alias: input 表示 inplace 为 true 时 op 写入输入并将其返回 |
扩展写法 6 |
| 3 | workload 行中的 S 写成整数列表 |
写一个 spec 8 |
5. AlibiFwdOp:没有张量输入¶
# src/tileops/manifest/spec/elementwise_generative.yaml
AlibiFwdOp:
family: elementwise
status: implemented
signature:
params:
seq_len: {type: int, kw_only: true}
num_heads: {type: int, kw_only: true}
out_dtype: {type: "float16 | bfloat16 | float32", default: float32, kw_only: true}
device: {type: "torch.device | str | None", default: null, kw_only: true}
outputs:
output: {dtype: out_dtype, shape: "[num_heads, seq_len, seq_len]"}
shape_rules:
- "seq_len > 0"
- "num_heads > 0"
workloads:
- {seq_len: 2048, num_heads: 32, out_dtype: float16, label: "mpt-7b-2k"}
- {seq_len: 2048, num_heads: 32, out_dtype: bfloat16, label: "mpt-7b-2k"}
# 其余行省略
roofline:
flops: "3 * num_heads * seq_len * seq_len"
表 5 AlibiFwdOp 中各处写法的说明
| No. | spec 中的写法 | 说明所在 |
|---|---|---|
| 1 | 所有 index 都来自构造参数,因此 spec 中没有 forall |
写一个 spec 4 |
| 2 | 输出的 dtype 直接使用 dtype 参数 out_dtype |
写一个 spec 7 |
| 3 | op 没有调用期张量输入,因此声明了 device 参数 |
扩展写法 5、调用与校验 4 |
| 4 | 两行的 label 相同,case id 以 dtype 参数的值区分,分别是 mpt-7b-2k-float16、mpt-7b-2k-bfloat16 |
写一个 spec 8 |