Checkpoint configuration and implementation zai-org/GLM-5 @ c183ef8, huggingface/transformers @ 5e4d630 · parameter count checked against the checkpoint’s tensor headers · How to read

in
Raw text
out
LL [B, T, 154880]
parameters
743,911,218,432 in all
Parameters

743,911,218,432 parameters in GLM-5

Exact model ownership reconciliation
ComponentCalculationParameters
Token embedding154,880×6,144154{,}880 \times 6{,}144951,582,720
Transformer blocks742,008,046,848 across its components742,008,046,848
Final RMSNorm6,1446{,}1446,144
Vocabulary projection6,144×154,8806{,}144 \times 154{,}880951,582,720
Model total743,911,218,432

Derived exact parameter total: 743,911,218,432. Sources contains the pinned configuration and implementation used for this derivation.

Derived from the pinned configuration and transformers implementation, and equal to the count of the checkpoint’s tensors read from its safetensors headers, less the multi-token-prediction layer the implementation does not load. The total includes the routers’ 19,200 correction-bias values, which the implementation holds as buffers.

In numbers

Fact sheet

Blocks
78: the first 3 dense, then 75 MoEThe configuration also declares 1 multi-token-prediction layer; the implementation skips it on load, and the atlas does not draw it.config.json 14config.json 35config.json 37modeling_glm_moe_dsa.py 648
Width
6,144config.json 17
Attention
64 heads; keys 192 + 64 rotary features, values 256; latents: query 2,048, key–value 512Lightning indexer: 32 heads of 128 features, keeping 2,048 positions per query.config.json 24config.json 33config.json 40–43config.json 57config.json 18–20
Feed-forward
256 routed + 1 shared experts; 8 routed chosen per token; 2,048 hidden features eachThe first 3 blocks have a dense SwiGLU of 12,288 hidden features instead.config.json 23–26config.json 30–34
Vocabulary
154,880config.json 58
Context
202,752 positions (max_position_embeddings)config.json 25
Parameters
743.9 B in all · 41.8 B used per token (5.6%)Both counts include every block’s indexer, and the embedding table and output head whole; without those two tables, 39.9 B per token. The model card gives “40B active”, the count without the two tables.config.json 30config.json 34modeling_glm_moe_dsa.py 535–559modeling_glm_moe_dsa.py 576–583README.md 32
KV cache
107.3 KiB per position, all layersThe 512-feature latent and 64-feature rotary key in bfloat16, and the 128-feature indexer key in bfloat16. Written in Prefill and Decode; the Full sequence view draws none.modeling_glm_moe_dsa.py 407–409modeling_glm_moe_dsa.py 236–237config.json 7modeling_glm_moe_dsa.py 122modeling_glm_moe_dsa.py 190–191modeling_glm_moe_dsa.py 228

Weights · whole model

GLM-5 · bfloat161.4 TiB
Tied readout · bfloat161.4 TiB

743,911,218,432 parameters: bfloat16, the configuration’s dtype, except the router’s bias and the indexer’s head weights, which the implementation keeps in float32. The separate output head holds 951,582,720 of them (0.13%), 1.8 GiB in bfloat16; tied to the embedding table, the weights would take 1.4 TiB.

config.json 17config.json 58config.json 7modeling_glm_moe_dsa.py 487–492modeling_glm_moe_dsa.py 647modeling_glm_moe_dsa.py 192modeling_glm_moe_dsa.py 649config.json 52modeling_glm_moe_dsa.py 753
Sources

Direct evidence

The released configuration: width, 78 layers of which 3 dense, 64 heads, 256 routed experts and one shared, routing (sigmoid scores, one expert group, top-8, route scale 2.5), MLA ranks and head widths, the indexer (32 heads of 128, top 2,048, interleaved RoPE), vocabulary, default RoPE with θ = 1,000,000, and one multi-token-prediction layer.

config · zai-org/GLM-5 / config.json
Pinned revision c183ef8c61fa ↗ · lines 1–59

Read code excerpt
{
  "architectures": [
    "GlmMoeDsaForCausalLM"
  ],
  "attention_bias": false,
  "attention_dropout": 0.0,
  "dtype": "bfloat16",
  "eos_token_id": [
    154820,
    154827,
    154829
  ],
  "ep_size": 1,
  "first_k_dense_replace": 3,
  "hidden_act": "silu",
  "head_dim": 64,
  "hidden_size": 6144,
  "index_head_dim": 128,
  "index_n_heads": 32,
  "index_topk": 2048,
  "indexer_rope_interleave": true,
  "initializer_range": 0.02,
  "intermediate_size": 12288,
  "kv_lora_rank": 512,
  "max_position_embeddings": 202752,
  "moe_intermediate_size": 2048,
  "moe_layer_freq": 1,
  "model_type": "glm_moe_dsa",
  "n_group": 1,
  "n_routed_experts": 256,
  "n_shared_experts": 1,
  "norm_topk_prob": true,
  "num_attention_heads": 64,
  "num_experts_per_tok": 8,
  "num_hidden_layers": 78,
  "num_key_value_heads": 64,
  "num_nextn_predict_layers": 1,
  "pad_token_id": 154820,
  "pretraining_tp": 1,
  "q_lora_rank": 2048,
  "qk_head_dim": 256,
  "qk_nope_head_dim": 192,
  "qk_rope_head_dim": 64,
  "rms_norm_eps": 1e-05,
  "rope_interleave": true,
  "rope_parameters": {
    "rope_theta": 1000000,
    "rope_type": "default"
  },
  "routed_scaling_factor": 2.5,
  "scoring_func": "sigmoid",
  "tie_word_embeddings": false,
  "topk_group": 1,
  "topk_method": "noaux_tc",
  "transformers_version": "5.0.2.dev0",
  "use_cache": true,
  "v_head_dim": 256,
  "vocab_size": 154880
}

Direct evidence

The implementation’s configuration: RoPE covers only the 64-feature rotary slice (head_dim is pointed at qk_rope_head_dim), every layer runs its own indexer (with no index_topk_freq set, indexer_types is "full" for every layer), and the first first_k_dense_replace layers use the dense MLP.

model-args · huggingface/transformers / configuration_glm_moe_dsa.py
Pinned revision 5e4d6304de55 ↗ · lines 135–156

Read code excerpt
    def __post_init__(self, **kwargs):
        # Per-layer indexer mode: a pattern (e.g. `"FSSF..."`) overrides the freq/offset schedule.
        if self.indexer_types is None:
            pattern = kwargs.get("index_topk_pattern")
            if pattern is not None:
                self.indexer_types = (
                    [{"F": "full", "S": "shared"}[c] for c in pattern] if isinstance(pattern, str) else list(pattern)
                )
            else:
                freq = max(kwargs.get("index_topk_freq", 1), 1)
                offset = kwargs.get("index_skip_topk_offset", 2)
                self.indexer_types = [
                    "full" if (max(i - offset + 1, 0) % freq) == 0 else "shared" for i in range(self.num_hidden_layers)
                ]
        self.qk_head_dim = self.qk_nope_head_dim + self.qk_rope_head_dim
        # RoPE applies only to the rope slice, so point `head_dim` at it: the inherited (Llama) rotary
        # embedding reads `config.head_dim` and then computes the right frequencies with no override needed.
        self.head_dim = self.qk_rope_head_dim
        # MLP layer types: the first `first_k_dense_replace` layers are dense, the rest are MoE.
        if self.mlp_layer_types is None:
            n_dense = min(self.first_k_dense_replace, self.num_hidden_layers)
            self.mlp_layer_types = ["dense"] * n_dense + ["sparse"] * (self.num_hidden_layers - n_dense)

Direct evidence

The model embeds tokens, numbers positions from the cached length, always builds the causal mask (the indexer needs it), applies the 78 blocks, normalizes and projects to vocabulary logits with an untied lm_head without upcasting them. The checkpoint’s layer 78, the multi-token-prediction layer, is ignored on load.

transformer · huggingface/transformers / modeling_glm_moe_dsa.py
Pinned revision 5e4d6304de55 ↗ · lines 648–802

Read code excerpt
    _keys_to_ignore_on_load_unexpected = [r"model\.layers\.78.*"]

… lines 649–695 omitted …

        if inputs_embeds is None:
            inputs_embeds: torch.Tensor = self.embed_tokens(input_ids)

        if use_cache and past_key_values is None:
            past_key_values = DynamicCache(config=self.config)

        if position_ids is None:
            past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
            position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
            position_ids = position_ids.unsqueeze(0)

        # It may already have been prepared by e.g. `generate`
        if not isinstance(causal_mask_mapping := attention_mask, dict):
            mask_kwargs = {
                "config": self.config,
                "inputs_embeds": inputs_embeds,
                "attention_mask": attention_mask,
                "past_key_values": past_key_values,
                "position_ids": position_ids,
                "allow_is_causal_skip": False,  # Always force creation to account for causality in the indexer
            }
            causal_mask_mapping = {"indexed_attention": create_causal_mask(**mask_kwargs)}

        hidden_states = inputs_embeds
        position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)

        topk_indices = None  # MAIN DIFF with DSV3.2
        for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]):
            hidden_states, topk_indices = decoder_layer(
                hidden_states,
                attention_mask=causal_mask_mapping["indexed_attention"],
                position_embeddings=position_embeddings,
                position_ids=position_ids,
                past_key_values=past_key_values,
                use_cache=use_cache,
                prev_topk_indices=topk_indices,  # MAIN DIFF with DSV3.2
                **kwargs,
            )

        hidden_states = self.norm(hidden_states)
        return BaseModelOutputWithPast(
            last_hidden_state=hidden_states,
            past_key_values=past_key_values,
        )

… lines 740–748 omitted …

    def __init__(self, config):
        super().__init__(config)
        self.model = GlmMoeDsaModel(config)
        self.vocab_size = config.vocab_size
        self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)

… lines 754–798 omitted …

        hidden_states = outputs.last_hidden_state
        # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
        slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
        logits = self.lm_head(hidden_states[:, slice_indices, :])