Skip to content

[model, ops] feat: Kimi K3 on Ascend NPU training enablement - #1291

Draft
wangyier7 wants to merge 24 commits into
ByteDance-Seed:mainfrom
wangyier7:feat/kimi-k3-ascend
Draft

wangyier7 wants to merge 24 commits into
ByteDance-Seed:mainfrom
wangyier7:feat/kimi-k3-ascend

Conversation

@wangyier7

@wangyier7 wangyier7 commented Oct 12, 2026 •

Copy link
Copy Markdown

What does this PR do?

Scope claim for the complete Kimi K3 Ascend NPU enablement. Kimi K3 is a multimodal MoE — MoonViT3d vision tower + hybrid KimiDelta linear-attention / MLA text backbone + fine-grained MoE with shared experts. The branch lands the model integration with a patch-generation pipeline, NPU kernels, training recipes, docs, and validation configs. Parallel-training adaptation (FSDP2 + EP + Ulysses sequence-parallel with KDA/MLA head sharding) is included in the model patches; performance tuning and scale-out will follow as separate PRs on top of this base.

The branch is rebased onto main@83059808 and re-registered on the post-#1142 VeomniOp registry: patch rules use VeomniOp handles, sequence-parallel attention rides the built-in adapter Ulysses (veomni_flash_attention_2, no _with_sp aliases), and the fused-MoE kernel reuses the relocated moe_experts/standard/npu.py helpers instead of vendored copies.

Checklist Before Starting

  • Search for relative PRs/issues and link here: none found — no existing kimi_k3 / Kimi K3 PR or issue in the repo.
  • PR title follows [{modules}] {type}: {description} format: [model, ops] feat: Kimi K3 multimodal MoE training on Ascend NPUs.

Test

Two existing CI-enumerated tests were extended to cover the K3 registrations; validation beyond CI runs on an out-of-repo training harness on 8× Ascend 910B3 (COCO val2017):

  • Extended: tests/ops/base/test_op_config_names.py (new chunk_kda_implementation / situ_and_mul_implementation field mappings) and tests/ops/base/test_builtin_entries.py (K3 rows in the builtin-entries snapshot: eager/ascendc KDA, eager/triton SituGLU, eager/fused_npu MoE, plus NPU defaults). The existing tests/models/transformers/test_generated_modeling_imports.py imports the new generated files.
  • pytest on NPU: ops contracts 72 passed; moe_experts + rms_norm + argument aliases 105 passed / 63 skipped (skips are CUDA-only); attention op/mask + flash-attention suites green; loss green.
  • Repo-wide patchgen --check green (33 configs); ruff check + ruff format --check clean under the CI-pinned ruff 0.13.2; scripts/ci/check_doc_task_paths.py passes.
  • Post-rebase NPU smoke (seq 1024, SP2 / EP2 / FSDP2; fused_npu + AscendC KDA + triton SituGLU + chunk_loss): 200 steps, zero errors, loss 13.51 → 6.72, VRAM peak 50.15 GB (parity with the pre-rebase 50.12 GB baseline), ~16.9 s/it; DCP checkpoint round-trip verified; the profile trace confirms the situ / KDA / fused-MoE kernels active.
  • Pre-rebase equivalence gates (earlier commits): step-0 loss bitwise identical across SP1/SP2; 300-step real-data runs across attention-backend eras (eager / AscendC / fused-flash).
  • Wiring a kimi_k3 entry into the e2e workflows is planned once the enablement is stable.

API and Usage Example

Three additive OpsImplementationConfig fields (default eager; fused backends opt-in via the recipes):

ops = OpsImplementationConfig(
    chunk_kda_implementation="ascendc",     # fused AscendC KDA kernel
    situ_and_mul_implementation="triton",   # fused Triton-ascend SituGLU kernel
    moe_implementation="fused_npu",         # situ fused MoE group-GEMM (EP > 1)
)

