Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@
概率图可选熵正则,forward 1.07x、train-out 1.45x、
train+probs 1.48x、generate 1.09x;fused backward off/on 1.45-1.50x
- `ops.sdpa_math` 包化,支持 `from ops.sdpa_math import register_a1`

- **embedding 第二平台: cambricon**(Cambricon MLU590 / torch_mlu)
- 新增 [ops/embedding/kernel/cambricon.py](ops/embedding/kernel/cambricon.py):
前向委托原生 `aten::index_select`,反向委托原生 `aten::embedding_backward`
——MLU 原生 `padding_idx` + `scale_grad_by_freq` 完整(6/6 组合 err=0),
**无需** P800/XPU 那套 inverse-frequency 补偿;`sparse=True` backward
显式 `NotImplementedError`(否则 torch_mlu 返回 COO 稀疏梯度)
- 新增多平台门面 [ops/embedding/kernel/platform.py](ops/embedding/kernel/platform.py):
按 `tensor.device.type` 路由 `mlu→cambricon` / `cuda→p800`,
附 `dispatch_key_for`/`synchronize`;`p800_kunlunxin.py` 逐字节未改
- A1 key = `AutogradPrivateUse1`:两个 key 实测都命中,但 `PrivateUse1`
会覆盖 functorch 的 batch rule(`BatchRulesModules.cpp`);Autograd key
同时与 p800 `AutogradCUDA` 同构
- 平台命名统一 `cambricon`(别名 `mlu`/`mlu590`/`cambricon-mlu590` 归一),
与 13 个既有 MLU 算子、`configs/devices/cambricon.yaml`、
`perf/baselines/cambricon.json` 同名
- 验证全绿:kernel 20/20 前向 + 6/6 反向 err 0、黄金 **174/174 逐位**、
A1 op 拦截 5 次(注册=直调)、应用层拦截 8 次 logits/梯度 0 diff、
greedy 1.00、`pytest tests/unit` 20 passed、`example.py cambricon` 三层 PASS
- perf gate 注册 `ops.embedding.cambricon.forward`(0.060ms / 142.8 GB/s)
与 `ops.embedding.native.forward`(0.045ms / 187.9 GB/s),
`perf/baselines/cambricon.json` 增至 33 条 case,门禁 `FAIL 0 · WARN 0 · NEW 0`
- 新增 [ops/embedding/reports/cambricon.md](ops/embedding/reports/cambricon.md)
与 `perf_fp16_cambricon.json` / `dispatch_cambricon.json`
- **新算子: [ops/embedding](ops/embedding/)**(`aten::embedding`,
A1 路线,p800-kunlunxin)
- forward 复用 XMLIR native `index_select` row-gather;任意 rank indices、
Expand All @@ -57,6 +81,7 @@
(含 `sparse=True` 前向)、6 组反向、`nn.Embedding` 应用层前向/反向
全部通过;perf gate 注册与 P800 基线更新,硬件级显式置空
- 新增 A1 dispatch 独立子进程基准,native→A1 附加开销约 0.024ms
(⚠️ 该 a1 数字因下述 Library GC 缺陷作废,待复测)
- **SDPA 第三平台: mlu590**(Cambricon MLU590 / torch_mlu)
- 新增 `kernel/backends/mlu590.py`:分层委托——
**TMO** `torch_mlu_ops.flash_attention`(半精度快路径)→
Expand Down Expand Up @@ -89,6 +114,19 @@
GQA、非 causal 与尾块正确,但 mask launch 失败且慢于厂商路径
2.1-6.5x,因此暂不接入生产 backend

