Skip to content

Add Qwen3 14B A8W8 kernels#642

Merged
zhangqi-chen merged 1 commit into
hw-native-sys:mainfrom
vegetabledoww:qwen3-a8w8-stage4-generate
Jul 9, 2026
Merged

Add Qwen3 14B A8W8 kernels#642
zhangqi-chen merged 1 commit into
hw-native-sys:mainfrom
vegetabledoww:qwen3-a8w8-stage4-generate

Conversation

@vegetabledoww

@vegetabledoww vegetabledoww commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Add the Qwen3-14B A8W8 kernel implementation used by the native serving path.

This PR keeps the existing BF16 Qwen3 path isolated and introduces separate A8W8 prefill/decode modules for the quantized model:

  • add prefill_hidden support for Qwen3-14B A8W8 hidden-state prefill chunks
  • add the optimized A8W8 decode_fwd layer kernel used by serving decode
  • handle INT8 weights, activation/weight scales, paged KV cache scale metadata, and A8W8-specific decode constants inside the A8W8 modules
  • keep scheduling, model loading, tokenizer, and request orchestration in pypto-serving rather than carrying standalone lib-side runners
  • keep the ordinary BF16 Qwen3-14B execution path separate from the A8W8 path

Implementation Notes

The lib-side deliverable is intentionally limited to kernels and kernel-adjacent compatibility:

  • models/qwen3/14b/prefill_fwd_a8w8.py implements the A8W8 prefill hidden path
  • models/qwen3/14b/decode_layer_a8w8.py implements the A8W8 decode layer path used by serving
  • golden/runner.py compatibility changes keep generated/runtime artifacts runnable for the JIT path
  • obsolete standalone debug/golden entry points were removed during slimming; debug-stage switches in the kernel remain available for targeted numerical diagnosis

Validation

End-to-end validation was run through the native serving stack with this kernel PR plus the matching serving/backend PRs:

  • prompt: 介绍一下北京故宫
  • generated tokens: 48
  • output quality: normal Chinese continuation
  • TTFT: 7.054s
  • TPOT: 67.8 ms/token
  • decode throughput: 14.76 tok/s

Focused serving and PyPTO checks also passed in the matching PRs.

Related PRs / Issues

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 18cbf1a5-0939-4f03-977b-27dfd695ede1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Extends golden/runner.py with L3 runtime compatibility shims, a _compile_jit_with_compat fallback helper, graceful rebuild handling, and a save_actual_data parameter in run/run_jit. Adds two new Qwen3-14B A8W8 JIT kernel files (decode_layer_a8w8.py, prefill_fwd_a8w8.py) totaling ~2800 lines, and fixes a pl.tensor.set_validshape API call in rms_lm_head.py.

Changes

Golden Runner Compatibility and save_actual_data

Layer / File(s) Summary
L3 and JIT compatibility patch helpers
golden/runner.py
Adds re/importlib.util imports and internal helpers for: C++ bitcast attribute patching, Python orchestration SSA rewriting, Worker.chip_contexts shim, submit_next_level wrapping, and per-kernel block_dim/aicpu_thread_num propagation from generated kernel_config.py files.
Wiring compat helpers + _compile_jit_with_compat + tests
golden/runner.py, tests/golden/test_runner.py
Calls L3 shims in _try_l3_dispatch, applies patch helpers in run() before execution, adds graceful ModuleNotFoundError fallback in _setup_runtime_dir, introduces _compile_jit_with_compat (prefers fn.compile, falls back to _bind_args+_compile_to_program+pypto.ir.compile), and covers both paths in TestJitCompileCompat.
save_actual_data in run() and run_jit()
golden/runner.py
Adds save_actual_data: bool = False to both public signatures, updates docstrings, and persists runtime outputs to work_dir/data/actual when save_data is enabled and either no golden_data dir is set or save_actual_data is True.

Qwen3-14B A8W8 Decode Kernel

