Initial commit: E4B-MarkBase model integration with passing tests
CI / build-and-test (push) Has been cancelled

- E4B-MarkBase model (42 layers, 4.4GB) loaded successfully
- All Phase 1-6 tests passed (model loading, forward pass, vision/audio towers, token generation, performance)
- All stress tests passed (5/5 in 127.6s)
  - Concurrent inference
  - Memory stress (67.5 tok/s, 0 NaN)
  - Continuous generation
  - Batch processing
  - Long-running stability
- Swift Metal inference engine with multimodal support
This commit is contained in:
MarkBase Admin
2026-06-23 18:12:35 +08:00
commit ac75faa0cc
301 changed files with 63426 additions and 0 deletions
+369
View File
@@ -0,0 +1,369 @@
#!/usr/bin/env python3
"""
Convert E4B model weights to MarkBase format.
Reads the MLX-community 4-bit quantized Gemma 4 E4B model and re-quantizes
the vision and audio tower weights into the MarkBase 4-bit packed format.
"""
import os
import sys
import shutil
import struct
import json
import numpy as np
import safetensors
SRC_DIR = os.path.expanduser(
"~/.cache/huggingface/hub/models--mlx-community--gemma-4-e4b-it-4bit/"
"snapshots/deb1db712068b1c9f83fb1c97f08c1204b9459a1"
)
DST_DIR = "/Users/accusys/MarkBase12B/models/E4B-MarkBase"
GROUP_SIZE = 64
SRC_MODEL = os.path.join(SRC_DIR, "model.safetensors")
DST_MODEL = os.path.join(DST_DIR, "model.safetensors")
DST_INDEX = os.path.join(DST_DIR, "model.safetensors.index.json")
def bf16_bytes_to_f32(data: bytes) -> np.ndarray:
"""Convert BF16 bytes to float32 numpy array."""
raw = np.frombuffer(data, dtype=np.uint16)
f32 = (raw.astype(np.uint32) << 16).view(np.float32)
return f32
def quantize_weight_4bit(weight_f32: np.ndarray, group_size: int = GROUP_SIZE):
"""
Group-wise 4-bit affine quantization.
weight_f32: shape [outDim, inDim], float32
Returns (packed_u32, scales_f32, biases_f32)
packed_u32: uint32 [outDim, inDim/8]
scales_f32: float32 [outDim, inDim/64]
biases_f32: float32 [outDim, inDim/64]
"""
out_dim, in_dim = weight_f32.shape
assert in_dim % group_size == 0, f"in_dim {in_dim} not divisible by group_size {group_size}"
assert in_dim % 8 == 0
# Reshape to [outDim, inDim/64, 64]
num_groups = in_dim // group_size
groups = weight_f32.reshape(out_dim, num_groups, group_size)
# Per-group min/max
group_min = groups.min(axis=-1) # [outDim, num_groups]
group_max = groups.max(axis=-1) # [outDim, num_groups]
scale = (group_max - group_min) / 15.0
bias = group_min
# Handle zero-range groups (scale == 0)
zero_scale_mask = scale == 0.0
scale[zero_scale_mask] = 1.0 # avoid division by zero
# Quantize
quantized = np.round((groups - bias[:, :, np.newaxis]) / scale[:, :, np.newaxis])
quantized = np.clip(quantized, 0, 15).astype(np.uint32)
# Pack 8 values into one U32
# pack order: q[0] at bits 0-3, q[1] at bits 4-7, ..., q[7] at bits 28-31
packed_shape = (out_dim, in_dim // 8)
packed = np.zeros(packed_shape, dtype=np.uint32)
# Reshape quantized to [outDim, inDim/8, 8]
quantized_reshaped = quantized.reshape(out_dim, in_dim // 8, 8)
for j in range(8):
packed |= (quantized_reshaped[:, :, j] << (j * 4))
return packed, scale.astype(np.float32), bias.astype(np.float32)
def is_linear_weight(name: str) -> bool:
"""Check if a tensor name corresponds to a linear weight that needs quantization."""
if name.startswith("language_model."):
return False
if name.startswith("embed_vision.") or name.startswith("embed_audio."):
return False
if name.endswith(".linear.weight"):
return True
if name == "vision_tower.patch_embedder.input_proj.weight":
return True
if name == "audio_tower.output_proj.weight":
return True
return False
def is_norm_weight(name: str) -> bool:
"""Check if a tensor name corresponds to a norm/weight that should stay as F32."""
if name.startswith("language_model."):
return False
if name.startswith("embed_vision.") or name.startswith("embed_audio."):
return False
if "norm" in name.lower() and name.endswith(".weight"):
return True
if name == "vision_tower.patch_embedder.position_embedding_table":
return True
if "per_dim_scale" in name:
return True
if "relative_k_proj.weight" in name:
return True
if "depthwise_conv1d.weight" in name:
return True
if "conv_norm.weight" in name:
return True
if "pre_layer_norm.weight" in name:
return True
if "post_layer_norm.weight" in name:
return True
if "norm_out.weight" in name:
return True
if "norm_pre_attn.weight" in name:
return True
if "norm_post_attn.weight" in name:
return True
if name.startswith("audio_tower.subsample_conv"):
return True
if name.startswith("audio_tower.subsample_conv_projection"):
return True
if name.endswith("output_proj.bias"):
return True
return False
def process_tensors():
"""Read source tensors, convert, and write output."""
os.makedirs(DST_DIR, exist_ok=True)
print("Reading source safetensor...")
with open(SRC_MODEL, "rb") as f:
src_data = f.read()
tensors = safetensors.deserialize(src_data)
print(f" Found {len(tensors)} tensors")
output_tensor_dict = {}
text_copied = 0
embed_copied = 0
vision_quantized = 0
vision_f32 = 0
audio_quantized = 0
audio_f32 = 0
skipped = 0
# Rust safetensors backend only accepts lowercase dtype names for writing.
DTYPE_MAP = {
"U32": "uint32",
"BF16": "bfloat16",
"F16": "float16",
"F32": "float32",
"I32": "int32",
"I64": "int64",
}
def add_tensor(name, shape, dtype, data):
if isinstance(data, bytearray):
data = bytes(data)
elif not isinstance(data, bytes):
data = data.tobytes()
py_dtype = DTYPE_MAP.get(dtype, dtype)
output_tensor_dict[name] = {
"shape": list(shape) if isinstance(shape, (list, tuple)) else shape,
"dtype": py_dtype,
"data": data,
}
for name, info in tensors:
dtype_tag = info["dtype"]
shape = info["shape"]
data = info["data"]
# --- Text model: copy as-is ---
if name.startswith("language_model."):
add_tensor(name, shape, dtype_tag, data)
text_copied += 1
continue
# --- Embed vision/audio projections: already quantized, copy as-is ---
if name.startswith("embed_vision.") or name.startswith("embed_audio."):
add_tensor(name, shape, dtype_tag, data)
embed_copied += 1
continue
# --- Vision/Audio tower input_min/max/output_min/output_max: skip ---
if ("input_min" in name or "input_max" in name or
"output_min" in name or "output_max" in name):
skipped += 1
continue
# --- Quantize linear weights ---
if is_linear_weight(name):
print(f" Quantizing: {name} shape={shape}")
weight_f32 = bf16_bytes_to_f32(data).reshape(shape)
packed, scales, biases = quantize_weight_4bit(weight_f32)
out_dim, in_dim = shape
# Strip `.linear` if present; otherwise use name directly.
# e.g. "q_proj.linear.weight" → "q_proj.weight" / ".scales" / ".biases"
# "input_proj.weight" → "input_proj.weight" / ".scales" / ".biases"
if ".linear.weight" in name:
weight_name = name.replace(".linear.weight", ".weight")
scales_name = name.replace(".linear.weight", ".scales")
biases_name = name.replace(".linear.weight", ".biases")
else:
weight_name = name
scales_name = name.replace(".weight", ".scales")
biases_name = name.replace(".weight", ".biases")
add_tensor(weight_name, [out_dim, in_dim // 8], "U32", packed)
add_tensor(scales_name, [out_dim, in_dim // GROUP_SIZE], "F32", scales)
add_tensor(biases_name, [out_dim, in_dim // GROUP_SIZE], "F32", biases)
if name.startswith("vision_tower."):
vision_quantized += 1
else:
audio_quantized += 1
continue
# --- Convert BF16 norms and special tensors to float32 ---
if is_norm_weight(name):
f32_array = bf16_bytes_to_f32(data).reshape(shape)
add_tensor(name, shape, "F32", f32_array)
if name.startswith("vision_tower."):
vision_f32 += 1
else:
audio_f32 += 1
continue
# --- Catch-all: convert any remaining BF16 to F32 ---
if dtype_tag == "BF16":
print(f" Converting BF16->F32: {name} shape={shape}")
f32_array = bf16_bytes_to_f32(data).reshape(shape)
add_tensor(name, shape, "F32", f32_array)
if name.startswith("vision_tower."):
vision_f32 += 1
else:
audio_f32 += 1
continue
# Should not reach here for any known tensor
print(f" WARNING: unhandled tensor: {name} dtype={dtype_tag} shape={shape}")
add_tensor(name, shape, dtype_tag, data)
print()
print(f"Text tensors copied: {text_copied}")
print(f"Embed tensors copied: {embed_copied}")
print(f"Vision quantized: {vision_quantized}")
print(f"Vision f32: {vision_f32}")
print(f"Audio quantized: {audio_quantized}")
print(f"Audio f32: {audio_f32}")
print(f"Input/output minmax skipped: {skipped}")
print(f"Total output tensors: {len(output_tensor_dict)}")
print("\nSerializing output safetensor...")
serialized = safetensors.serialize(output_tensor_dict)
with open(DST_MODEL, "wb") as f:
f.write(serialized)
# Write index file
total_bytes = os.path.getsize(DST_MODEL)
weight_map = {name: "model.safetensors" for name in output_tensor_dict}
index_data = {
"metadata": {"total_size": total_bytes},
"weight_map": weight_map,
}
with open(DST_INDEX, "w") as f:
json.dump(index_data, f, indent=2)
print(f"Output model: {DST_MODEL} ({total_bytes} bytes)")
print(f"Output index: {DST_INDEX}")
def copy_metadata_files():
"""Copy non-weight files from source to destination."""
os.makedirs(DST_DIR, exist_ok=True)
metadata_files = [
"config.json",
"generation_config.json",
"tokenizer.json",
"tokenizer_config.json",
"processor_config.json",
"chat_template.jinja",
]
for fn in metadata_files:
src = os.path.join(SRC_DIR, fn)
dst = os.path.join(DST_DIR, fn)
if os.path.exists(src):
shutil.copy2(src, dst)
print(f" Copied {fn}")
else:
print(f" WARNING: {fn} not found in source")
def verify_output():
"""Verify the output safetensor can be read back."""
print("\nVerifying output...")
try:
with open(DST_MODEL, "rb") as f:
data = f.read()
tensors = safetensors.deserialize(data)
keys = [t[0] for t in tensors]
print(f" Output contains {len(keys)} tensors")
# Build a lookup by key
tensor_map = {t[0]: t[1] for t in tensors}
# Verify a text tensor
sample = "language_model.model.layers.0.input_layernorm.weight"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
# Verify a vision quantized tensor
sample = "vision_tower.encoder.layers.0.self_attn.q_proj.weight"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
sample = "vision_tower.encoder.layers.0.self_attn.q_proj.scales"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
# Verify a vision norm tensor
sample = "vision_tower.encoder.layers.0.input_layernorm.weight"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
# Verify audio quantized
sample = "audio_tower.layers.0.self_attn.q_proj.weight"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
# Verify embed_vision
sample = "embed_vision.embedding_projection.weight"
if sample in tensor_map:
info = tensor_map[sample]
print(f" {sample}: dtype={info['dtype']} shape={info['shape']}")
print(" All checks passed!")
except Exception as e:
print(f" ERROR during verification: {e}")
sys.exit(1)
def main():
print("=== E4B to MarkBase Converter ===\n")
print(f"Source: {SRC_MODEL}")
print(f"Destination: {DST_DIR}\n")
copy_metadata_files()
process_tensors()
verify_output()
print("\nDone! Model converted successfully.")
if __name__ == "__main__":
main()