Skip to content

Add DeepSeek-V4-Flash export support - #405

Merged
justinchuby merged 5 commits into
mainfrom
dsv4-flash-export
Jul 25, 2026
Merged

Add DeepSeek-V4-Flash export support#405
justinchuby merged 5 commits into
mainfrom
dsv4-flash-export

Conversation

@justinchuby

Copy link
Copy Markdown
Member

Summary

  • register deepseek_v4 and map the real GGUF deepseek4 architecture
  • export V4 Q/KV/grouped-output projections, Hyper-Connections, hash/sqrt-softplus MoE routing, shared experts, and clamped SwiGLU
  • add dense causal-attention preview fallback with KV cache plus 4/8-bit MatMulNBits graph support
  • add GGUF metadata/tensor mappings and onnx-genai / ort-genai runtime aliases
  • document the authoritative HF/GGUF config and V3-to-V4 architecture gap

Validation

  • 151 passed focused DeepSeek/GGUF/config tests
  • 37 passed DeepSeek graph/checker tests
  • 759 passed, 210 skipped V4/GGUF/model-coverage tests
  • 5 passed runtime CLI tests
  • Ruff lint and format checks pass

Deferred follow-ups

  • CSA/HCA learned KV compression, sparse indexer, attention sinks, and per-layer compressed RoPE (dense fallback is not numerically equivalent)
  • optional MTP component export
  • direct packed dynamic int2/int1 and MXFP4 expert import: add a runtime custom op plus mobius EP-capability configuration, and/or track the required MatMulNBits functionality in ONNX Runtime
  • optimized split-GGUF packed-expert repacking for the Unsloth shards

Closes no issue.

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing 68fdc67b246e5e

Model Sub-model Changes Status
bert (feature-extraction) model 0
falcon model 0
gemma2 model 0
gemma4 (gemma4) decoder 0
gemma4 (gemma4) embedding 0
gemma4 (gemma4) vision_encoder 0
gemma4_text model 0
gpt2 model 0
llama model 0
llama (static-cache) model 0
mamba (ssm-text-generation) model 0
phi3 model 0
phi3 (static-cache) model 0
qwen model 0
qwen (static-cache) model 0
qwen2 model 0
qwen2 (static-cache) model 0
qwen2_moe model 0
qwen2_moe (static-cache) model 0
qwen3 model 0
qwen3 (static-cache) model 0
qwen3_5_moe (hybrid-text-generation) model 0
qwen3_5_text (hybrid-text-generation) model 0
qwen3_5_vl (hybrid-qwen-vl) decoder 0
qwen3_5_vl (hybrid-qwen-vl) embedding 0
qwen3_5_vl (hybrid-qwen-vl) vision_encoder 0
qwen3_moe model 0
qwen3_moe (static-cache) model 0
qwen3_next (hybrid-text-generation) model 0
t5 (seq2seq) decoder 0
t5 (seq2seq) encoder 0
whisper (speech-to-text) decoder 0
whisper (speech-to-text) encoder 0

No architecture changes detected.


Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

Performance Comparison

Comparing 68fdc67b246e5e

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0%
bert (feature-extraction) num_nodes 60 60 +0.0%
falcon model_size_bytes 364 KB 364 KB +0.0%
falcon num_nodes 68 68 +0.0%
gemma2 model_size_bytes 428 KB 428 KB +0.0%
gemma2 num_nodes 107 107 +0.0%
gpt2 model_size_bytes 388 KB 388 KB +0.0%
gpt2 num_nodes 54 54 +0.0%
llama model_size_bytes 425 KB 425 KB +0.0%
llama num_nodes 62 62 +0.0%
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0%
llama (static-cache) num_nodes 58 58 +0.0%
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0%
mamba (ssm-text-generation) num_nodes 98 98 +0.0%
phi3 model_size_bytes 421 KB 421 KB +0.0%
phi3 num_nodes 60 60 +0.0%
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0%
phi3 (static-cache) num_nodes 56 56 +0.0%
qwen2 model_size_bytes 425 KB 425 KB +0.0%
qwen2 num_nodes 62 62 +0.0%
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0%
qwen2 (static-cache) num_nodes 58 58 +0.0%
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0%
qwen3_5_moe (hybrid-text-generation) num_nodes 275 275 +0.0%
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0%
qwen3_5_text (hybrid-text-generation) num_nodes 129 129 +0.0%
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0%
qwen3_5_vl (hybrid-qwen-vl) num_nodes 413 413 +0.0%
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0%
t5 (seq2seq) num_nodes 166 166 +0.0%
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0%
whisper (speech-to-text) num_nodes 128 128 +0.0%

No performance regressions.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.02093% with 40 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/mobius/models/deepseek_v4.py 90.84% 19 Missing and 19 partials ⚠️
src/mobius/_configs/_base.py 93.10% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@justinchuby

Copy link
Copy Markdown
Member Author

♻️ Rebased onto main to pick up #398 (onnx-genai InferenceMetadata export). Resolved the same __main__.py conflict: --runtime onnx-genai routes to #398's write_inference_metadata; stale alias CLI test updated accordingly. DeepSeek-V4-Flash export preview commit intact on top.

@justinchuby

Copy link
Copy Markdown
Member Author

Updated with DeepSeek-V4-Flash MTP + CSA export (commit 7e26e6e):

  • MTP sidecar: separate export with hidden-state (HC) input and ORT GenAI metadata for the multi-token-prediction head.
  • CSA (compressed sparse attention): 0/4/128 schedule, sparse-index + compression tensors, attention sinks, with a dense fallback so it runs on any runtime today.
  • Quantized GGUF passthrough preserved.