Layer / File(s) Summary
Architecture constants, shapes, and assertions
models/qwen3/14b/decode_layer_a8w8.py
Defines module header, debug-stage config, all fixed architecture constants, derived tensor/cache/tiling shapes, and alignment assertions.
_decode_layer: RMSNorm, QKV projection, RoPE, KV cache
models/qwen3/14b/decode_layer_a8w8.py
Implements _decode_layer entrypoint: tensor allocation, input RMSNorm, INT8 activation quantization, Q/K/V INT8 matmul+dequant, RoPE, paged KV cache INT8 write with per-row scales, and fa_work_table construction.
Fused paged attention and online softmax
models/qwen3/14b/decode_layer_a8w8.py
Creates accumulator scratch, dequantizes K-cache tiles, executes fa_fused for per-block softmax partials, then reduces via online_softmax to produce attn_out.
Out-projection, MLP, debug branches, and decode_fwd
models/qwen3/14b/decode_layer_a8w8.py
Implements split-K out-projection, residual add, post-RMSNorm, MLP gate/up/SiLU/down split-K accumulation, debug-stage branches, final output consolidation, and the 40-layer decode_fwd wrapper.

Qwen3-14B A8W8 Prefill Kernel and rms_lm_head Fix

Layer / File(s) Summary
Constants, prefill_layer signature, and dynamic bindings
models/qwen3/14b/prefill_fwd_a8w8.py
Defines module header, dimension/tiling constants, debug-stage config, and prefill_layer exported kernel signature with all dynamic tensor shapes.
RMSNorm, activation quantization, QKV projections, and head RMSNorm
models/qwen3/14b/prefill_fwd_a8w8.py
Outer batch/token-tile iteration, input RMSNorm, INT8 activation quantization, A8W8 Q projection with dequant, shared K/V projections, and per-head Q/K RMSNorm.
RoPE, KV cache update, and chunked causal attention
models/qwen3/14b/prefill_fwd_a8w8.py
Applies RoPE, writes quantized K/V into paged cache with per-row scales, and runs chunked causal attention with online softmax and on-the-fly K/V dequantization.
Out-projection, RMSNorm, MLP, debug stages, and per-layer return
models/qwen3/14b/prefill_fwd_a8w8.py
A8W8 output projection with residual add and post-RMSNorm, debug-stage branches for intermediate tensor writes, non-debug MLP (SiLU gate, up, down projections), and per-layer return.
prefill_hidden_a8w8 wrapper and rms_lm_head API fix
models/qwen3/14b/prefill_fwd_a8w8.py, models/qwen3/14b/rms_lm_head.py
prefill_hidden_a8w8 kernel: token-major tiling copy, multi-layer prefill_layer iteration, and final hidden-state write. Fixes pl.set_validshapepl.tensor.set_validshape in rms_lm_head.py.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • hw-native-sys/pypto-lib#222: Introduces the run_jit() golden harness that this PR extends with save_actual_data and _compile_jit_with_compat.
  • hw-native-sys/pypto-lib#484: Refactors run_jit to use the public JITFunction.compile API, directly preceding this PR's fallback compatibility layer for when that API is absent.

Suggested labels

enhancement

