qwen2vl-polygen / serving.py
ga11en's picture
serving panel: requests-per-GPU multiple to 3.7x (nearly 4x), T=2 cached
8402e8e verified
Raw
History Blame Contribute Delete
9.28 kB
"""Serving-economics panel for the Polygen x Qwen2-VL Space.
A self-contained HTML fragment (inline CSS, no JS, no external assets) rendered
into a Gradio gr.HTML block. The requests-per-GPU capacity bars play once whenever
the fragment is (re)rendered; `app.py` re-renders it on each "Run comparison" click
by passing a changing `data-run` nonce, so the animation replays on the user's
action rather than looping on its own.
The figures are measured: NVIDIA H200, Qwen2-VL-7B, vLLM continuous batching.
Source: `tools/runpod_results/results_serving_throughput_7B.json` (throughput, T=2,
cached visual tokens); storage from the SDK tier registry. This panel makes a
throughput and storage claim only -- no per-request latency / wall-clock claim.
"""
# ruff: noqa: E501 (self-contained HTML fragment; inline CSS lines do not wrap)
# `data-run="__NONCE__"` is replaced per render (not str.format, because the
# inline CSS is full of literal braces). A different nonce makes the gr.HTML
# value differ, so Gradio replaces the DOM and the play-once animation restarts.
_PANEL = """<div class="pg-serv" data-run="__NONCE__">
<style>
/* Datasent 2026 brand palette (matches docs/polygen_theme/custom.css):
Minsk purple primary, bright blue accent, lavender light shades, white page. */
.pg-serv { --bg:#ffffff; --card:#e6ebfc; --line:#c1cef7; --txt:#222222;
--muted:#4f4f7a; --base:#9aa0ad; --win:#3c3475; --winsoft:#4caaff;
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
color: var(--txt); background: var(--bg); padding: 22px 20px; border-radius: 14px;
border: 1px solid var(--line); max-width: 860px; margin: 0 auto; line-height: 1.5; }
.pg-serv h2 { margin: 0 0 2px; font-size: 1.35rem; font-weight: 800; letter-spacing: -0.01em; color: var(--win); }
.pg-serv .sub { color: var(--muted); margin: 0 0 18px; font-size: 0.95rem; }
.pg-serv .race { background: var(--card); border: 1px solid var(--line);
border-radius: 12px; padding: 16px 18px 18px; margin-bottom: 16px; }
.pg-serv .race h3 { margin: 0 0 12px; font-size: 0.82rem; text-transform: uppercase;
letter-spacing: 0.08em; color: var(--muted); font-weight: 600; }
.pg-serv .lane { display: grid; grid-template-columns: 88px 1fr 84px;
align-items: center; gap: 10px; margin: 9px 0; }
.pg-serv .lane .who { font-size: 0.9rem; font-weight: 600; }
.pg-serv .track { position: relative; height: 22px; background: #ffffff;
border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.pg-serv .fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 5px;
transform: scaleX(0); transform-origin: left; }
/* Capacity bars, not a time race: both fill over the SAME duration (one shared
per-GPU-second beat); the polygen bar reaches ~3.7x the baseline's width, so
it reads as more throughput per GPU, not an earlier finish. Plays ONCE per
render and holds (animation-fill-mode: forwards); app.py re-renders on each
Run comparison, which replays it. */
.pg-serv .fill.base { width: 26%; background: linear-gradient(90deg,#d2d5dc,var(--base));
animation: pg-grow 1.4s ease-out forwards; }
.pg-serv .fill.poly { width: 96%; background: linear-gradient(90deg,var(--winsoft),var(--win));
animation: pg-grow 1.4s ease-out forwards; }
@keyframes pg-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
.pg-serv .fill { transform: scaleX(1); animation: none; } }
.pg-serv .ms { font-variant-numeric: tabular-nums; font-size: 0.9rem; text-align: right; }
.pg-serv .ms.win { color: var(--win); font-weight: 700; }
.pg-serv .racecap { color: var(--muted); font-size: 0.84rem; margin: 10px 2px 0; }
.pg-serv .racecap b { color: var(--win); }
.pg-serv .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px,1fr));
gap: 10px; margin: 4px 0 14px; }
.pg-serv .card { background: var(--card); border: 1px solid var(--line);
border-radius: 11px; padding: 13px 14px; }
.pg-serv .card .big { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
.pg-serv .card .big.win { color: var(--win); }
.pg-serv .card .lab { font-size: 0.82rem; color: var(--txt); font-weight: 600; margin-top: 2px; }
.pg-serv .card .basis { font-size: 0.74rem; color: var(--muted); margin-top: 3px; }
.pg-serv .note { background: #f2f5fd; border: 1px solid var(--line); border-left: 3px solid var(--winsoft);
border-radius: 8px; padding: 11px 14px; font-size: 0.85rem; color: var(--muted); }
.pg-serv .note b { color: var(--txt); }
.pg-serv details.more { margin: 0 0 2px; }
.pg-serv details.more > summary { cursor: pointer; font-size: 0.85rem; font-weight: 700;
color: var(--win); padding: 2px 0; }
.pg-serv details.more > summary:hover { color: var(--winsoft); }
.pg-serv details.more .note { margin-top: 8px; }
.pg-serv .tiers { font-size: 0.82rem; color: var(--muted); margin: 0 2px 12px; }
.pg-serv .tiers b { color: var(--txt); }
/* The app's dark theme redefines --body-text-color and applies it via prose
rules that outrank this white-island panel's own colors; re-assert each
under .dark .pg-serv so the panel stays dark-text-on-light in dark mode. */
.dark .pg-serv { color: var(--txt) !important; }
.dark .pg-serv h2 { color: var(--win) !important; }
.dark .pg-serv .sub, .dark .pg-serv .race h3, .dark .pg-serv .racecap,
.dark .pg-serv .card .basis, .dark .pg-serv .tiers, .dark .pg-serv .note { color: var(--muted) !important; }
.dark .pg-serv .lane .who, .dark .pg-serv .ms, .dark .pg-serv .card .lab,
.dark .pg-serv .card .big, .dark .pg-serv .note b,
.dark .pg-serv .tiers b { color: var(--txt) !important; }
.dark .pg-serv .ms.win, .dark .pg-serv .card .big.win, .dark .pg-serv .racecap b,
.dark .pg-serv details.more > summary { color: var(--win) !important; }
</style>
<h2>Same answer. More requests per GPU.</h2>
<p class="sub">Polygen compresses Qwen2-VL's visual tokens before the language model reads them.
At the T=2 operating point (accuracy <b style="color:var(--win)">+7.4pp above baseline</b>,
a statistical tie with the best tier), the shorter visual sequence is a smaller KV cache and
less attention compute, so one GPU serves more concurrent requests.</p>
<div class="race">
<h3>Requests per GPU &nbsp;&middot;&nbsp; T=2 &nbsp;&middot;&nbsp; precomputed visual tokens</h3>
<div class="lane">
<span class="who">Baseline</span>
<span class="track"><span class="fill base"></span></span>
<span class="ms">1x</span>
</div>
<div class="lane">
<span class="who" style="color:var(--win)">Polygen</span>
<span class="track"><span class="fill poly"></span></span>
<span class="ms win">~3.7x</span>
</div>
<p class="racecap">Per GPU, polygen sustains about <b>3.7x (nearly 4x)</b> the requests per second,
so the same load runs on roughly a quarter of the GPUs. For precomputed / cached visual tokens
(retrieval, repeated queries) -- the pattern the RAG demo shows.</p>
</div>
<div class="grid">
<div class="card"><div class="big win">~3.7x</div><div class="lab">Requests per GPU</div>
<div class="basis">roughly a quarter the GPUs, T=2, cached</div></div>
<div class="card"><div class="big win">~5x</div><div class="lab">Smaller stored representation</div>
<div class="basis">visual-token cache</div></div>
<div class="card"><div class="big win">+7.4pp</div><div class="lab">Accuracy vs baseline</div>
<div class="basis">ScienceQA, T=2 (above baseline)</div></div>
</div>
<p class="tiers"><b>Tiers, chosen per workload.</b> T=3 is the accuracy peak (+8.4pp on ScienceQA);
T=2, shown here, is the compression peak (+7.4pp, a statistical tie) where the throughput gain is
largest; lower tiers trade accuracy for more compression.</p>
<details class="more"><summary>What this is</summary>
<p class="note">The gain is throughput and storage: a shorter visual sequence is a smaller KV cache
and less attention compute, so a GPU serves more concurrent requests and the cached representation
is smaller. Measured for precomputed / cached visual tokens (retrieval, repeated queries) under
vLLM continuous batching on an NVIDIA H200 with Qwen2-VL-7B.</p>
</details>
</div>"""
def render_serving_story(nonce: str = "0") -> str:
"""Return the serving-economics panel HTML fragment.
Args:
nonce: A value that varies per render so a Gradio `gr.HTML` update sees a
different string, replaces the DOM, and restarts the play-once bars.
Returns:
An HTML fragment (no doctype) suitable for a `gr.HTML` block.
"""
return _PANEL.replace("__NONCE__", str(nonce))
if __name__ == "__main__":
# Regenerate the standalone browser preview from this single source of truth.
with open("serving_story.html", "w", encoding="utf-8") as _fh:
_fh.write('<!doctype html>\n<meta charset="utf-8" />\n')
_fh.write(render_serving_story("preview"))
print("wrote serving_story.html")