Upload make_profile.py with huggingface_hub
Browse files- make_profile.py +63 -0
make_profile.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate StarNodes converter profiles for MiniMax-H3 from the bf16 safetensors header.
|
| 2 |
+
|
| 3 |
+
Two variants:
|
| 4 |
+
minimax_h3_nvfp4_mixed.json - AdaLN kept at FP8, attn/mlp at NVFP4 (recommended)
|
| 5 |
+
minimax_h3_nvfp4_full.json - everything incl. AdaLN at NVFP4 (aggressive)
|
| 6 |
+
|
| 7 |
+
Kept at BF16 in both: all biases, all norms, rope freqs, patch/time/condition
|
| 8 |
+
embedders and the final output heads (~0.04B params total, 0.1% of the model).
|
| 9 |
+
"""
|
| 10 |
+
import json, struct, sys, os, datetime
|
| 11 |
+
|
| 12 |
+
SRC = "/workspace/ComfyUI/models/diffusion_models/minimax_h3_ref2va_bf16.safetensors"
|
| 13 |
+
OUT_DIR = "/workspace/ComfyUI/custom_nodes/comfyui-starnodes-modelconverter/profiles"
|
| 14 |
+
|
| 15 |
+
with open(SRC, "rb") as f:
|
| 16 |
+
n = struct.unpack("<Q", f.read(8))[0]
|
| 17 |
+
hdr = json.loads(f.read(n))
|
| 18 |
+
keys = sorted(k for k in hdr if k != "__metadata__")
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def classify(key, adaln_fmt):
|
| 22 |
+
# non-weight tensors and everything tiny stays bf16
|
| 23 |
+
if not key.endswith(".weight"):
|
| 24 |
+
return "BF16"
|
| 25 |
+
if "norm" in key or key.endswith("inv_freq"):
|
| 26 |
+
return "BF16"
|
| 27 |
+
if any(t in key for t in ("patch_proj", "time_embedder", "condition_proj", "final_layer")):
|
| 28 |
+
return "BF16"
|
| 29 |
+
if "adaln" in key:
|
| 30 |
+
return adaln_fmt
|
| 31 |
+
if ".attn." in key or ".mlp." in key:
|
| 32 |
+
return "NVFP4"
|
| 33 |
+
return "BF16"
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def build(adaln_fmt, name):
|
| 37 |
+
layers, counts = {}, {}
|
| 38 |
+
for k in keys:
|
| 39 |
+
fmt = classify(k, adaln_fmt)
|
| 40 |
+
layers[k] = fmt
|
| 41 |
+
counts[fmt] = counts.get(fmt, 0) + 1
|
| 42 |
+
if fmt != "BF16":
|
| 43 |
+
base = k[: -len(".weight")]
|
| 44 |
+
layers[f"{base}.weight_scale"] = "FP32_SCALE"
|
| 45 |
+
layers[f"{base}.comfy_quant"] = "METADATA"
|
| 46 |
+
prof = {
|
| 47 |
+
"__metadata__": {
|
| 48 |
+
"original_model_name": name,
|
| 49 |
+
"original_model_path": SRC,
|
| 50 |
+
"timestamp": datetime.datetime.now().isoformat(),
|
| 51 |
+
"total_layers": len(layers),
|
| 52 |
+
"created_by": "hand-authored for MiniMax-H3 (33.12B: adaln 39.4%, mlp 36.3%, attn 24.2%)",
|
| 53 |
+
},
|
| 54 |
+
"layers": layers,
|
| 55 |
+
}
|
| 56 |
+
path = os.path.join(OUT_DIR, f"{name}.json")
|
| 57 |
+
with open(path, "w") as f:
|
| 58 |
+
json.dump(prof, f, indent=1)
|
| 59 |
+
print(f"{name}: {counts} -> {path}")
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
build("FP8_E4M3FN + SCALE", "minimax_h3_nvfp4_mixed")
|
| 63 |
+
build("NVFP4", "minimax_h3_nvfp4_full")
|