Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Silver Regression Explorer</title> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script> | |
| <style> | |
| :root{ | |
| --bg0:#f6f7f9; | |
| --bg1:#e4e7ec; | |
| --bg2:#c8ced8; | |
| --surface:#ffffff; | |
| --surface2:#f9fafc; | |
| --surface3:#eef2f7; | |
| --ink:#111318; | |
| --ink2:#2f3540; | |
| --muted:#5e6675; | |
| --muted2:#788190; | |
| --accent:#2f6fed; | |
| --accent2:#1f9d7a; | |
| --line:#d8dde6; | |
| --line2:#b7bfcc; | |
| --shadow:0 18px 45px rgba(29,38,52,.12); | |
| --shadow2:0 10px 24px rgba(29,38,52,.10); | |
| --radius:8px; | |
| --radius2:8px; | |
| --radius3:8px; | |
| } | |
| body[data-theme="dark"]{ | |
| --bg0:#101216; | |
| --bg1:#161a21; | |
| --bg2:#202631; | |
| --surface:#181d25; | |
| --surface2:#202631; | |
| --surface3:#252d39; | |
| --ink:#f2f5f9; | |
| --ink2:#d7dde7; | |
| --muted:#a5adba; | |
| --muted2:#87909f; | |
| --accent:#7fb0ff; | |
| --accent2:#72d4ba; | |
| --line:#303847; | |
| --line2:#465163; | |
| --shadow:0 18px 50px rgba(0,0,0,.38); | |
| --shadow2:0 10px 24px rgba(0,0,0,.30); | |
| } | |
| *{box-sizing:border-box} | |
| html{scroll-behavior:smooth} | |
| body{ | |
| margin:0; | |
| min-height:100vh; | |
| padding:24px; | |
| color:var(--ink); | |
| font-family:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| background: | |
| linear-gradient(180deg, rgba(255,255,255,.72), rgba(255,255,255,0) 260px), | |
| linear-gradient(135deg, var(--bg0), var(--bg1) 48%, var(--bg2)); | |
| transition: background .25s ease, color .25s ease; | |
| } | |
| body[data-theme="dark"]{ | |
| background: | |
| linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,0) 280px), | |
| linear-gradient(135deg, var(--bg0), var(--bg1) 50%, var(--bg2)); | |
| } | |
| .app{max-width:1540px;margin:0 auto;display:grid;gap:18px} | |
| .hero, .panel, .chart-card, .info-card, .disclaimer{ | |
| border:1px solid var(--line); | |
| background:linear-gradient(180deg, rgba(255,255,255,.96), rgba(247,249,252,.92)); | |
| box-shadow:var(--shadow); | |
| backdrop-filter:blur(12px); | |
| transition: background .25s ease, border-color .25s ease, color .25s ease, box-shadow .25s ease; | |
| } | |
| body[data-theme="dark"] .hero, | |
| body[data-theme="dark"] .panel, | |
| body[data-theme="dark"] .chart-card, | |
| body[data-theme="dark"] .info-card, | |
| body[data-theme="dark"] .disclaimer{ | |
| border-color:var(--line); | |
| background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.025)); | |
| } | |
| .hero{ | |
| border-radius:var(--radius); | |
| padding:26px; | |
| position:relative; | |
| overflow:hidden; | |
| } | |
| .hero::before{ | |
| content:""; | |
| position:absolute; | |
| inset:0 0 auto; | |
| height:4px; | |
| pointer-events:none; | |
| background:linear-gradient(90deg, var(--accent), var(--accent2), rgba(255,255,255,.6)); | |
| } | |
| body[data-theme="dark"] .hero::before{ | |
| background:linear-gradient(90deg, var(--accent), var(--accent2), rgba(255,255,255,.16)); | |
| } | |
| .hero::after{ | |
| content:""; | |
| position:absolute; | |
| inset:0; | |
| pointer-events:none; | |
| background:linear-gradient(90deg, rgba(47,111,237,.08), transparent 42%, rgba(31,157,122,.07)); | |
| } | |
| body[data-theme="dark"] .hero::after{ | |
| background:linear-gradient(90deg, rgba(127,176,255,.08), transparent 42%, rgba(114,212,186,.06)); | |
| } | |
| .hero-top{ | |
| position:relative; | |
| z-index:1; | |
| display:flex; | |
| align-items:flex-start; | |
| justify-content:space-between; | |
| gap:16px; | |
| flex-wrap:wrap; | |
| } | |
| .eyebrow{ | |
| position:relative;z-index:1; | |
| text-transform:uppercase; | |
| letter-spacing:.18em; | |
| font-size:11px; | |
| color:var(--muted); | |
| margin-bottom:12px; | |
| font-weight:700; | |
| } | |
| body[data-theme="dark"] .eyebrow{color:var(--muted)} | |
| h1{ | |
| position:relative;z-index:1; | |
| margin:0; | |
| font-size:clamp(34px, 4.6vw, 64px); | |
| line-height:1; | |
| letter-spacing:0; | |
| font-weight:880; | |
| } | |
| .title-silver{ | |
| background:linear-gradient(180deg, #ffffff 0%, #dce3ee 38%, #6d7687 100%); | |
| -webkit-background-clip:text; | |
| background-clip:text; | |
| color:transparent; | |
| text-shadow:0 1px 0 rgba(255,255,255,.36); | |
| } | |
| body[data-theme="dark"] .title-silver{ | |
| background:linear-gradient(180deg, #ffffff 0%, #ccd7e6 36%, #8793a5 100%); | |
| -webkit-background-clip:text; | |
| background-clip:text; | |
| color:transparent; | |
| text-shadow:none; | |
| } | |
| .sub{ | |
| position:relative;z-index:1; | |
| margin:14px 0 0; | |
| max-width:1060px; | |
| color:var(--muted); | |
| line-height:1.65; | |
| font-size:14px; | |
| } | |
| .theme-toggle-group{ | |
| position:relative; | |
| z-index:1; | |
| display:flex; | |
| gap:8px; | |
| flex-wrap:wrap; | |
| align-items:center; | |
| justify-content:flex-end; | |
| } | |
| .theme-pill{ | |
| padding:10px 14px; | |
| border-radius:var(--radius3); | |
| font-size:13px; | |
| border:1px solid var(--line); | |
| background:var(--surface); | |
| color:var(--ink2); | |
| box-shadow:0 1px 0 rgba(255,255,255,.75) inset; | |
| } | |
| body[data-theme="dark"] .theme-pill{ | |
| border-color:var(--line); | |
| background:var(--surface2); | |
| color:var(--ink); | |
| } | |
| .layout{display:grid;grid-template-columns:360px minmax(0,1fr);gap:18px;align-items:start} | |
| .panel{ | |
| position:sticky;top:18px; | |
| border-radius:var(--radius); | |
| padding:18px; | |
| background:linear-gradient(180deg, rgba(255,255,255,.96), rgba(247,249,252,.92)); | |
| } | |
| body[data-theme="dark"] .panel{background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.025))} | |
| .panel h2, .chart-card h2, .info-card h2{ | |
| margin:0 0 14px; | |
| font-size:12px; | |
| color:#6d7380; | |
| text-transform:uppercase; | |
| letter-spacing:.16em; | |
| font-weight:850; | |
| } | |
| body[data-theme="dark"] .panel h2, | |
| body[data-theme="dark"] .chart-card h2, | |
| body[data-theme="dark"] .info-card h2{color:#a8afbd} | |
| .section{margin-bottom:18px} | |
| .section-label{ | |
| display:block; | |
| margin-bottom:10px; | |
| color:#4d525e; | |
| font-size:11px; | |
| text-transform:uppercase; | |
| letter-spacing:.15em; | |
| font-weight:800; | |
| } | |
| body[data-theme="dark"] .section-label{color:#c0c6d1} | |
| .btn-grid{display:flex;flex-wrap:wrap;gap:8px} | |
| button, .chip, .tiny-btn, .org-chip, .pill{ | |
| border:1px solid var(--line); | |
| background:linear-gradient(180deg, var(--surface), var(--surface3)); | |
| color:var(--ink2); | |
| padding:10px 13px; | |
| border-radius:var(--radius3); | |
| cursor:pointer; | |
| font:inherit; | |
| font-size:13px; | |
| user-select:none; | |
| transition:transform .16s ease, border-color .16s ease, background .16s ease, color .16s ease, box-shadow .16s ease; | |
| outline:none; | |
| box-shadow:0 1px 0 rgba(255,255,255,.72) inset; | |
| } | |
| body[data-theme="dark"] button, | |
| body[data-theme="dark"] .chip, | |
| body[data-theme="dark"] .tiny-btn, | |
| body[data-theme="dark"] .org-chip, | |
| body[data-theme="dark"] .pill{ | |
| border-color:var(--line); | |
| background:linear-gradient(180deg, var(--surface2), var(--surface)); | |
| color:var(--ink); | |
| box-shadow:none; | |
| } | |
| button:hover, .chip:hover, .tiny-btn:hover, .org-chip:hover, .pill:hover{ | |
| transform:translateY(-1px); | |
| border-color:var(--line2); | |
| color:var(--ink); | |
| box-shadow:0 10px 22px rgba(29,38,52,.10); | |
| } | |
| body[data-theme="dark"] button:hover, | |
| body[data-theme="dark"] .chip:hover, | |
| body[data-theme="dark"] .tiny-btn:hover, | |
| body[data-theme="dark"] .org-chip:hover, | |
| body[data-theme="dark"] .pill:hover{ | |
| border-color:var(--line2); | |
| color:#fff; | |
| box-shadow:0 10px 24px rgba(0,0,0,.18); | |
| } | |
| button:focus-visible, .chip:focus-visible, .search:focus-visible, .select:focus-visible{ | |
| box-shadow:0 0 0 3px rgba(47,111,237,.18); | |
| } | |
| body[data-theme="dark"] button:focus-visible, | |
| body[data-theme="dark"] .chip:focus-visible, | |
| body[data-theme="dark"] .search:focus-visible, | |
| body[data-theme="dark"] .select:focus-visible{ | |
| box-shadow:0 0 0 3px rgba(127,176,255,.22); | |
| } | |
| button.active, .chip.active, .tiny-btn.active, .org-chip.active, .pill.active{ | |
| color:#0f1724; | |
| border-color:rgba(47,111,237,.45); | |
| background:linear-gradient(180deg, #ffffff, #e9f0ff); | |
| box-shadow:0 0 0 1px rgba(47,111,237,.12) inset, 0 8px 18px rgba(47,111,237,.10); | |
| } | |
| body[data-theme="dark"] button.active, | |
| body[data-theme="dark"] .chip.active, | |
| body[data-theme="dark"] .tiny-btn.active, | |
| body[data-theme="dark"] .org-chip.active, | |
| body[data-theme="dark"] .pill.active{ | |
| color:#ffffff; | |
| border-color:rgba(127,176,255,.44); | |
| background:linear-gradient(180deg, rgba(127,176,255,.24), rgba(127,176,255,.10)); | |
| } | |
| .search, .select{ | |
| width:100%; | |
| border:1px solid var(--line); | |
| background:var(--surface); | |
| color:var(--ink); | |
| border-radius:var(--radius3); | |
| padding:12px 14px; | |
| outline:none; | |
| font:inherit; | |
| box-shadow:0 1px 0 rgba(255,255,255,.8) inset; | |
| } | |
| body[data-theme="dark"] .search, | |
| body[data-theme="dark"] .select{ | |
| border-color:var(--line); | |
| background:var(--surface2); | |
| color:var(--ink); | |
| box-shadow:none; | |
| } | |
| .search::placeholder{color:#8a909c} | |
| body[data-theme="dark"] .search::placeholder{color:#8f96a4} | |
| .search:focus, .select:focus{border-color:rgba(47,111,237,.45);background:white} | |
| body[data-theme="dark"] .search:focus, body[data-theme="dark"] .select:focus{border-color:rgba(127,176,255,.45);background:rgba(255,255,255,.08)} | |
| .toggle-row{display:flex;gap:10px;flex-wrap:wrap} | |
| .small-note{color:#6f7684;font-size:12px;line-height:1.6;margin-top:10px} | |
| body[data-theme="dark"] .small-note{color:#aab1bf} | |
| .prediction-list{ | |
| margin-top:12px; | |
| display:grid; | |
| gap:8px; | |
| } | |
| .prediction-item{ | |
| display:flex; | |
| justify-content:space-between; | |
| gap:10px; | |
| align-items:center; | |
| padding:10px 12px; | |
| border-radius:var(--radius3); | |
| border:1px solid var(--line); | |
| background:linear-gradient(180deg, var(--surface), var(--surface2)); | |
| font-size:13px; | |
| line-height:1.35; | |
| } | |
| body[data-theme="dark"] .prediction-item{ | |
| border-color:var(--line); | |
| background:linear-gradient(180deg, var(--surface2), var(--surface)); | |
| } | |
| .prediction-item .label{font-weight:800;color:#111318} | |
| body[data-theme="dark"] .prediction-item .label{color:#f4f5f7} | |
| .prediction-item .value{font-variant-numeric:tabular-nums;color:#3c424c;font-weight:800} | |
| body[data-theme="dark"] .prediction-item .value{color:#dfe4ec} | |
| body[data-mode="mobile"] .desktop-only{ | |
| display:none ; | |
| } | |
| body[data-mode="mobile"]{ | |
| padding:14px; | |
| } | |
| body[data-mode="mobile"] .hero{ | |
| padding:20px; | |
| } | |
| body[data-mode="mobile"] .hero .sub{ | |
| display:none; | |
| } | |
| body[data-mode="mobile"] h1{ | |
| font-size:clamp(30px, 8vw, 46px); | |
| line-height:1; | |
| } | |
| body[data-mode="mobile"] .layout{ | |
| grid-template-columns:1fr; | |
| gap:14px; | |
| } | |
| body[data-mode="mobile"] .panel{ | |
| position:static; | |
| padding:14px; | |
| } | |
| body[data-mode="mobile"] .chart-card{ | |
| min-height:auto; | |
| padding:14px 14px 10px; | |
| } | |
| body[data-mode="mobile"] .canvas-wrap{ | |
| height:420px; | |
| } | |
| body[data-mode="mobile"] .chart-title{ | |
| font-size:17px; | |
| } | |
| body[data-mode="mobile"] .chart-sub{ | |
| font-size:12px; | |
| } | |
| body[data-mode="mobile"] .org-shell{ | |
| padding:10px; | |
| } | |
| body[data-mode="mobile"] .stat-grid{ | |
| grid-template-columns:1fr; | |
| } | |
| body[data-mode="mobile"] .prediction-item{ | |
| padding:9px 10px; | |
| font-size:12px; | |
| } | |
| body[data-mode="mobile"] .theme-toggle-group{ | |
| gap:6px; | |
| } | |
| .stat-grid{display:grid;grid-template-columns:repeat(2, minmax(0,1fr));gap:10px;margin-top:8px} | |
| .stat{ | |
| background:linear-gradient(180deg, rgba(255,255,255,.94), rgba(230,234,240,.84)); | |
| border:1px solid rgba(16,17,20,.08); | |
| border-radius:var(--radius3); | |
| padding:13px; | |
| min-height:74px; | |
| } | |
| body[data-theme="dark"] .stat{background:linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.03));border-color:var(--line)} | |
| .stat .k{color:#6f7684;font-size:10px;text-transform:uppercase;letter-spacing:.14em;font-weight:800} | |
| body[data-theme="dark"] .stat .k{color:#aab1bf} | |
| .stat .v{margin-top:7px;color:#111318;font-size:18px;font-weight:900;font-variant-numeric:tabular-nums;line-height:1.1} | |
| body[data-theme="dark"] .stat .v{color:#f4f5f7} | |
| .chart-card{ | |
| border-radius:var(--radius); | |
| padding:18px 18px 12px; | |
| min-height:820px; | |
| overflow:hidden; | |
| background:linear-gradient(180deg, rgba(255,255,255,.98), rgba(247,249,252,.92)); | |
| } | |
| body[data-theme="dark"] .chart-card{background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03))} | |
| .chart-top{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px} | |
| .chart-title{margin:0;font-size:19px;font-weight:860;letter-spacing:0} | |
| .chart-sub{margin:5px 0 0;color:#66707d;font-size:13px;line-height:1.5;max-width:980px} | |
| body[data-theme="dark"] .chart-sub{color:#aab1bf} | |
| .badge{ | |
| padding:9px 12px;border-radius:var(--radius3); | |
| background:linear-gradient(180deg, var(--surface), var(--surface3)); | |
| border:1px solid var(--line); | |
| color:#13161c; | |
| font-size:13px; | |
| font-variant-numeric:tabular-nums; | |
| white-space:nowrap; | |
| box-shadow:var(--shadow2) | |
| } | |
| body[data-theme="dark"] .badge{ | |
| background:linear-gradient(180deg, var(--surface2), var(--surface)); | |
| border-color:var(--line); | |
| color:#f4f5f7; | |
| } | |
| .callout{ | |
| margin-top:11px;display:inline-flex;align-items:center;gap:10px; | |
| padding:9px 12px;border-radius:var(--radius3);border:1px solid var(--line); | |
| background:linear-gradient(180deg, var(--surface), var(--surface2)); | |
| color:#14171c;font-size:12px; | |
| } | |
| body[data-theme="dark"] .callout{ | |
| border-color:var(--line); | |
| background:linear-gradient(180deg, var(--surface2), var(--surface)); | |
| color:#f4f5f7; | |
| } | |
| .callout .dot{ | |
| width:9px;height:9px;border-radius:999px; | |
| background:linear-gradient(180deg, var(--accent), var(--accent2)); | |
| box-shadow:0 0 12px rgba(47,111,237,.20); | |
| flex:0 0 auto; | |
| border:1px solid rgba(16,17,20,.08); | |
| } | |
| .canvas-wrap{position:relative;height:680px} | |
| canvas{width:100% ;height:100% } | |
| .info-grid{display:grid;grid-template-columns:repeat(4, minmax(0, 1fr));gap:14px} | |
| .info-card{ | |
| border-radius:var(--radius);padding:16px; | |
| background:linear-gradient(180deg, var(--surface), var(--surface2)); | |
| } | |
| body[data-theme="dark"] .info-card{background:linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.03))} | |
| .info-card .label{color:#6f7684;font-size:11px;text-transform:uppercase;letter-spacing:.13em;font-weight:800} | |
| body[data-theme="dark"] .info-card .label{color:#aab1bf} | |
| .info-card .big{margin-top:7px;color:#111318;font-size:22px;font-weight:900;font-variant-numeric:tabular-nums;line-height:1.1} | |
| body[data-theme="dark"] .info-card .big{color:#f4f5f7} | |
| .disclaimer{ | |
| border-radius:var(--radius); | |
| background:linear-gradient(180deg, rgba(255,255,255,.92), rgba(240,243,248,.82)); | |
| padding:16px; | |
| color:#646b79; | |
| line-height:1.68; | |
| font-size:13px; | |
| } | |
| body[data-theme="dark"] .disclaimer{color:#aab1bf} | |
| .disclaimer strong{color:#111318;font-weight:900} | |
| body[data-theme="dark"] .disclaimer strong{color:#f4f5f7} | |
| .cta-grid{display:grid;grid-template-columns:repeat(2, minmax(0,1fr));gap:12px;margin-top:12px} | |
| .cta-link{ | |
| display:block;text-decoration:none; | |
| border:1px solid rgba(16,17,20,.10); | |
| border-radius:var(--radius); | |
| background:linear-gradient(180deg, var(--surface), var(--surface2)); | |
| padding:14px 16px;color:#111318; | |
| transition:transform .15s ease, border-color .15s ease, background .15s ease; | |
| } | |
| body[data-theme="dark"] .cta-link{ | |
| border-color:rgba(255,255,255,.10); | |
| background:linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.04)); | |
| color:#f4f5f7; | |
| } | |
| .cta-link:hover{transform:translateY(-1px);border-color:var(--line2);background:linear-gradient(180deg, #ffffff, rgba(232,236,242,.98))} | |
| body[data-theme="dark"] .cta-link:hover{border-color:rgba(255,255,255,.20);background:linear-gradient(180deg, rgba(255,255,255,.12), rgba(255,255,255,.06))} | |
| .cta-kicker{color:#6f7684;font-size:11px;text-transform:uppercase;letter-spacing:.13em;margin-bottom:6px;font-weight:800} | |
| body[data-theme="dark"] .cta-kicker{color:#aab1bf} | |
| .cta-title{color:#111318;font-weight:900;line-height:1.35;font-size:14px} | |
| body[data-theme="dark"] .cta-title{color:#f4f5f7} | |
| .cta-sub{margin-top:5px;color:#616776;font-size:13px;line-height:1.5} | |
| body[data-theme="dark"] .cta-sub{color:#b0b7c4} | |
| .org-shell{ | |
| border:1px solid var(--line); | |
| border-radius:var(--radius); | |
| background:linear-gradient(180deg, var(--surface), var(--surface2)); | |
| padding:12px; | |
| box-shadow:var(--shadow2); | |
| } | |
| body[data-theme="dark"] .org-shell{border-color:var(--line);background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03))} | |
| .org-header{ | |
| display:flex; | |
| align-items:center; | |
| justify-content:space-between; | |
| gap:10px; | |
| margin-bottom:10px; | |
| } | |
| .org-header strong{ | |
| font-size:12px; | |
| letter-spacing:.14em; | |
| text-transform:uppercase; | |
| color:#4f5561; | |
| } | |
| body[data-theme="dark"] .org-header strong{color:#c0c6d1} | |
| .org-summary{font-size:12px;color:#68707d} | |
| body[data-theme="dark"] .org-summary{color:#aab1bf} | |
| .org-controls{display:grid;gap:10px} | |
| .org-search-row{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:center} | |
| .org-chip-row{ | |
| display:flex; | |
| flex-wrap:wrap; | |
| gap:8px; | |
| max-height:240px; | |
| overflow:auto; | |
| padding-right:2px; | |
| } | |
| .org-chip{ | |
| font-size:12px; | |
| padding:9px 12px; | |
| border-radius:var(--radius3); | |
| white-space:nowrap; | |
| } | |
| .org-chip.all{font-weight:800} | |
| .scrollbar-slim::-webkit-scrollbar{width:10px;height:10px} | |
| .scrollbar-slim::-webkit-scrollbar-thumb{background:rgba(16,17,20,.14);border-radius:999px;border:3px solid rgba(255,255,255,.82)} | |
| body[data-theme="dark"] .scrollbar-slim::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);border:3px solid rgba(0,0,0,.18)} | |
| .scrollbar-slim::-webkit-scrollbar-track{background:transparent} | |
| .mini-line{ | |
| width:100%;height:1px; | |
| background:linear-gradient(90deg, transparent, rgba(16,17,20,.14), transparent); | |
| margin:10px 0 14px; | |
| } | |
| body[data-theme="dark"] .mini-line{background:linear-gradient(90deg, transparent, rgba(255,255,255,.18), transparent)} | |
| @media (max-width:1120px){ | |
| .layout{grid-template-columns:1fr} | |
| .panel{position:static} | |
| .canvas-wrap{height:700px} | |
| .info-grid{grid-template-columns:repeat(2, minmax(0,1fr))} | |
| } | |
| @media (max-width:760px){ | |
| body{padding:16px} | |
| .hero, .panel, .chart-card, .info-card{border-radius:var(--radius)} | |
| .canvas-wrap{height:520px} | |
| .stat-grid{grid-template-columns:1fr} | |
| .info-grid{grid-template-columns:1fr} | |
| .cta-grid{grid-template-columns:1fr} | |
| .org-search-row{grid-template-columns:1fr} | |
| .hero-top{flex-direction:column;align-items:flex-start} | |
| .theme-toggle-group{justify-content:flex-start} | |
| } | |
| </style> | |
| </head> | |
| <body data-theme="light"> | |
| <div class="app"> | |
| <section class="hero"> | |
| <div class="hero-top"> | |
| <div> | |
| <div class="eyebrow">Regression explorer</div> | |
| <h1><span class="title-silver">SLM Regression Line </span></h1> | |
| <p class="sub"> | |
| Choose a benchmark, filter by org or size, and compare models to the size trend. Furthermore, you can submit specific parameter counts and see the predicted benchmark scores. Enjoy! | |
| </p> | |
| </div> | |
| <div class="theme-toggle-group"> | |
| <button id="themeLight" class="theme-pill active" type="button">Light Silver</button> | |
| <button id="themeDark" class="theme-pill" type="button">Dark Silver</button> | |
| <button id="modeDesktop" class="theme-pill active" type="button">Computer mode</button> | |
| <button id="modeMobile" class="theme-pill" type="button">Mobile mode</button> | |
| </div> | |
| </div> | |
| </section> | |
| <div class="layout"> | |
| <aside class="panel"> | |
| <h2>Controls</h2> | |
| <div class="section"> | |
| <span class="section-label">Benchmark</span> | |
| <div class="btn-grid" id="benchmarkButtons"></div> | |
| </div> | |
| <div class="section"> | |
| <span class="section-label">Search models</span> | |
| <input id="searchBox" class="search" type="text" placeholder="Type a model or org name..." /> | |
| <div class="small-note">Filters the visible points only.</div> | |
| </div> | |
| <div class="section"> | |
| <span class="section-label">Predict scores</span> | |
| <div class="org-shell"> | |
| <div class="org-controls"> | |
| <div class="org-search-row"> | |
| <input id="paramInput" class="search" type="text" placeholder="Enter 12M, 250K, or 1.5B" /> | |
| <button id="predictBtn" class="tiny-btn" type="button">Predict</button> | |
| </div> | |
| <div class="small-note">Uses the current benchmark fits to estimate scores for the entered parameter count.</div> | |
| <div id="predictionSummary" class="small-note" style="margin-top:0"></div> | |
| <div id="predictionList" class="prediction-list"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="section"> | |
| <span class="section-label">Parameter buckets</span> | |
| <div class="btn-grid" id="bucketButtons"></div> | |
| <div class="small-note">Buckets only change which points are visible. The regression line still uses the full eligible set.</div> | |
| </div> | |
| <div class="section desktop-only"> | |
| <span class="section-label">Filter by org</span> | |
| <div class="org-shell"> | |
| <div class="org-header"> | |
| <strong>Orgs</strong> | |
| <div class="org-summary" id="orgSummary">All orgs</div> | |
| </div> | |
| <div class="org-controls"> | |
| <div class="org-search-row"> | |
| <input id="orgSearch" class="search" type="text" placeholder="Search orgs..." /> | |
| <button id="clearOrg" class="tiny-btn">Clear</button> | |
| </div> | |
| <div class="org-chip-row scrollbar-slim" id="orgChips"></div> | |
| </div> | |
| </div> | |
| <div class="small-note">This filter is only for visibility. The regression line is still computed from the full eligible set.</div> | |
| </div> | |
| <div class="section desktop-only"> | |
| <span class="section-label">Point emphasis</span> | |
| <div class="toggle-row"> | |
| <button id="toggleOutliers" class="chip" aria-pressed="false">Show residual labels</button> | |
| <button id="toggleLineOnly" class="chip" aria-pressed="false">Line emphasis</button> | |
| </div> | |
| <div class="small-note">These toggles will change which model points are visible. </div> | |
| </div> | |
| <div class="section desktop-only"> | |
| <span class="section-label">Regression stats</span> | |
| <div class="stat-grid"> | |
| <div class="stat"><div class="k">Curvature</div><div class="v" id="statSlope">—</div></div> | |
| <div class="stat"><div class="k">Mid-slope</div><div class="v" id="statIntercept">—</div></div> | |
| <div class="stat"><div class="k">Center score</div><div class="v" id="statMSE">—</div></div> | |
| <div class="stat"><div class="k">RMSE</div><div class="v" id="statRMSE">—</div></div> | |
| <div class="stat"><div class="k">R²</div><div class="v" id="statR2">—</div></div> | |
| </div> | |
| <div class="small-note" id="fitNote">The line is locked to the full eligible dataset for the selected benchmark.</div> | |
| </div> | |
| </aside> | |
| <main style="display:grid; gap:18px;"> | |
| <section class="chart-card"> | |
| <div class="chart-top"> | |
| <div> | |
| <h2 class="chart-title" id="chartTitle">Average score vs log parameters</h2> | |
| <div class="callout"> | |
| <span class="dot"></span> | |
| <span>Hover for details. Click a point to open the model page.</span> | |
| </div> | |
| </div> | |
| <div class="badge" id="countBadge">0 visible / 0 bins</div> | |
| </div> | |
| <div class="canvas-wrap"> | |
| <canvas id="scatterChart"></canvas> | |
| </div> | |
| </section> | |
| <section class="info-grid desktop-only"> | |
| <div class="info-card"><div class="label">Selected benchmark</div><div class="big" id="infoBenchmark">Avg</div></div> | |
| <div class="info-card"><div class="label">Visible models</div><div class="big" id="infoCount">0</div></div> | |
| <div class="info-card"><div class="label">Fit bins</div><div class="big" id="infoFitCount">0</div></div> | |
| <div class="info-card"><div class="label">Mean absolute residual</div><div class="big" id="infoMAE">—</div></div> | |
| <div class="info-card"><div class="label">Residual spread</div><div class="big" id="infoResidualSpread">—</div></div> | |
| <div class="info-card"><div class="label">Visible match rate</div><div class="big" id="infoMatchRate">—</div></div> | |
| <div class="info-card"><div class="label">Visible orgs</div><div class="big" id="infoOrgs">—</div></div> | |
| <div class="info-card"><div class="label">Plot mode</div><div class="big" id="infoMode">Silver</div></div> | |
| </section> | |
| <div class="cta-grid"> | |
| <a class="cta-link" href="https://huggingface.co/spaces/fromziro/SLM_Regression_Line/discussions" target="_blank" rel="noopener noreferrer"> | |
| <div class="cta-kicker">Contribute</div> | |
| <div class="cta-title">Want to add your model? Open a discussion or PR.</div> | |
| <div class="cta-sub">Send a model link, and it can be reviewed for inclusion.</div> | |
| </a> | |
| <a class="cta-link" href="https://huggingface.co/spaces/AxiomicLabs/Open_SLM_Leaderboard" target="_blank" rel="noopener noreferrer"> | |
| <div class="cta-kicker">Deep dive</div> | |
| <div class="cta-title">Need a more detailed breakdown of your model?</div> | |
| <div class="cta-sub">Go here for a fuller analysis and broader comparisons.</div> | |
| </a> | |
| </div> | |
| </section> | |
| </main> | |
| </div> | |
| </div> | |
| <script> | |
| const MODELS = [ | |
| { name: 'SmolLM2-135M', org: 'HuggingFace', params: 135000000, arc_easy: 0.5858585858585859, arc_challenge: 0.2960750853242321, piqa: 0.6849836779107725, hellaswag: 0.43108942441744674, avg_4: 0.5177858993388165, url: 'https://huggingface.co/HuggingFaceTB/SmolLM2-135M' }, | |
| { name: 'GPT-X2-125M', org: 'AxiomicLabs', params: 125081664, arc_easy: 0.5151515151515151, arc_challenge: 0.2764505119453925, piqa: 0.6751904243743199, hellaswag: 0.40529774945230035, avg_4: 0.4898234185711896, url: 'https://huggingface.co/AxiomicLabs/GPT-X2-125M' }, | |
| { name: 'GPT-X-125M', org: 'AxiomicLabs', params: 124561728, arc_easy: 0.5075757575757576, arc_challenge: 0.2687713310580205, piqa: 0.6517954298150164, hellaswag: 0.36496713802031466, avg_4: 0.464060299783275, url: 'https://huggingface.co/AxiomicLabs/GPT-X-125M' }, | |
| { name: 'MobileLLM-R1-140M-base', org: 'Facebook', params: 140000000, arc_easy: 0.4992424242424242, arc_challenge: 0.24744027303754265, piqa: 0.6322089227421109, hellaswag: 0.3384379853648824, avg_4: 0.44383, url: 'https://huggingface.co/facebook/MobileLLM-R1-140M-base' }, | |
| { name: 'Supra-50M-Base', org: 'SupraLabs', params: 51786240, arc_easy: 0.460016835016835, arc_challenge: 0.25, piqa: 0.6207834602829162, hellaswag: 0.31776538538139815, avg_4: 0.4252144857313513, url: 'https://huggingface.co/SupraLabs/Supra-50M-Base' }, | |
| { name: 'Supra-50M-Instruct', org: 'SupraLabs', params: 51786240, arc_easy: 0.444, arc_challenge: 0.273, piqa: 0.5947, hellaswag: 0.2909, avg_4: 0.403, url: 'https://huggingface.co/SupraLabs/Supra-50M-Instruct' }, | |
| { name: 'Supra-50M-Reasoning', org: 'SupraLabs', params: 51786240, arc_easy: 0.4444, arc_challenge: 0.2739, piqa: 0.593, hellaswag: 0.291, avg_4: 0.4006, url: 'https://huggingface.co/SupraLabs/Supra-50M-Reasoning' }, | |
| { name: 'SmolLM-135M', org: 'HuggingFace', params: 135000000, arc_easy: 0.5631, arc_challenge: 0.2901, piqa: 0.6828, hellaswag: 0.427, avg_4: 0.4908, url: 'https://huggingface.co/HuggingFaceTB/SmolLM-135M' }, | |
| { name: 'OPT-125M', org: 'Facebook', params: 125000000, arc_easy: 0.4028, arc_challenge: 0.227, piqa: 0.6224, hellaswag: 0.3131, avg_4: 0.3913, url: 'https://huggingface.co/facebook/opt-125m' }, | |
| { name: 'GPT-2', org: 'OpenAI', params: 124000000, arc_easy: 0.3935, arc_challenge: 0.2235, piqa: 0.6208, hellaswag: 0.3126, avg_4: 0.3892, url: 'https://huggingface.co/openai-community/gpt2' }, | |
| { name: 'Spark-5M-Base-v4', org: 'LH-Tech-AI', params: 5000000, arc_easy: 0.3316, arc_challenge: 0.215, piqa: 0.5332, hellaswag: 0.2703, avg_4: 0.325, url: 'https://huggingface.co/LH-Tech-AI/Spark-5M-Base-v4' }, | |
| { name: 'Supra-Mini-v5-8M', org: 'SupraLabs', params: 7870000, arc_easy: 0.3321, arc_challenge: 0.2116, piqa: 0.5403, hellaswag: 0.2637, avg_4: 0.3219, url: 'https://huggingface.co/SupraLabs/Supra-Mini-v5-8M' }, | |
| { name: 'Pythia-70M', org: 'EleutherAI', params: 70000000, arc_easy: 0.3165, arc_challenge: 0.2363, piqa: 0.5348, hellaswag: 0.2749, avg_4: 0.3657, url: 'https://huggingface.co/EleutherAI/pythia-70m' }, | |
| { name: 'Supra-Mini-v4-2M', org: 'SupraLabs', params: 2620000, arc_easy: 0.3098, arc_challenge: 0.215, piqa: 0.519, hellaswag: 0.2552, avg_4: 0.3188, url: 'https://huggingface.co/SupraLabs/Supra-Mini-v4-2M' }, | |
| { name: 'Pythia-31M', org: 'EleutherAI', params: 31000000, arc_easy: 0.3388, arc_challenge: 0.2167, piqa: 0.5626, hellaswag: 0.2714, avg_4: 0.3474, url: 'https://huggingface.co/EleutherAI/pythia-31m' }, | |
| { name: 'Stentor3-50M', org: 'StentorLabs', params: 50000000, arc_easy: 0.2967, arc_challenge: 0.2167, piqa: 0.5375, hellaswag: 0.271, avg_4: 0.3335, url: 'https://huggingface.co/StentorLabs/Stentor3-50M' }, | |
| { name: 'Stentor3-20M', org: 'StentorLabs', params: 20000000, arc_easy: 0.295, arc_challenge: 0.2312, piqa: 0.5506, hellaswag: 0.2706, avg_4: 0.3394, url: 'https://huggingface.co/StentorLabs/Stentor3-20M' }, | |
| { name: 'Portimbria-150M', org: 'StentorLabs', params: 151026432, arc_easy: 0.3582, arc_challenge: 0.1877, piqa: 0.5827, hellaswag: 0.2709, avg_4: 0.3499, url: 'https://huggingface.co/StentorLabs/Portimbria-150M' }, | |
| { name: 'nanowhale-100m-base', org: 'HuggingFace', params: 100000000, arc_easy: 0.2879, arc_challenge: 0.2483, piqa: 0.518, hellaswag: 0.2631, avg_4: 0.3293, url: 'https://huggingface.co/HuggingFaceTB/nanowhale-100m-base' }, | |
| { name: 'Pythia-14M', org: 'EleutherAI', params: 14000000, arc_easy: 0.3228, arc_challenge: 0.21, piqa: 0.5588, hellaswag: 0.262, avg_4: 0.3384, url: 'https://huggingface.co/EleutherAI/pythia-14m' }, | |
| { name: 'Tenete-8M', org: 'Harley-ml', params: 8000000, arc_easy: 0.3169, arc_challenge: 0.2184, piqa: 0.5566, hellaswag: 0.2675, avg_4: 0.3409, url: 'https://huggingface.co/Harley-ml/Tenete-8M' }, | |
| { name: 'Dillion-1.2M', org: 'Harley-ml', params: 1281384, arc_easy: 0.3119, arc_challenge: 0.2278, piqa: 0.5305, hellaswag: 0.2665, avg_4: 0.3338, url: 'https://huggingface.co/Harley-ml/Dillion-1.2M' }, | |
| { name: 'CinnabarLM-1.4M-Base', org: 'MihaiPopa-1', params: 1510000, arc_easy: 0.2854, arc_challenge: 0.2338, piqa: 0.525, hellaswag: 0.2708, avg_4: 0.3416, url: 'https://huggingface.co/MihaiPopa-1/CinnabarLM-1.4M-Base' }, | |
| { name: 'CinnabarLM-4M-Base', org: 'MihaiPopa-1', params: 4230000, arc_easy: 0.2828, arc_challenge: 0.227, piqa: 0.5229, hellaswag: 0.2771, avg_4: 0.3302, url: 'https://huggingface.co/MihaiPopa-1/CinnabarLM-4M-Base' }, | |
| { name: 'CinnabarLM-1.5M-Base', org: 'MihaiPopa-1', params: 1710000, arc_easy: 0.2811, arc_challenge: 0.2193, piqa: 0.5294, hellaswag: 0.2708, avg_4: 0.3338, url: 'https://huggingface.co/MihaiPopa-1/CinnabarLM-1.5M-Base' }, | |
| { name: 'Dillionv2-1.3M', org: 'Harley-ml', params: 1285200, arc_easy: 0.2963, arc_challenge: 0.2224, piqa: 0.5305, hellaswag: 0.2738, avg_4: 0.3292, url: 'https://huggingface.co/Harley-ml/Dillionv2-1.3M' }, | |
| { name: 'KeyLM-75M', org: 'Eclipse-Senpai', params: 75251200, arc_easy: 0.3573, arc_challenge: 0.2398, piqa: 0.605, hellaswag: 0.2966, avg_4: 0.3947, url: 'https://huggingface.co/Eclipse-Senpai/KeyLM-75M' }, | |
| { name: 'Supra-Mini-v6-1M', org: 'SupraLabs', params: 1410688, arc_easy: 0.3068, arc_challenge: 0.2048, piqa: 0.537, hellaswag: 0.2722, avg_4: 0.3322, url: 'https://huggingface.co/SupraLabs/Supra-Mini-v6-1M' }, | |
| { name: 'GPT-S-1.4M', org: 'AxiomicLabs', params: 1426000, arc_easy: 0.3186, arc_challenge: 0.221, piqa: 0.5511, hellaswag: 0.2686, avg_4: 0.3341, url: 'https://huggingface.co/AxiomicLabs/GPT-S-1.4M' }, | |
| { name: 'Archaea-74M', org: 'GODELEV', params: 74016256, arc_easy: 0.3906, arc_challenge: 0.227, piqa: 0.5827, hellaswag: 0.2727, avg_4: 0.3812, url: 'https://huggingface.co/GODELEV/Archaea-74M' }, | |
| { name: 'Cali-0.1B', org: 'Sandroeth', params: 123782400, arc_easy: 0.2753, arc_challenge: 0.2449, piqa: 0.5212, hellaswag: 0.2684, avg_4: 0.3274, url: 'https://huggingface.co/Sandroeth/cali-0.1B' }, | |
| { name: 'Quark-50M', org: 'ThingAI', params: 56666496, arc_easy: 0.3678, arc_challenge: 0.2526, piqa: 0.5783, hellaswag: 0.2848, avg_4: 0.3717, url: 'https://huggingface.co/ThingAI/Quark-50m' }, | |
| { name: 'Quark-135M', org: 'ThingAI', params: 134561088, arc_easy: 0.4789, arc_challenge: 0.2824, piqa: 0.5865, hellaswag: 0.3137, avg_4: 0.4143, url: 'https://huggingface.co/ThingAI/Quark-135m' }, | |
| { name: 'Veyra-30M-Base', org: 'veyra-ai', params: 34611712, arc_easy: 0.3594, arc_challenge: 0.2389, piqa: 0.5903, hellaswag: 0.2787, avg_4: 0.3692, url: 'https://huggingface.co/veyra-ai/veyra-30m-base-5b-tokens' }, | |
| { name: 'Syn-2.6M', org: 'FromZero', params: 2604210, arc_easy: 0.3211, arc_challenge: 0.2039, piqa: 0.5365, hellaswag: 0.2702, avg_4: 0.3331, url: 'https://huggingface.co/fromziro/Syn-2.6M' }, | |
| { name: 'Ant-5M', org: 'GODELEV', params: 4713344, arc_easy: 0.2639, arc_challenge: 0.2577, piqa: 0.4864, hellaswag: 0.2599, avg_4: 0.3195, url: 'https://huggingface.co/GODELEV/Ant-5m' }, | |
| { name: 'Er-Medium-12.5M', org: 'FromZero', params: 12497520, arc_easy: 0.3476, arc_challenge: 0.2082, piqa: 0.5783, hellaswag: 0.2841, avg_4: 0.3668, url: 'https://huggingface.co/fromziro/Er-Medium-12.5M' }, | |
| { name: 'michel-tiny', org: 'finnianx', params: 55719040, arc_easy: 0.3737, arc_challenge: 0.2176, piqa: 0.5734, hellaswag: 0.2815, avg_4: 0.3502, url: 'https://huggingface.co/finnianx/michel-tiny' }, | |
| { name: 'OdinNext-138M-Base', org: 'joelhenwang', params: 138449696, arc_easy: 0.4508, arc_challenge: 0.2381, piqa: 0.5952, hellaswag: 0.2809, avg_4: 0.392, url: 'https://huggingface.co/joelhenwang/OdinNext-138M-Base' }, | |
| { name: 'OdinNext-138M-Instruct', org: 'joelhenwang', params: 138451232, arc_easy: 0.444, arc_challenge: 0.2312, piqa: 0.5865, hellaswag: 0.2886, avg_4: 0.3888, url: 'https://huggingface.co/joelhenwang/OdinNext-138M-Instruct' }, | |
| { name: 'michel-micro', org: 'finnianx', params: 28355072, arc_easy: 0.3859, arc_challenge: 0.2312, piqa: 0.5762, hellaswag: 0.2823, avg_4: 0.3803, url: 'https://huggingface.co/finnianx/michel-micro' }, | |
| { name: 'kirk-tung', org: 'RTC', params: 53111296, arc_easy: 0.3043, arc_challenge: 0.2201, piqa: 0.5261, hellaswag: 0.2632, avg_4: 0.3184, url: 'https://huggingface.co/rtc2022/kirk-tung' }, | |
| { name: 'ettin-decoder-32m', org: 'JHU CLSP', params: 32081344, arc_easy: 0.3173, arc_challenge: 0.2201, piqa: 0.5229, hellaswag: 0.2779, avg_4: 0.3348, url: 'https://huggingface.co/jhu-clsp/ettin-decoder-32m' }, | |
| { name: 'ettin-decoder-17m', org: 'JHU CLSP', params: 16913600, arc_easy: 0.3165, arc_challenge: 0.2227, piqa: 0.5337, hellaswag: 0.2739, avg_4: 0.3438, url: 'https://huggingface.co/jhu-clsp/ettin-decoder-17m' }, | |
| { name: 'Er-Tiny-1.3M', org: 'FromZero', params: 1332744, arc_easy: 0.3009, arc_challenge: 0.2235, piqa: 0.5272, hellaswag: 0.2767, avg_4: 0.3292, url: 'https://huggingface.co/fromziro/Er-Tiny-1.3M' }, | |
| { name: 'michel-nano', org: 'finnianx', params: 5963008, arc_easy: 0.3329, arc_challenge: 0.227, piqa: 0.5479, hellaswag: 0.2712, avg_4: 0.3464, url: 'https://huggingface.co/finnianx/michel-nano' }, | |
| { name: 'Supra-1.5-50M-base-exp', org: 'SupraLabs', params: 51786240, arc_easy: 0.484, arc_challenge: 0.2551, piqa: 0.6001, hellaswag: 0.2978, avg_4: 0.4288, url: 'https://huggingface.co/SupraLabs/Supra-1.5-50M-base-exp' }, | |
| { name: 'ettin-decoder-68m', org: 'JHU CLSP', params: 68457664, arc_easy: 0.3274, arc_challenge: 0.2304, piqa: 0.5218, hellaswag: 0.2781, avg_4: 0.3394, url: 'https://huggingface.co/jhu-clsp/ettin-decoder-68m' }, | |
| { name: 'ettin-decoder-150m', org: 'JHU CLSP', params: 149655232, arc_easy: 0.2997, arc_challenge: 0.2423, piqa: 0.5125, hellaswag: 0.2595, avg_4: 0.3189, url: 'https://huggingface.co/jhu-clsp/ettin-decoder-150m' }, | |
| { name: 'Ant-10M', org: 'GODELEV', params: 9902336, arc_easy: 0.2753, arc_challenge: 0.2824, piqa: 0.5065, hellaswag: 0.2696, avg_4: 0.3302, url: 'https://huggingface.co/GODELEV/Ant-19m' }, | |
| { name: 'Supra-1.5-50M-Instruct-exp', org: 'SupraLabs', params: 51786240, arc_easy: 0.4394, arc_challenge: 0.2611, piqa: 0.5941, hellaswag: 0.2926, avg_4: 0.4077, url: 'https://huggingface.co/SupraLabs/Supra-1.5-50M-Instruct-exp' }, | |
| { name: 'SLM-10M', org: 'Liodon AI', params: 9968640, arc_easy: 0.3552, arc_challenge: 0.2346, piqa: 0.5707, hellaswag: 0.274, avg_4: 0.3401, url: 'https://huggingface.co/liodon-ai/slm-10m' }, | |
| { name: 'Doge-20M', org: 'SmallDoge', params: 13118728, arc_easy: 0.3338, arc_challenge: 0.2073, piqa: 0.543, hellaswag: 0.2661, avg_4: 0.3236, url: 'https://huggingface.co/SmallDoge/Doge-20M' }, | |
| { name: 'LH-Tech-AI/Quark-v2-0.5M', org: 'LH-Tech-AI', params: 465504, arc_easy: 0.2836700336700337, arc_challenge: 0.22696245733788395, piqa: 0.5103373231773667, hellaswag: 0.2552280422226648, avg_4: 0.30708401794759005, url: 'https://huggingface.co/LH-Tech-AI/Quark-v2-0.5M' }, | |
| { name: 'LH-Tech-AI/Quark-0.5M', org: 'LH-Tech-AI', params: 465504, arc_easy: 0.29292929292929293, arc_challenge: 0.23208191126279865, piqa: 0.514145810663765, hellaswag: 0.2515435172276439, avg_4: 0.30910481700352405, url: 'https://huggingface.co/LH-Tech-AI/Quark-0.5M' }, | |
| { name: 'SupraLabs/MicroSupra-1k', org: 'SupraLabs', params: 1037, arc_easy: 0.26725589225589225, arc_challenge: 0.24488054607508533, piqa: 0.48313384113166485, hellaswag: 0.24945230033857796, avg_4: 0.29785984136262333, url: 'https://huggingface.co/SupraLabs/MicroSupra-1k' }, | |
| { name: 'SupraLabs/Supra-Mini-v2-0.1M', org: 'SupraLabs', params: 167760, arc_easy: 0.2840909090909091, arc_challenge: 0.2440273037542662, piqa: 0.4929270946681175, hellaswag: 0.2544313881696873, avg_4: 0.30551021467393485, url: 'https://huggingface.co/SupraLabs/Supra-Mini-v2-0.1M' }, | |
| { name: 'SupraLabs/Supra-Mini-v3-0.5M', org: 'SupraLabs', params: 467648, arc_easy: 0.2815656565656566, arc_challenge: 0.23122866894197952, piqa: 0.5032644178454843, hellaswag: 0.2546305516829317, avg_4: 0.30500259958503706, url: 'https://huggingface.co/SupraLabs/Supra-Mini-v3-0.5M' }, | |
| { name: 'AxiomicLabs/GPT-S-5M', org: 'AxiomicLabs', params: 5158464, arc_easy: 0.3324915824915825, arc_challenge: 0.21160409556313994, piqa: 0.5685527747551686, hellaswag: 0.273451503684525, avg_4: 0.3503980378849074, url: 'https://huggingface.co/AxiomicLabs/GPT-S-5M' }, | |
| { name: 'GODELEV/Ant-5M', org: 'GODELEV', params: 4713344, arc_easy: 0.2638888888888889, arc_challenge: 0.257679180887372, piqa: 0.48639825897714906, hellaswag: 0.2599083847839076, avg_4: 0.30509948534467235, url: 'https://huggingface.co/GODELEV/Ant-5M' }, | |
| { name: 'veyra-ai/Veyra-30M-Base', org: 'veyra-ai', params: 34611712, arc_easy: 0.35942760942760943, arc_challenge: 0.23890784982935154, piqa: 0.5903155603917302, hellaswag: 0.2787293367855009, avg_4: 0.3692233471040932, url: 'https://huggingface.co/veyra-ai/Veyra-30M-Base' }, | |
| { name: 'Abiray/Kshana-170M-Base', org: 'Abiray', params: 169906752, arc_easy: 0.5046296296296297, arc_challenge: 0.2883959044368601, piqa: 0.6605005440696409, hellaswag: 0.3975303724357698, avg_4: 0.47554968859483593, url: 'https://huggingface.co/Abiray/Kshana-170M-Base' }, | |
| { name: 'cmpatino/nanowhale-100m', org: 'cmpatino', params: 110369621, arc_easy: 0.3409090909090909, arc_challenge: 0.2235494880546075, piqa: 0.5674646354733406, hellaswag: 0.26867157936666003, avg_4: 0.35491651949252023, url: 'https://huggingface.co/cmpatino/nanowhale-100m' }, | |
| { name: 'nickypro/tinyllama-15M', org: 'nickypro', params: 15191712, arc_easy: 0.27946127946127947, arc_challenge: 0.22184300341296928, piqa: 0.5321001088139282, hellaswag: 0.2689703246365266, avg_4: 0.3357823510426074, url: 'https://huggingface.co/nickypro/tinyllama-15M' }, | |
| { name: 'MultivexAI/Plyx-15M', org: 'MultivexAI', params: 16060672, arc_easy: 0.3085016835016835, arc_challenge: 0.21331058020477817, piqa: 0.529379760609358, hellaswag: 0.25761800438159727, avg_4: 0.3228536782377339, url: 'https://huggingface.co/MultivexAI/Plyx-15M' }, | |
| { name: 'MultivexAI/Aurelius-Llama-4.0M-v1.0', org: 'MultivexAI', params: 4033728, arc_easy: 0.2668350168350168, arc_challenge: 0.24488054607508533, piqa: 0.5059847660500544, hellaswag: 0.25761800438159727, avg_4: 0.3179348053267532, url: 'https://huggingface.co/MultivexAI/Aurelius-Llama-4.0M-v1.0' }, | |
| { name: 'Tralalabs/PicoLM-15M', org: 'Tralalabs', params: 19032576, arc_easy: 0.27735690235690236, arc_challenge: 0.23293515358361774, piqa: 0.5250272034820457, hellaswag: 0.25562636924915355, avg_4: 0.3148621238349137, url: 'https://huggingface.co/Tralalabs/PicoLM-15M' }, | |
| { name: 'CromIA/MicroLM2-1M', org: 'CromIA', params: 1705600, arc_easy: 0.27441077441077444, arc_challenge: 0.24573378839590443, piqa: 0.499455930359086, hellaswag: 0.2548297151961761, avg_4: 0.3039513220882634, url: 'https://huggingface.co/CromIA/MicroLM2-1M' }, | |
| { name: 'Harley-ml/MiniMD-28M', org: 'Harley-ml', params: 28061568, arc_easy: 0.27146464646464646, arc_challenge: 0.2354948805460751, piqa: 0.5348204570184983, hellaswag: 0.2815176259709221, avg_4: 0.3294000998266804, url: 'https://huggingface.co/Harley-ml/MiniMD-28M' }, | |
| { name: 'Harley-ml/PicoWord-5k', org: 'Harley-ml', params: 5092, arc_easy: 0.24537037037037038, arc_challenge: 0.24658703071672355, piqa: 0.5206746463547334, hellaswag: 0.2748456482772356, avg_4: 0.30727060662356864, url: 'https://huggingface.co/Harley-ml/PicoWord-5k' }, | |
| { name: 'EleutherAI/pythia-160m', org: 'EleutherAI', params: 162322944, arc_easy: 0.39646464646464646, arc_challenge: 0.2363481228668942, piqa: 0.6191512513601741, hellaswag: 0.30262895837482573, avg_4: 0.41544723722088583, url: 'https://huggingface.co/EleutherAI/pythia-160m' }, | |
| { name: 'peft-internal-testing/opt-125m', org: 'peft-internal-testing', params: 125239296, arc_easy: 0.40025252525252525, arc_challenge: 0.22440273037542663, piqa: 0.6202393906420022, hellaswag: 0.3157737502489544, avg_4: 0.4213909021369317, url: 'https://huggingface.co/peft-internal-testing/opt-125m' }, | |
| { name: 'JackFram/llama-160m', org: 'JackFram', params: 162417408, arc_easy: 0.35648148148148145, arc_challenge: 0.2380546075085324, piqa: 0.6403699673558215, hellaswag: 0.34704242182832107, avg_4: 0.422477869182767, url: 'https://huggingface.co/JackFram/llama-160m' }, | |
| { name: 'erwanf/gpt2-mini', org: 'erwanf', params: 38604288, arc_easy: 0.34974747474747475, arc_challenge: 0.22696245733788395, piqa: 0.5837867247007617, hellaswag: 0.26757618004381595, avg_4: 0.3718686911288584, url: 'https://huggingface.co/erwanf/gpt2-mini' }, | |
| { name: 'SimpleStories/SimpleStories-1.25M', org: 'SimpleStories', params: 1245824, arc_easy: 0.25084175084175087, arc_challenge: 0.25170648464163825, piqa: 0.5065288356909684, hellaswag: 0.24815773750248954, avg_4: 0.3066404037027792, url: 'https://huggingface.co/SimpleStories/SimpleStories-1.25M' }, | |
| { name: 'nisten/Biggie-SmoLlm-0.15B-Base', org: 'nisten', params: 152215488, arc_easy: 0.5185185185185185, arc_challenge: 0.2883959044368601, piqa: 0.6594124047878128, hellaswag: 0.39982075283808005, avg_4: 0.4753188893042979, url: 'https://huggingface.co/nisten/Biggie-SmoLlm-0.15B-Base' }, | |
| { name: 'distilbert/distilgpt2', org: 'distilbert', params: 81912576, arc_easy: 0.36574074074074076, arc_challenge: 0.2295221843003413, piqa: 0.5984766050054406, hellaswag: 0.27504481179047996, avg_4: 0.3870288867618822, url: 'https://huggingface.co/distilbert/distilgpt2' }, | |
| { name: 'FrontiersMind/Nandi-Mini-150M', org: 'FrontiersMind', params: 153412928, arc_easy: 0.5214646464646465, arc_challenge: 0.26621160409556316, piqa: 0.64689880304679, hellaswag: 0.37134037044413465, avg_4: 0.47265964184311693, url: 'https://huggingface.co/FrontiersMind/Nandi-Mini-150M' }, | |
| { name: 'amd/AMD-Llama-135m', org: 'amd', params: 134105856, arc_easy: 0.3181818181818182, arc_challenge: 0.26023890784982934, piqa: 0.6071817192600653, hellaswag: 0.2713602867954591, avg_4: 0.3461261263434566, url: 'https://huggingface.co/amd/AMD-Llama-135m' }, | |
| { name: 'state-spaces/mamba-130m-hf', org: 'state-spaces', params: 129135360, arc_easy: 0.41919191919191917, arc_challenge: 0.24232081911262798, piqa: 0.6322089227421109, hellaswag: 0.3525194184425413, avg_4: 0.4466829854669691, url: 'https://huggingface.co/state-spaces/mamba-130m-hf' }, | |
| { name: 'PleIAs/Monad', org: 'PleIAs', params: 56656128, arc_easy: 0.4036195286195286, arc_challenge: 0.24914675767918087, piqa: 0.5478781284004353, hellaswag: 0.3069109739095798, avg_4: 0.3853659212686808, url: 'https://huggingface.co/PleIAs/Monad' }, | |
| { name: 'arnir0/Tiny-LLM', org: 'arnir0', params: 12988992, arc_easy: 0.30387205387205385, arc_challenge: 0.22440273037542663, piqa: 0.5614798694232862, hellaswag: 0.2620991834295957, avg_4: 0.33384172613245877, url: 'https://huggingface.co/arnir0/Tiny-LLM' }, | |
| { name: 'Maykeye/TinyLLama-v0', org: 'Maykeye', params: 4621376, arc_easy: 0.2563131313131313, arc_challenge: 0.22525597269624573, piqa: 0.5136017410228509, hellaswag: 0.25871340370444135, avg_4: 0.3062502077399361, url: 'https://huggingface.co/Maykeye/TinyLLama-v0' }, | |
| { name: 'EleutherAI/pythia-14m-deduped', org: 'EleutherAI', params: 14067712, arc_easy: 0.29924242424242425, arc_challenge: 0.20819112627986347, piqa: 0.55930359085963, hellaswag: 0.2620991834295957, avg_4: 0.33316704502828287, url: 'https://huggingface.co/EleutherAI/pythia-14m-deduped' }, | |
| { name: 'abideen/Bitnet-Llama-70M', org: 'abideen', params: 77473536, arc_easy: 0.2542087542087542, arc_challenge: 0.29436860068259385, piqa: 0.49510337323177367, hellaswag: 0.26558454491137223, avg_4: 0.3131276722216144, url: 'https://huggingface.co/abideen/Bitnet-Llama-70M' }, | |
| { name: 'codelion/gpt-2-70m', org: 'codelion', params: 64085504, arc_easy: 0.3543771043771044, arc_challenge: 0.2167235494880546, piqa: 0.5690968443960827, hellaswag: 0.26837283409679347, avg_4: 0.3575113272933605, url: 'https://huggingface.co/codelion/gpt-2-70m' }, | |
| { name: 'crumb/gpt2023', org: 'crumb', params: 124439808, arc_easy: 0.3998316498316498, arc_challenge: 0.23037542662116042, piqa: 0.6289445048966268, hellaswag: 0.3111929894443338, avg_4: 0.4212667548065598, url: 'https://huggingface.co/crumb/gpt2023' }, | |
| { name: 'Felladrin/Minueza-32M-Base', org: 'Felladrin', params: 32792760, arc_easy: 0.3312289562289562, arc_challenge: 0.23122866894197952, piqa: 0.5560391730141458, hellaswag: 0.2635929097789285, avg_4: 0.3489861711239427, url: 'https://huggingface.co/Felladrin/Minueza-32M-Base' }, | |
| { name: 'raincandy-u/TinyChat-1776K', org: 'raincandy-u', params: 1776960, arc_easy: 0.265993265993266, arc_challenge: 0.21843003412969283, piqa: 0.5125136017410229, hellaswag: 0.24596693885680143, avg_4: 0.29828585661761464, url: 'https://huggingface.co/raincandy-u/TinyChat-1776K' }, | |
| { name: 'OuteAI/Lite-Oute-1-65M', org: 'OuteAI', params: 65020416, arc_easy: 0.36952861952861954, arc_challenge: 0.21928327645051193, piqa: 0.6017410228509249, hellaswag: 0.2837084246166102, avg_4: 0.38637481192636225, url: 'https://huggingface.co/OuteAI/Lite-Oute-1-65M' }, | |
| { name: 'PicoKittens/PicoMistral-23M', org: 'PicoKittens', params: 23599488, arc_easy: 0.2975589225589226, arc_challenge: 0.22696245733788395, piqa: 0.5565832426550599, hellaswag: 0.2614021111332404, avg_4: 0.3325121434979931, url: 'https://huggingface.co/PicoKittens/PicoMistral-23M' }, | |
| { name: 'EleutherAI/pythia-70m-deduped-v0', org: 'EleutherAI', params: 70426624, arc_easy: 0.36363636363636365, arc_challenge: 0.2175767918088737, piqa: 0.5930359085963003, hellaswag: 0.2840071698864768, avg_4: 0.3831138080172334, url: 'https://huggingface.co/EleutherAI/pythia-70m-deduped-v0' }, | |
| { name: 'rhysjones/gpt2-124M-edu-fineweb-10B', org: 'rhysjones', params: 124439808, arc_easy: 0.48358585858585856, arc_challenge: 0.2551194539249147, piqa: 0.6273122959738846, hellaswag: 0.3322047400916152, avg_4: 0.4393445596882627, url: 'https://huggingface.co/rhysjones/gpt2-124M-edu-fineweb-10B' }, | |
| { name: 'weiser/30M-0.4', org: 'weiser', params: 30339456, arc_easy: 0.351010101010101, arc_challenge: 0.2150170648464164, piqa: 0.5957562568008705, hellaswag: 0.27325234017128064, avg_4: 0.3662733726996935, url: 'https://huggingface.co/weiser/30M-0.4' }, | |
| { name: 'Felladrin/Minueza-2-96M', org: 'Felladrin', params: 96005280, arc_easy: 0.36069023569023567, arc_challenge: 0.23720136518771331, piqa: 0.5854189336235038, hellaswag: 0.26906990639314876, avg_4: 0.37524065880773166, url: 'https://huggingface.co/Felladrin/Minueza-2-96M' }, | |
| { name: 'crumb/distilpythia', org: 'crumb', params: 70426624, arc_easy: 0.3367003367003367, arc_challenge: 0.22781569965870307, piqa: 0.5832426550598476, hellaswag: 0.2717586138219478, avg_4: 0.3667386105033305, url: 'https://huggingface.co/crumb/distilpythia' }, | |
| { name: 'AICrossSim/clm-60m', org: 'AICrossSim', params: 82101120, arc_easy: 0.30765993265993263, arc_challenge: 0.21843003412969283, piqa: 0.5184983677910773, hellaswag: 0.25054769966142204, avg_4: 0.31430062482303256, url: 'https://huggingface.co/AICrossSim/clm-60m' }, | |
| { name: 'PicoKittens/PicoStories-853K', org: 'PicoKittens', params: 853120, arc_easy: 0.255050505050505, arc_challenge: 0.22013651877133106, piqa: 0.5119695321001088, hellaswag: 0.26488747261501694, avg_4: 0.3128200823244073, url: 'https://huggingface.co/PicoKittens/PicoStories-853K' }, | |
| { name: 'allenai/OLMo-1B-hf', org: 'allenai', params: 1200000000, arc_easy: 0.574, arc_challenge: 0.311, piqa: 0.751, hellaswag: 0.629, avg_4: 0.56625, url: 'https://huggingface.co/allenai/OLMo-1B-hf' }, | |
| { name: 'apple/OpenELM-1_1B', org: 'apple', params: 1100000000, arc_easy: 0.554, arc_challenge: 0.323, piqa: 0.756, hellaswag: 0.648, avg_4: 0.57025, url: 'https://huggingface.co/apple/OpenELM-1_1B' }, | |
| { name: 'state-spaces/mamba2-1.3b', org: 'state-spaces', params: 1300000000, arc_easy: 0.642, arc_challenge: 0.333, piqa: 0.737, hellaswag: 0.600, avg_4: 0.57800, url: 'https://huggingface.co/state-spaces/mamba2-1.3b' }, | |
| { name: 'microsoft/phi-1_5', org: 'microsoft', params: 1400000000, arc_easy: 0.732, arc_challenge: 0.480, piqa: 0.755, hellaswag: 0.626, avg_4: 0.64825, url: 'https://huggingface.co/microsoft/phi-1_5' }, | |
| { name: 'Qwen/Qwen2-1.5B', org: 'Qwen', params: 1500000000, arc_easy: 0.604, arc_challenge: 0.350, piqa: 0.755, hellaswag: 0.654, avg_4: 0.59075, url: 'https://huggingface.co/Qwen/Qwen2-1.5B' }, | |
| { name: 'RWKV/rwkv-6-world-1b6', org: 'RWKV', params: 1600000000, arc_easy: 0.567, arc_challenge: 0.341, piqa: 0.735, hellaswag: 0.583, avg_4: 0.55650, url: 'https://huggingface.co/RWKV/rwkv-6-world-1b6' }, | |
| { name: 'stabilityai/stablelm-2-1_6b', org: 'stabilityai', params: 1600000000, arc_easy: 0.681, arc_challenge: 0.389, piqa: 0.767, hellaswag: 0.690, avg_4: 0.63175, url: 'https://huggingface.co/stabilityai/stablelm-2-1_6b' }, | |
| { name: 'HuggingFaceTB/SmolLM-1.7B', org: 'HuggingFaceTB', params: 1700000000, arc_easy: 0.735, arc_challenge: 0.464, piqa: 0.761, hellaswag: 0.658, avg_4: 0.65450, url: 'https://huggingface.co/HuggingFaceTB/SmolLM-1.7B' }, | |
| { name: 'h2oai/h2o-danube2-1.8b-base', org: 'h2oai', params: 1800000000, arc_easy: 0.690, arc_challenge: 0.399, piqa: 0.773, hellaswag: 0.724, avg_4: 0.64650, url: 'https://huggingface.co/h2oai/h2o-danube2-1.8b-base' }, | |
| { name: 'google/recurrentgemma-2b', org: 'google', params: 2700000000, arc_easy: 0.618, arc_challenge: 0.299, piqa: 0.688, hellaswag: 0.618, avg_4: 0.55575, url: 'https://huggingface.co/google/recurrentgemma-2b' }, | |
| { name: 'Qwen/Qwen2.5-0.5B', org: 'Qwen', params: 494032768, arc_easy: 0.587, arc_challenge: 0.324, piqa: 0.700, hellaswag: 0.521, avg_4: 0.55345, url: 'https://huggingface.co/Qwen/Qwen2.5-0.5B' }, | |
| { name: 'LiquidAI/LFM2.5-350M-Base', org: 'LiquidAI', params: 354483968, arc_easy: 0.688, arc_challenge: 0.410, piqa: 0.672, hellaswag: 0.452, avg_4: 0.55711, url: 'https://huggingface.co/LiquidAI/LFM2.5-350M-Base' }, | |
| { name: 'Qwen/Qwen1.5-0.5B', org: 'Qwen', params: 463987712, arc_easy: 0.524, arc_challenge: 0.296, piqa: 0.693, hellaswag: 0.492, avg_4: 0.52592, url: 'https://huggingface.co/Qwen/Qwen1.5-0.5B' }, | |
| { name: 'bigscience/bloomz-560m', org: 'bigscience', params: 559214592, arc_easy: 0.502, arc_challenge: 0.258, piqa: 0.655, hellaswag: 0.370, avg_4: 0.46342, url: 'https://huggingface.co/bigscience/bloomz-560m' }, | |
| { name: 'tiiuae/Falcon-H1-Tiny-90M-Base', org: 'tiiuae', params: 91131072, arc_easy: 0.489, arc_challenge: 0.282, piqa: 0.652, hellaswag: 0.375, avg_4: 0.46167, url: 'https://huggingface.co/tiiuae/Falcon-H1-Tiny-90M-Base' }, | |
| { name: 'EleutherAI/pythia-410m', org: 'EleutherAI', params: 405334016, arc_easy: 0.457, arc_challenge: 0.243, piqa: 0.672, hellaswag: 0.406, avg_4: 0.48145, url: 'https://huggingface.co/EleutherAI/pythia-410m' }, | |
| { name: 'openai-community/gpt2-medium', org: 'openai-community', params: 354823168, arc_easy: 0.436, arc_challenge: 0.250, piqa: 0.664, hellaswag: 0.394, avg_4: 0.47212, url: 'https://huggingface.co/openai-community/gpt2-medium' }, | |
| { name: 'EleutherAI/pythia-1b', org: 'EleutherAI', params: 1011781632, arc_easy: 0.490, arc_challenge: 0.270, piqa: 0.692, hellaswag: 0.472, avg_4: 0.51795, url: 'https://huggingface.co/EleutherAI/pythia-1b' }, | |
| ]; | |
| const BENCHMARKS = [ | |
| { key: 'avg', label: 'Avg' }, | |
| { key: 'arc_easy', label: 'ARC-Easy' }, | |
| { key: 'arc_challenge', label: 'ARC-Challenge' }, | |
| { key: 'hellaswag', label: 'HellaSwag' }, | |
| { key: 'piqa', label: 'PIQA' } | |
| ]; | |
| const BENCHMARK_NAMES = { | |
| avg: 'Average', | |
| arc_easy: 'ARC-Easy', | |
| arc_challenge: 'ARC-Challenge', | |
| hellaswag: 'HellaSwag', | |
| piqa: 'PIQA' | |
| }; | |
| const MIN_PLOT_PARAMS = 500000; | |
| let activeBenchmark = 'avg'; | |
| let activeSearch = ''; | |
| let activeOrg = 'all'; | |
| let activeOrgSearch = ''; | |
| let activeParamBucket = 'all'; | |
| let chart = null; | |
| let showResidualLabels = false; | |
| let lineEmphasis = false; | |
| let activeTheme = 'light'; | |
| let activeMode = localStorage.getItem('silverRegressionMode') || 'desktop'; | |
| const META_KEYS = new Set(['name', 'org', 'params', 'url']); | |
| const fmtParams = (n) => { | |
| if (n >= 1e9) return `${(n / 1e9).toFixed(2)}B`; | |
| if (n >= 1e6) return `${(n / 1e6).toFixed(2)}M`; | |
| if (n >= 1e3) return `${(n / 1e3).toFixed(2)}K`; | |
| return String(n); | |
| }; | |
| const toPct = (v) => v * 100; | |
| const clampScore = (v) => Number.isFinite(v) ? Math.min(100, Math.max(0, v)) : null; | |
| const escapeHtml = (value) => String(value).replace(/[&<>"']/g, ch => ({ | |
| '&': '&', | |
| '<': '<', | |
| '>': '>', | |
| '"': '"', | |
| "'": ''' | |
| }[ch])); | |
| const BUCKETS = [ | |
| { key: 'all', label: 'All' }, | |
| { key: 'lt1m', label: '<1M' }, | |
| { key: '1_10m', label: '1-10M' }, | |
| { key: '11_50m', label: '11-50M' }, | |
| { key: '51_100m', label: '51-100M' }, | |
| { key: '100_200m', label: '100-200M' }, | |
| { key: '201_500m', label: '201-500M' }, | |
| { key: 'gt500m', label: '>500M' } | |
| ]; | |
| function parseParamCount(input) { | |
| const raw = String(input ?? '').trim().replace(/[,\s]/g, '').toUpperCase(); | |
| if (!raw) return null; | |
| const match = raw.match(/^([0-9]*\.?[0-9]+)([KMB])?$/); | |
| if (!match) return null; | |
| const value = Number(match[1]); | |
| if (!Number.isFinite(value) || value <= 0) return null; | |
| const suffix = match[2] || ''; | |
| const mult = suffix === 'K' ? 1e3 : suffix === 'M' ? 1e6 : suffix === 'B' ? 1e9 : 1; | |
| return value * mult; | |
| } | |
| function formatScore(v) { | |
| return Number.isFinite(v) ? `${clampScore(v).toFixed(2)}%` : '—'; | |
| } | |
| function bucketForParams(params) { | |
| if (!Number.isFinite(params)) return 'all'; | |
| if (params < 1e6) return 'lt1m'; | |
| if (params <= 10e6) return '1_10m'; | |
| if (params <= 50e6) return '11_50m'; | |
| if (params <= 100e6) return '51_100m'; | |
| if (params <= 200e6) return '100_200m'; | |
| if (params <= 500e6) return '201_500m'; | |
| return 'gt500m'; | |
| } | |
| function trimmedMean(values, trimFraction = 0.1) { | |
| const arr = values.filter(Number.isFinite).sort((a, b) => a - b); | |
| if (!arr.length) return 0; | |
| const trim = Math.floor(arr.length * trimFraction); | |
| const sliced = arr.slice(trim, Math.max(trim + 1, arr.length - trim)); | |
| const used = sliced.length ? sliced : arr; | |
| return used.reduce((a, b) => a + b, 0) / used.length; | |
| } | |
| function buildBinnedFitSamples(points) { | |
| if (!Array.isArray(points) || points.length < 2) return []; | |
| const xs = points.map(p => p.x).filter(Number.isFinite); | |
| if (!xs.length) return []; | |
| const minX = Math.min(...xs); | |
| const maxX = Math.max(...xs); | |
| const range = Math.max(1e-6, maxX - minX); | |
| const targetBins = Math.max(5, Math.min(14, Math.round(Math.sqrt(points.length)))); | |
| const binWidth = Math.max(0.08, range / targetBins); | |
| const firstEdge = Math.floor(minX / binWidth) * binWidth; | |
| const bins = new Map(); | |
| for (const p of points) { | |
| const idx = Math.floor((p.x - firstEdge) / binWidth); | |
| if (!bins.has(idx)) bins.set(idx, []); | |
| bins.get(idx).push(p); | |
| } | |
| const samples = []; | |
| for (const [idx, group] of [...bins.entries()].sort((a, b) => a[0] - b[0])) { | |
| const xsInBin = group.map(p => p.x).filter(Number.isFinite); | |
| const ysInBin = group.map(p => p.y).filter(Number.isFinite); | |
| if (!xsInBin.length || !ysInBin.length) continue; | |
| const binX = xsInBin.reduce((a, b) => a + b, 0) / xsInBin.length; | |
| const binY = ysInBin.length >= 4 | |
| ? trimmedMean(ysInBin, 0.15) | |
| : (ysInBin.reduce((a, b) => a + b, 0) / ysInBin.length); | |
| samples.push({ | |
| x: binX, | |
| y: binY, | |
| count: 1, | |
| modelCount: group.length, | |
| binIndex: idx, | |
| params: group[0]?.params, | |
| name: `${group.length} models in size bin`, | |
| org: 'bin', | |
| url: group[0]?.url | |
| }); | |
| } | |
| samples.sort((a, b) => a.x - b.x); | |
| return samples; | |
| } | |
| function benchmarkFit(key) { | |
| const fitModels = MODELS.filter(m => { | |
| const score = getMetricValue(m, key); | |
| return Number.isFinite(m.params) && | |
| m.params >= MIN_PLOT_PARAMS && | |
| score !== null && | |
| score !== undefined && | |
| Number.isFinite(score); | |
| }); | |
| if (fitModels.length < 2) return null; | |
| const fitData = fitModels.map(m => { | |
| const score = getMetricValue(m, key); | |
| return { | |
| name: m.name, | |
| org: m.org, | |
| params: m.params, | |
| score: toPct(score), | |
| url: m.url, | |
| x: Math.log10(m.params), | |
| y: toPct(score) | |
| }; | |
| }); | |
| const fitSamples = buildBinnedFitSamples(fitData); | |
| const fit = bestLinearFit(fitSamples); | |
| const rawFit = enrichLinearFit(weightedLinearRegression(fitData), fitData, 'raw-linear'); | |
| return { fitData, fit, rawFit, fitSamples }; | |
| } | |
| function buildPredictionRows(paramCount) { | |
| return BENCHMARKS.map(({ key, label }) => { | |
| const bundle = benchmarkFit(key); | |
| if (!bundle || bundle.fit.n < 2) return { key, label, predicted: null }; | |
| const x = Math.log10(paramCount); | |
| return { key, label, predicted: clampScore(evaluateFit(bundle.fit, x)) }; | |
| }); | |
| } | |
| function getMetricValue(model, key) { | |
| if (key === 'avg') { | |
| const values = Object.entries(model) | |
| .filter(([k, v]) => typeof v === 'number' && Number.isFinite(v) && !META_KEYS.has(k) && !k.startsWith('avg')) | |
| .map(([, v]) => v); | |
| if (!values.length) return null; | |
| return values.reduce((a, b) => a + b, 0) / values.length; | |
| } | |
| return model[key]; | |
| } | |
| function median(values) { | |
| if (!values.length) return 0; | |
| const sorted = [...values].sort((a, b) => a - b); | |
| const mid = Math.floor(sorted.length / 2); | |
| return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; | |
| } | |
| function weightedMedian(values, weights) { | |
| const pairs = values | |
| .map((v, i) => [v, Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1)]) | |
| .filter(([v, w]) => Number.isFinite(v) && Number.isFinite(w) && w > 0) | |
| .sort((a, b) => a[0] - b[0]); | |
| if (!pairs.length) return 0; | |
| const total = pairs.reduce((acc, [, w]) => acc + w, 0); | |
| let acc = 0; | |
| for (const [value, weight] of pairs) { | |
| acc += weight; | |
| if (acc >= total / 2) return value; | |
| } | |
| return pairs[pairs.length - 1][0]; | |
| } | |
| function evaluatePolynomial(coefficients, x) { | |
| if (!coefficients?.length) return 0; | |
| let y = 0; | |
| for (let i = 0; i < coefficients.length; i += 1) { | |
| y = (y * x) + coefficients[i]; | |
| } | |
| return y; | |
| } | |
| function polynomialDerivative(coefficients, x) { | |
| if (!coefficients?.length || coefficients.length < 2) return 0; | |
| const degree = coefficients.length - 1; | |
| let y = 0; | |
| for (let i = 0; i < degree; i += 1) { | |
| const power = degree - i; | |
| y = (y * x) + (coefficients[i] * power); | |
| } | |
| return y; | |
| } | |
| function solveLinearSystem(matrix, vector) { | |
| const n = vector.length; | |
| const a = matrix.map((row, i) => [...row, vector[i]]); | |
| for (let col = 0; col < n; col += 1) { | |
| let pivotRow = col; | |
| let pivotAbs = Math.abs(a[col][col]); | |
| for (let row = col + 1; row < n; row += 1) { | |
| const cand = Math.abs(a[row][col]); | |
| if (cand > pivotAbs) { | |
| pivotAbs = cand; | |
| pivotRow = row; | |
| } | |
| } | |
| if (pivotAbs < 1e-12) { | |
| return null; | |
| } | |
| if (pivotRow !== col) { | |
| const tmp = a[col]; | |
| a[col] = a[pivotRow]; | |
| a[pivotRow] = tmp; | |
| } | |
| const pivot = a[col][col]; | |
| for (let j = col; j <= n; j += 1) { | |
| a[col][j] /= pivot; | |
| } | |
| for (let row = 0; row < n; row += 1) { | |
| if (row === col) continue; | |
| const factor = a[row][col]; | |
| if (Math.abs(factor) < 1e-12) continue; | |
| for (let j = col; j <= n; j += 1) { | |
| a[row][j] -= factor * a[col][j]; | |
| } | |
| } | |
| } | |
| return a.map(row => row[n]); | |
| } | |
| function weightedPolynomialRegression(points, degree = 1, weights = null) { | |
| const n = points.length; | |
| if (!n) return { degree, coefficients: [0], mse: 0, rmse: 0, r2: 0, n: 0, weightSum: 0 }; | |
| const actualDegree = Math.max(0, Math.min(degree, n - 1)); | |
| const size = actualDegree + 1; | |
| const matrix = Array.from({ length: size }, () => Array(size).fill(0)); | |
| const vector = Array(size).fill(0); | |
| for (let i = 0; i < n; i += 1) { | |
| const p = points[i]; | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| if (!w) continue; | |
| const basis = []; | |
| for (let d = actualDegree; d >= 0; d -= 1) { | |
| basis.push(p.x ** d); | |
| } | |
| for (let r = 0; r < size; r += 1) { | |
| vector[r] += w * basis[r] * p.y; | |
| for (let c = 0; c < size; c += 1) { | |
| matrix[r][c] += w * basis[r] * basis[c]; | |
| } | |
| } | |
| } | |
| let coefficients = solveLinearSystem(matrix, vector); | |
| if (!coefficients) { | |
| if (actualDegree === 0) { | |
| const avg = points.reduce((acc, p, i) => { | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| return acc + w * p.y; | |
| }, 0); | |
| const sw = points.reduce((acc, p, i) => acc + Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1), 0); | |
| coefficients = [sw ? avg / sw : 0]; | |
| } else { | |
| return weightedPolynomialRegression(points, actualDegree - 1, weights); | |
| } | |
| } | |
| const predictions = points.map(p => evaluatePolynomial(coefficients, p.x)); | |
| const sw = points.reduce((acc, p, i) => acc + Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1), 0); | |
| const yMean = sw ? points.reduce((acc, p, i) => acc + Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1) * p.y, 0) / sw : 0; | |
| const sse = points.reduce((acc, p, i) => { | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| const resid = p.y - predictions[i]; | |
| return acc + w * resid * resid; | |
| }, 0); | |
| const sst = points.reduce((acc, p, i) => { | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| return acc + w * (p.y - yMean) ** 2; | |
| }, 0); | |
| const mse = sw ? sse / sw : 0; | |
| const rmse = Math.sqrt(mse); | |
| const r2 = sst > 0 ? 1 - (sse / sst) : 0; | |
| return { degree: actualDegree, coefficients, mse, rmse, r2, n, weightSum: sw }; | |
| } | |
| function weightedLinearRegression(points, weights = null) { | |
| return weightedPolynomialRegression(points, 1, weights); | |
| } | |
| function linearRegression(points) { | |
| return weightedPolynomialRegression(points, 1); | |
| } | |
| function enrichLinearFit(fit, points, method = fit?.method || 'linear') { | |
| const clean = (points || []).filter(p => Number.isFinite(p.x) && Number.isFinite(p.y)); | |
| const n = clean.length; | |
| const slope = fit?.coefficients?.[0] ?? 0; | |
| const intercept = fit?.coefficients?.[1] ?? 0; | |
| const xMean = n ? clean.reduce((acc, p) => acc + p.x, 0) / n : 0; | |
| const yMean = n ? clean.reduce((acc, p) => acc + p.y, 0) / n : 0; | |
| const sse = clean.reduce((acc, p) => acc + (p.y - evaluatePolynomial([slope, intercept], p.x)) ** 2, 0); | |
| const sst = clean.reduce((acc, p) => acc + (p.y - yMean) ** 2, 0); | |
| const mse = n ? sse / n : 0; | |
| return { | |
| ...fit, | |
| degree: 1, | |
| coefficients: [slope, intercept], | |
| slope, | |
| intercept, | |
| xMean, | |
| centerValue: evaluatePolynomial([slope, intercept], xMean), | |
| centerSlope: slope, | |
| curvature: 0, | |
| mse, | |
| rmse: Math.sqrt(mse), | |
| r2: sst > 0 ? 1 - (sse / sst) : 0, | |
| n, | |
| method | |
| }; | |
| } | |
| function fitError(fit, points) { | |
| const residuals = (points || []) | |
| .map(p => p.y - evaluateFit(fit, p.x)) | |
| .filter(Number.isFinite) | |
| .sort((a, b) => Math.abs(a) - Math.abs(b)); | |
| if (!residuals.length) return Infinity; | |
| const trim = Math.floor(residuals.length * 0.1); | |
| const used = residuals.slice(0, Math.max(1, residuals.length - trim)); | |
| return Math.sqrt(used.reduce((acc, r) => acc + r * r, 0) / used.length); | |
| } | |
| function bestLinearFit(fitSamples) { | |
| const candidates = [ | |
| enrichLinearFit(robustLinearRegression(fitSamples), fitSamples, 'robust-linear'), | |
| enrichLinearFit(weightedLinearRegression(fitSamples), fitSamples, 'binned-linear') | |
| ]; | |
| candidates.sort((a, b) => fitError(a, fitSamples) - fitError(b, fitSamples)); | |
| return candidates[0]; | |
| } | |
| function robustPolynomialRegression(points, degree = 2) { | |
| const n = points.length; | |
| if (n < 2) return weightedPolynomialRegression(points, degree); | |
| const baseWeights = points.map(p => Math.max(1, Number.isFinite(p.count) ? p.count : 1)); | |
| let weights = [...baseWeights]; | |
| let fit = weightedPolynomialRegression(points, degree, weights); | |
| for (let iter = 0; iter < 10; iter += 1) { | |
| const residuals = points.map((p, i) => p.y - evaluateFit(fit, p.x)); | |
| const residMedian = median(residuals); | |
| const absDeviations = residuals.map(r => Math.abs(r - residMedian)); | |
| const scale = Math.max(1e-6, 1.4826 * median(absDeviations)); | |
| const huberK = 1.345 * scale; | |
| const xMedian = median(points.map(p => p.x)); | |
| const xScale = Math.max(1e-6, 1.4826 * median(points.map(p => Math.abs(p.x - xMedian)))); | |
| const nextWeights = points.map((p, i) => { | |
| const resid = Math.abs(residuals[i] - residMedian); | |
| let w = baseWeights[i]; | |
| if (resid > huberK) w *= huberK / resid; | |
| const leverage = Math.abs(p.x - xMedian) / xScale; | |
| w *= 1 / (1 + 0.18 * leverage + 0.02 * leverage * leverage); | |
| return Math.max(w, 1e-6); | |
| }); | |
| const next = weightedPolynomialRegression(points, degree, nextWeights); | |
| const delta = next.coefficients.reduce((acc, coef, i) => acc + Math.abs((fit.coefficients[i] ?? 0) - coef), 0); | |
| fit = next; | |
| weights = nextWeights; | |
| if (delta < 1e-10) break; | |
| } | |
| const xMean = points.reduce((acc, p, i) => { | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| return acc + w * p.x; | |
| }, 0) / Math.max(1e-12, weights.reduce((a, b) => a + b, 0)); | |
| fit.xMean = xMean; | |
| fit.centerValue = evaluateFit(fit, xMean); | |
| fit.centerSlope = polynomialDerivative(fit.coefficients, xMean); | |
| fit.curvature = fit.coefficients.length >= 3 ? fit.coefficients[0] : 0; | |
| fit.method = `robust-degree-${fit.degree}`; | |
| fit.effectiveN = weights.reduce((a, b) => a + b, 0); | |
| return fit; | |
| } | |
| function robustLinearRegression(points) { | |
| const n = points.length; | |
| if (n < 2) return weightedPolynomialRegression(points, 1); | |
| const baseWeights = points.map(p => Math.max(1, Number.isFinite(p.count) ? p.count : 1)); | |
| const slopes = []; | |
| const slopeWeights = []; | |
| for (let i = 0; i < n; i += 1) { | |
| for (let j = i + 1; j < n; j += 1) { | |
| const dx = points[j].x - points[i].x; | |
| if (Math.abs(dx) < 1e-12) continue; | |
| slopes.push((points[j].y - points[i].y) / dx); | |
| slopeWeights.push(baseWeights[i] * baseWeights[j]); | |
| } | |
| } | |
| let slope = slopes.length ? weightedMedian(slopes, slopeWeights) : 0; | |
| if (!Number.isFinite(slope)) { | |
| slope = weightedLinearRegression(points, baseWeights).coefficients[0] ?? 0; | |
| } | |
| let intercept = weightedMedian( | |
| points.map(p => p.y - slope * p.x), | |
| baseWeights | |
| ); | |
| if (!Number.isFinite(intercept)) intercept = 0; | |
| let fit = { | |
| degree: 1, | |
| coefficients: [slope, intercept], | |
| mse: 0, | |
| rmse: 0, | |
| r2: 0, | |
| n, | |
| weightSum: baseWeights.reduce((a, b) => a + b, 0), | |
| method: 'theil-sen-seeded-linear' | |
| }; | |
| let weights = [...baseWeights]; | |
| for (let iter = 0; iter < 6; iter += 1) { | |
| const residuals = points.map(p => p.y - evaluateFit(fit, p.x)); | |
| const residMedian = median(residuals); | |
| const absDeviations = residuals.map(r => Math.abs(r - residMedian)); | |
| const scale = Math.max(1e-6, 1.4826 * median(absDeviations)); | |
| const huberK = 1.345 * scale; | |
| const xMedian = median(points.map(p => p.x)); | |
| const xScale = Math.max(1e-6, 1.4826 * median(points.map(p => Math.abs(p.x - xMedian)))); | |
| const nextWeights = points.map((p, i) => { | |
| const resid = Math.abs(residuals[i] - residMedian); | |
| let w = baseWeights[i]; | |
| if (resid > huberK) w *= huberK / resid; | |
| const leverage = Math.abs(p.x - xMedian) / xScale; | |
| w *= 1 / (1 + 0.14 * leverage + 0.015 * leverage * leverage); | |
| return Math.max(w, 1e-6); | |
| }); | |
| const nextFit = weightedPolynomialRegression(points, 1, nextWeights); | |
| fit = nextFit; | |
| weights = nextWeights; | |
| if (iter > 0) { | |
| const delta = Math.abs((fit.coefficients[0] ?? 0) - slope) + Math.abs((fit.coefficients[1] ?? 0) - intercept); | |
| if (delta < 1e-10) break; | |
| } | |
| slope = fit.coefficients[0] ?? slope; | |
| intercept = fit.coefficients[1] ?? intercept; | |
| } | |
| const xMean = points.reduce((acc, p, i) => { | |
| const w = Math.max(0, Number.isFinite(weights?.[i]) ? weights[i] : 1); | |
| return acc + w * p.x; | |
| }, 0) / Math.max(1e-12, weights.reduce((a, b) => a + b, 0)); | |
| fit.xMean = xMean; | |
| fit.centerValue = evaluateFit(fit, xMean); | |
| fit.centerSlope = fit.coefficients[0] ?? 0; | |
| fit.slope = fit.coefficients[0] ?? 0; | |
| fit.intercept = fit.coefficients[1] ?? 0; | |
| fit.curvature = 0; | |
| fit.effectiveN = weights.reduce((a, b) => a + b, 0); | |
| fit.method = 'robust-linear'; | |
| return fit; | |
| } | |
| function evaluateFit(fit, x) { | |
| return evaluatePolynomial(fit?.coefficients || [0], x); | |
| } | |
| function fitSlopeAt(fit, x) { | |
| return polynomialDerivative(fit?.coefficients || [0], x); | |
| } | |
| function fitCenter(fit) { | |
| return fit?.xMean ?? 0; | |
| } | |
| function fitSummaryValue(fit) { | |
| return fit?.centerValue ?? 0; | |
| } | |
| function formatFitEquation(fit) { | |
| if (!fit?.coefficients?.length) return '—'; | |
| const coeffs = fit.coefficients; | |
| if (fit.degree === 1 && coeffs.length >= 2) { | |
| return `${coeffs[0].toFixed(4)}x + ${coeffs[1].toFixed(2)}`; | |
| } | |
| if (fit.degree >= 2 && coeffs.length >= 3) { | |
| return `${coeffs[0].toFixed(4)}x² + ${coeffs[1].toFixed(4)}x + ${coeffs[2].toFixed(2)}`; | |
| } | |
| return coeffs.map(v => v.toFixed(4)).join(', '); | |
| } | |
| function getEligibleModels() { | |
| return MODELS.filter(m => { | |
| const score = getMetricValue(m, activeBenchmark); | |
| return Number.isFinite(m.params) && | |
| m.params >= MIN_PLOT_PARAMS && | |
| score !== null && | |
| score !== undefined && | |
| Number.isFinite(score); | |
| }); | |
| } | |
| function getVisibleModels() { | |
| const q = activeSearch.trim().toLowerCase(); | |
| return getEligibleModels().filter(m => { | |
| if (activeOrg !== 'all' && m.org !== activeOrg) return false; | |
| if (activeParamBucket !== 'all' && bucketForParams(m.params) !== activeParamBucket) return false; | |
| if (!q) return true; | |
| return m.name.toLowerCase().includes(q) || m.org.toLowerCase().includes(q); | |
| }); | |
| } | |
| function getOrgList() { | |
| return [...new Set(MODELS.map(m => m.org))].sort((a, b) => a.localeCompare(b)); | |
| } | |
| function setChipState(btn, active) { | |
| btn.classList.toggle('active', active); | |
| btn.setAttribute('aria-pressed', active ? 'true' : 'false'); | |
| } | |
| function applyTheme(theme) { | |
| activeTheme = theme; | |
| document.body.dataset.theme = theme; | |
| setChipState(document.getElementById('themeLight'), theme === 'light'); | |
| setChipState(document.getElementById('themeDark'), theme === 'dark'); | |
| localStorage.setItem('silverRegressionTheme', theme); | |
| render(); | |
| } | |
| function renderBenchmarkButtons() { | |
| const box = document.getElementById('benchmarkButtons'); | |
| box.innerHTML = BENCHMARKS.map(b => ` | |
| <button type="button" class="${b.key === activeBenchmark ? 'active' : ''}" data-key="${escapeHtml(b.key)}">${escapeHtml(b.label)}</button> | |
| `).join(''); | |
| box.querySelectorAll('button').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| activeBenchmark = btn.dataset.key; | |
| renderOrgUI(); | |
| render(); | |
| }); | |
| }); | |
| } | |
| function renderOrgUI() { | |
| const allOrgs = getOrgList(); | |
| const orgSearch = activeOrgSearch.trim().toLowerCase(); | |
| const orgs = orgSearch | |
| ? allOrgs.filter(o => o.toLowerCase().includes(orgSearch)) | |
| : allOrgs; | |
| const chips = document.getElementById('orgChips'); | |
| const summary = document.getElementById('orgSummary'); | |
| summary.textContent = activeOrg === 'all' ? 'All orgs' : `Org: ${activeOrg}`; | |
| chips.innerHTML = [ | |
| `<button type="button" class="org-chip all ${activeOrg === 'all' ? 'active' : ''}" data-org="all">All</button>`, | |
| ...orgs.map(org => `<button type="button" class="org-chip ${activeOrg === org ? 'active' : ''}" data-org="${escapeHtml(org)}">${escapeHtml(org)}</button>`) | |
| ].join(''); | |
| chips.querySelectorAll('button').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| activeOrg = btn.dataset.org; | |
| document.getElementById('orgSummary').textContent = activeOrg === 'all' ? 'All orgs' : `Org: ${activeOrg}`; | |
| renderOrgUI(); | |
| render(); | |
| }); | |
| }); | |
| } | |
| function renderBucketUI() { | |
| const box = document.getElementById('bucketButtons'); | |
| box.innerHTML = BUCKETS.map(b => ` | |
| <button type="button" class="chip ${b.key === activeParamBucket ? 'active' : ''}" data-bucket="${escapeHtml(b.key)}">${escapeHtml(b.label)}</button> | |
| `).join(''); | |
| box.querySelectorAll('button').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| activeParamBucket = btn.dataset.bucket; | |
| renderBucketUI(); | |
| render(); | |
| }); | |
| }); | |
| } | |
| function applyMode(mode) { | |
| activeMode = mode; | |
| document.body.dataset.mode = mode; | |
| setChipState(document.getElementById('modeDesktop'), mode === 'desktop'); | |
| setChipState(document.getElementById('modeMobile'), mode === 'mobile'); | |
| localStorage.setItem('silverRegressionMode', mode); | |
| render(); | |
| } | |
| function updatePredictionPanel() { | |
| const input = document.getElementById('paramInput'); | |
| const summary = document.getElementById('predictionSummary'); | |
| const list = document.getElementById('predictionList'); | |
| const value = parseParamCount(input.value); | |
| if (value === null) { | |
| summary.textContent = 'Enter a parameter count like 12M, 250K, or 1.5B.'; | |
| list.innerHTML = ''; | |
| return; | |
| } | |
| summary.textContent = `Parameter count: ${fmtParams(value)} (${value.toLocaleString()})`; | |
| const rows = buildPredictionRows(value); | |
| list.innerHTML = rows.map(row => { | |
| const label = row.label === 'Avg' ? 'Average' : row.label; | |
| return ` | |
| <div class="prediction-item"> | |
| <div class="label">${escapeHtml(label)}</div> | |
| <div class="value">${formatScore(row.predicted)}</div> | |
| </div> | |
| `; | |
| }).join(''); | |
| } | |
| function updateStats(fit, visibleCount, residuals, rawCount, binCount, rawFit) { | |
| document.getElementById('statSlope').textContent = fit.n >= 2 ? (fit.curvature ?? 0).toFixed(6) : '—'; | |
| document.getElementById('statIntercept').textContent = fit.n >= 2 ? (fit.centerSlope ?? fit.slope ?? 0).toFixed(4) : '—'; | |
| document.getElementById('statMSE').textContent = fit.n >= 2 ? `${clampScore(fit.centerValue ?? fitSummaryValue(fit)).toFixed(2)}%` : '—'; | |
| document.getElementById('statRMSE').textContent = fit.n >= 2 ? fit.rmse.toFixed(2) : '—'; | |
| document.getElementById('statR2').textContent = fit.n >= 2 ? fit.r2.toFixed(3) : '—'; | |
| document.getElementById('countBadge').textContent = `${visibleCount} visible / ${binCount} bins`; | |
| document.getElementById('infoBenchmark').textContent = BENCHMARK_NAMES[activeBenchmark] || activeBenchmark; | |
| document.getElementById('infoCount').textContent = String(visibleCount); | |
| document.getElementById('infoFitCount').textContent = String(binCount); | |
| const absMean = residuals.length ? residuals.reduce((a, b) => a + Math.abs(b), 0) / residuals.length : 0; | |
| const mean = residuals.length ? residuals.reduce((a, b) => a + b, 0) / residuals.length : 0; | |
| const spread = residuals.length ? Math.sqrt(residuals.reduce((a, b) => a + (b - mean) ** 2, 0) / residuals.length) : 0; | |
| document.getElementById('infoMAE').textContent = residuals.length ? `${absMean.toFixed(2)} pts` : '—'; | |
| document.getElementById('infoResidualSpread').textContent = residuals.length ? `${spread.toFixed(2)} pts` : '—'; | |
| const orgCount = new Set(getVisibleModels().map(m => m.org)).size; | |
| document.getElementById('infoOrgs').textContent = `${orgCount} orgs`; | |
| document.getElementById('infoMatchRate').textContent = `${visibleCount}/${rawCount}`; | |
| document.getElementById('infoMode').textContent = activeMode === 'mobile' ? 'Mobile' : 'Computer'; | |
| document.getElementById('fitNote').textContent = | |
| `Fit uses ${rawCount} eligible models collapsed into ${binCount} size bins for ${BENCHMARK_NAMES[activeBenchmark] || activeBenchmark}. Raw-point RMSE is ${rawFit.n >= 2 ? rawFit.rmse.toFixed(2) : '—'}; binned fit RMSE is ${fit.n >= 2 ? fit.rmse.toFixed(2) : '—'}. Search and org filters only affect visibility.`; | |
| } | |
| function setText(id, value) { | |
| const target = document.getElementById(id); | |
| if (target) target.textContent = value; | |
| } | |
| const residualLabelPlugin = { | |
| id: 'residualLabelPlugin', | |
| afterDatasetsDraw(chartInstance) { | |
| if (!showResidualLabels) return; | |
| const datasetIndex = 1; | |
| const meta = chartInstance.getDatasetMeta(datasetIndex); | |
| const dataset = chartInstance.data.datasets[datasetIndex]; | |
| if (!meta || meta.hidden || !dataset?.data?.length) return; | |
| const { ctx, chartArea } = chartInstance; | |
| ctx.save(); | |
| ctx.font = '700 11px Inter, system-ui, sans-serif'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.lineWidth = 1; | |
| meta.data.forEach((point, index) => { | |
| const raw = dataset.data[index]; | |
| if (!raw || !Number.isFinite(raw.residual) || Math.abs(raw.residual) < 3) return; | |
| const label = `${raw.residual >= 0 ? '+' : ''}${raw.residual.toFixed(1)}`; | |
| const metrics = ctx.measureText(label); | |
| const width = metrics.width + 10; | |
| const height = 18; | |
| let x = point.x + 8; | |
| let y = point.y - 12; | |
| x = Math.min(chartArea.right - width - 2, Math.max(chartArea.left + 2, x)); | |
| y = Math.min(chartArea.bottom - height / 2 - 2, Math.max(chartArea.top + height / 2 + 2, y)); | |
| ctx.fillStyle = activeTheme === 'light' ? 'rgba(255,255,255,.92)' : 'rgba(15,18,24,.92)'; | |
| ctx.strokeStyle = raw.residual >= 0 ? 'rgba(47,111,237,.42)' : 'rgba(31,157,122,.42)'; | |
| ctx.beginPath(); | |
| ctx.roundRect(x, y - height / 2, width, height, 5); | |
| ctx.fill(); | |
| ctx.stroke(); | |
| ctx.fillStyle = activeTheme === 'light' ? '#111318' : '#f2f5f9'; | |
| ctx.fillText(label, x + 5, y); | |
| }); | |
| ctx.restore(); | |
| } | |
| }; | |
| function render() { | |
| const fitModels = getEligibleModels(); | |
| const visibleModels = getVisibleModels(); | |
| const fitData = fitModels.map(m => { | |
| const score = getMetricValue(m, activeBenchmark); | |
| return { | |
| name: m.name, | |
| org: m.org, | |
| params: m.params, | |
| score: toPct(score), | |
| url: m.url, | |
| x: Math.log10(m.params), | |
| y: toPct(score) | |
| }; | |
| }); | |
| const data = visibleModels.map(m => { | |
| const score = getMetricValue(m, activeBenchmark); | |
| return { | |
| name: m.name, | |
| org: m.org, | |
| params: m.params, | |
| score: toPct(score), | |
| url: m.url, | |
| x: Math.log10(m.params), | |
| y: toPct(score) | |
| }; | |
| }); | |
| const chartTitleMap = { | |
| avg: 'Average score vs log parameters', | |
| arc_easy: 'ARC-Easy vs log parameters', | |
| arc_challenge: 'ARC-Challenge vs log parameters', | |
| hellaswag: 'HellaSwag vs log parameters', | |
| piqa: 'PIQA vs log parameters' | |
| }; | |
| setText('chartTitle', chartTitleMap[activeBenchmark] || 'Regression vs log parameters'); | |
| setText('chartSub', | |
| 'Binned linear regression on log10(parameters) for the selected benchmark. Each size bin contributes one equally weighted sample, so the line tracks the average score by parameter region instead of point density.'); | |
| if (fitData.length < 2) { | |
| setText('chartSub', 'Need at least 2 eligible models to fit a line.'); | |
| document.getElementById('countBadge').textContent = `${visibleModels.length} visible / ${fitData.length} bins`; | |
| document.getElementById('infoBenchmark').textContent = BENCHMARK_NAMES[activeBenchmark] || activeBenchmark; | |
| document.getElementById('infoCount').textContent = String(visibleModels.length); | |
| document.getElementById('infoFitCount').textContent = String(fitData.length); | |
| document.getElementById('infoMAE').textContent = '—'; | |
| document.getElementById('infoResidualSpread').textContent = '—'; | |
| document.getElementById('statSlope').textContent = '—'; | |
| document.getElementById('statIntercept').textContent = '—'; | |
| document.getElementById('statRMSE').textContent = '—'; | |
| document.getElementById('statR2').textContent = '—'; | |
| if (chart) chart.destroy(); | |
| return; | |
| } | |
| const fitSamples = buildBinnedFitSamples(fitData); | |
| const fit = bestLinearFit(fitSamples); | |
| const rawFit = enrichLinearFit(weightedLinearRegression(fitData), fitData, 'raw-linear'); | |
| const visibleResiduals = data.map(d => d.y - clampScore(evaluateFit(fit, d.x))); | |
| data.forEach((d, i) => { | |
| d.residual = visibleResiduals[i]; | |
| d.prediction = clampScore(evaluateFit(fit, d.x)); | |
| }); | |
| updateStats(fit, data.length, visibleResiduals, fitData.length, fitSamples.length, rawFit); | |
| updatePredictionPanel(); | |
| const xMin = Math.min(...fitData.map(d => d.x)); | |
| const xMax = Math.max(...fitData.map(d => d.x)); | |
| const xPad = Math.max(0.18, (xMax - xMin) * 0.09); | |
| const lineSteps = 50; | |
| const regressionLine = []; | |
| for (let i = 0; i <= lineSteps; i += 1) { | |
| const t = i / lineSteps; | |
| const rawX = (xMin - xPad) + ((xMax + xPad) - (xMin - xPad)) * t; | |
| regressionLine.push({ x: rawX, y: clampScore(evaluateFit(fit, rawX)) }); | |
| } | |
| const yMin = Math.min(...fitData.map(d => d.y), ...regressionLine.map(p => p.y)) - 2.2; | |
| const yMax = Math.max(...fitData.map(d => d.y), ...regressionLine.map(p => p.y)) + 2.2; | |
| if (chart) chart.destroy(); | |
| const ctx = document.getElementById('scatterChart').getContext('2d'); | |
| chart = new Chart(ctx, { | |
| type: 'scatter', | |
| data: { | |
| datasets: [ | |
| { | |
| type: 'line', | |
| label: 'Regression', | |
| data: regressionLine, | |
| borderColor: activeTheme === 'light' ? 'rgba(47,111,237,0.92)' : 'rgba(127,176,255,0.95)', | |
| borderWidth: lineEmphasis ? 4 : 3, | |
| borderDash: lineEmphasis ? [] : [2, 8], | |
| borderCapStyle: 'round', | |
| pointRadius: 0, | |
| tension: 0, | |
| order: 0 | |
| }, | |
| { | |
| label: 'Models', | |
| data, | |
| parsing: false, | |
| pointRadius: activeMode === 'mobile' ? (lineEmphasis ? 5 : 5) : (lineEmphasis ? 6 : 7), | |
| pointHoverRadius: activeMode === 'mobile' ? 10 : 12, | |
| pointHitRadius: activeMode === 'mobile' ? 18 : 24, | |
| borderWidth: 1.5, | |
| backgroundColor: (ctx) => { | |
| const raw = ctx.raw; | |
| if (!raw) return activeTheme === 'light' ? 'rgba(20,22,27,0.95)' : 'rgba(245,246,248,0.95)'; | |
| const abs = Math.abs(raw.residual ?? 0); | |
| if (showResidualLabels && abs > 3.0) { | |
| return raw.residual >= 0 ? (activeTheme === 'light' ? 'rgba(47,111,237,0.95)' : 'rgba(127,176,255,0.98)') : 'rgba(31,157,122,0.92)'; | |
| } | |
| if (activeTheme === 'light') { | |
| return raw.residual >= 0 ? 'rgba(31,42,58,0.94)' : 'rgba(118,129,146,0.92)'; | |
| } | |
| return raw.residual >= 0 ? 'rgba(232,240,255,0.98)' : 'rgba(127,218,196,0.90)'; | |
| }, | |
| borderColor: (ctx) => { | |
| const raw = ctx.raw; | |
| if (!raw) return activeTheme === 'light' ? 'rgba(255,255,255,0.88)' : 'rgba(255,255,255,0.82)'; | |
| if (activeTheme === 'light') { | |
| return raw.residual >= 0 ? 'rgba(255,255,255,0.98)' : 'rgba(20,22,27,0.50)'; | |
| } | |
| return raw.residual >= 0 ? 'rgba(255,255,255,0.98)' : 'rgba(18,19,23,0.42)'; | |
| }, | |
| hoverBackgroundColor: 'rgba(255,255,255,1)', | |
| hoverBorderColor: 'rgba(16,17,20,1)', | |
| order: 2, | |
| showLine: false | |
| } | |
| ] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| animation: { duration: 0 }, | |
| interaction: { mode: 'nearest', intersect: true }, | |
| onHover: (event, elements) => { | |
| const target = event?.native?.target; | |
| if (target && target.style) target.style.cursor = elements.length ? 'pointer' : 'default'; | |
| }, | |
| onClick: (event, elements) => { | |
| if (!elements.length) return; | |
| const hit = elements[0]; | |
| if (hit.datasetIndex !== 1) return; | |
| const item = chart.data.datasets[hit.datasetIndex].data[hit.index]; | |
| if (item?.url) window.open(item.url, '_blank', 'noopener,noreferrer'); | |
| }, | |
| plugins: { | |
| legend: { display: false }, | |
| tooltip: { | |
| enabled: true, | |
| backgroundColor: 'rgba(10,11,14,0.98)', | |
| borderColor: 'rgba(255,255,255,0.18)', | |
| borderWidth: 1, | |
| titleColor: '#ffffff', | |
| bodyColor: '#dbe0e8', | |
| titleFont: { size: 13, weight: '700' }, | |
| bodyFont: { size: 12 }, | |
| padding: 12, | |
| displayColors: false, | |
| caretPadding: 10, | |
| cornerRadius: 12, | |
| callbacks: { | |
| title: (items) => items[0]?.raw?.name || '', | |
| label: (item) => { | |
| const d = item.raw; | |
| const predicted = clampScore(evaluateFit(fit, d.x)); | |
| const resid = d.y - predicted; | |
| return [ | |
| `Org: ${d.org}`, | |
| `Params: ${fmtParams(d.params)} (${d.params.toLocaleString()})`, | |
| `Score: ${d.score.toFixed(2)}%`, | |
| `Residual: ${resid >= 0 ? '+' : ''}${resid.toFixed(2)} pts`, | |
| `Predicted (robust line): ${predicted.toFixed(2)}%` | |
| ]; | |
| }, | |
| afterLabel: (item) => { | |
| const d = item.raw; | |
| return showResidualLabels ? `Residual label: ${d.residual.toFixed(2)} pts` : ''; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| x: { | |
| type: 'linear', | |
| min: Math.max(3.3, xMin - 0.20), | |
| max: xMax + 0.15, | |
| grid: { color: activeTheme === 'light' ? 'rgba(16,17,20,0.07)' : 'rgba(255,255,255,0.08)' }, | |
| ticks: { | |
| color: activeTheme === 'light' ? '#737a87' : '#aab1bf', | |
| callback: v => `10^${Number(v).toFixed(1)}` | |
| }, | |
| title: { | |
| display: true, | |
| text: 'Log₁₀(parameters)', | |
| color: activeTheme === 'light' ? '#616876' : '#b8bfcb', | |
| font: { weight: '700' } | |
| } | |
| }, | |
| y: { | |
| min: Math.max(0, yMin), | |
| max: yMax, | |
| grid: { color: activeTheme === 'light' ? 'rgba(16,17,20,0.07)' : 'rgba(255,255,255,0.08)' }, | |
| ticks: { | |
| color: activeTheme === 'light' ? '#737a87' : '#aab1bf', | |
| callback: v => `${Number(v).toFixed(0)}%` | |
| }, | |
| title: { | |
| display: true, | |
| text: 'Score (%)', | |
| color: activeTheme === 'light' ? '#616876' : '#b8bfcb', | |
| font: { weight: '700' } | |
| } | |
| } | |
| } | |
| }, | |
| plugins: [residualLabelPlugin] | |
| }); | |
| } | |
| document.getElementById('searchBox').addEventListener('input', (e) => { | |
| activeSearch = e.target.value || ''; | |
| render(); | |
| }); | |
| document.getElementById('predictBtn').addEventListener('click', updatePredictionPanel); | |
| document.getElementById('paramInput').addEventListener('input', updatePredictionPanel); | |
| document.getElementById('modeDesktop').addEventListener('click', () => applyMode('desktop')); | |
| document.getElementById('modeMobile').addEventListener('click', () => applyMode('mobile')); | |
| document.getElementById('orgSearch').addEventListener('input', (e) => { | |
| activeOrgSearch = e.target.value || ''; | |
| renderOrgUI(); | |
| }); | |
| document.getElementById('clearOrg').addEventListener('click', () => { | |
| activeOrg = 'all'; | |
| activeOrgSearch = ''; | |
| document.getElementById('orgSearch').value = ''; | |
| renderOrgUI(); | |
| render(); | |
| }); | |
| const residualBtn = document.getElementById('toggleOutliers'); | |
| residualBtn.addEventListener('click', () => { | |
| showResidualLabels = !showResidualLabels; | |
| setChipState(residualBtn, showResidualLabels); | |
| render(); | |
| }); | |
| const lineBtn = document.getElementById('toggleLineOnly'); | |
| lineBtn.addEventListener('click', () => { | |
| lineEmphasis = !lineEmphasis; | |
| setChipState(lineBtn, lineEmphasis); | |
| render(); | |
| }); | |
| document.getElementById('themeLight').addEventListener('click', () => applyTheme('light')); | |
| document.getElementById('themeDark').addEventListener('click', () => applyTheme('dark')); | |
| const savedTheme = localStorage.getItem('silverRegressionTheme'); | |
| if (savedTheme === 'dark' || savedTheme === 'light') { | |
| activeTheme = savedTheme; | |
| } | |
| document.body.dataset.theme = activeTheme; | |
| setChipState(document.getElementById('themeLight'), activeTheme === 'light'); | |
| setChipState(document.getElementById('themeDark'), activeTheme === 'dark'); | |
| const savedMode = localStorage.getItem('silverRegressionMode'); | |
| if (savedMode === 'mobile' || savedMode === 'desktop') { | |
| activeMode = savedMode; | |
| } | |
| document.body.dataset.mode = activeMode; | |
| setChipState(document.getElementById('modeDesktop'), activeMode === 'desktop'); | |
| setChipState(document.getElementById('modeMobile'), activeMode === 'mobile'); | |
| renderBenchmarkButtons(); | |
| renderBucketUI(); | |
| renderOrgUI(); | |
| updatePredictionPanel(); | |
| render(); | |
| </script> | |
| </body> | |
| </html> | |