The recipes set attn_implementation="veomni_flash_attention_2" — sequence parallelism comes from the adapter's built-in Ulysses, no name-suffix toggles. Recipes: configs/multimodal/kimi_k3/kimi_k3_vl{,_ascendc}.yaml; end-to-end walkthrough in docs/examples/kimi_k3.md. Env gates: K3_KDA_HEAD_SHARD=0 rolls back to the full-gather KDA path (default on); K3_KDA_SP_TIMING=1 is an opt-in phase-timing dump.

Design & Code Changes

  • veomni/models/transformers/kimi_k3/ — vendored model (source/) + patch-generation configs (source of truth; every patch and adaptation fix enumerated in their docstrings; VeomniOp handle pattern) + committed generated/ NPU/GPU modeling files with .diff companions (verified by patchgen --check, never hand-edited) + EP parallel plan + checkpoint tensor converter (targets the relocated veomni.models.checkpoint package).
  • NPU kernels registered as platform ops: chunked KDA (AscendC, 795 L), SituGLU (triton, 260 L), situ fused MoE group-GEMM (rebased onto moe_experts/standard/npu.py); rms_norm torch_npu variant.
  • Framework changes are additive: kernels registry, COCO→K3 conversations data transform + converter script, argument aliases, trainer micro-batch plumbing, README support table, docs.

Commit layout (17 commits): the original landing series ([ops] kernels, [model] validation configs, [model] to_empty fix, [trainer] config-driven VLM training, [scripts] COCO converter, [docs] recipe, [chore] community-readiness, [configs] GPU recipe, [docs] toctree), followed by the main-rebase series: merge of main@83059808, [model] refactor: patch rules → VeomniOp handles, [model] fix: SP → built-in Ulysses + op value names, [ops] fix: op metadata contract, [model] fix: checkpoint converter re-point, [ops] fix: situ fused-MoE onto relocated helpers, [model] fix: timing console notice, [model, ops] chore: ruff format + patchgen diff refresh.

Checklist Before Submitting

  • Read the Contribute Guide — yes
  • Applied pre-commit checks — yes: ruff check + ruff format --check (CI-pinned ruff 0.13.2), repo-wide patchgen --check (33 configs), and scripts/ci/check_doc_task_paths.py all green locally
  • Added/updated documentation — yes: docs/examples/kimi_k3.md (toctree-registered) + README support table
  • If tasks/ training scripts were moved or renamed — N/A (no tasks/ changes; the recipes call the existing tasks/train_vlm.py, doc task paths verified)
  • Tests — extended two existing CI-enumerated tests (see Test); e2e workflow wiring planned once stable

Note: the GPU generated modeling file is produced by the same patch pipeline and is NPU-validated only (no GPU environment was available).

@CLAassistant

CLAassistant commented Oct 12, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions Bot added the ascend everything about Ascend support label Oct 12, 2026
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@wangyier7 wangyier7 changed the title [model, ops] feat: Kimi K3 multimodal MoE on Ascend NPU training enablement [model, ops] feat: Kimi K3 on Ascend NPU training enablement Oct 12, 2026
@Coach257

Copy link
Copy Markdown
Collaborator

Heads-up on ordering: #1142 ([BREAKING][ops, model] refactor: replace OpSlot with VeomniOp) is planned to land before this PR, so please rebase onto main after it merges and build the kernel changes here on the new op registry.

What changes in #1142:

  • OpSlot / OpsConfigSlot / KERNEL_REGISTRY / KernelSpec (veomni.ops.dispatch, veomni.ops.kernel_registry) are removed.
  • Every kernel is a row registered with register_op(op, variant, impl, ..., requirement=..., requires=(...)), keyed by (op, variant, impl, device). The device is chosen with GpuKernelRequirement / NpuKernelRequirement / MluKernelRequirement.
  • Modeling code holds a handle: VeomniOp(op, variant, resolve_op_impl("<field>_implementation")). It does not read config fields or bind slots.
  • Kernels live under veomni/ops/kernels/<op>/<variant>/<impl>.py, with the rows in veomni/ops/kernels/<op>/__init__.py. Many files moved.

