Instructions to use yitongl/minimax-h3-nvfp4-lambda-modality with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MiniMax H3
How to use yitongl/minimax-h3-nvfp4-lambda-modality with MiniMax H3:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 4,696 Bytes
0692312 | 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 | #!/usr/bin/env python
"""What each modality pays when lambda was calibrated on a different one.
The end-to-end runs put a number on the *outcome* -- lambda=video lands in a different sample than
BF16 does while lambda=all tracks it -- but not on the mechanism. This does, from the per-modality
statistics alone, with no GPU.
NVFP4 groups 16 consecutive input channels under one FP8 scale set by that group's absmax. A
channel whose own absmax is far below its group's absmax spends its mantissa on range it never
uses, and the loss is `log2(group_absmax / channel_absmax)` bits. That quantity is what smoothing
exists to reduce: `X/lambda` is the activation the kernel actually sees, so lambda reshapes exactly
this profile.
The point is that `W * lambda` is one weight and every modality's rows pass through it. Pick lambda
from video's absmax and video's profile flattens -- but text and audio are divided by a vector that
has nothing to do with their own profile, and an uncorrelated divisor makes a profile *sharper*,
not flatter. This prints the bits lost per modality under each lambda, so "video's gain" and
"text's loss" are on the same axis.
The `lambda = 1` column is the no-smoothing floor, i.e. what every modality pays if nobody is
favoured.
"""
from __future__ import annotations
import argparse
from pathlib import Path
import torch
MODALITIES = ("video", "text", "audio")
BLOCK = 16
def bits_lost(absmax: torch.Tensor, lam: torch.Tensor) -> float:
"""Mean bits a channel loses to its 16-wide group's scale, after dividing by lambda."""
a = (absmax.double() / lam.double()).clamp_min(1e-12)
n = (a.numel() // BLOCK) * BLOCK
g = a[:n].reshape(-1, BLOCK)
return float(torch.log2(g.amax(dim=1, keepdim=True) / g).mean())
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--stats", required=True, help="stats_modal_768p.pt")
ap.add_argument("--calibs", nargs="+", required=True, help="tag=path.pt, e.g. all=...pt")
ap.add_argument("--top", type=int, default=8)
args = ap.parse_args()
st = torch.load(args.stats, map_location="cpu", weights_only=False)["stats"]
cal = {}
for spec in args.calibs:
tag, path = spec.split("=", 1)
cal[tag] = torch.load(path, map_location="cpu", weights_only=False)["layers"]
tags = ["1"] + list(cal)
rows = {m: {t: [] for t in tags} for m in MODALITIES}
per_layer = []
for name, s in st.items():
if name not in next(iter(cal.values())):
continue
lams = {"1": torch.ones_like(s["video"]["absmax"])}
lams.update({t: cal[t][name]["lambda"].float() for t in cal})
rec = {"layer": name}
for m in MODALITIES:
am = s[m]["absmax"].float()
if float(am.max()) == 0.0: # audio is absent from these clips for some layers
continue
for t in tags:
v = bits_lost(am, lams[t])
rows[m][t].append(v)
rec[f"{m}/{t}"] = v
per_layer.append(rec)
print(f"bits lost to the block-16 scale, mean over channels, median over layers "
f"({len(per_layer)} layers)\n")
head = "modality".ljust(10) + "".join(f"lam={t}".rjust(12) for t in tags)
print(head)
print("-" * len(head))
for m in MODALITIES:
if not rows[m]["1"]:
print(f"{m:<10}" + " (no rows in calibration data)")
continue
cells = []
for t in tags:
v = sorted(rows[m][t])
cells.append(f"{v[len(v)//2]:.3f}".rjust(12))
print(f"{m:<10}" + "".join(cells))
print("\nchange vs no smoothing (negative = smoothing helps that modality)")
print(head)
print("-" * len(head))
for m in MODALITIES:
if not rows[m]["1"]:
continue
base = sorted(rows[m]["1"]); base = base[len(base) // 2]
cells = []
for t in tags:
v = sorted(rows[m][t]); v = v[len(v) // 2]
cells.append(("--" if t == "1" else f"{v - base:+.3f}").rjust(12))
print(f"{m:<10}" + "".join(cells))
if "video" in cal:
worst = sorted(per_layer, key=lambda r: -(r.get("text/video", 0) - r.get("text/all", 0)))
print(f"\nlayers where lambda=video costs text the most, vs lambda=all:")
for r in worst[: args.top]:
print(f" {r['layer']:<48} text {r.get('text/all', float('nan')):.3f} -> "
f"{r.get('text/video', float('nan')):.3f} "
f"video {r.get('video/all', float('nan')):.3f} -> "
f"{r.get('video/video', float('nan')):.3f}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|