### Fixed
- `ops/embedding/script/bench_dispatch.py` a1 分支裸调 `register_a1`:
返回的 `torch.library.Library` 无引用时被 GC,**析构即反注册**,旧写法
测的是未注册状态(`F.embedding` 落回原生)。改为持有 `_a1_lib` 并断言;
全仓扫描确认为唯一裸调用点(sdpa 与各测试均持有 `lib`)
- 作废待复测:P800 a1 数字 `A1−native ≈0.024ms`、"A1 与 direct 同档/略快"
(本机无 `torch_xmlir` 无法重测;native / direct 两行仍有效)
- 三层精度结论不受影响(测试持有 `lib`,拦截计数 5/8 均 > 0)
- MLU 修复后复测:A1 − native ≈ **+0.059ms**、A1 − direct ≈ **+0.044ms**
- `ops/embedding/script/bench_perf.py` 反向分支原为 XPU 专用的
`if not scale:` 跳过,MLU 上拿不到 `scale_grad_by_freq` 对照——
改为按平台 try/except 逐个尝试原生 scale,两平台反向表均含 native 对照

## [0.13.0] - 2026-09-17

### Added
Expand Down
4 changes: 4 additions & 0 deletions ops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@ grep -rl my_op . | xargs sed -i 's/my_op/<你的算子名>/g'

> 硬件平台合计 **3 个**:`ascend910`(sdpa / sdpa_math)· `p800-kunlunxin`(sdpa / sdpa_math / embedding)· `cambricon` / `mlu590`(MLU590,sdpa + 13 个算子)。 算子级明细见下表「硬件平台」列与各算子的 `REPORT.md` 表头。

> 硬件平台合计 **3 个**:`ascend910`(仅 sdpa)· `p800-kunlunxin`(sdpa / embedding)· `cambricon` / `mlu590`(MLU590,sdpa · embedding · 13 个 Torch/Triton 级算子)。 算子级明细见下表「硬件平台」列与各算子的 `REPORT.md` 表头。

| 算子 | 硬件平台 | 开发级别 | 路线 | 状态 | 交付报告 | 备注 |
|---|---|---|---|---|---|---|
| [sdpa](sdpa/)(scaled_dot_product_attention) | **3** · ascend910 / p800-kunlunxin / mlu590 | Triton / 厂商委托 | A1(aten 拦截) | ✅ 定稿 | [REPORT](sdpa/REPORT.md) | ascend910 + p800-kunlunxin + mlu590 · 三平台黄金 397/397(Ascend 历史 265/265) · [平台绑定](sdpa/PLATFORM.md) / [多平台合并](sdpa/MERGE.md) |
| [sdpa_math](sdpa_math/)(aten::_scaled_dot_product_attention_math) | 2 · ascend910 / p800-kunlunxin | Triton / vendor O/LSE + exact-P | A1(aten 拦截) | ✅ 定稿 | [REPORT](sdpa_math/REPORT.md) | SDPA math 后端(双输出 out+概率图)· 三平台黄金 175/175 · NPU fp16 1.16-2.03x · P800 direct 1.46-2.21x native |
| [embedding](embedding/)(aten::embedding) | 2 · p800-kunlunxin / ascend910 | 厂商委托 / Triton 探针 | A1(aten 拦截) | ✅ 定稿 | [REPORT](embedding/REPORT.md) | p800-kunlunxin + ascend910 · 稠密查表/反向 · 黄金 117/117(Ascend 三层+350 PASS)|

| [embedding](embedding/)(aten::embedding) | **2** · p800-kunlunxin / cambricon | 厂商委托 / Triton 探针 | A1(aten 拦截) | ✅ 定稿 | [REPORT](embedding/REPORT.md) | p800-kunlunxin + cambricon · 稠密查表/反向 · 黄金 174/174 逐位 · [MLU 报告](embedding/reports/cambricon.md) |
| [type_as](type_as/) | 1 · cambricon | Triton 级 | A1 aten | 三层全绿 | [REPORT.md](type_as/REPORT.md) | 黄金 111/111;位级一致 |
| [clone](clone/) | 1 · cambricon | Triton 级 | A1 aten | 三层全绿 | [REPORT.md](clone/REPORT.md) | 黄金 48/48;存储独立 |
| [contiguous](contiguous/) | 1 · cambricon | Triton 级 | A1 aten | 三层全绿 | [REPORT.md](contiguous/REPORT.md) | 黄金 114/114;转置 swiz 提速 ~80x |
Expand Down
56 changes: 52 additions & 4 deletions ops/embedding/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# embedding-op: `aten::embedding` P800/Kunlunxin 实现
# embedding-op: `aten::embedding` P800/Kunlunxin + Cambricon MLU 实现