Known runtime gaps (dense fallback used until these land):

  1. Native sparse KV-cache / index gather ops (currently materialized dense).
  2. Iterative MTP orchestration (multi-step draft/verify cache sharing).

Validation: Ruff clean; 82 passed / 0 failed in the DeepSeek+MTP+CSA test scope (152 in the agent's full run).

justinchuby and others added 3 commits July 25, 2026 00:01
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 25, 2026 00:08

Copilot AI 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.

Pull request overview

Adds DeepSeek-V4-Flash export support to mobius, including a new model/task pair, GGUF config + tensor mapping for the deepseek4 GGUF architecture, and ORT GenAI export metadata (including an optional MTP sidecar).

Changes:

  • Introduces DeepSeekV4CausalLMModel and DeepSeekV4Task (decoder + optional MTP sidecar) and registers deepseek_v4 across the registry/tasks.
  • Adds DeepSeek4 GGUF metadata extraction + tensor-name mapping, plus loader support for deferred quantized projections.
  • Extends ORT GenAI auto-export to recognize deepseek_v4, handle multi-component packages’ decoder filename, and emit mtp_config.json when present; adds unit tests and design doc.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/model_coverage_test.py Adds deepseek_v4 to “registered without test_model_id” coverage list.
tests/_test_configs.py Adds representative tiny config coverage for deepseek_v4.
src/mobius/tasks/_deepseek_v4.py New task building decoder and optional mtp sidecar graphs with KV cache I/O.
src/mobius/tasks/init.py Exposes DeepSeekV4Task and registers task key deepseek-v4.
src/mobius/models/deepseek_v4.py New DeepSeek-V4 dense-fallback model implementation + weight remapping.
src/mobius/models/deepseek_v4_flash_test.py Adds config extraction, graph-build, mapping, quantization, and ORT GenAI metadata tests.
src/mobius/models/init.py Exports DeepSeekV4CausalLMModel.
src/mobius/integrations/ort_genai/auto_export.py Adds model-type alias, fixes decoder filename for multi-component packages, emits mtp_config.json.
src/mobius/integrations/gguf/_tensor_mapping.py Adds deepseek4 tensor mapping and “@ suffix” rule for no-suffix params.
src/mobius/integrations/gguf/_tensor_mapping_test.py Adds mapping tests for deepseek4.
src/mobius/integrations/gguf/_reader_test.py Adds arch→model_type mapping and DeepSeek4 config extraction test.
src/mobius/integrations/gguf/_config_mapping.py Adds DeepSeek4 metadata field mapping + YaRN rope_scaling assembly + swiglu_limit list handling.
src/mobius/integrations/gguf/_builder.py Treats deferred GGUF quantized projections as repack targets.
src/mobius/_registry.py Registers deepseek_v4 model type, default model id, and metadata tags.
src/mobius/_configs/_base.py Adds DeepSeek-V4 config fields and HF config extraction logic.
DSV4_FLASH_EXPORT.md Documents DeepSeek-V4-Flash authoritative config and architecture gaps.

Comment on lines +137 to +145
self.hash_routing = layer_id < config.num_hash_layers
self.weight = nn.Parameter([self.num_experts, config.hidden_size])
if self.hash_routing:
self.tid2eid = nn.Parameter(
[config.vocab_size, self.top_k], dtype=ir.DataType.INT32
)
else:
self.bias = nn.Parameter([self.num_experts])

Comment on lines +163 to +165
if self.hash_routing:
selected_experts = op.Gather(self.tid2eid, input_ids, axis=0)
else:
@justinchuby

Copy link
Copy Markdown
Member Author

Addressed both Copilot findings: the router bias is now materialized for hash-routed layers so all GGUF checkpoint biases load, and hash-route expert indices are cast to INT64 before GatherElements.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 25, 2026 00:51

Copilot AI 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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/mobius/tasks/_deepseek_v4.py:64

  • KV cache output stamping is hard-coded to num_kv_heads=1. This should use config.num_key_value_heads to keep the present KV output types consistent with the cache inputs and the resolved config.
        _register_kv_cache_outputs(
            builder,
            presents,
            batch=batch,
            num_kv_heads=1,

Comment on lines +36 to +44
past_key_values = _make_kv_cache_inputs(
builder,
num_layers,
1,
config.head_dim,
config.dtype,
batch,
past_sequence_length,
)
Comment on lines +864 to +870
num_hash_layers=(
getattr(config, "num_hash_layers", None)
or getattr(config, "n_hash_layers", 0)
or _leading_layer_type_count(
getattr(config, "mlp_layer_types", None), "hash_moe"
)
),
Copilot AI review requested due to automatic review settings July 25, 2026 01:55

Copilot AI 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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comment on lines +670 to +673
hidden_states = op.Expand(
op.Unsqueeze(hidden_states, [-2]),
[1, 1, self.hc_mult, 1],
)
@justinchuby
justinchuby marked this pull request as ready for review July 25, 2026 02:12
@justinchuby
justinchuby requested a review from a team July 25, 2026 02:12
@justinchuby
justinchuby merged commit 5544f2c into main Jul 25, 2026
22 of 24 checks passed
@justinchuby
justinchuby deleted the dsv4-flash-export branch July 25, 2026 02:12
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