How to register and call an op: veomni/ops/README.md → Registering an op and Calling an op from modeling; config fields and available impls: docs/design/op_selection.md.

For this PR specifically:

  • veomni/ops/kernels/moe/ became veomni/ops/kernels/moe_experts/, with NPU MoE in moe_experts/standard/npu.py. rms_norm/npu.py became rms_norm/standard/npu.py.
  • The new families (glu, kda, and the npu_situ_gemm MoE path) should be added as veomni/ops/kernels/<op>/<variant>/<impl>.py plus register_op rows with NpuKernelRequirement().
  • Kimi K3's patch_gen should call them through VeomniOp instead of OpSlot.

…pipeline

Vendored Kimi K3 (MoonViT3d vision tower + hybrid KimiDelta linear-attention /
MLA text backbone + fine-grained MoE with shared experts) under
veomni/models/transformers/kimi_k3/:

- source/: HF modeling + config + kda_fallback (eager fallbacks), with 18
  adaptation fixes (dtype / varlen / packing / SP-loss causal shift,
  head-sharded KDA lasp5 path with g_post kept local)
- kimi_k3_{gpu,npu}_patch_gen_config.py: 14 patches + 6 OpSlot guards
  (rms_norm, moe_experts standard+kimi_k3, causal chunked CE loss,
  situ_and_mul, chunk_kda name hijack); npu config mirrors the gpu config
- generated/: patchgen output for both backends (incl. .diff), regen'd with
  the uv.lock-pinned ruff so check_patchgen stays drift-free
- parallel_plan.py (EP plan) + checkpoint_tensor_converter.py + registration

GPU generated file carries the same patch set but is NPU-validated only.
…used MoE)

- chunk_kda: fused AscendC forward+backward via flash-linear-attention-npu
  (kimi_k3 variant, varlen cu_seqlens + use_gate_in_kernel; eager
  chunk_kda_naive stays the fallback; the triton 'npu' backend was dropped
  after an EP>1 NaN race and 8-card OOM)
- situ_and_mul: vendored Triton-ascend SituGLU kernel (kimi_k3 variant)
- moe_experts/kimi_k3: group-gemm situ fused MoE forward (EP-aware, reads
  SituGLU beta/linear_beta off the act module)
- rms_norm: defensive dtype alignment for aclnnRmsNorm fp32-x + bf16-gamma
- OpsImplementationConfig: situ_and_mul_implementation / chunk_kda_implementation
  fields (default eager; opt-in fused backends)
…alwidth 10.61B)

- kimi_k3_toy: tiny smoke config (196M)
- kimi_k3_stage6: reduced-depth smoke config (2.69B)
- kimi_k3_realwidth: full real per-layer widths incl. real vision tower
  (10.61B); used for the 30-step SP2 equivalence gate (peak 48.4 GiB)
…/A_log)

FSDP2 meta flow materializes params with to_empty and relies on _init_weights to restore them, but two families hit no branch: (1) norm weights (KimiRMSNorm, nn.LayerNorm/RMSNorm) stayed zero - dead forward with loss==ln(V); (2) KimiDeltaAttention construction defaults (ShortConvolution is an nn.Conv1d subclass; A_log) stayed zero - q=k=v==0 puts chunk_kda at an exact bilinear saddle, zeroing gradients for the whole KDA branch. Both _init_weights copies now restore construction defaults (norm ones; Conv1d reset_parameters; A_log=log(U[1,16])). Verified: 239/239 params with nonzero grads at steps 0/150/299, 300-step coco loss 13.60->4.50 at 1.24s/step.
- kimi_k3 conversation transform (single-placeholder media template, 1-D per-sample tensors) + module-level picklable expanded-length fn

- model hooks via patchgen: get_position_id_func; get_extra_collate_infos (vision-redundant SP contract: pixel_values/grid_thws exempt from sp-slice); get_dyn_bsz_length_fn (partial of module-level fn; budgets model-side-expanded vision tokens for dynamic batching)

