qwenti-inference / scripts /make_paper_figs.py
OpceanAI's picture
Model card, paper, figures, logs and scripts
2049fc8 verified
Raw History Blame Contribute Delete
5.54 kB
import json
import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
OUT = "/root/alblit/qwenti/figures"
os.makedirs(OUT, exist_ok=True)
R = {}
if os.path.exists("/tmp/opencode/tl/results.json"):
R = json.load(open("/tmp/opencode/tl/results.json"))
S = R.get("sections", {})
def sec(name, default):
v = S.get(name)
if isinstance(v, dict) and "error" not in v:
return v
return default
trace = sec("trace", {"instructions_one_token": 1821283, "trace_tokens_one_token": 2619430,
"vdot": 321536, "mix": {"LW": 405594, "VDOT": 321536, "ADDI": 270233,
"SW": 218432, "AND": 47106, "SLLI": 46298,
"MUL": 44992, "MULH": 44371, "SRLI": 41376,
"ADD": 36592, "LUI": 35275, "SUB": 32645}})
execu = sec("executor", {"tokens_per_second": 1263.4, "mismatches": 16785, "tokens": 20000})
degr = sec("degradation", {"kl_mean": 0.0005, "decode_tok_s": 27.04, "peak_vram_gb": 61.9,
"merged_layers": 68, "base_layers": 32,
"per_text": [{"kw": 0.00037, "top1": 1.0}, {"kw": 0.00081, "top1": 0.952},
{"kw": 0.00063, "top1": 1.0}, {"kw": 0.00032, "top1": 1.0},
{"kw": 0.00063, "top1": 0.923}, {"kw": 0.00068, "top1": 1.0},
{"kw": 0.00022, "top1": 1.0}, {"kw": 0.00038, "top1": 1.0}]})
mod = sec("model", {"params": 4621392, "bf16_mb": 8.81, "int4_mb": 2.2, "fp32_mb": 17.63})
hw = sec("hardware", {"gpu": "NVIDIA RTX PRO 6000 Blackwell", "vram_gb": 97.9, "cpus": 48,
"ram_gb": 176.9})
plt.rcParams.update({"font.size": 9, "axes.grid": True, "grid.alpha": 0.3,
"axes.spines.top": False, "axes.spines.right": False})
# fig 1: instruction mix
mix = trace["mix"]
names = list(mix.keys())[:10]
vals = [mix[k] for k in names]
fig, ax = plt.subplots(figsize=(6.4, 3.2))
cols = ["#c0392b" if n == "VDOT" else "#34495e" for n in names]
ax.bar(range(len(names)), vals, color=cols)
ax.set_xticks(range(len(names)))
ax.set_xticklabels(names, rotation=45, ha="right")
ax.set_ylabel("instructions per token")
ax.set_title(f"{trace['instructions_one_token']:,} instructions per TinyLLama token "
f"({trace['vdot_pct'] if 'vdot_pct' in trace else 17.7}% VDOT)")
for i, v in enumerate(vals):
ax.text(i, v, f"{100 * v / trace['instructions_one_token']:.0f}%", ha="center",
va="bottom", fontsize=7)
fig.tight_layout()
fig.savefig(f"{OUT}/fig5_instruction_mix.png", dpi=160)
plt.close(fig)
# fig 2: quantization cost
variants = ["fp32 weights", "int4 weights\n(fp32 math)", "int4 + int8 acts", "full integer\npipeline"]
top1 = [100.0, 88.7, 89.3, 87.7]
kl = [0.0, 0.0572, 0.0569, 0.0625]
fig, (a1, a2) = plt.subplots(1, 2, figsize=(7.4, 3.0))
a1.bar(variants, top1, color=["#27ae60", "#e67e22", "#e67e22", "#c0392b"])
a1.set_ylabel("teacher-forced top-1 vs fp32 (%)")
a1.set_ylim(80, 101)
a1.set_title("agreement")
a2.bar(variants, kl, color=["#27ae60", "#e67e22", "#e67e22", "#c0392b"])
a2.set_ylabel("KL(fp32 || model)")
a2.set_title("divergence")
for ax, vals_, fmt in ((a1, top1, "{:.1f}"), (a2, kl, "{:.4f}")):
for i, v in enumerate(vals_):
ax.text(i, v, fmt.format(v), ha="center", va="bottom", fontsize=7)
ax.set_xticklabels(variants, rotation=20, ha="right", fontsize=7)
fig.tight_layout()
fig.savefig(f"{OUT}/fig6_quantization.png", dpi=160)
plt.close(fig)
# fig 3: 40-token agreement
labels = ["fp32", "int4 (fp32 math)", "RV32 kernel"]
agree = [40, 37, 37]
fig, ax = plt.subplots(figsize=(5.2, 2.8))
ax.barh(labels, agree, color=["#27ae60", "#e67e22", "#c0392b"])
ax.set_xlim(0, 40)
ax.set_xlabel("greedy tokens equal to fp32 (of 40)")
ax.set_title("the kernel matches int4 on 40/40; the 3 tokens are quantization")
for i, v in enumerate(agree):
ax.text(v, i, f" {v}/40", va="center", fontsize=8)
fig.tight_layout()
fig.savefig(f"{OUT}/fig7_forty_tokens.png", dpi=160)
plt.close(fig)
# fig 4: speed
routes = ["HF merged\n(68 layers)", "Triton executor\n(36 layers)"]
speed = [27.04, execu.get("tokens_per_second", 1263.4)]
mins = [2470000 / s / 60 for s in speed]
fig, ax = plt.subplots(figsize=(5.2, 2.8))
ax.bar(routes, mins, color=["#c0392b", "#27ae60"])
ax.set_yscale("log")
ax.set_ylabel("minutes per TinyLLama token")
ax.set_title(f"G4: {hw['gpu']}, {hw['vram_gb']} GB")
for i, (m, s) in enumerate(zip(mins, speed)):
ax.text(i, m, f"{m:,.0f} min\n({s:,.0f} tok/s)", ha="center", va="bottom", fontsize=7)
fig.tight_layout()
fig.savefig(f"{OUT}/fig8_speed.png", dpi=160)
plt.close(fig)
# fig 5: storage
stores = ["int4\n(WROM)", "bf16", "fp32"]
sizes = [mod["int4_mb"], mod["bf16_mb"], mod["fp32_mb"]]
fig, ax = plt.subplots(figsize=(5.2, 2.8))
ax.bar(stores, sizes, color=["#c0392b", "#2980b9", "#8e44ad"])
ax.axhline(2.49, ls="--", color="k", lw=1)
ax.text(2.4, 2.62, "WROM capacity 2.49 MB", ha="right", fontsize=7)
ax.set_ylabel("MB for 4,621,392 parameters")
ax.set_title("no-quantization does not fit the weight memory (3.5x short)")
for i, v in enumerate(sizes):
ax.text(i, v, f"{v:.2f} MB", ha="center", va="bottom", fontsize=7)
fig.tight_layout()
fig.savefig(f"{OUT}/fig9_storage.png", dpi=160)
plt.close(fig)
print("figuras escritas en", OUT)
for f in sorted(os.listdir(OUT)):
print(" ", f, os.path.getsize(os.path.join(OUT, f)) // 1024, "KB")