Skip to content

DeepSeek V4-Pro

models/deepseek_v4_pro/ is the Ascend 950 (A5) implementation for DeepSeek-V4 Pro, with an optional Flash architecture preset. Select the preset at import and compile time with DEEPSEEK_V4_VARIANT=pro|flash or --variant pro|flash.

Deployment configuration

The PRO and FLASH presets in config.py define the architecture-specific shapes and layer schedules. Pro remains the default so existing operator entry points and DailyCI keep their prior behavior.

Deployment property Value
Speculative decoding MTP = 1 (DECODE_SEQ = 2)
Decode batch per card 4 requests → 8 token rows per step
Decode context length up to 16,384 positions (KERNEL_MAX_SEQ_LEN), 128-token pages
Prefill shape one request of 128 tokens per program
Platform Ascend A5 (-p a5); full forwards are device-only
Expert parallelism --ep 2/4/8, 384 / ep routed experts per rank
LM-head parallelism --tp 2/4/8 vocab shards; LM_HEAD_TP_SIZE = 8 is the deployment value
Other components no tensor parallelism — attention is data-parallel, MoE is expert-parallel
Quantization Hybrid MXFP8-MXFP4 — MXFP8 for the dense path, MXFP4 for the routed-expert weights
Serving none — no pypto-serving deployment consumes this tree

PRO.max_position_embeddings keeps the architectural one-million-position value, but admitting 1 M positions would need a ~64× larger physical pool than the cases allocate and a host-side golden nobody can compute. PRO_KERNEL therefore replaces it with KERNEL_MAX_SEQ_LEN = 16384 — an 8k prompt plus 512 decode steps, the budget the Flash cases already exercise. Raise that one constant if a case needs a longer context.

Native MXFP8-MXFP4 is not implemented yet. The tracked kernels run an INT8 stand-in with the same tensor split as V4-Flash: gen_routed_weight in expert_routed.py re-quantizes off the MXFP4 grid into INT8 rather than feeding the cube MXFP4 weights.

Model shape and layer schedule

Pro is wider and deeper than Flash: 7168 hidden, 128 attention heads, a 1536 Q-LoRA rank, 16 output-projection groups, moe_intermediate_size = 3072, 384 routed experts with top-6 routing plus 1 shared expert, and an indexer top-k of 1024. compress_ratios carries 62 entries — 61 model layers plus the MTP layer:

Ratio Path Layers Count
128 HCA — ratio-128 compressor, deterministic top-k 0, 1, 3, 5, …, 59 31
4 CSA — ratio-4 compressor plus the learned indexer 2, 4, …, 60 30
0 SWA — sliding window only the MTP layer 1

Unlike Flash, the main stack has no SWA layer; SWA appears only in the MTP layer, which is why decode_attention_swa is reachable from decode_mtp but not from decode_fwd. The first three layers route by hash (num_hash_layers = 3).

Model structure, top down

decode_fwd and prefill_fwd

Both hand-unroll the layer schedule inside one rank-generic @pl.jit kernel launched per EP rank, with every attention and MoE stage in its own pl.scope():

decode_fwd     layers 0, 1        decode_attention_hca → moe
               loop over pairs    decode_attention_csa → moe   (even layers)
                                  decode_attention_hca → moe   (odd layers)
               layer 60           decode_attention_csa → moe
               tail               hc_head → rms_norm

prefill_fwd    same schedule with prefill_attention_{hca,csa} → moe,
               tail               hc_head → rms_norm

Both forwards finish with the final norm and LM-head sampling. The standalone lm_head.py entry point validates that distributed tail separately.

One layer

attention   hc_pre → rmsnorm → qkv_proj_rope → (compress / index) → sparse_attn → hc_post
moe         hc_pre → gate → expert_shared → dispatch → expert_routed → combine → hc_post

decode_layer and prefill_layer expose exactly this pair as standalone two-rank harnesses.

Attention paths

decode_attention_swa   hc_pre → rmsnorm → qkv_proj_rope
                              → decode_sparse_attn_swa                   → hc_post
decode_attention_hca   hc_pre → rmsnorm → qkv_proj_rope
                              → decode_compressor_ratio128
                              → decode_sparse_attn_hca                   → hc_post
decode_attention_csa   hc_pre → rmsnorm → qkv_proj_rope
                              → decode_compressor_ratio4 (main + inner)
                              → decode_indexer → decode_indexer_compressor
                              → decode_sparse_attn                       → hc_post

prefill_attention_swa  hc_pre/hc_post + rmsnorm + qkv_proj_rope + prefill_sparse_attn
prefill_attention_hca  … + prefill_compressor_ratio128
prefill_attention_csa  … + prefill_compressor_ratio4
                          + prefill_indexer → prefill_indexer_compressor

decode_sparse_attn is the CSA variant here (the Flash tree names it decode_sparse_attn_csa); all three own the fused grouped output projection. rope_tables generates the RoPE/YaRN tables on the host and decode_metadata lowers the fixture's paged-cache metadata.

MTP path

mtp_projection  e_proj(enorm(hidden)) + h_proj(hnorm(prev_hidden))
decode_mtp      mtp_projection → decode_attention_swa → moe → hc_head → rmsnorm
prefill_mtp     mtp_projection → prefill_attention_swa → moe → hc_head → rmsnorm

prefill_mtp reuses prefill_fwd's driver for the main-model pass.

Files

Group Files
Full forward decode_fwd.py, prefill_fwd.py
Layer composition decode_layer.py, prefill_layer.py
MTP decode_mtp.py, prefill_mtp.py, mtp_projection.py
Decode attention orchestration decode_attention_swa.py, decode_attention_csa.py, decode_attention_hca.py
Decode sparse attention (fused o-proj) decode_sparse_attn.py, decode_sparse_attn_swa.py, decode_sparse_attn_hca.py
Decode compressors and indexer decode_compressor_ratio4.py, decode_compressor_ratio128.py, decode_indexer.py, decode_indexer_compressor.py
Prefill attention and cache prefill_attention_swa.py, prefill_attention_csa.py, prefill_attention_hca.py, prefill_sparse_attn.py, prefill_compressor_ratio4.py, prefill_compressor_ratio128.py, prefill_indexer.py, prefill_indexer_compressor.py
Shared transforms rmsnorm.py, qkv_proj_rope.py, hc_pre.py, hc_post.py, hc_head.py
MoE and output moe.py, gate.py, expert_shared.py, expert_routed.py, lm_head.py
Metadata and host helpers config.py, decode_metadata.py, rope_tables.py

config.py, decode_metadata.py, and rope_tables.py have no __main__ block and are imported rather than run. Which entry points CI schedules is defined by the daily model workflow.