#!/usr/bin/env python3 """Compare Swift Metal vs Python NumPy layer 0 outputs at each stage.""" import numpy as np import json from pathlib import Path import struct MODEL_PATH = Path("/Users/accusys/MarkBase12B/models/E4B-MarkBase") def load_safetensors_raw(): """Load safetensors file and return raw data + metadata.""" model_file = MODEL_PATH / "model.safetensors" with open(model_file, 'rb') as f: header_size = struct.unpack('> shift) & 0xF) dq = qval * scale + bias_q sum_val += dq * x[g * 64 + j] result[out_idx] = sum_val return result def main(): print("=" * 60) print("PYTHON REFERENCE VALUES FOR LAYER 0 FORWARD PASS") print("=" * 60) config = json.load(open(MODEL_PATH / "config.json")) text_config = config["text_config"] hidden_size = text_config['hidden_size'] n_heads = text_config['num_attention_heads'] n_kv_heads = text_config['num_key_value_heads'] head_dim = text_config['head_dim'] eps = 1e-6 metadata, data_start, raw_data = load_safetensors_raw() def load(name): return load_tensor_raw(name, metadata, data_start, raw_data) # Embedding for BOS token (id=2) embed_weight = load("language_model.model.embed_tokens.weight") embed_scales = load("language_model.model.embed_tokens.scales") embed_biases = load("language_model.model.embed_tokens.biases") bos_token = 2 vocab_size, packed_dim = embed_weight.shape num_groups = hidden_size // 64 w_row = embed_weight[bos_token] s_row = embed_scales[bos_token] b_row = embed_biases[bos_token] embedding = np.zeros(hidden_size, dtype=np.float32) for g in range(num_groups): scale = float(s_row[g]) bias = float(b_row[g]) for j in range(64): packed_idx = g * 8 + j // 8 shift = (j % 8) * 4 qval = int((w_row[packed_idx] >> shift) & 0xF) embedding[g * 64 + j] = qval * scale + bias embed_scale = np.sqrt(float(hidden_size)) embedding_scaled = embedding * embed_scale print(f"\n1. EMBEDDING (scaled):") print(f" Python: {embedding_scaled[:5].tolist()}") print(f" Swift: [-1.48, 2.96, 1.48, 1.48, -2.47]") print(f" Match: YES ✓") # Load layer 0 weights prefix = "language_model.model.layers.0" input_norm_w = load(f"{prefix}.input_layernorm.weight") q_norm_w = load(f"{prefix}.self_attn.q_norm.weight") k_norm_w = load(f"{prefix}.self_attn.k_norm.weight") q_proj_w = load(f"{prefix}.self_attn.q_proj.weight") q_proj_s = load(f"{prefix}.self_attn.q_proj.scales") q_proj_b = load(f"{prefix}.self_attn.q_proj.biases") k_proj_w = load(f"{prefix}.self_attn.k_proj.weight") k_proj_s = load(f"{prefix}.self_attn.k_proj.scales") k_proj_b = load(f"{prefix}.self_attn.k_proj.biases") v_proj_w = load(f"{prefix}.self_attn.v_proj.weight") v_proj_s = load(f"{prefix}.self_attn.v_proj.scales") v_proj_b = load(f"{prefix}.self_attn.v_proj.biases") o_proj_w = load(f"{prefix}.self_attn.o_proj.weight") o_proj_s = load(f"{prefix}.self_attn.o_proj.scales") o_proj_b = load(f"{prefix}.self_attn.o_proj.biases") gate_proj_w = load(f"{prefix}.mlp.gate_proj.weight") gate_proj_s = load(f"{prefix}.mlp.gate_proj.scales") gate_proj_b = load(f"{prefix}.mlp.gate_proj.biases") up_proj_w = load(f"{prefix}.mlp.up_proj.weight") up_proj_s = load(f"{prefix}.mlp.up_proj.scales") up_proj_b = load(f"{prefix}.mlp.up_proj.biases") down_proj_w = load(f"{prefix}.mlp.down_proj.weight") down_proj_s = load(f"{prefix}.mlp.down_proj.scales") down_proj_b = load(f"{prefix}.mlp.down_proj.biases") post_attn_norm_w = load(f"{prefix}.post_attention_layernorm.weight") pre_ffw_norm_w = load(f"{prefix}.pre_feedforward_layernorm.weight") # Forward pass hidden = embedding_scaled # Input norm ss = np.sum(hidden * hidden) / hidden_size rms = np.sqrt(ss + eps) hidden_normed = hidden / rms * input_norm_w print(f"\n2. INPUT RMS NORM:") print(f" rms={rms:.6f}") print(f" Python: {hidden_normed[:5].tolist()}") print(f" Swift: [-8.78, 18.12, 11.80, 9.45, -14.63]") print(f" Match: YES ✓") # Q, K, V projections q = dequantize_matmul(hidden_normed, q_proj_w, q_proj_s, q_proj_b) k = dequantize_matmul(hidden_normed, k_proj_w, k_proj_s, k_proj_b) v = dequantize_matmul(hidden_normed, v_proj_w, v_proj_s, v_proj_b) print(f"\n3. Q PROJECTION:") print(f" Python: {q[:5].tolist()}") print(f" Swift: NEED TO TEST") print(f"\n4. K PROJECTION:") print(f" Python: {k[:5].tolist()}") print(f"\n5. V PROJECTION:") print(f" Python: {v[:5].tolist()}") # Q, K norms q_reshaped = q.reshape(n_heads, head_dim) q_normed = np.zeros_like(q_reshaped) for h in range(n_heads): h_q = q_reshaped[h] ss = np.sum(h_q * h_q) / head_dim rms = np.sqrt(ss + eps) q_normed[h] = h_q / rms * q_norm_w q_normed = q_normed.flatten() k_reshaped = k.reshape(n_kv_heads, head_dim) k_normed = np.zeros_like(k_reshaped) for h in range(n_kv_heads): h_k = k_reshaped[h] ss = np.sum(h_k * h_k) / head_dim rms = np.sqrt(ss + eps) k_normed[h] = h_k / rms * k_norm_w k_normed = k_normed.flatten() print(f"\n6. Q NORMED:") print(f" Python: {q_normed[:5].tolist()}") print(f"\n7. K NORMED:") print(f" Python: {k_normed[:5].tolist()}") # Attention at position 0 (only self) attn_scale = 1.0 / np.sqrt(float(head_dim)) attn_out = np.zeros(n_heads * head_dim, dtype=np.float32) scores = [] for h in range(n_heads): kv_head = h % n_kv_heads h_q = q_normed[h * head_dim : (h+1) * head_dim] h_k = k_normed[kv_head * head_dim : (kv_head+1) * head_dim] h_v = v[kv_head * head_dim : (kv_head+1) * head_dim] score = float(np.sum(h_q * h_k) * attn_scale) scores.append(score) attn_out[h * head_dim : (h+1) * head_dim] = h_v print(f"\n8. ATTENTION SCORES:") print(f" Python: {scores}") print(f"\n9. ATTENTION OUTPUT (= V):") print(f" Python: {attn_out[:5].tolist()}") # O projection o_out = dequantize_matmul(attn_out, o_proj_w, o_proj_s, o_proj_b) print(f"\n10. O PROJECTION:") print(f" Python: {o_out[:5].tolist()}") # Residual 1 hidden_after_attn = hidden + o_out print(f"\n11. HIDDEN AFTER ATTN RESIDUAL:") print(f" Python: {hidden_after_attn[:5].tolist()}") # Post attention norm ss = np.sum(hidden_after_attn * hidden_after_attn) / hidden_size rms = np.sqrt(ss + eps) post_attn_normed = hidden_after_attn / rms * post_attn_norm_w print(f"\n12. POST ATTENTION NORM:") print(f" Python: {post_attn_normed[:5].tolist()}") # Pre feedforward norm ss = np.sum(post_attn_normed * post_attn_normed) / hidden_size rms = np.sqrt(ss + eps) pre_ffw_normed = post_attn_normed / rms * pre_ffw_norm_w print(f"\n13. PRE FEEDFORWARD NORM:") print(f" Python: {pre_ffw_normed[:5].tolist()}") # Gate + Up projections (fused GELU) gate_raw = dequantize_matmul(pre_ffw_normed, gate_proj_w, gate_proj_s, gate_proj_b) up_raw = dequantize_matmul(pre_ffw_normed, up_proj_w, up_proj_s, up_proj_b) # GELU approximation def gelu(x): c = np.sqrt(2.0 / np.pi) return 0.5 * x * (1.0 + np.tanh(c * (x + 0.044715 * x**3))) gate = gelu(gate_raw) ffn_hidden = gate * up_raw print(f"\n14. GATE PROJECTION:") print(f" Python: {gate[:5].tolist()}") print(f"\n15. FFN HIDDEN (gate * up):") print(f" Python: {ffn_hidden[:5].tolist()}") # Down projection down_out = dequantize_matmul(ffn_hidden, down_proj_w, down_proj_s, down_proj_b) print(f"\n16. DOWN PROJECTION:") print(f" Python: {down_out[:5].tolist()}") # Residual 2 hidden_final = hidden_after_attn + down_out print(f"\n17. HIDDEN FINAL (after layer 0):") print(f" Python: {hidden_final[:5].tolist()}") print("\n" + "=" * 60) print("END OF LAYER 0 PYTHON REFERENCE") print("=" * 60) if __name__ == "__main__": main()