按 FlagOS-OP 算子模板开发,范围为需求中的**普通稠密 Embedding 查表**:

Expand All @@ -23,8 +23,18 @@
| 验证 | kernel 20 forward + 6 backward;黄金 174/174;A1;应用层全绿 |
| 性能 | 大 shape 与 native embedding 基本持平(0.89-1.00x);Triton gather 慢 11-102x |

| 平台 | **2 个**:p800-kunlunxin / torch_xmlir;cambricon(MLU590)/ torch_mlu |
| 路线 | A1 拦截:P800 = `AutogradCUDA`,MLU = `AutogradPrivateUse1` |
| forward 生产实现 | 两平台均委托 native `aten::index_select` row gather |
| dense backward | native `aten::embedding_backward`(MLU 原生完整;XPU 缺分支见下) |
| `scale_grad_by_freq` | P800:per-occurrence inverse-frequency 补偿;MLU:原生实现直接委托 |
| 验证 | 两平台 kernel 20 forward + 6 backward;黄金 174/174 逐位;A1;应用层全绿 |
| 性能 | P800 大 shape 0.89-1.00x native;MLU 0.65-1.12x native;Triton gather 慢一个量级 |

## 快速开始

P800/Kunlunxin:

```bash
python3 example.py p800-kunlunxin # 或 EMBEDDING_PROFILE=ascend910 python3 example.py

Expand All @@ -37,6 +47,22 @@ python3 script/bench_dispatch.py --device cuda:1 \
--json-out reports/dispatch_p800-kunlunxin.json
```

Cambricon MLU(`MLU_VISIBLE_DEVICES=7`,测试卡 `mlu:0`):

```bash
python3 example.py cambricon

python3 script/check_accuracy.py --impl cambricon --device mlu:0
python3 script/bench_perf.py --device mlu:0 --dtype float16 \
--json-out reports/perf_fp16_cambricon.json
python3 scripts/perf_run.py --device cambricon --pattern ops.embedding
python3 scripts/perf_compare.py --device cambricon
python3 script/bench_dispatch.py --device mlu:0 \
--json-out reports/dispatch_cambricon.json
```

平台接入细节见 [reports/cambricon.md](reports/cambricon.md)。

## 实现策略

### Forward
Expand All @@ -50,6 +76,10 @@ torch.ops.aten.index_select(weight, 0, flat_indices)

这避免 A1 注册后的 dispatcher 递归,同时复用 XMLIR 的 native row-gather。

Cambricon MLU 侧同样委托 `aten::index_select`,与 CPU 参考逐位一致
(`kernel/cambricon.py`)。两平台由 [kernel/platform.py](kernel/platform.py)
按 `tensor.device.type` 路由,测试、bench 与 A1 注册共用同一条调用路径。

多 rank indices 先 flatten,再恢复:

```text
Expand All @@ -64,7 +94,11 @@ torch.ops.aten.index_select(weight, 0, flat_indices)
aten::embedding_backward
```

`scale_grad_by_freq=True` 时 XPU native 报:
**Cambricon MLU:原生 `aten::embedding_backward` 完整**——`padding_idx` 与
`scale_grad_by_freq=True` 都已实现且与 CPU 参考 6/6 组合 `err=0`,因此直接
委托、无任何补偿代码(与 P800 的 XPU 方案形成对照)。

**P800/Kunlunxin** 上 `scale_grad_by_freq=True` 时 XPU native 报:

```text
Check scale_grad_by_freq == false failed
Expand All @@ -77,7 +111,8 @@ Check scale_grad_by_freq == false failed
3. 再交给 dense backward 求和;
4. 保持 padding 行梯度为 0。

该路径与 CPU `aten::embedding_backward` 语义对齐。
该路径与 CPU `aten::embedding_backward` 语义对齐(仅 P800/XPU 需要;
MLU 直接走原生分支)。

## Triton 实验

Expand Down Expand Up @@ -126,6 +161,18 @@ P800/Kunlunxin Triton gather 性能已达到 native row-gather
本页数字来自当前锁定镜像与组织 gatherFIX 算法的 P800 特化探针;更新版
FlagGems 仍应按环境升级 runbook 重测。

MLU 上同一探针更不具竞争力(fp16,[perf_fp16_cambricon.json](reports/perf_fp16_cambricon.json)):

| shape | native | ours/index_select | Triton |
|---|---:|---:|---:|
| 1k×D128 | 0.0445ms | 0.0681ms | 0.2995ms |
| 16k×D128 | 0.0451ms | 0.0612ms | 2.3029ms |
| 131k×D128 | 0.0662ms | 0.0819ms | 失败(`grid=65536 > 65535`) |
| 16k×D512 | 0.0617ms | 0.0550ms | 10.5459ms |

即比 native 慢 6.7-171x,且 131k indices 会撞 Triton grid 上限直接 launch
失败——Triton gather 在两平台都只作精度对照。

## FlagOS 框架测试口径

框架/应用验证运行在 FlagOS 算子栈内:
Expand All @@ -147,4 +194,5 @@ flag_gems.only_enable(include=["gelu"]) # 消费方 surrounding op 走 FlagGems
- 不覆盖稀疏 / fused optimizer;
- weight 仅支持 FP32 / FP16 / BF16;
- indices 支持 int64 / int32;
- CPU profile 仅用于 reference,生产 backend 绑定 XMLIR/CUDA。
- CPU profile 仅用于 reference,生产 backend 绑定 XMLIR/CUDA(P800)与
torch_mlu(cambricon),由 [kernel/platform.py](kernel/platform.py) 按设备路由。
113 changes: 113 additions & 0 deletions ops/embedding/REPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
| 路线 | **A1**(aten 拦截) |
| 日期 / 状态 | 2026-09-30 / 定稿(第二平台) |

| 算子 | `aten::embedding` |
| 范围 | 普通查表 forward + dense backward;`sparse=True` forward 可用,稀疏 backward 不覆盖 |
| 硬件平台 | **2 个**:Kunlunxin P800(profile `p800-kunlunxin`,`torch_xmlir`);Cambricon MLU590(profile `cambricon`,`torch_mlu`) |
| 路线 | A1:P800 = `AutogradCUDA`,MLU = `AutogradPrivateUse1` |
| 日期 / 状态 | 2026-09-24 / 两平台三层与黄金全绿 |

## 实现矩阵(每平台)

| 平台 | 级别 | 文件 | 生产路径 | 状态 |
Expand Down Expand Up @@ -39,6 +45,40 @@ gather,行采集是厂商库强项,**生产委托是两平台一致的工程
| dispatch(p800) | `script/bench_dispatch.py` | A1 vs native 附加约 0.024ms |
| gatherFIX 对照(p800) | `script/probe_gatherfix.py` | 正确性 0 error;P800 特化比 native 慢 10.9-177.9x |

| 平台 / 级别 | 文件 | 状态 | 说明 |
|---|---|---|---|
| P800 厂商委托 | [kernel/p800_kunlunxin.py](kernel/p800_kunlunxin.py) | ✅ | forward 走 native `index_select`;dense backward 走 native `embedding_backward`;XPU 缺 `scale_grad_by_freq` → 自实现 inverse-frequency 补偿 |
| Cambricon MLU 委托 | [kernel/cambricon.py](kernel/cambricon.py) | ✅ | forward 走 native `index_select`;backward 走 native `embedding_backward`(`padding_idx`/`scale_grad_by_freq` 完整,无需补偿);`sparse=True` backward 显式拒绝 |
| 多平台门面 | [kernel/platform.py](kernel/platform.py) | ✅ | 按 `tensor.device.type` 路由后端,附 `dispatch_key_for` / `synchronize`;测试与 A1 注册共用 |
| Triton 级 | [kernel/triton_level.py](kernel/triton_level.py) | ✅ 探针 | 正确但比 native gather 慢,未接入生产 |
| torch 级 | [kernel/torch_level.py](kernel/torch_level.py) | ✅ | 独立 index-select 参考/对照 |
| 硬件级 | [kernel/hardware_level/README.md](kernel/hardware_level/README.md) | ⬜ 置空 | native row-gather 已达到生产水位,暂无重写收益 |

## 验证矩阵(三层,P800)

| 层级 | 入口 | 结果 |
|---|---|---|
| kernel forward | `test/kernel_level.py p800-kunlunxin` | 20/20,FP32/FP16/BF16 全部 0 error |
| kernel backward | 同上 | 6/6;重复 index、padding、`scale_grad_by_freq` 全部 0 error |
| 黄金 | `script/check_accuracy.py --impl p800` | 174/174,worst=0 |
| A1 op | `test/op_level.py` | 拦截 5 次;hooked=direct 逐位;dense/scale/sparse 边界全绿 |
| 应用层 | `test/framework_level.py`(FlagGems enabled) | `nn.Embedding` + MLP;logits/梯度 0 diff;贪心一致率 1.00 |
| 性能 | `script/bench_perf.py` | 大 shape native parity;Triton 显著慢 |
| dispatch | `script/bench_dispatch.py` | native / direct 行有效;**A1 行作废待复测**(见遗留 4) |

## 验证矩阵(三层,cambricon / MLU590)

| 层级 | 入口 | 结果 |
|---|---|---|
| kernel forward | `test/kernel_level.py cambricon` | 20/20,FP32/FP16/BF16 全部 0 error |
| kernel backward | 同上 | 6/6 全部 `err=0`(含 `scale_grad_by_freq`,原生实现);守卫 2 项通过 |
| 黄金 | `script/check_accuracy.py --impl cambricon --device mlu:0` | 174/174,worst=0(逐位) |
| A1 op | `test/op_level.py cambricon` | 拦截 5 次;hooked=direct 逐位;dense/scale grad 0 error;sparse fwd 接受 / bwd 拒绝 |
| 应用层 | `test/framework_level.py cambricon` | 拦截 8 次;logits 0 diff;贪心一致率 1.00;FlagGems gelu 生效 |
| 性能 | `script/bench_perf.py --device mlu:0` | 见下表;gate `FAIL 0 · WARN 0 · NEW 0` |
| dispatch | `script/bench_dispatch.py --device mlu:0` | A1 − native ≈ **+0.059ms**(3 轮 0.059/0.060/0.061) |
| 单测 | `pytest tests/unit -q` | 20 passed |

## 性能速览(fp16)

| shape | ours(index_select) | native F.embedding | Triton 探针 |
Expand All @@ -49,15 +89,88 @@ gather,行采集是厂商库强项,**生产委托是两平台一致的工程

完整数据: reports/perf_fp16_ascend910.json。

P800 forward(fp16):

| shape | ours | native | Triton | ours/native |
|---|---:|---:|---:|---:|
| 1k×D128 | 0.0680ms | 0.0358ms | 0.2403ms | 0.526x |
| 16k×D128 | 0.0514ms | 0.0494ms | 2.2206ms | 0.963x |
| 131k×D128 | 0.1665ms | 0.1530ms | 16.9373ms | 0.919x |
| 16k×D512 | 0.0616ms | 0.0548ms | 8.7184ms | 0.889x |
| vocab128k 16k×D128 | 0.0514ms | 0.0515ms | 2.2458ms | 1.001x |

P800 backward 16k×D128:

## A1 注册点(平台差异,sdpa 开发报告 §3.1 证据链复用)

torch_npu 栈拦截点为 **AutogradPrivateUse1**(PrivateUse1 永不命中);
register_a1 已按 dispatch_key 自动选择 backend(p800→AutogradCUDA /
ascend→AutogradPrivateUse1),或显式 `platform="ascend910"`。

cambricon forward(fp16,[perf_fp16_cambricon.json](reports/perf_fp16_cambricon.json)):

| shape | ours | native | Triton | ours/native |
|---|---:|---:|---:|---:|
| 1k×D128 | 0.0681ms | 0.0445ms | 0.2995ms | 0.654x |
| 16k×D128 | 0.0612ms | 0.0451ms | 2.3029ms | 0.736x |
| 131k×D128 | 0.0819ms | 0.0662ms | 失败(grid 65536>65535) | 0.809x |
| 16k×D512 | 0.0550ms | 0.0617ms | 10.5459ms | **1.123x** |
| vocab128k 16k×D128 | 0.0525ms | 0.0404ms | 2.3306ms | 0.769x |

cambricon backward 16k×D128:

| mode | ours | native | ours/native |
|---|---:|---:|---:|
| dense | 0.2651ms | 0.2497ms | 0.942x |
| scale_grad_by_freq | 0.2944ms | 0.2796ms | 0.950x |

性能门禁(cambricon):`ops.embedding.cambricon.forward` 0.060ms / 142.8 GB/s,
`ops.embedding.native.forward` 0.045ms / 187.9 GB/s;`perf/baselines/cambricon.json`
共 33 条 case。

## 结论与遗留

## 结论

第二平台按 MERGE 流程合入: 生产路径与 P800 同构(厂商委托),
三层 + 黄金 + 性能全绿,委托实现 err=0.0。Triton 探针数据进一步
佐证两平台一致的结论——embedding 峰值属厂商库,Triton 价值在
长尾与可移植(若未来需要自定义 padding 语义/量化查表再启用)。

第二平台(cambricon)进一步印证:**原生算子能力决定实现复杂度**——MLU 的
`embedding_backward` 完整,MLU 后端因此是纯委托(零补偿代码);XPU 缺
`scale_grad_by_freq`,P800 后端才需要 inverse-frequency 补偿。两平台共用同一
套三层测试与 174 条黄金数据,逐位判据一致。

## 交付物清单

| 内容 | 位置 |
|---|---|
| 需求 | [requirement.md](requirement.md) |
| 语义参考 | [reference.py](reference.py) |
| P800 backend | [kernel/p800_kunlunxin.py](kernel/p800_kunlunxin.py) |
| Cambricon backend | [kernel/cambricon.py](kernel/cambricon.py) |
| 多平台门面 | [kernel/platform.py](kernel/platform.py) |
| A1 注册 | [register.py](register.py) |
| 一键三层 | [example.py](example.py) |
| 测试报告 | [reports/test-report.md](reports/test-report.md) |
| 精度报告 | [reports/accuracy.md](reports/accuracy.md) |
| 性能报告 | [reports/performance.md](reports/performance.md) |
| 开发报告 | [reports/development.md](reports/development.md) |
| cambricon 平台报告 | [reports/cambricon.md](reports/cambricon.md) |
| cambricon 性能原始数据 | [reports/perf_fp16_cambricon.json](reports/perf_fp16_cambricon.json) |
| cambricon dispatch 原始数据 | [reports/dispatch_cambricon.json](reports/dispatch_cambricon.json) |
| perf 门禁基线 | `perf/baselines/cambricon.json`(33 case,含本算子 2 条) |

## 遗留

1. `sparse=True` backward / sparse weight gradient 不在本期范围(MLU 侧显式
`NotImplementedError`,避免 torch_mlu 返回 COO 稀疏梯度);
2. `scale_grad_by_freq=True` 是能力补齐路径:P800 比 dense backward 慢约 47%,
MLU 慢约 11%;
3. Triton gather 仅保留为平台证据,不作为生产实现(MLU 上 131k indices 还会
撞 grid 65535 上限);
4. **P800 的 A1 dispatch 数字作废待复测**:历史 `+0.0241ms` 出自
`bench_dispatch.py` 未持有 `torch.library.Library` 的缺陷(析构即反注册,
实测的是未注册状态),本机无 `torch_xmlir` 无法重测;native / direct 两行
仍然有效。详见 [reports/cambricon.md](reports/cambricon.md) §7。
Loading
Loading