SPB Git

spb/localvm-research Public License

Running LLMs larger than memory on a consumer Mac — falsification-driven research: margin-gated deferred refinement, out-of-core verification on Apple Silicon. TR-01 published.

Python 63.2% JavaScript 23.5% CSS 11.8% Shell 0.9% Makefile 0.5%
10.0 KB · 193 lines python
Raw Blame History
1#!/usr/bin/env python32# =============================================================================3#  Project   : localvm-research4#  File      : tools/make_pub_figures.py5#  Purpose   : Generate publication SVG figures from committed results JSON6#  Author    : Simon-Pierre Boucher7#  Contact   : contact@spboucher.ai8#  Created   : 2026-08-129#  Modified  : 2026-08-1210#  Platform  : macOS / Apple Silicon (arm64)11#  License   : All rights reserved (research code)12# =============================================================================13"""Regenerates docs/publications/figures/*.svg from results/ (reproducible).1415Palette: validated categorical slots (see dataviz reference; CVD-checked):16blue #2a78d6, orange #eb6834, aqua #1baf7a. Ink/grid tokens match the site.17"""1819from __future__ import annotations2021import glob22import json23import math24from pathlib import Path2526ROOT = Path(__file__).resolve().parent.parent27OUT = ROOT / "docs" / "publications" / "figures"28OUT.mkdir(parents=True, exist_ok=True)2930INK, INK2, MUTED, GRID, BASE = "#0b0b0b", "#52514e", "#898781", "#e1e0d9", "#c3c2b7"31BLUE, ORANGE, AQUA = "#2a78d6", "#eb6834", "#1baf7a"32FONT = "font-family='system-ui, -apple-system, sans-serif'"33MONO = "font-family='ui-monospace, Menlo, monospace'"343536def latest(pattern: str) -> dict:37    return json.load(open(sorted(glob.glob(str(ROOT / pattern)))[-1]))383940def svg_open(w: int, h: int) -> list[str]:41    return [f"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 {w} {h}' "42            f"width='{w}' height='{h}'>",43            f"<rect width='{w}' height='{h}' fill='#fcfcfb'/>"]444546def text(x, y, s, size=12, fill=INK2, anchor="start", weight="400", mono=False):47    f = MONO if mono else FONT48    return (f"<text x='{x:.1f}' y='{y:.1f}' {f} font-size='{size}' fill='{fill}' "49            f"text-anchor='{anchor}' font-weight='{weight}'>{s}</text>")505152# ---------------------------------------------------------------- F1: SSD53def fig1_ssd() -> None:54    d = latest("results/expH_ssd_feasibility/*/results.json")55    cells = [c for c in d["cells"] if c["nocache"] and not c["gpu_load"]56             and c["pattern"] == "random" and c["block_bytes"] <= 1 << 20]57    series: dict[int, list] = {}58    for c in cells:59        series.setdefault(c["threads"], []).append((c["block_bytes"], c["mb_per_s_mean"]))60    W, H, ML, MR, MT, MB_ = 640, 330, 64, 84, 20, 4661    iw, ih = W - ML - MR, H - MT - MB_62    xs = lambda b: ML + (math.log2(b) - 12) / 8 * iw63    ys = lambda v: MT + ih - (math.log10(v) - math.log10(50)) / (math.log10(20000) - math.log10(50)) * ih64    out = svg_open(W, H)65    for v in (100, 1000, 10000):66        out.append(f"<line x1='{ML}' y1='{ys(v):.1f}' x2='{ML+iw}' y2='{ys(v):.1f}' stroke='{GRID}'/>")67        out.append(text(ML - 8, ys(v) + 4, f"{v//1000} GB/s" if v >= 1000 else f"{v} MB/s",68                        11, MUTED, "end", mono=True))69    for b in (4096, 16384, 65536, 262144, 1048576):70        lbl = "1 MiB" if b >= 1048576 else f"{b//1024} KiB"71        out.append(text(xs(b), MT + ih + 18, lbl, 11, MUTED, "middle", mono=True))72    out.append(f"<line x1='{ML}' y1='{MT+ih}' x2='{ML+iw}' y2='{MT+ih}' stroke='{BASE}'/>")73    colors = {1: BLUE, 4: ORANGE, 8: AQUA}74    for qd, pts in sorted(series.items()):75        pts.sort()76        c = colors[qd]77        pd = " ".join(f"{'M' if i == 0 else 'L'}{xs(b):.1f},{ys(v):.1f}" for i, (b, v) in enumerate(pts))78        out.append(f"<path d='{pd}' fill='none' stroke='{c}' stroke-width='2'/>")79        for b, v in pts:80            out.append(f"<circle cx='{xs(b):.1f}' cy='{ys(v):.1f}' r='4' fill='{c}' "81                       f"stroke='#fcfcfb' stroke-width='1.5'/>")82        out.append(text(xs(pts[-1][0]) + 10, ys(pts[-1][1]) + 4, f"QD {qd}", 12, c, weight="600"))83    out.append(text(ML + iw / 2, H - 8, "random read block size (F_NOCACHE cold, log–log)", 12, INK2, "middle"))84    out.append("</svg>")85    (OUT / "f1_ssd_envelope.svg").write_text("\n".join(out))868788# ---------------------------------------------------------------- F2: expG scale89def fig2_escalation() -> None:90    runs = sorted(glob.glob(str(ROOT / "results/expG_decision_stability/*/results.json")))91    data = {}92    for r in runs:93        d = json.load(open(r))94        if d["n_trajectories"] < 40:95            continue96        scale = "8B" if "8B" in d["config"]["model"] else "1.7B"97        data[scale] = {int(b): s.get("escalation_frac_for_99pct")98                       for b, s in d["results_by_bits"].items() if int(b) >= 3}99    W, H, ML, MR, MT, MB_ = 560, 320, 64, 80, 20, 46100    iw, ih = W - ML - MR, H - MT - MB_101    xs = {3: ML + iw * 0.12, 4: ML + iw * 0.5, 8: ML + iw * 0.88}102    ys = lambda v: MT + ih - v / 0.7 * ih103    out = svg_open(W, H)104    for v in (0.2, 0.4, 0.6):105        out.append(f"<line x1='{ML}' y1='{ys(v):.1f}' x2='{ML+iw}' y2='{ys(v):.1f}' stroke='{GRID}'/>")106        out.append(text(ML - 8, ys(v) + 4, f"{int(v*100)}%", 11, MUTED, "end", mono=True))107    out.append(f"<line x1='{ML}' y1='{MT+ih}' x2='{ML+iw}' y2='{MT+ih}' stroke='{BASE}'/>")108    for b in (3, 4, 8):109        out.append(text(xs[b], MT + ih + 18, f"{b}-bit base", 12, MUTED, "middle"))110    for scale, color in (("1.7B", BLUE), ("8B", ORANGE)):111        pts = [(b, v) for b, v in sorted(data.get(scale, {}).items()) if v]112        pd = " ".join(f"{'M' if i == 0 else 'L'}{xs[b]:.1f},{ys(v):.1f}" for i, (b, v) in enumerate(pts))113        out.append(f"<path d='{pd}' fill='none' stroke='{color}' stroke-width='2'/>")114        for b, v in pts:115            out.append(f"<circle cx='{xs[b]:.1f}' cy='{ys(v):.1f}' r='4.5' fill='{color}' "116                       f"stroke='#fcfcfb' stroke-width='1.5'/>")117            dy = 20 if (scale == "8B" and b == 8) else -10  # avoid series-label collision118            out.append(text(xs[b], ys(v) + dy, f"{v*100:.0f}%", 11, color, "middle", "600", mono=True))119        out.append(text(xs[pts[-1][0]] + 12, ys(pts[-1][1]) + 4, f"Qwen3-{scale}", 12, color, weight="600"))120    out.append(text(ML + iw / 2, H - 8, "tokens needing escalation for 99% greedy agreement", 12, INK2, "middle"))121    out.append("</svg>")122    (OUT / "f2_escalation_scale.svg").write_text("\n".join(out))123124125# ---------------------------------------------------------------- F3: continuum126def fig3_continuum() -> None:127    runs = [json.load(open(p)) for p in sorted(glob.glob(str(ROOT / "results/candidate_01/*/results.json")))]128    d = [r for r in runs if "quality_bf16_judge" in r][-1]129    q = d["quality_bf16_judge"]130    pts = [("pure q4", 0.0, q["pure_q4"]["mean_logprob_bf16"]),131           ("τ=1.0", 150, q["margin_tau1.0"]["mean_logprob_bf16"]),132           ("τ=2.0", 211, q["margin_tau2.0"]["mean_logprob_bf16"]),133           ("verify-all", 237, q["verify-all_tau2.0"]["mean_logprob_bf16"])]134    ceiling = q["pure_q8"]["mean_logprob_bf16"]135    W, H, ML, MR, MT, MB_ = 620, 330, 74, 40, 26, 46136    iw, ih = W - ML - MR, H - MT - MB_137    xs = lambda v: ML + v / 260 * iw138    ys = lambda v: MT + ih - (v + 0.42) / 0.34 * ih139    out = svg_open(W, H)140    for v in (-0.4, -0.3, -0.2, -0.1):141        out.append(f"<line x1='{ML}' y1='{ys(v):.1f}' x2='{ML+iw}' y2='{ys(v):.1f}' stroke='{GRID}'/>")142        out.append(text(ML - 8, ys(v) + 4, f"{v:.1f}", 11, MUTED, "end", mono=True))143    for v in (0, 100, 200):144        out.append(text(xs(v), MT + ih + 18, f"{v} MB", 11, MUTED, "middle", mono=True))145    out.append(f"<line x1='{ML}' y1='{MT+ih}' x2='{ML+iw}' y2='{MT+ih}' stroke='{BASE}'/>")146    out.append(f"<line x1='{ML}' y1='{ys(ceiling):.1f}' x2='{ML+iw}' y2='{ys(ceiling):.1f}' "147               f"stroke='{MUTED}' stroke-dasharray='5,4'/>")148    out.append(text(ML + 4, ys(ceiling) + 15, "resident-q8 ceiling (2.15 GB in RAM)", 11, MUTED))149    pd = " ".join(f"{'M' if i == 0 else 'L'}{xs(x):.1f},{ys(y):.1f}" for i, (_, x, y) in enumerate(pts))150    out.append(f"<path d='{pd}' fill='none' stroke='{BLUE}' stroke-width='2'/>")151    for name, x, y in pts:152        out.append(f"<circle cx='{xs(x):.1f}' cy='{ys(y):.1f}' r='5' fill='{BLUE}' "153                   f"stroke='#fcfcfb' stroke-width='2'/>")154        if name == "verify-all":155            out.append(text(xs(x) - 11, ys(y) + 4, name, 12, INK, "end", "600"))156        else:157            out.append(text(xs(x) + 9, ys(y) + (14 if name == "pure q4" else -9), name, 12, INK, weight="600"))158    out.append(text(ML + iw / 2, H - 8, "verification bytes streamed per token (Qwen3-1.7B, W=32)", 12, INK2, "middle"))159    out.append(text(16, MT + ih / 2, "bf16-judge mean logprob →", 12, INK2, "middle")160               .replace(">", f" transform='rotate(-90 16 {MT+ih/2})'>", 1))161    out.append("</svg>")162    (OUT / "f3_quality_bytes_continuum.svg").write_text("\n".join(out))163164165# ---------------------------------------------------------------- F4: 32B166def fig4_scale32b() -> None:167    d = latest("results/candidate_01_scale32b/20260812T055506Z/results.json")168    q = d["quality_8b_judge"]169    rows = [("pure q4 — only config that fits (17.5 GB)", q["pure_q4"]["mean_logprob_8b_judge"]),170            ("margin τ=2.0 — q8 streamed on low margins", q["margin_tau2.0"]["mean_logprob_8b_judge"]),171            ("verify-all — q8 streamed every window", q["verify-all_tau2.0"]["mean_logprob_8b_judge"])]172    W, H, ML, MR, MT = 640, 210, 26, 90, 24173    row_h = 52174    x0, x1 = -0.80, -0.40175    xs = lambda v: ML + (v - x0) / (x1 - x0) * (W - ML - MR)176    out = svg_open(W, H)177    for i, (name, v) in enumerate(rows):178        y = MT + i * row_h + 20179        color = BLUE if i else MUTED180        out.append(text(ML, y - 8, name, 12.5, INK2))181        out.append(f"<line x1='{xs(x0)}' y1='{y+9}' x2='{xs(v):.1f}' y2='{y+9}' "182                   f"stroke='{color}' stroke-width='9' stroke-linecap='round'/>")183        out.append(text(xs(v) + 10, y + 13, f"{v:.3f}", 12, INK, weight="650", mono=True))184    out.append(text(ML, H - 10, "8B-judge mean logprob (higher is better) · Qwen3-32B on a 48 GB Mac — "185                    "resident q8 is impossible", 11.5, MUTED))186    out.append("</svg>")187    (OUT / "f4_32b_outofcore.svg").write_text("\n".join(out))188189190if __name__ == "__main__":191    fig1_ssd(); fig2_escalation(); fig3_continuum(); fig4_scale32b()192    print("figures written to", OUT)193