pub struct ModelConfig {Show 122 fields
pub hidden_size: usize,
pub num_hidden_layers: usize,
pub intermediate_size: usize,
pub vocab_size: usize,
pub num_attention_heads: usize,
pub num_attention_heads_per_layer: Vec<usize>,
pub num_key_value_heads: usize,
pub head_dim: usize,
pub partial_rotary_factor: f64,
pub linear_num_key_heads: usize,
pub linear_key_head_dim: usize,
pub linear_num_value_heads: usize,
pub linear_value_head_dim: usize,
pub linear_conv_kernel_dim: usize,
pub num_experts: usize,
pub zero_expert_num: usize,
pub num_experts_per_tok: usize,
pub moe_intermediate_size: usize,
pub shared_expert_intermediate_size: usize,
pub norm_topk_prob: bool,
pub decoder_sparse_step: usize,
pub layer_types: Vec<LayerType>,
pub mtp_layer_types: Vec<LayerType>,
pub full_attention_interval: usize,
pub sliding_window: u32,
pub max_position_embeddings: usize,
pub rope_theta: f64,
pub rms_norm_eps: f64,
pub bos_token_id: u32,
pub glm5next_router_mode: Glm5NextRouterMode,
pub eos_token_id: u32,
pub eos_token_ids: Vec<u32>,
pub tie_word_embeddings: bool,
pub lm_head_bf16_override: Option<bool>,
pub lm_head_fp8: bool,
pub model_type: String,
pub mtp_num_hidden_layers: usize,
pub dspark_block_size: usize,
pub dspark_noise_token_id: u32,
pub dspark_target_layer_ids: Vec<usize>,
pub dspark_markov_rank: usize,
pub hybrid_override_pattern: String,
pub mamba_num_heads: usize,
pub mamba_head_dim: usize,
pub ssm_state_size: usize,
pub n_groups: usize,
pub expand: usize,
pub n_routed_experts: usize,
pub norm_eps: f64,
pub conv_kernel: usize,
pub moe_shared_expert_intermediate_size: usize,
pub routed_scaling_factor: f64,
pub linear_gate_lower_bound: f32,
pub swiglu_limit: f32,
pub mlp_only_layers: Vec<usize>,
pub moe_latent_size: usize,
pub moe_intermediate_sizes: Vec<usize>,
pub num_experts_per_toks: Vec<usize>,
pub kv_lora_rank: usize,
pub kv_layer_dims: Vec<(usize, usize)>,
pub q_lora_rank: usize,
pub qk_nope_head_dim: usize,
pub qk_rope_head_dim: usize,
pub v_head_dim: usize,
pub ngram_vocab_size_ratio: usize,
pub emb_neighbor_num: usize,
pub emb_split_num: usize,
pub ngram_vocab_size_base: usize,
pub ngram_split_parts: usize,
pub ple_layer_ids: Vec<usize>,
pub ple_conv_kernel_size: usize,
pub o_lora_rank: usize,
pub o_groups: usize,
pub yarn_mscale: f32,
pub yarn_mscale_all_dim: f32,
pub hc_mult: usize,
pub hc_sinkhorn_iters: usize,
pub hc_eps: f32,
pub hc_lowrank: usize,
pub final_norm_identity: bool,
pub compress_ratios: Vec<usize>,
pub index_n_heads: usize,
pub index_head_dim: usize,
pub index_topk: usize,
pub index_compress_ratio: usize,
pub index_kpool: usize,
pub index_kpool_always_select_tail: bool,
pub num_hash_layers: usize,
pub yarn_factor: f32,
pub yarn_beta_slow: f32,
pub yarn_beta_fast: f32,
pub yarn_original_max_position_embeddings: usize,
pub yarn_attention_factor: f32,
pub llama_4_scaling_beta: f32,
pub llama_4_scaling_original_max_position_embeddings: usize,
pub vision: Option<VisionConfig>,
pub quantization_config: Option<QuantizationConfig>,
pub attn_gated: bool,
pub gdn_norm_sigmoid: bool,
pub nested_config: bool,
pub mrope_section: [usize; 3],
pub mrope_interleaved: bool,
pub weight_prefix: String,
pub profile: bool,
pub ep_rank: usize,
pub ep_world_size: usize,
pub tp_rank: usize,
pub tp_world_size: usize,
pub serve_max_seq_len: usize,
pub fp8_kv_calibration_tokens: usize,
pub fp8_kv_headroom: f32,
pub final_logit_softcapping: f32,
pub embed_scale: f32,
pub scoring_func: String,
pub use_routing_bias: bool,
pub qk_norm_type: String,
pub num_mtp_modules: usize,
pub mtp_transformer_layers: usize,
pub rotary_dim: usize,
pub dflash_capture_layers: Vec<usize>,
pub dflash_gamma: Option<usize>,
pub adapter_max_rank: usize,
}Expand description
Model configuration parsed from HuggingFace config.json.
Single source of truth for model dimensions. All kernel launch parameters and buffer sizes derive from this struct.
Fields§
§intermediate_size: usize§vocab_size: usize§num_attention_heads: usize§num_attention_heads_per_layer: Vec<usize>Per-layer Q-head counts for heterogeneous attention models. Empty means
every layer uses num_attention_heads.
num_key_value_heads: usizeGQA: number of K/V heads (≤ num_attention_heads). MQA when 1.
head_dim: usize§partial_rotary_factor: f64Fraction of head_dim that gets RoPE-rotated. 1.0 = full RoPE,
0.5 = half-rotated (Phi-style). Default 1.0.
linear_num_key_heads: usize§linear_key_head_dim: usize§linear_num_value_heads: usize§linear_value_head_dim: usize§linear_conv_kernel_dim: usize1D causal-conv kernel size on the SSM input (typically 3 or 4).
num_experts: usize§zero_expert_num: usizeLongCat-Flash zero-computation “identity” experts: the router scores
num_experts + zero_expert_num logits, and a token routed to an
expert id >= num_experts receives the INPUT itself scaled by the
routing weight instead of an expert FFN. 0 = no zero-experts.
num_experts_per_tok: usizeTop-K experts activated per token (the “A” in 35B-A3B = 3B active params).
moe_intermediate_size: usize§norm_topk_prob: boolRenormalize routing probabilities so the K active experts sum to 1 after top-K selection. Qwen3.5+ sets true; older Qwen2 MoE variants set false.
decoder_sparse_step: usizeMoE block stride: layer i uses MoE iff i % decoder_sparse_step == 0. 1 = every layer is MoE. Mistral / DeepSeek-style stagger
uses 2.
layer_types: Vec<LayerType>Per-layer kind (FullAttention | LinearAttention | …) parsed from
HF config. When empty, falls back to full_attention_interval.
mtp_layer_types: Vec<LayerType>Per-layer kind for the extra layers that sit past num_hidden_layers:
multi-token-prediction / NextN blocks. Empty for models that have none.
Kept separate from layer_types on purpose. GLM-5.3-Flash’s layer 45 is a real
decoder layer with its own attention block, but num_hidden_layers is 45 and
config.layer_types has 45 entries covering 0..=44 — so layer 45 has no honest
slot there. Appending it would make every length check and every “iterate the text
stack” loop silently include a speculative-decoding layer. Look it up through
ModelConfig::layer_type_at, which routes indices past the text stack here.
full_attention_interval: usizeStride for full-attention layers in hybrid models when
layer_types is empty: every Nth layer is FullAttention, the
rest LinearAttention. 1 = every layer is full attention.
sliding_window: u32Gemma-4 hybrid-attention sliding window size (0 = full attention).
Sliding layers only attend to the last sliding_window KV positions;
full layers (every 6th in Gemma-4) ignore this (effectively 0).
Parsed from HF config.json sliding_window field. Uses nullable_u32
because Nemotron-H (and some other models) set it to null in JSON.
max_position_embeddings: usize§rope_theta: f64§rms_norm_eps: f64§bos_token_id: u32BOS token ID (null → 0 for models without explicit BOS).
glm5next_router_mode: Glm5NextRouterModeWhich dtype ladder GLM-5.3’s MoE router runs in. See Glm5NextRouterMode — this is a
semantic switch, and HfFp32 is the production default.
eos_token_id: u32The PRIMARY stop token. See ModelConfig::eos_ids for the complete set — a config may
declare several, and this holds only the first.
eos_token_ids: Vec<u32>The COMPLETE stop-token set. HF configs are allowed to declare eos_token_id as an
array, and several real checkpoints do — GLM-5.3-Flash declares three:
154820 <|endoftext|>, 154827 <|user|>, 154829 <|observation|>. eos_token_id
above holds only the PRIMARY one (element 0), which is what every scalar consumer and
every chat template wants; collapsing to it and discarding the rest is what made an
agent model unable to stop on its own turn terminators.
Populated by parse_config for every model family from the raw JSON, scalar or array.
Empty means “not populated” (a hand-built ModelConfig), NOT “no stop tokens” — read it
through ModelConfig::eos_ids, never directly.
tie_word_embeddings: bool§lm_head_bf16_override: Option<bool>CLI override (--lm-head-dtype) for LM-head quantization, set at serve time
(not from config.json). Some(true) = force BF16 lm_head; Some(false) = force
the model’s quantized lm_head; None = use the model-config-driven default.
Consumed by skip_lm_head_quantization(). Replaces the ATLAS_LMHEAD_BF16 env var.
lm_head_fp8: boolWhen skip_lm_head_quantization() == false, quantize the LM head to FP8
(E4M3, per-row scales, decoded via w8a16_gemv) instead of NVFP4.
Set by --lm-head-dtype fp8. Additive: leaves the NVFP4/BF16 paths
byte-identical when false.
model_type: String§dspark_block_size: usizeNumber of query positions generated by one semi-autoregressive draft pass. Zero means the checkpoint does not declare checkpoint-native DSpark.
dspark_noise_token_id: u32Token used to initialize the non-anchor positions in a DSpark block.
dspark_target_layer_ids: Vec<usize>Target layers whose hidden states are concatenated for the DSpark input.
dspark_markov_rank: usizeWidth of the low-rank Markov token transition head.
hybrid_override_pattern: String§mamba_num_heads: usize§mamba_head_dim: usize§ssm_state_size: usize§n_groups: usize§expand: usize§n_routed_experts: usizeNemotron-H uses n_routed_experts (mapped to num_experts in parse_config).
norm_eps: f64Nemotron-H uses norm_eps (mapped to rms_norm_eps in parse_config).
conv_kernel: usizeNemotron-H conv kernel size (mapped to linear_conv_kernel_dim in parse_config).
Nemotron-H shared expert intermediate (mapped to shared_expert_intermediate_size).
routed_scaling_factor: f64Nemotron-H routed scaling factor for expert outputs.
linear_gate_lower_bound: f32KDA forget-gate lower bound (linear_attn_config.gate_lower_bound). GLM-5.3 declares
-5.0; it bounds the log-decay kda_gate produces, so a defaulted 0.0 would clamp the
decay to a completely different range. Read by the glm5_next parser, never guessed.
swiglu_limit: f32SwiGLU clamp bound (swiglu_limit). 0.0 = the model does not clamp.
🔴 GLM-5.3-Flash declares swiglu_limit = 10.0, and the clamp is asymmetric:
gate is upper-bounded only, up is bounded both ways. Read, never defaulted for a
model that declares it — a missing clamp is invisible on well-scaled activations and
silently wrong on the tails (see kernels/gb10/common/glm5next_ffn.cu).
mlp_only_layers: Vec<usize>Decoder-layer indices that use a dense MLP instead of routed experts.
moe_latent_size: usizeLatentMoE: latent projection dimension for routed experts (Super 120B).
When present, routed experts operate in latent space [moe_latent_size]
instead of full [hidden_size]. Absent for Nano 30B.
moe_intermediate_sizes: Vec<usize>Per-layer MoE intermediate sizes (Nemotron-H Puzzle heterogeneous channel
pruning). Length == num_hidden_layers; 0 for non-MoE layers. Empty =
fall back to scalar moe_intermediate_size for every MoE layer.
num_experts_per_toks: Vec<usize>Per-layer top-K expert counts (Puzzle). Same layout as
moe_intermediate_sizes. Empty = use scalar num_experts_per_tok.
kv_lora_rank: usizeKV latent dimension for compressed cache. 0 = standard attention (no MLA).
kv_layer_dims: Vec<(usize, usize)>Per-layer KV cache dimensions (num_kv_heads, head_dim). Populated by loaders for heterogeneous-attention models (e.g. Gemma-4 with sliding and full attention having different head counts and dims). Empty for homogeneous models.
q_lora_rank: usizeQuery latent dimension for low-rank Q projection. 0 = standard Q.
qk_nope_head_dim: usizeNon-rotary portion of Q/K per head (NoPE component).
qk_rope_head_dim: usizeRotary portion of Q/K per head (RoPE component).
v_head_dim: usizeValue dimension per head (may differ from head_dim in MLA).
ngram_vocab_size_ratio: usizeN-gram table size multiplier: each table has ~ratio*vocab_size rows (LongCat-Lite: 78 → ~10.2M rows/table). 0 = no n-gram embeddings.
emb_neighbor_num: usizeLargest n-gram size N (LongCat-Lite: 4 → bigram/trigram/4-gram).
emb_split_num: usizeIndependent hash splits K per n-gram size (LongCat-Lite: 4).
ngram_vocab_size_base: usizeRows per n-gram HEAD, absolute (ngram_vocab_size_base).
The Qwen4-Exp form of the same idea LongCat expresses as a ratio:
LongCat says “ratio x vocab_size rows per table”, Qwen says
“20,000,000 rows per head” outright. Mutually exclusive with
ngram_vocab_size_ratio — whichever the checkpoint declares wins,
and the authoritative per-head sizes/offsets ship as I64 tensors
(ngram_heads_vocab_sizes / ngram_heads_offsets) which the loader
reads rather than re-deriving. 0 = not a base-form checkpoint.
ngram_split_parts: usizePhysical shard count of the n-gram table (split_ngram_parts).
PURELY a file-layout fact, NOT an architectural one: Qwen4-Exp stores
one logical [sum(head_vocabs), ngram_dim] table as 128 equal
shard_N.weight tensors. The head ranges are independent of the
shard boundaries and a head can straddle several shards, so the row
cache must address the logical table and translate. 0 = unsharded.
ple_layer_ids: Vec<usize>Decoder layers that carry a PLE (per-layer-embedding) n-gram
injection (ple_layer_ids). Qwen4-Exp injects at ONE layer, not at
the token embedding the way LongCat does — which is why this is a
layer list and not a flag. Empty = no PLE.
ple_conv_kernel_size: usizeDepthwise conv width inside the PLE block (ple_conv_kernel_size).
0 = no conv.
o_lora_rank: usizeOutput projection latent dimension for low-rank O projection.
DeepSeek-V4 uses o_lora_rank to compress the output projection.
0 = standard O (no low-rank compression).
o_groups: usizeNumber of block-diagonal groups for the grouped O projection (wo_a).
DeepSeek-V4-Flash splits the n_heads*head_dim attention output into
o_groups independent groups, each projected to o_lora_rank before the
follow-up wo_b mixes the o_groups*o_lora_rank vector back to hidden_size.
0 = ungrouped (dense O).
yarn_mscale: f32YaRN attention-temperature mscale (rope_scaling.mscale). HF default
is 1.0 when absent. DeepSeek folds _mscale into the rope cos/sin.
yarn_mscale_all_dim: f32YaRN attention-temperature mscale_all_dim (rope_scaling.mscale_all_dim).
HF default is 0.0 when absent. Used in the _mscale ratio that scales
the rope cos/sin (and, when non-zero, the softmax scale).
hc_mult: usizeNumber of hyper-connection residual streams per block (hc_mult).
0 = disabled (every model except DeepSeek-V4). DeepSeek-V4 uses 4.
hc_sinkhorn_iters: usizeNumber of Sinkhorn normalization iterations for the HC mixing matrix
(hc_sinkhorn_iters). DeepSeek-V4 default is 20.
hc_eps: f32Numerical-stability epsilon for HC sigmoid/softmax/Sinkhorn (hc_eps).
DeepSeek-V4 default is 1e-6.
hc_lowrank: usizeRank of the hyper-connection input mixer (hc_lowrank).
Qwen4-Exp mixes the hc_mult residual streams through a LOW-RANK
pair — input_mix_weight_down [r, hc_mult*hidden] then
input_mix_weight_up [hc_mult*hidden, r] — where DeepSeek-V4 uses a
Sinkhorn-normalized square matrix. The two share hc_mult and the
stream-major layout but NOT the mixing math, so a non-zero value here
selects the low-rank variant. 0 = DeepSeek-V4’s Sinkhorn form.
final_norm_identity: boolThe checkpoint carries NO final normalization before lm_head: the
real one is applied inside the hyper-connection mixer while the
residual streams collapse. Applying the engine’s ones-placeholder RMS
anyway still DIVIDES the hidden by its per-token RMS, which flattens
the logits by a per-token factor (measured 1.16-1.63x vs the reference
forward on qwen4_exp) – an uninvited temperature multiplier that
argmax survives but sampling does not. When set, the final-norm step
becomes an identity copy.
compress_ratios: Vec<usize>Per-layer compression ratios for hybrid attention (CSA/HCA). 0 = full attention, >0 = compressed attention with that ratio. Length equals num_hidden_layers. Empty = all layers full attention.
index_n_heads: usizeNumber of semantic-indexer heads used by DeepSeek-V4 CSA layers.
index_head_dim: usizePer-head dimension of the DeepSeek-V4 semantic indexer.
index_topk: usizeMaximum compressed-history rows selected per query by the semantic indexer.
index_compress_ratio: usizeIndexer compression ratio, recorded WITHOUT populating
compress_ratios.
Qwen3.8-Flash-Next’s QSA indexer is inert below its budget — selection
is topk(min(budget/ratio, complete_blocks)), so at
seq_len <= index_topk every block is chosen and dense attention is
exact. Keeping compress_ratios empty stops DeepSeek-V4’s compressor
being dispatched in its place; keeping the ratio here lets a loader
refuse above the budget instead of silently attending densely.
0 = no indexer.
index_kpool: usizeGLM-5.3 DSA: tokens per k-pool (index_kpool). The pool budget is
index_topk / index_kpool, so this is not cosmetic — it sets how many
candidates the top-k actually ranks. 0 = model has no k-pooling.
index_kpool_always_select_tail: boolGLM-5.3 DSA: always append the trailing partial pool’s tokens to the
selection, widening the emitted index row by index_kpool - 1.
num_hash_layers: usizeNumber of hash-based attention layers (DeepSeek-V4 HCA). 0 = none.
yarn_factor: f32YaRN scaling factor (yarn.factor). 0.0 = YaRN disabled, use plain RoPE.
yarn_beta_slow: f32YaRN low-rotation cutoff (yarn.alpha in Mistral params,
beta_slow in HF transformers terminology).
yarn_beta_fast: f32YaRN high-rotation cutoff (yarn.beta in Mistral params,
beta_fast in HF transformers terminology).
yarn_original_max_position_embeddings: usizeYaRN original context length used for the correction range
(yarn.original_max_position_embeddings).
yarn_attention_factor: f32Multiplier applied to both YaRN cosine and sine values. 1.0 means no attention-temperature scaling.
llama_4_scaling_beta: f32llama_4_scaling Q temperature beta (llama_4_scaling.beta).
Q is multiplied by 1 + beta * log(1 + floor(pos / original_max_pos))
after RoPE. 0.0 = disabled. Mistral Small 4 uses 0.1.
llama_4_scaling_original_max_position_embeddings: usizellama_4_scaling original context length for the Q temperature scale.
vision: Option<VisionConfig>Vision encoder configuration parsed from vision_config in config.json.
None for text-only models.
quantization_config: Option<QuantizationConfig>Advertised quantization format + algorithm + per-module ignore list.
Populated from config.json::quantization_config or a sibling
hf_quant_config.json at parse_config time. None for
un-quantized BF16/FP16 checkpoints. Consumed by the QuantFormat
dispatcher (crates/spark-model/src/quant_format/) to pick the
correct on-disk loader without guessing from tensor names.
attn_gated: boolWhether Q projection includes an output gate (Q+Gate interleaved, 2x q_dim). False for Qwen3-VL, Nemotron-H, Mistral (ungated Q).
gdn_norm_sigmoid: boolThe GDN gated-norm’s gate activation is SIGMOID rather than SiLU.
The reference constructs its RMSNormGated with
activation = output_gate_type or hidden_act, so on a checkpoint
with output_gate_type: "sigmoid" (Qwen3.8-Flash-Next) BOTH the
attention output gate and the GDN norm gate are sigmoid. Every other
Qwen-family GDN model gates with SiLU. Found by the qwen4_exp phase-E
bisect: recurrence proven correct, norm stage off at cos 0.81, and
sigmoid closed it to 0.0.
nested_config: boolWhether config.json wraps the LLM config in a nested field (e.g., text_config).
Determines weight prefix auto-detection behavior.
mrope_section: [usize; 3]MRoPE (multi-modal rotary position embedding) section sizes in
[T, H, W] order. [0, 0, 0] = scalar RoPE (default for Qwen3.5
and earlier). Qwen3.6 uses [11, 11, 10]. Summed × 2 == rotary_dim.
mrope_interleaved: boolMRoPE channel layout: true = round-robin [T H W T H W …] (Qwen3.6),
false = contiguous [T…T | H…H | W…W] (Qwen3-VL non-interleaved).
Ignored when mrope_section == [0, 0, 0].
weight_prefix: String§profile: bool--profile: skip CUDA graphs, sync and time each layer.
Carried here rather than through ATLAS_PROFILE, which serve.rs used
to set_var at runtime under a // SAFETY: called before any threads are spawned comment that was already false — the tokio pool, the
startup blocking thread, the signal listener, the TUI thread and the
OOM watchdog all exist by then, and a concurrent getenv during
setenv is UB. A field on the config the model already receives has
none of that hazard.
ep_rank: usize§ep_world_size: usize§tp_rank: usizeTP rank within the TP sub-communicator. 0 if tp_world_size==1.
tp_world_size: usizeNumber of TP ranks. 1 = no TP. Composes with EP statically: attention/MLP weights are TP-sharded; MoE expert weights are EP-sharded.
serve_max_seq_len: usizeThe serve’s --max-seq-len. 0 when nobody set it (a unit test, an offline tool),
which every reader must treat as “unknown” and fall back from — never as zero
context. Distinct from max_position_embeddings, which is the checkpoint’s claim
(1,048,576 on GLM-5.3) rather than what this process reserved memory for.
fp8_kv_calibration_tokens: usizeNumber of warmup tokens for online FP8 KV scale calibration. 0 = disabled (use static scales from checkpoint or uncalibrated 1.0).
fp8_kv_headroom: f32Headroom multiplier on the first-observe absmax when freezing the online
FP8 KV scale (--fp8-kv-headroom, default 2.0). The first observe sees
only the first prefill chunk, so the frozen scale covers headroom× its
observed max — later tokens that grow don’t clip, at <1 bit of precision.
final_logit_softcapping: f32Final logit softcapping: logits = cap * tanh(logits / cap). 0.0 = disabled (default for all models except Gemma-4 which uses 30.0).
embed_scale: f32Embedding scale factor: embeddings *= scale after lookup. 0.0 = disabled (default). Gemma models use sqrt(hidden_size).
scoring_func: StringMoE routing activation. “” = default softmax. “sigmoid” = DeepSeek-V3
/ MiniMax-M2 style: raw gate logits pass through sigmoid to produce
per-expert scores in (0,1), independent (not normalized across
experts). Top-k selection may use a bias term (see moe_routing_bias).
use_routing_bias: boolIf true, a per-expert e_score_correction_bias tensor is added to
routing scores for top-k selection only (not dispatch weighting).
This is the DeepSeek-V3 loss-free balancing trick. The bias tensor
itself lives in the checkpoint (typically one [num_experts] vector
per MoE layer).
qk_norm_type: StringQK normalization granularity. “” = none (Qwen3-Next default).
“per_layer” = each attention layer has its own learned q_layernorm /
k_layernorm weight of shape [head_dim], applied after Q/K projection
and before RoPE (MiniMax M2).
num_mtp_modules: usizeNumber of sequential MTP draft modules. 0 = no MTP. 1 = existing Atlas MTP path (Qwen3.5). 3 = MiniMax M2 (each module is a single transformer layer that predicts one future token).
mtp_transformer_layers: usizeTransformer layers per MTP module. 1 for MiniMax M2 (3 modules × 1 layer = 3 future-token predictors).
rotary_dim: usizeExplicit rotary dimension from config (bypasses partial_rotary_factor
computation). MiniMax M2 ships rotary_dim: 64 while head_dim=128,
so the rotary factor is 0.5 — we honor the explicit int value when
present for byte-exact rope dim.
dflash_capture_layers: Vec<usize>Target-model layer indices to capture intermediate hidden states from
for DFlash speculative decoding. Sourced from the drafter’s
dflash_config.target_layer_ids (e.g., [1, 10, 19, 28, 37] for
Qwen3.6-35B-A3B-DFlash). Empty when DFlash is disabled — its presence
gates TransformerModel::dflash_hidden_save allocation and the
per-layer capture hooks. Order matters: shallow-to-deep concatenation
is what the drafter’s fc projection expects.
dflash_gamma: Option<usize>Resolved DFlash drafter γ (block size), set by the factory alongside
dflash_capture_layers. Sizes the SSM verify intermediate pools at
the ACTUAL K = γ+1 instead of the legacy 17-wide ceiling — at γ=8,
C=8 that ceiling alone cost ~12 GB of pool (2026-08-19 256K/C8 boot
ledger). None = DFlash inactive (or unknown → 17-wide fallback).
adapter_max_rank: usizeLoRA adapter rank ceiling (--max-lora-rank). 0 = LoRA disabled.
Set programmatically before model build (never parsed from the HF
config.json); the only consumer is BufferSizes, which sizes the
adapter delta scratch from it. adapter_* naming avoids the MLA
*lora_rank collision (config.rs:182-207).
Implementations§
Source§impl ModelConfig
impl ModelConfig
pub fn qwen3_next_80b_nvfp4() -> Self
Source§impl ModelConfig
impl ModelConfig
Sourcepub fn eos_ids(&self) -> Vec<u32>
pub fn eos_ids(&self) -> Vec<u32>
Every configured stop-token id, primary first.
Falls back to vec![eos_token_id] when eos_token_ids was never populated, so a
hand-built ModelConfig and a scalar-EOS checkpoint both behave exactly as before.
Sourcepub fn layer_type_at(&self, layer_idx: usize) -> Option<LayerType>
pub fn layer_type_at(&self, layer_idx: usize) -> Option<LayerType>
Layer type for a given layer index. Falls back to full_attention_interval if layer_types is empty. Layer kind for ANY index in the checkpoint, including layers past the text stack.
layer_type covers the text stack only. Indices >= num_hidden_layers are
MTP/NextN layers and resolve through mtp_layer_types; that is what lets GLM-5.3’s
layer 45 be represented as the sparse-attention block it actually is, rather than
being appended to the text stack and silently swept into every text-layer loop.
Sourcepub fn sparse_attention_layers(&self) -> Vec<usize>
pub fn sparse_attention_layers(&self) -> Vec<usize>
Layers (text stack only) whose mixer is deepseek_sparse_attention.
Sourcepub fn has_sparse_attention(&self) -> bool
pub fn has_sparse_attention(&self) -> bool
True when any layer — text stack or MTP — needs the sparse-attention
indexer. Scheduling and cache sizing both key off this, so it must not be
answered from layer_types alone.
pub fn layer_type(&self, layer_idx: usize) -> LayerType
Sourcepub fn num_attention_layers(&self) -> usize
pub fn num_attention_layers(&self) -> usize
Number of attention (KV-cache-consuming) layers: full, sliding, and
sparse. All three write to the paged KV cache — only which keys they
read differs (all / a window / a runtime-selected top-k) — so every
consumer sized from this count — KV pool num_layers,
attn_layer_dtypes, loader layer_kv_dtypes indexing — must see them
all. Step 3.7 is the only model emitting SlidingAttention layer types
(12 full + 33 sliding); counting full-only there undersized the dtype
vec and panicked the loader at layer 13.
🪤 The same omission recurred for SparseAttention: GLM-5.3-Flash is
34 linear_attention + 11 deepseek_sparse_attention, so a full/sliding
filter returned 0 and the KV pool came out zero-sized (“KV cache block
size is zero”, measured 2026-08-28). Delegating to
LayerType::is_attention is what keeps this honest: the predicate lives
next to the enum, so a new variant is answered in one place.
Sourcepub fn num_ssm_layers(&self) -> usize
pub fn num_ssm_layers(&self) -> usize
Number of SSM (linear attention) layers.
Sourcepub fn has_recurrent_state(&self) -> bool
pub fn has_recurrent_state(&self) -> bool
Whether this model carries recurrent (SSM / linear-attention) state —
the honest capability signal for the SSM snapshot tiers. Derived from
Self::num_ssm_layers so the config-level predicate and the runtime
pool predicate (ssm_pool.num_ssm_layers > 0) agree by construction
(SSOT). A pure-attention model (dense or MoE) returns false:
requesting an SSM tier for it must fail fast, never silently no-op.
Sourcepub fn has_experts(&self) -> bool
pub fn has_experts(&self) -> bool
Whether this model has MoE routed experts — the capability signal for the expert-streaming tier. Keyed on config, never on observed expert tensors (EP ranks legitimately own zero local expert tensors).
Sourcepub fn rotary_dim(&self) -> usize
pub fn rotary_dim(&self) -> usize
Rotary embedding dimension.
Priority:
- Explicit
rotary_dimfield (MiniMax M2 — integer in config.json). partial_rotary_factor * head_dim(Qwen3/Gemma-4 convention — float).
Sourcepub fn ssm_qkvz_size(&self) -> usize
pub fn ssm_qkvz_size(&self) -> usize
SSM projection output size: Q + K + V + Z concatenated.
Sourcepub fn ssm_qkv_size(&self) -> usize
pub fn ssm_qkv_size(&self) -> usize
SSM QKV projection output size (without Z): Q + K + V.
Sourcepub fn ssm_z_size(&self) -> usize
pub fn ssm_z_size(&self) -> usize
SSM Z gate projection output size.
Sourcepub fn ssm_ba_size(&self) -> usize
pub fn ssm_ba_size(&self) -> usize
SSM beta+alpha projection output size.
Sourcepub fn local_expert_range(&self) -> (usize, usize)
pub fn local_expert_range(&self) -> (usize, usize)
Range of expert indices local to this EP rank. Returns (start, end) where start is inclusive and end is exclusive.
Sourcepub fn is_local_expert(&self, expert_id: usize) -> bool
pub fn is_local_expert(&self, expert_id: usize) -> bool
Whether the given expert ID is local to this EP rank.
Sourcepub fn tp_shard_range(&self, total: usize) -> (usize, usize)
pub fn tp_shard_range(&self, total: usize) -> (usize, usize)
Range [start, end) of a total-sized dimension owned by this TP rank.
total must be divisible by tp_world_size. Returns (0, total) when
TP is disabled.
Sourcepub fn tp_shard_dim(&self, total: usize) -> usize
pub fn tp_shard_dim(&self, total: usize) -> usize
Per-rank shard size for a total-sized dimension under TP.
Sourcepub fn layer_prefix(&self, layer_idx: usize) -> String
pub fn layer_prefix(&self, layer_idx: usize) -> String
Weight key prefix for layer-level weights.
Returns "model.layers" for flat models (qwen3_next),
or "model.language_model.layers" for conditional generation models (qwen3_5_moe).
Sourcepub fn capabilities(&self) -> ModelCapabilities
pub fn capabilities(&self) -> ModelCapabilities
Derive model-agnostic capabilities from this config.
Sourcepub fn is_qwen35(&self) -> bool
pub fn is_qwen35(&self) -> bool
Factory use only. Prefer config.attn_gated or config.capabilities().
Sourcepub fn is_qwen35_dense(&self) -> bool
pub fn is_qwen35_dense(&self) -> bool
Factory use only.
Sourcepub fn is_qwen3_vl(&self) -> bool
pub fn is_qwen3_vl(&self) -> bool
Factory use only.
Recognises the upstream qwen3_vl_moe model_type (Qwen3-VL MoE)
and Qwen3.5-VL — which ships with model_type = "qwen3_5" plus
architectures = ["Qwen3_5ForConditionalGeneration"] and a
populated vision_config block. The vision_config presence is
the durable signal: the trunk model_type stays qwen3_5 whether
the checkpoint is text-only or VL, but VL ships an extra
vision encoder which the parser exposes as config.vision.
Sourcepub fn skip_lm_head_quantization(&self) -> bool
pub fn skip_lm_head_quantization(&self) -> bool
Whether to skip NVFP4 quantization of the LM head.
MLA models (kv_lora_rank > 0) lose logit precision under NVFP4.
Gemma-4 dense (31B): the LM head ties to BF16 embed_tokens whose
rows have heavy outliers (final_norm.weight max=510, several
embedding rows in similar range). The runtime BF16→NVFP4 path
uses a single per-tensor absmax for scale2, which forces a
coarse scale that loses ~7 bits in normal-magnitude rows. For a
262 144-row vocab matrix that compounds into the 0.14-margin
argmax flip on creative prompts (verified 2026-05-01 via FP32
lm_head bisection: NVFP4 output had top1= a 21.85 vs FP32 BF16
view top1= a 21.85 — quantization noise was visible in the
SAME logit channel that flipped the tiebreak). Skipping the
runtime quantization keeps the LM head as plain BF16 dense; the
FP32 lm_head path (gated by ATLAS_GEMMA4_FP32_LMHEAD=1) can
then act on full-precision weights without the NVFP4 floor.
Sourcepub fn mamba2_d_inner(&self) -> usize
pub fn mamba2_d_inner(&self) -> usize
Mamba-2 d_inner = mamba_num_heads * mamba_head_dim.
Sourcepub fn mamba2_d_xbc(&self) -> usize
pub fn mamba2_d_xbc(&self) -> usize
Mamba-2 d_xBC = d_inner + 2 * n_groups * ssm_state_size. This is the dimension that goes through conv1d (x + B + C concatenated).
Sourcepub fn mamba2_in_proj_size(&self) -> usize
pub fn mamba2_in_proj_size(&self) -> usize
Mamba-2 in_proj output size = z + xBC + dt.
Sourcepub fn ssm_h_state_bytes(&self) -> usize
pub fn ssm_h_state_bytes(&self) -> usize
Per-layer SSM hidden state size in bytes (FP32). Dispatches on SSM architecture: Mamba-2 vs GDN, using config fields.
Sourcepub fn ssm_conv_state_bytes(&self) -> usize
pub fn ssm_conv_state_bytes(&self) -> usize
Per-layer SSM conv state size in bytes (FP32).
Sourcepub fn ssm_state_norm_dims(&self) -> (usize, usize, usize)
pub fn ssm_state_norm_dims(&self) -> (usize, usize, usize)
SSM state normalization dimensions: (num_heads, k_dim, v_dim). Used by the state normalization kernel to prevent drift.
Sourcepub fn moe_input_size(&self) -> usize
pub fn moe_input_size(&self) -> usize
MoE expert input dimension: latent size if LatentMoE, else hidden_size.
Sourcepub fn moe_intermediate_size_for(&self, layer: usize) -> usize
pub fn moe_intermediate_size_for(&self, layer: usize) -> usize
Routed expert intermediate size for layer i.
Puzzle checkpoints prune channels non-uniformly across MoE layers;
look up moe_intermediate_sizes[i] when populated, else the scalar.
Sourcepub fn num_experts_per_tok_for(&self, layer: usize) -> usize
pub fn num_experts_per_tok_for(&self, layer: usize) -> usize
Top-K experts per token for layer i (Puzzle per-block schedule).
Sourcepub fn max_moe_intermediate_size(&self) -> usize
pub fn max_moe_intermediate_size(&self) -> usize
Max routed intermediate across all layers (buffer / scratch sizing).
Sourcepub fn num_moe_layers(&self) -> usize
pub fn num_moe_layers(&self) -> usize
Number of MoE-only layers (Nemotron-H).
Sourcepub fn kv_only_prefix_cache_is_safe(&self) -> bool
pub fn kv_only_prefix_cache_is_safe(&self) -> bool
Whether the radix prefix cache captures every state needed to resume
this model exactly. Preflight SSOT for build_prefix_cache.
Sourcepub fn kv_only_swap_out_is_safe(&self) -> bool
pub fn kv_only_swap_out_is_safe(&self) -> bool
Whether a sequence may be swapped out to the --swap-space-gb pool and
restored from it. Preflight SSOT for resolve_swap_space_gb.
save_sequence_state_dispatch writes KV blocks plus the SsmLayerState
of each LayerType::LinearAttention layer, and nothing else; the
swap-out then calls free_sequence, which hands every remaining
per-layer state to #821’s release_state. A model that is not
KV-complete therefore resumes with a freshly ZEROED pool behind a KV
image that assumes a populated one — a silently wrong answer, not a
crash. Distinct from the prefix-cache predicate because they are
distinct guarantees; they happen to have the same answer today.
Trait Implementations§
Source§impl Clone for ModelConfig
impl Clone for ModelConfig
Source§fn clone(&self) -> ModelConfig
fn clone(&self) -> ModelConfig
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more