Skip to content

Commit 96f2745

Browse files
authored
Merge pull request #4 from RAGEN-AI/claude/hello-rdvrtf
Make the LAGEN page easier to skim
2 parents d4a0629 + 466d573 commit 96f2745

19 files changed

Lines changed: 216 additions & 87 deletions

‎src/lagen/components/CalibrationFigure.astro‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import palette from '../data/paper-palette.json';
44
import FigureReadout from './FigureReadout.astro';
55
const methods = [['fixed', 'Fixed'], ['normal', 'Normal'], ['iid', 'IID'], ['temporal', 'Temporal']];
66
const models = [['qwenoft', 'OpenVLA'], ['qwengr00t', 'GR00T']];
7-
const taskNames: Record<string, string> = { flappy: 'Flappy Bird', inverted_pendulum: 'Inverted Pendulum', mikasa_intercept_grab_fast: 'InterceptGrabFast' };
7+
const taskNames: Record<string, string> = { flappy: 'Flappy Bird', inverted_pendulum: 'Inverted Pendulum', mikasa_intercept_grab_fast: 'Intercept Grab (Fast)' };
88
const taskColors: Record<string, string> = { flappy: palette.gray, inverted_pendulum: palette.coral, mikasa_intercept_grab_fast: palette.peach };
99
const gpuNames: Record<string, string> = { rtx3090: 'RTX 3090', rtx4090: 'RTX 4090', rtx5090: 'RTX 5090', l40s: 'L40S', a100: 'A100' };
1010
const markers: Record<string, string> = {
@@ -71,7 +71,7 @@ const panels = models.map(([model, modelName]) => ({ model, modelName, methods:
7171
</template>;
7272
})))}
7373
<FigureReadout id="calibration-figure" />
74-
<figcaption>Both axes show return relative to the same zero-latency baseline (100%). The diagonal marks equal simulated and measured returns. Sim − real shows their difference in percentage points.</figcaption>
74+
<figcaption>Both axes show the return relative to the same baseline without latency (100%). On the diagonal line, the simulated return is equal to the measured return. “Sim − real” is the difference in percentage points.</figcaption>
7575
</figure>
7676
<style>
7777
.calibration-row { margin-top: 28px; }

‎src/lagen/components/Contents.astro‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@
22
<nav aria-label="Page contents">
33
<ul>
44
<li>
5-
<a href="#demo">Demo</a>
5+
<a href="#demo">The problem</a>
66
<ul>
7-
<li><a href="#failure-demo">Example: latency in action</a></li>
7+
<li><a href="#failure-demo">Demo</a></li>
88
<li><a href="#problem">Failure analysis</a></li>
99
</ul>
1010
</li>
11-
<li><a href="#results">Results</a></li>
11+
<li><a href="#results">Train with latency</a></li>
1212
<li>
1313
<a href="#method">Method</a>
1414
<ul>
1515
<li>
1616
<a href="#profiling">Profiling</a>
1717
<ul>
18-
<li><a href="#calibration">Sim2real calibration</a></li>
19-
<li><a href="#latency-bursts">Latency bursts</a></li>
18+
<li><a href="#latency-bursts">Slow-request groups</a></li>
19+
<li><a href="#calibration">Simulation check</a></li>
2020
</ul>
2121
</li>
2222
<li><a href="#pipeline">Pipeline</a></li>
2323
</ul>
2424
</li>
2525
<li>
26-
<a href="#findings">Experiments</a>
26+
<a href="#findings">Three questions</a>
2727
<ul>
2828
<li><a href="#training">Mean vs. profile</a></li>
2929
<li><a href="#transfer">Latency transfer</a></li>

‎src/lagen/components/CrossTaskFigure.astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ const x = (value: number) => plot.left + (value + .2) / 4.4 * plot.width;
4949
<dl>{[panel.zero, panel.mixed].map((values, i) => <><dt><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="4" fill={colors[i]} /></svg>{labels[i]}</dt><dd>{values[column]}</dd></>)}</dl>
5050
</template>))}
5151
<FigureReadout id="cross-task-figure" />
52-
<figcaption>Both policies train on Demon Attack. Each point shows mean return over 20 episodes. Returns use each task’s native scale.</figcaption>
52+
<figcaption>We train both policies on Demon Attack. Each point shows the mean return over 20 episodes. Each task uses its own return scale.</figcaption>
5353
</figure>