- data_loader: optional dyn_bsz_length_fn override; base trainer consumes the model hook (no-op for text models)

- configs: Kimi K3 Ascend training recipe + data/k3_coco.yaml

- verified: 30-step official-path run rc=0, loss 12.99->6.23, dcp + trainer-state checkpoints saved
…dataset reproduction)

argparse CLI matching scripts/multimodal/convert_data conventions; k3_coco.yaml now points at the in-repo tool
…trace cleanup

- configs: native full-width preset (configs/model_configs/kimi_k3/kimi_k3.json,
  layer table asserted against the release config); Ascend recipe renamed to
  kimi_k3_vl_ascendc.yaml with config_path wiring; drop superseded toy configs
  (kimi_k3_stage6, kimi_k3_realwidth)
- docs: README modernization; docs/examples/kimi_k3.md rework
- model: comment cleanup (drop internal phase/fix numbering and dev dates) +
  patchgen resync of the generated files
- kernels: drop stage/fix references from kda / moe docstrings
kimi_k3_vl.yaml mirrors the Ascend recipe (same reduced layout, data, and
parallel topology) with the GPU-valid op stack: flash-attn SP wrapper,
liger rms norm, chunked CE, eager KDA / SituGLU. The fused Kimi-specific
kernels (chunk_kda AscendC, situ fused MoE, situ_and_mul) are NPU-only, so
on GPU they run the pure-PyTorch eager paths and SituGLU experts always
take the eager expert loop (moe_implementation has no effect for this
model on GPU).
@wangyier7
wangyier7 force-pushed the feat/kimi-k3-ascend branch from ff0e98d to d021438 Compare October 19, 2026 04:31
docs/examples/kimi_k3.md was missing from the Examples toctree in
docs/index.md; under fail_on_warning Sphinx raises
"document isn't included in any toctree" and the Read the Docs build
fails. Add the entry.
…3 ops

Conflict resolution:
- README: keep our restructure; fold in upstream's MiniMax H3 row,
  op_selection link fix, and the 2025/08 news entry
- kernels/__init__.py: take the new family table; add kda + situ_and_mul
- moe/: drop the removed old family package; move npu_situ_gemm.py into
  moe_experts/kimi_k3/ as the fused_npu row with an eager twin
- rms_norm: drop the old npu.py; re-apply the aclnnRmsNorm mixed-dtype guard
  on the new standard/torch_npu.py raw pair (cast in forward, cast back in
  backward)
- models: re-point the kimi_k3 package init at the new
  veomni.models.registry (MODELING/CONFIG registries moved out of loader.py)

Also: glu/ -> situ_and_mul/ with eager+triton rows (impl value renamed
npu -> triton per the new naming rule); kda/ re-registered with eager +
ascendc rows; NPU recipe values updated (situ npu -> triton, rms_norm npu ->
torch_npu). Generated modeling files still reference the removed OpSlot API
and are regenerated in the follow-up commit.
…tern

Follow-up to the origin/main merge (ByteDance-Seed#1142 OpSlot -> VeomniOp refactor):
- KimiRMSNorm / SituAndMul: __init__-bound instance-local VeomniOp handles
  (rms_norm/standard, situ_and_mul/kimi_k3) replacing the OpSlot guards
- PatchedKimiK3Experts: branchless dispatch through an instance-local
  moe_experts VeomniOp (kimi_k3 variant for SituGLU, standard otherwise);
  the eager expert loop is now a registered row, not an in-rule fallback
- CE loss: ForCausalLMLoss bound to a cross_entropy_loss/standard VeomniOp
  via functools.partial on both KimiLinearForCausalLM and
  KimiK3ForConditionalGeneration (variant renamed causal -> standard)
- chunk_kda: name hijack now dispatches through a lazily-resolved
  chunk_kda/kimi_k3 VeomniOp (first-call resolution follows the ops config
  installed at model-build time)
- NPU config re-registers the new __init__ overrides; regen both targets

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ascend everything about Ascend support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants