#!/usr/bin/env python3 """Build a tiny, deterministic random-init qwen4_exp TEXT fixture (stdlib only). Purpose: Qwen/Qwen3.8-Flash-Next (released 2026-08-24) is a large multimodal Qwen4ExpForConditionalGeneration MoE with a hybrid linear+full attention stack, ngram vocab, an indexer, PLE, hyper-connections, and an MTP head, so nobody can instantiate it in CI or on a laptop. This fixture ships a ~0.3 MB random-init TEXT checkpoint plus a reduced config that keeps the real qwen4_exp / qwen4_exp_text field names (layer_types, linear_*, ngram_*, indexer_*, ple_*, hc_*, mtp, rope_parameters, vision_config) 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. Random-init: NOT trained and NOT a quality claim. The tensor set is a REDUCED standard-attention + MoE convention; the real model's linear-attention (conv/ssm), ngram, indexer, PLE, hyper-connection, MTP, and vision/projector tensors are NOT included (see README omissions). Geometry is documented in the README. """ import hashlib import json import math import os import struct M64 = (1 << 64) - 1 SEED = 20260903 SCALE = 0.02 # ---- tiny geometry (reduced from the real text_config, documented in README) ---- VOCAB = 256 HIDDEN = 64 LAYERS = 4 HEADS = 4 KV_HEADS = 2 HEAD_DIM = 16 MOE_INTER = 32 SHARED_INTER = 32 NUM_EXPERTS = 8 TOPK = 2 class SplitMix64: """SplitMix64 + Box-Muller, identical to the llama/t5/glm fixtures.""" 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(): shapes = { "model.embed_tokens.weight": (VOCAB, HIDDEN), "model.norm.weight": (HIDDEN,), } ones = {"model.norm.weight"} for layer in range(LAYERS): p = "model.layers.%d." % layer shapes[p + "input_layernorm.weight"] = (HIDDEN,) shapes[p + "post_attention_layernorm.weight"] = (HIDDEN,) ones.add(p + "input_layernorm.weight") ones.add(p + "post_attention_layernorm.weight") shapes[p + "self_attn.q_proj.weight"] = (HEADS * HEAD_DIM, HIDDEN) shapes[p + "self_attn.k_proj.weight"] = (KV_HEADS * HEAD_DIM, HIDDEN) shapes[p + "self_attn.v_proj.weight"] = (KV_HEADS * HEAD_DIM, HIDDEN) shapes[p + "self_attn.o_proj.weight"] = (HIDDEN, HEADS * HEAD_DIM) shapes[p + "mlp.gate.weight"] = (NUM_EXPERTS, HIDDEN) for expert in range(NUM_EXPERTS): e = p + "mlp.experts.%d." % expert shapes[e + "gate_proj.weight"] = (MOE_INTER, HIDDEN) shapes[e + "up_proj.weight"] = (MOE_INTER, HIDDEN) shapes[e + "down_proj.weight"] = (HIDDEN, MOE_INTER) shapes[p + "mlp.shared_expert.gate_proj.weight"] = (SHARED_INTER, HIDDEN) shapes[p + "mlp.shared_expert.up_proj.weight"] = (SHARED_INTER, HIDDEN) shapes[p + "mlp.shared_expert.down_proj.weight"] = (HIDDEN, SHARED_INTER) rng = SplitMix64(SEED) out = {} for name in sorted(shapes): 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") print("header_len=%d data_len=%d tensors=%d" % (header_len, data_len, len(tensors))) print("total_params=%d" % (data_len // 4)) if __name__ == "__main__": main()