‎src/lagen/components/DegradationFigure.astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const inset = { left: 172, top: 54, width: 82, height: 62 };
8282
<div class="tooltip-values"></div>
8383
</div>
8484
<div class="chart-sr-only" data-chart-announcement aria-live="polite" aria-atomic="true"></div>
85-
<figcaption>Each point uses a fixed action delay. The game plots show mean return. InterceptGrabFast shows success rate over 200 episodes.</figcaption>
85+
<figcaption>Each point shows one fixed action delay. For the games, the plots show the mean return. For Intercept Grab (Fast), the plot shows the success rate over 200 episodes. The small plots show the delays above zero at a larger scale.</figcaption>
8686
</figure>
8787
<script>
8888
import '../scripts/degradation';

‎src/lagen/components/FailureDemo.astro‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const next = demos[1];
88
---
99
<section class="demo-section" id="failure-demo" aria-labelledby="demo-title">
1010
<div class="section-width demo-heading">
11-
<h2 id="demo-title">Timing changes the outcome</h2>
12-
<p>Both runs start from the same state and replay the same actions. Use the slider to delay the actions on the right.</p>
11+
<h2 id="demo-title">A small delay makes the same actions fail</h2>
12+
<p>Both videos start from the same state and use the same actions. The right video applies each action later, as on a real GPU. Move the slider to change the delay.</p>
1313
</div>
1414
<div class="demo-carousel" data-demo>
1515
<div class="demo-toolbar section-width">

‎src/lagen/components/HistoryFigure.astro‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const methods = [
1313
const asset = (name: string) => '/lagen/' + 'assets/history/' + name;
1414
const frame = (i: number) => asset('frame_0' + i + '.png');
1515
const y = (value: number) => 286 - (value - 50) / 100 * 240;
16-
const ghostTrailNAReason = 'Ghost trail is not suitable for first-person shooters such as Deadly Corridor, so this condition was not evaluated.';
16+
const ghostTrailNAReason = 'The ghost trail is not suitable for first-person games such as Deadly Corridor. Thus, we did not evaluate this condition.';
1717
---
1818
<figure id="history-figure" data-linked-figure aria-label="Visual-history mechanisms linked to results on three tasks">
1919
<div class="history-layout">
@@ -55,7 +55,7 @@ const ghostTrailNAReason = 'Ghost trail is not suitable for first-person shooter
5555
<div class="history-panels">
5656
{panels.map((panel, task) => <section class="history-panel">
5757
<h5>{panel.task}</h5>
58-
<p class="history-delay">{panel.delay} frames of delay</p>
58+
<p class="history-delay">Delay: {panel.delay} frames</p>
5959
<svg viewBox="0 0 340 310" aria-label={panel.task + ' mean returns and 95% confidence intervals'} data-choice-group data-roving>
6060
{[50,75,100,125,150].map(value => <g>
6161
<line x1="48" x2="334" y1={y(value)} y2={y(value)} class={value === 100 ? 'linked-reference' : 'linked-grid'} stroke-dasharray={value === 100 ? '4 4' : undefined} />
@@ -83,7 +83,7 @@ const ghostTrailNAReason = 'Ghost trail is not suitable for first-person shooter
8383
{cell ? <dl><dt>Return</dt><dd>{cell.mean.toFixed(2)}%</dd><dt>95% interval</dt><dd>{cell.low.toFixed(2)}–{cell.high.toFixed(2)}%</dd><dt>Episodes</dt><dd>{cell.episodes}</dd><dt>Delay</dt><dd>{panel.delay} raw frames</dd></dl> : <p>{ghostTrailNAReason}</p>}
8484
</template>))}
8585
<LinkedReadout id="history-figure" />
86-
<figcaption>100% marks the single-frame baseline at the same delay. Delays are three frames on Flappy Bird and six on Demon Attack and Deadly Corridor. Error bars show episode-level 95% intervals from one training run. OpenVLA uses 100 evaluation episodes per condition, and WanOFT uses 20. Ghost trail was not evaluated on Deadly Corridor.</figcaption>
86+
<figcaption>100% is the return with a single-frame input at the same delay. The delay is three frames on Flappy Bird and six frames on Demon Attack and Deadly Corridor. Error bars show 95% intervals over episodes from one training run. OpenVLA uses 100 evaluation episodes for each condition. WanOFT uses 20. We did not evaluate the ghost trail on Deadly Corridor.</figcaption>
8787
</figure>
8888
<script>
8989
const figure = document.querySelector<HTMLElement>('#history-figure')!;

‎src/lagen/components/LatencyApproachesFigure.astro‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ const approaches = [
44
key: 'execution',
55
title: 'Reduce latency',
66
description: 'Two inference-duration bars share one start: the shorter blue bar finishes earlier than the gray bar, with a left-pointing arrow showing the saved time. Action execution shows two equal eight-action chunks on two rows of a shared time axis. The lower chunk starts four steps later. During its two-step inference delay, the upper chunk continues executing the rose prefix. The lower hatched cells retain that prefix. A downward arrow marks the switch to the new actions when inference finishes; the unused upper tail is hollow.',
7-
caption: 'Accelerate inference. Predict new actions while executing the current ones.',
7+
caption: 'Make inference faster. Predict new actions while the agent does the current actions.',
88
},
99
{
1010
key: 'training',
1111
title: 'Train with latency (ours)',
1212
description: 'The same aligned inference-duration bars and two asynchronous action chunks are preserved. Their filled regions and the saved-time and handoff arrows use 40 percent opacity. Node borders, module connections and labels remain fully opaque. The upper chunk supplies committed actions while the lower chunk is computed, then execution switches to the lower row. The purple deployment profile supplies delays during simulated training, not an input to Policy.',
13-
caption: 'Reproduce deployment latency in simulation. Train agents to act under these delays.',
13+
caption: 'Use the deployment latency in simulation. Train agents to act with this latency.',
1414
},
1515
];
1616
---
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
// Secondary figures stay open on wide screens and start collapsed on phones.
3+
interface Props {
4+
summary: string;
5+
}
6+
const { summary } = Astro.props;
7+
---
8+
<details class="mobile-collapse" open>
9+
<summary>{summary}</summary>
10+
<slot />
11+
</details>
12+
<script>
13+
const query = window.matchMedia('(max-width: 700px)');
14+
const sync = () => document.querySelectorAll<HTMLDetailsElement>('.mobile-collapse').forEach(details => { details.open = !query.matches; });
15+
sync();
16+
query.addEventListener('change', sync);
17+
</script>
Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,110 @@
11
---
2+
import palette from '../data/paper-palette.json';
23
const src = '/lagen/' + 'assets/figures/framework.png';
4+
// Schematic Temporal profile: mostly fast requests with persistent slow periods.
5+
const profile = [3, 3.4, 3, 3.2, 12, 12, 12, 12, 3.4, 3, 3.3, 2.9, 3.2, 12, 12, 12, 3, 3.3];
6+
const profilePath = profile.map((value, i) => `${i ? 'L' : 'M'}${6 + i * 11},${46 - value * 3}`).join('');
7+
const steps = [
8+
{
9+
key: 'profile',
10+
title: 'Measure the deployment',
11+
text: 'Measure the latency for the target GPU, model, and task. Fit a profile that also shows groups of slow requests.',
12+
},
13+
{
14+
key: 'teacher',
15+
title: 'Train a teacher with simulated latency',
16+
text: 'In simulation, each action starts after a latency from the profile. An RL teacher learns to act with this latency.',
17+
},
18+
{
19+
key: 'distill',
20+
title: 'Teach the VLA',
21+
text: 'Fine-tune the VLA on the actions of the teacher. DAgger is optional.',
22+
},
23+
{
24+
key: 'deploy',
25+
title: 'Act with the same latency',
26+
text: 'The VLA receives the task, the latency as text, and optional recent frames.',
27+
},
28+
];
329
---
430
<figure id="pipeline-figure" class="paper-figure">
5-
<div class="pipeline-image" tabindex="0" role="region" aria-label="Original paper pipeline figure">
6-
<img src={src} width="3988" height="1771" loading="lazy" alt="LAGEN pipeline from the paper: profile deployment timing using Fixed, Normal, IID or Temporal generators; train a latency teacher through fresh reinforcement-learning interactions; distill teacher demonstrations into a VLA with optional DAgger; deploy the VLA with delayed-action execution." />
7-
</div>
8-
<figcaption>The agent interacts with the simulator under delays sampled from the latency profile. ActionReady marks when a predicted action becomes available. The curves show schematic latency profiles.</figcaption>
31+
<ol class="pipeline-steps">
32+
{steps.map((step, i) => (
33+
<li class="pipeline-step">
34+
<div class="pipeline-visual" aria-hidden="true">
35+
{step.key === 'profile' && (
36+
<svg viewBox="0 0 200 56">
37+
<path d="M4 4V50H198" fill="none" stroke={palette.gray} stroke-width="1" />
38+
<path d={profilePath} fill="none" stroke={palette.purple} stroke-width="2" stroke-linejoin="round" />
39+
{profile.map((value, j) => <circle cx={6 + j * 11} cy={46 - value * 3} r="2.2" fill={palette.purple} />)}
40+
</svg>
41+
)}
42+
{step.key === 'teacher' && (
43+
<svg viewBox="0 0 200 56">
44+
<path d="M8 26H192" stroke={palette.gray} stroke-width="1.2" />
45+
<path d="M186 22l6 4-6 4" fill="none" stroke={palette.gray} stroke-width="1.2" />
46+
<circle cx="22" cy="26" r="5" fill="white" stroke={palette.blue} stroke-width="2" />
47+
<circle cx="150" cy="26" r="5" fill={palette.blue} />
48+
<text x="22" y="12" text-anchor="middle">observe</text>
49+
<text x="150" y="12" text-anchor="middle">act</text>
50+
<path d="M22 42H150M22 38v8M150 38v8" fill="none" stroke={palette.rose} stroke-width="1.5" />
51+
<text x="86" y="54" text-anchor="middle" class="accent">sampled delay</text>
52+
</svg>
53+
)}
54+
{step.key === 'distill' && (
55+
<svg viewBox="0 0 200 56">
56+
<rect x="4" y="12" width="52" height="30" rx="6" fill="#f6e9ec" stroke={palette.rose} />
57+
<text x="30" y="31" text-anchor="middle">Teacher</text>
58+
<path d="M60 27H76m-5-4 5 4-5 4" fill="none" stroke={palette.gray} stroke-width="1.3" />
59+
<rect x="80" y="12" width="46" height="30" rx="6" fill="white" stroke={palette.gray} />
60+
<text x="103" y="31" text-anchor="middle">Labels</text>
61+
<path d="M130 27H146m-5-4 5 4-5 4" fill="none" stroke={palette.gray} stroke-width="1.3" />
62+
<rect x="150" y="12" width="46" height="30" rx="6" fill="#eceff3" stroke={palette.blue} />
63+
<text x="173" y="31" text-anchor="middle">VLA</text>
64+
</svg>
65+
)}
66+
{step.key === 'deploy' && (
67+
<div class="pipeline-chips">
68+
<span>Task</span><span class="accent">Latency: 150 ms.</span><span>Visual history</span>
69+
</div>
70+
)}
71+
</div>
72+
<h4><span class="pipeline-number">{i + 1}</span>{step.title}</h4>
73+
<p>{step.text}</p>
74+
</li>
75+
))}
76+
</ol>
77+
<figcaption>We use the same latency profile for training and for evaluation.</figcaption>
78+
<details class="pipeline-original">
79+
<summary>Full pipeline figure from the paper</summary>
80+
<a href={src} target="_blank" rel="noopener" class="pipeline-image" aria-label="Open the full-resolution pipeline figure in a new tab">
81+
<img src={src} width="3988" height="1771" loading="lazy" alt="LAGEN pipeline from the paper: profile deployment timing using Fixed, Normal, IID or Temporal generators; train a latency teacher through fresh reinforcement-learning interactions; distill teacher demonstrations into a VLA with optional DAgger; deploy the VLA with delayed-action execution." />
82+
</a>
83+
<p class="figure-note">Select the figure to open it at full size. ActionReady shows the time when a predicted action is available. The curves show example latency profiles.</p>
84+
</details>
985
</figure>
1086
<style>
11-
.pipeline-image { overflow-x: auto; }
12-
.pipeline-image img { display: block; width: 100%; min-width: 1100px; max-width: none; height: auto; }
87+
.pipeline-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; counter-reset: none; }
88+
.pipeline-step { position: relative; display: flex; flex-direction: column; padding: 18px; border: 1px solid var(--rule); border-radius: 12px; background: white; }
89+
.pipeline-step:not(:last-child)::after { content: '→'; position: absolute; top: 44px; right: -15px; z-index: 1; width: 14px; text-align: center; color: var(--muted); font-size: 18px; }
90+
.pipeline-visual { height: 64px; display: flex; align-items: center; margin-bottom: 14px; }
91+
.pipeline-visual svg { width: 100%; height: 100%; overflow: visible; }
92+
.pipeline-visual text { font-size: 12px; fill: var(--ink); font-family: inherit; }
93+
.pipeline-visual text.accent { fill: var(--rose); font-weight: 600; }
94+
.pipeline-chips { display: flex; flex-wrap: wrap; gap: 6px; }
95+
.pipeline-chips span { padding: 3px 9px; border: 1px solid var(--rule); border-radius: 999px; font-size: 14px; background: var(--paper); }
96+
.pipeline-chips .accent { border-color: var(--rose); color: var(--rose); background: #fbf2f4; font-weight: 600; }
97+
.pipeline-step h4 { display: flex; align-items: baseline; gap: 8px; font-size: 18px; font-weight: 650; line-height: 1.35; margin: 0 0 8px; }
98+
.pipeline-number { flex: none; display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; background: var(--purple); color: white; font-size: 14px; font-weight: 700; }
99+
.pipeline-step p { margin: 0; font-size: 16px; line-height: 1.6; color: var(--muted); }
100+
.pipeline-image { display: block; overflow-x: auto; cursor: zoom-in; }
101+
.pipeline-image img { display: block; width: 100%; min-width: 900px; height: auto; }
102+
@container (max-width: 960px) {
103+
.pipeline-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
104+
.pipeline-step:nth-child(2)::after { display: none; }
105+
}
106+
@container (max-width: 560px) {
107+
.pipeline-steps { grid-template-columns: minmax(0, 1fr); gap: 22px; }
108+
.pipeline-step:not(:last-child)::after { content: '↓'; top: auto; bottom: -21px; right: auto; left: 50%; transform: translateX(-50%); display: block; }
109+
}
13110
</style>

‎src/lagen/components/ProfilesFigure.astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const outline = bins.map(({ edge, index }) => `${x(Math.max(45, edge))},${y(data
4949
<dl>{methods.map((method, column) => <><dt>{method.name}</dt><dd>{data.counts[column][index].toLocaleString('en-US')}</dd></>)}</dl>
5050
</template>)}
5151
<LinkedReadout id="profiles-figure" />
52-
<figcaption>Measured latency and sequences generated by four fitted models. Select a latency range to highlight matching requests across all five sequences. The displayed range is 45–100 ms. Distributions use the full sequences.</figcaption>
52+
<figcaption>The measured latency, and sequences from four fitted models. Select a latency range to highlight the matching requests in all five sequences. The plots show the range 45–100 ms. The distributions use the full sequences.</figcaption>
5353
</figure>
5454
<script>import '../scripts/profiles';</script>
5555
<style>

0 commit comments

Comments
 (0)