#!/usr/bin/env python3 """Build a tiny, deterministic deepseek_v4 (DeepSeek-V4-Flash-Vision-Exp) fixture. Purpose: a byte-reproducible random-init TEXT checkpoint plus a reduced config that keeps the real deepseek_v4 field names (MLA q_lora_rank/o_lora_rank/o_groups, MoE routed+shared experts, DSA index_*, num_hash_layers, MTP num_nextn_predict_layers, swiglu_limit, sliding_window, yarn rope) so loaders, quant planners, and CI jobs can exercise the new architecture's config parsing, expert-table sizing, and safetensors load path without the real weights. No third-party deps (stdlib only). """ import hashlib import json import math import os import struct M64 = (1 << 64) - 1 SEED = 20260903 SCALE = 0.02 # ---- fixture geometry (tiny on purpose; real names, small numbers) ---- VOCAB = 256 HIDDEN = 64 LAYERS = 4 HEADS = 4 KV_HEADS = 1 # faithful: base num_key_value_heads == 1 HEAD_DIM = 16 INTER = 128 # dense mlp intermediate (unused; all layers MoE here) MOE_INTER = 32 N_ROUTED = 8 N_SHARED = 1 TOPK = 2 Q_LORA_RANK = 32 O_LORA_RANK = 32 O_GROUPS = 4 QK_NOPE_HEAD_DIM = 16 QK_ROPE_HEAD_DIM = 8 V_HEAD_DIM = 16 class SplitMix64: def __init__(self, seed): self.state = seed & M64 self._spare = None def next_u64(self): self.state = (self.state + 0x9E3779B97F4A7C15) & M64 z = self.state z = ((z ^ (z >> 30)) * 0xBF584A7F17C119E3) & M64 z = ((z ^ (z >> 27)) * 0x94D049BB133111EB) & M64 return z ^ (z >> 31) def uniform(self): return (self.next_u64() >> 11) / float(1 << 53) def gauss(self): if self._spare is not None: value, self._spare = self._spare, None return value u1 = 1.0 - self.uniform() u2 = self.uniform() radius = math.sqrt(-2.0 * math.log(u1)) theta = 2.0 * math.pi * u2 self._spare = radius * math.sin(theta) return radius * math.cos(theta) def build_tensors(): """Return {name: (shape, dtype, bytes)} in sorted-name consumption order. Reduced standard-attention + MoE convention (documented in README): the real MLA compressed tensors, DSA index tensors, hash-layer tensors, MTP head, and vision encoder are NOT included. """ names = [] for i in range(LAYERS): p = "model.layers.%d." % i names += [ p + "input_layernorm.weight", p + "post_attention_layernorm.weight", p + "self_attn.q_a_proj.weight", p + "self_attn.q_b_proj.weight", p + "self_attn.kv_a_proj.weight", p + "self_attn.kv_b_proj.weight", p + "self_attn.q_a_layernorm.weight", p + "self_attn.kv_a_layernorm.weight", p + "self_attn.o_proj.weight", p + "mlp.gate.weight", ] for e in range(N_ROUTED): names += [ p + "mlp.experts.%d.gate_proj.weight" % e, p + "mlp.experts.%d.up_proj.weight" % e, p + "mlp.experts.%d.down_proj.weight" % e, ] for s in range(N_SHARED): names += [ p + "mlp.shared_experts.%d.gate_proj.weight" % s, p + "mlp.shared_experts.%d.up_proj.weight" % s, p + "mlp.shared_experts.%d.down_proj.weight" % s, ] names += ["model.embed_tokens.weight", "model.norm.weight"] shapes = { "model.embed_tokens.weight": (VOCAB, HIDDEN), "model.norm.weight": (HIDDEN,), } for i in range(LAYERS): p = "model.layers.%d." % i shapes[p + "input_layernorm.weight"] = (HIDDEN,) shapes[p + "post_attention_layernorm.weight"] = (HIDDEN,) shapes[p + "self_attn.q_a_proj.weight"] = (Q_LORA_RANK, HIDDEN) shapes[p + "self_attn.q_b_proj.weight"] = (HEADS * (QK_NOPE_HEAD_DIM + QK_ROPE_HEAD_DIM), Q_LORA_RANK) shapes[p + "self_attn.kv_a_proj.weight"] = (Q_LORA_RANK, HIDDEN) shapes[p + "self_attn.kv_b_proj.weight"] = (QK_NOPE_HEAD_DIM + QK_ROPE_HEAD_DIM + V_HEAD_DIM, Q_LORA_RANK) shapes[p + "self_attn.q_a_layernorm.weight"] = (Q_LORA_RANK,) shapes[p + "self_attn.kv_a_layernorm.weight"] = (Q_LORA_RANK,) shapes[p + "self_attn.o_proj.weight"] = (HIDDEN, HEADS * V_HEAD_DIM) shapes[p + "mlp.gate.weight"] = (N_ROUTED, HIDDEN) for e in range(N_ROUTED): shapes[p + "mlp.experts.%d.gate_proj.weight" % e] = (MOE_INTER, HIDDEN) shapes[p + "mlp.experts.%d.up_proj.weight" % e] = (MOE_INTER, HIDDEN) shapes[p + "mlp.experts.%d.down_proj.weight" % e] = (HIDDEN, MOE_INTER) for s in range(N_SHARED): shapes[p + "mlp.shared_experts.%d.gate_proj.weight" % s] = (MOE_INTER, HIDDEN) shapes[p + "mlp.shared_experts.%d.up_proj.weight" % s] = (MOE_INTER, HIDDEN) shapes[p + "mlp.shared_experts.%d.down_proj.weight" % s] = (HIDDEN, MOE_INTER) ones = {"model.norm.weight"} for i in range(LAYERS): p = "model.layers.%d." % i ones.add(p + "input_layernorm.weight") ones.add(p + "post_attention_layernorm.weight") ones.add(p + "self_attn.q_a_layernorm.weight") ones.add(p + "self_attn.kv_a_layernorm.weight") rng = SplitMix64(SEED) out = {} for name in sorted(names): shape = shapes[name] count = 1 for dim in shape: count *= dim if name in ones: values = [1.0] * count else: values = [rng.gauss() * SCALE for _ in range(count)] blob = b"".join(struct.pack("", "eos_token": "", "unk_token": "", "pad_token": "", "model_input_names": ["input_ids"]}, handle, indent=2, sort_keys=True) handle.write("\n") with open(os.path.join(out_dir, "special_tokens_map.json"), "w") as handle: json.dump({"additional_special_tokens": ["", ""], "bos_token": "", "eos_token": "", "pad_token": "", "unk_token": ""}, handle, indent=2, sort_keys=True) handle.write("\n") lines = [] for name in sorted(tensors): shape, dtype, blob = tensors[name] lines.append("%s %s %s %d %s" % (name, dtype, "x".join(map(str, shape)), len(blob), hashlib.sha256(blob).hexdigest())) with open(os.path.join(out_dir, "checksums.txt"), "w") as handle: handle.write("\n".join(lines) + "\n") total_params = sum(1 for t in tensors.values() for _ in range(t[0][0] * (t[0][1] if len(t[0]) > 1 else 1))) print("header_len=%d data_len=%d tensors=%d" % (header_len, data_len, len(tensors))) print("total_params=%d" % total_params) if __name__ == "__main__": main()