🐇 A rabbit writes tensors in INT8 today,
With paged KV cache tucked neatly away.
save_actual_data now writes what we ran,
And compat shims patch every generated scan.
Forty decode layers, prefill in a loop—
The warren compiles, and the kernels regroup! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title succinctly states the main change: adding Qwen3 14B A8W8 kernels.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description matches the added Qwen3 A8W8 kernels and runner compatibility changes in the changeset.

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces full-layer decode and prefill forward passes for Qwen3-14B with A8W8 quantization, alongside compatibility shims and patching utilities in the test runner. The review feedback focuses on performance optimizations in the prefill implementation, suggesting the vectorization of row-by-row dequantization loops (for Q, K, and V projections) and the SiLU activation loop to eliminate scalar loop overhead on the NPU. Additionally, the reviewer recommends removing redundant pre-zeroing of the SiLU tile and simplifying a conditional boolean assignment in the runner utility.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread models/qwen3/14b/prefill_fwd_a8w8.py
Comment thread models/qwen3/14b/prefill_fwd_a8w8.py
Comment thread models/qwen3/14b/prefill_fwd_a8w8.py
Comment thread models/qwen3/14b/prefill_fwd_a8w8.py Outdated
Comment thread golden/runner.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@golden/runner.py`:
- Line 317: Ruff B010 is flagging the constant-name setattr usage in the Worker
setup. Replace the setattr-based property assignment in the code that defines
chip_contexts, and the similar assignment mentioned for the other location, with
direct class attribute assignment while preserving the same property behavior.
Use the existing Worker and property(_chip_contexts) symbols to locate the
affected spots and update both occurrences consistently.
- Around line 804-805: The docstring for the data-saving behavior is incomplete:
`save_actual_data` is documented only for the `golden_data` path, but `Runner`
also writes `data/actual` in the non-golden path even when it is false. Update
the documentation near the `Runner`/data persistence logic to describe both
branches clearly, or adjust the condition so `data/actual` is only saved when
intended; make sure the explanation matches the behavior in the relevant
`save_actual_data` handling and `golden_data` flow.
- Around line 391-395: The import handling in runner.py is too broad because the
ModuleNotFoundError around rebuild_kernel_cpp_from_pto also hides missing
transitive dependencies inside pypto.runtime.debug.pto_rebuild. Update the
fallback in the code path that imports rebuild_kernel_cpp_from_pto so it only
returns work_dir when the debug module itself is unavailable, and let other
import failures surface instead of silently reusing stale artifacts.
- Around line 1100-1101: run_jit() is missing the same generated-artifact
patching that run() applies, so JIT-compiled or reloaded runtime_dir artifacts
can still fail on bitcast/host_orch compatibility. After
_compile_jit_with_compat() and after any runtime_dir reload logic in run_jit(),
invoke the same patch helpers used by run() on the compiled output_dir /
work_dir before proceeding. Use the existing run(), _compile_jit_with_compat(),
and runtime_dir handling paths as the reference points so the JIT flow matches
the non-JIT artifact normalization.
- Around line 965-975: The JIT fallback compile path in runner.py is dropping
distributed settings, so entries that rely on L3/distributed mode are compiled
with the wrong configuration. Update the ir.compile call in the fallback that
rebuilds the ir.Program to forward compile_cfg["distributed_config"] (or the
equivalent distributed config value) alongside the existing run_config fields,
using the ir.compile entry point and the surrounding fallback logic as the place
to fix it.

In `@models/qwen3/14b/decode_layer_a8w8.py`:
- Line 193: The comments in the affected decode layer sections use ambiguous
multiplication glyphs that Ruff flags as RUF003. Update the marked comment text
in decode_layer_a8w8.py to replace each non-ASCII multiplication symbol with
plain ASCII wording like x or by, and apply the same cleanup in the other
flagged comment blocks near the related SEQ_TILE/head references.
- Around line 19-25: The copied harness docstring in decode_layer_a8w8.py is
stale and conflicts with the current serving path. Update or remove the header
block near the decode harness so it no longer says the program does not compile
and no longer references obsolete standalone script names; instead, describe the
native serving flow through decode_fwd and keep the docstring aligned with the
current kernel entrypoint and behavior.

In `@models/qwen3/14b/prefill_fwd_a8w8.py`:
- Around line 1120-1125: The final writeback in the prefill path is assembling a
full token tile into dynamic output even when the last tile is partial. Update
the writeback logic around out_chunk, out_out_quant_chunk_bf16, and pl.assemble
in prefill_fwd_a8w8 to trim the chunk with the same set_validshape handling used
for resid1_chunk before any out writeback, and make sure the same fix is applied
in the debug branches as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 25cbdbf0-d212-4a1a-b664-b3666d82adc1

📥 Commits

Reviewing files that changed from the base of the PR and between fd651c0 and c0e0128.

📒 Files selected for processing (5)
  • golden/runner.py
  • models/qwen3/14b/decode_layer_a8w8.py
  • models/qwen3/14b/prefill_fwd_a8w8.py
  • models/qwen3/14b/rms_lm_head.py
  • tests/golden/test_runner.py

Comment thread golden/runner.py Outdated
Comment thread golden/runner.py Outdated
Comment thread golden/runner.py Outdated
Comment thread golden/runner.py Outdated
Comment thread golden/runner.py Outdated
Comment thread models/qwen3/14b/decode_layer_a8w8.py Outdated
Comment thread models/qwen3/14b/decode_layer_a8w8.py Outdated
Comment thread models/qwen3/14b/prefill_fwd_a8w8.py Outdated
Add Qwen3-14B A8W8 prefill/decode kernels while keeping the path isolated from the BF16 Qwen3-14B implementation.

Decode composes generic PyPTO primitives directly for INT8 accumulation dequantization instead of relying on a PyPTO model-specific composite op.

Validation: 48-token generation for prompt '介绍一下北京故宫' completed with normal text quality, TTFT 6.220s, TPOT 70.5 ms/token after rebuilding pypto_core.
@vegetabledoww vegetabledoww force-pushed the qwen3-a8w8-stage4-generate branch from 352b23b to 44c6f3c Compare July 9, 2026 01:38
@zhangqi-chen zhangqi-chen merged commit 1ebb119 into hw-native-sys:main Jul 9, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants