File size: 6,863 Bytes
8c00b68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python3
"""Validate repository structure, config, tokenizer IDs, and Safetensors index."""

from __future__ import annotations

import json
import math
import re
import struct
from pathlib import Path


ROOT = Path(__file__).resolve().parent
INTERNAL_PATH_RE = re.compile(r"/(?:wbl" r"-fast|home)/|usr" r"s/|skt-" r"shared")
EXPECTED_SPECIAL_TOKENS = {
    163692: "<|pad|>",
    163702: "<|im_start|>",
    163704: "<|im_end|>",
    163840: "<|audio_start|>",
    163841: "<|audio_end|>",
    163842: "<|speaker_embedding_placeholder|>",
    163843: "<|audio_output_placeholder|>",
    163844: "<|audio_input_placeholder|>",
    163845: "<|audio_output_pad|>",
    163846: "<|audio_output_end_pad|>",
}
REQUIRED_FILES = {
    ".gitattributes",
    "README.md",
    "SHA256SUMS",
    "chat_template.jinja",
    "config.json",
    "configuration_axk1.py",
    "configuration_raon.py",
    "model.safetensors.index.json",
    "modeling_axk1.py",
    "modeling_raon.py",
    "provenance.json",
    "requirements.txt",
    "special_tokens_map.json",
    "tokenizer.json",
    "tokenizer_config.json",
    "validate_model.py",
}


def load_json(name: str) -> dict:
    with (ROOT / name).open(encoding="utf-8") as handle:
        return json.load(handle)


def iter_named_values(value: object, name: str = ""):
    if isinstance(value, dict):
        for key, child in value.items():
            child_name = f"{name}.{key}" if name else key
            yield from iter_named_values(child, child_name)
    elif isinstance(value, list):
        for index, child in enumerate(value):
            yield from iter_named_values(child, f"{name}[{index}]")
    else:
        yield name, value


def read_safetensors_header(path: Path) -> dict:
    with path.open("rb") as handle:
        raw_length = handle.read(8)
        if len(raw_length) != 8:
            raise AssertionError(f"{path.name}: missing Safetensors header length")
        (header_length,) = struct.unpack("<Q", raw_length)
        if header_length <= 0 or header_length > 1_000_000_000:
            raise AssertionError(f"{path.name}: invalid header length {header_length}")
        header = json.loads(handle.read(header_length))
    return header


def main() -> None:
    missing = sorted(name for name in REQUIRED_FILES if not (ROOT / name).is_file())
    assert not missing, f"Missing required files: {missing}"

    config = load_json("config.json")
    assert config["model_type"] == "raon"
    assert config["architectures"] == ["RaonModel"]
    assert config["auto_map"] == {
        "AutoConfig": "configuration_raon.RaonConfig",
        "AutoModel": "modeling_raon.RaonModel",
        "AutoModelForCausalLM": "modeling_raon.RaonModel",
    }
    assert config["text_model_config"]["model_type"] == "AXK1"

    for field_name, field_value in iter_named_values(config):
        if field_name.endswith("_name_or_path") or field_name == "text_model_path":
            assert field_value in ("", None), f"Internal model path remains at {field_name}: {field_value!r}"

    for path in ROOT.iterdir():
        if path.is_file() and path.suffix in {".json", ".md", ".py", ".txt", ".jinja"}:
            text = path.read_text(encoding="utf-8")
            assert not INTERNAL_PATH_RE.search(text), f"Internal path found in {path.name}"

    tokenizer = load_json("tokenizer.json")
    added_tokens = {int(item["id"]): item["content"] for item in tokenizer["added_tokens"]}
    for token_id, token_text in EXPECTED_SPECIAL_TOKENS.items():
        assert added_tokens.get(token_id) == token_text, (
            f"Tokenizer mismatch for ID {token_id}: "
            f"expected {token_text!r}, found {added_tokens.get(token_id)!r}"
        )

    index = load_json("model.safetensors.index.json")
    weight_map = index["weight_map"]
    expected_keys = set(weight_map)
    shard_names = sorted(set(weight_map.values()))
    assert len(shard_names) == 9, f"Expected 9 shards, found {len(shard_names)}"

    header_keys: set[str] = set()
    total_tensor_elements = 0
    total_tensor_bytes = 0
    routed_experts: dict[tuple[int, int], int] = {}
    routed_pattern = re.compile(r"^text_model\.layers\.(\d+)\.mlp\.experts\.(\d+)\.")
    for shard_name in shard_names:
        shard_path = ROOT / shard_name
        assert shard_path.is_file(), f"Missing shard: {shard_name}"
        header = read_safetensors_header(shard_path)
        for tensor_name, tensor_info in header.items():
            if tensor_name == "__metadata__":
                continue
            assert tensor_name not in header_keys, f"Duplicate tensor: {tensor_name}"
            assert weight_map.get(tensor_name) == shard_name, (
                f"Index maps {tensor_name} to {weight_map.get(tensor_name)!r}, "
                f"but it is stored in {shard_name}"
            )
            header_keys.add(tensor_name)
            tensor_elements = math.prod(tensor_info["shape"])
            total_tensor_elements += tensor_elements
            if match := routed_pattern.match(tensor_name):
                expert_key = (int(match.group(1)), int(match.group(2)))
                routed_experts[expert_key] = routed_experts.get(expert_key, 0) + tensor_elements
            start, end = tensor_info["data_offsets"]
            total_tensor_bytes += end - start

    assert header_keys == expected_keys, (
        f"Index/header key mismatch: "
        f"{len(expected_keys - header_keys)} missing, "
        f"{len(header_keys - expected_keys)} unexpected"
    )
    metadata = index["metadata"]
    assert metadata["total_parameters"] == 21_197_920_833
    # Safetensors may include persistent buffers, so total tensor elements can
    # be larger than the model parameter count recorded by save_pretrained.
    assert total_tensor_elements >= metadata["total_parameters"]
    assert total_tensor_bytes == metadata["total_size"], (
        f"Tensor byte mismatch: {total_tensor_bytes} != {metadata['total_size']}"
    )

    top_k = int(config["text_model_config"]["num_experts_per_tok"])
    routed_total = sum(routed_experts.values())
    active_routed = 0
    for layer in sorted({layer for layer, _ in routed_experts}):
        layer_experts = sorted(
            (value for (expert_layer, _), value in routed_experts.items() if expert_layer == layer),
            reverse=True,
        )
        active_routed += sum(layer_experts[:top_k])
    active_parameters = metadata["total_parameters"] - routed_total + active_routed
    assert active_parameters == 3_456_014_913

    print(
        "Repository validation passed: "
        f"{len(header_keys):,} tensors, "
        f"{metadata['total_parameters']:,} total parameters, "
        f"{active_parameters:,} active parameters, "
        f"{total_tensor_bytes:,} tensor bytes, "
        f"{len(shard_names)} shards."
    )


if __name__ == "__main__":
    main()