robot-folding / app /src /content /embeds /folding /rabc-explainer.html
pepijn223's picture
pepijn223 HF Staff
Improve DAgger explainer, add conclusion and expand references
f0f3d44 unverified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
:root { --bg: transparent; --text: #e8eaf0; --subtext: #8b8fa8; --grid: rgba(255,255,255,0.08); }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: var(--bg); font-family: system-ui, sans-serif; color: var(--text); }
.controls {
display: flex; align-items: center; gap: 14px; justify-content: center;
margin: 0 0 4px; font-size: 14px; flex-wrap: wrap;
}
.controls label { color: var(--subtext); font-weight: 600; }
.controls input[type=range] {
width: 140px; accent-color: #6366f1; cursor: pointer;
}
.kval { color: #e8eaf0; font-weight: 700; min-width: 48px; }
.axis text { fill: #8b8fa8; font-size: 12px; }
.axis path, .axis line { stroke: rgba(255,255,255,0.15); }
.grid line { stroke: var(--grid); }
.grid path { stroke: none; }
.legend-row {
display: flex; gap: 16px; justify-content: center; font-size: 13px;
color: var(--subtext); margin-top: 6px; flex-wrap: wrap;
}
.legend-row span { display: flex; align-items: center; gap: 5px; }
.legend-swatch { width: 12px; height: 4px; border-radius: 2px; flex-shrink: 0; }
</style>
</head>
<body>
<div class="controls">
<label>κ threshold:</label>
<input type="range" id="kappa-slider" min="0" max="0.05" step="0.001" value="0.015"/>
<span class="kval" id="kappa-val">0.015</span>
</div>
<svg id="rabc-svg"></svg>
<div class="legend-row">
<span><span class="legend-swatch" style="background:#22d3ee"></span>SARM progress</span>
<span><span class="legend-swatch" style="background:#10b981"></span>Full weight (δ &gt; κ)</span>
<span><span class="legend-swatch" style="background:#eab308"></span>Soft weight (0 ≤ δ ≤ κ)</span>
<span><span class="legend-swatch" style="background:#ef4444"></span>Zero weight (δ &lt; 0)</span>
</div>
<script>
function _initRABC() {
// Simulated SARM progress for a realistic folding episode
const N = 120;
const progressRaw = [];
const seed = [
0,0.01,0.02,0.03,0.04,0.06,0.08,0.10,0.12,0.14,
0.16,0.18,0.20,0.22,0.24,0.26,0.28,0.28,0.27,0.26,
0.26,0.27,0.28,0.30,0.32,0.34,0.36,0.38,0.40,0.42,
0.44,0.45,0.45,0.45,0.44,0.44,0.45,0.46,0.48,0.50,
0.52,0.54,0.56,0.58,0.60,0.62,0.64,0.66,0.68,0.70,
0.72,0.73,0.74,0.74,0.73,0.72,0.71,0.70,0.70,0.71,
0.72,0.74,0.76,0.78,0.80,0.81,0.82,0.83,0.84,0.85,
0.85,0.85,0.86,0.86,0.87,0.88,0.89,0.90,0.91,0.92,
0.93,0.93,0.93,0.93,0.94,0.94,0.95,0.95,0.96,0.96,
0.96,0.97,0.97,0.97,0.98,0.98,0.98,0.98,0.99,0.99,
0.99,0.99,0.99,1.0,1.0,1.0,1.0,1.0,1.0,1.0,
1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0
];
for (let i = 0; i < N; i++) progressRaw.push(seed[i]);
const CHUNK = 5;
function computeDeltas(progress) {
const deltas = [];
for (let i = 0; i < progress.length; i++) {
const j = Math.min(i + CHUNK, progress.length - 1);
deltas.push(progress[j] - progress[i]);
}
return deltas;
}
function computeWeights(deltas, kappa) {
const posDeltas = deltas.filter(d => d >= 0);
let mu = posDeltas.length ? posDeltas.reduce((a,b)=>a+b,0)/posDeltas.length : 0;
mu = Math.max(mu, 0);
const variance = posDeltas.length > 1
? posDeltas.reduce((s,d)=>s+(d-mu)*(d-mu),0)/(posDeltas.length-1) : 0.0001;
const sigma = Math.sqrt(variance);
return deltas.map(d => {
if (d > kappa) return 1.0;
if (d < 0) return 0.0;
const lo = mu - 2*sigma, hi = mu + 2*sigma;
const range = hi - lo;
if (range < 0.0001) return d >= 0 ? 1 : 0;
return Math.max(0, Math.min(1, (d - lo) / range));
});
}
const container = document.getElementById("rabc-svg").parentElement;
const svg = d3.select("#rabc-svg");
function render() {
svg.selectAll("*").remove();
const kappa = parseFloat(document.getElementById("kappa-slider").value);
document.getElementById("kappa-val").textContent = kappa.toFixed(3);
const deltas = computeDeltas(progressRaw);
const weights = computeWeights(deltas, kappa);
const W = container.clientWidth || 700;
const margin = { top: 12, right: 16, bottom: 56, left: 46 };
const totalH = Math.max(260, Math.min(360, W * 0.42));
const progressH = totalH * 0.55;
const gap = 24;
const weightH = totalH - progressH - gap;
const H = totalH + margin.top + margin.bottom;
const w = W - margin.left - margin.right;
svg.attr("width", W).attr("height", H);
const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
const x = d3.scaleLinear().domain([0, N-1]).range([0, w]);
const yP = d3.scaleLinear().domain([0, 1]).range([progressH, 0]);
const yW = d3.scaleLinear().domain([0, 1]).range([weightH, 0]);
const wG = g.append("g").attr("transform", `translate(0,${progressH + gap})`);
// Progress grid + axis
g.append("g").attr("class","grid")
.call(d3.axisLeft(yP).ticks(4).tickSize(-w).tickFormat(""));
g.append("g").attr("class","axis")
.call(d3.axisLeft(yP).ticks(4).tickFormat(d3.format(".1f")));
g.append("text").attr("x",-progressH/2).attr("y",-36).attr("transform","rotate(-90)")
.attr("text-anchor","middle").attr("fill","#8b8fa8").attr("font-size",12).text("SARM progress");
// Weight grid + axis
wG.append("g").attr("class","grid")
.call(d3.axisLeft(yW).ticks(3).tickSize(-w).tickFormat(""));
wG.append("g").attr("class","axis")
.call(d3.axisLeft(yW).ticks(3).tickFormat(d3.format(".1f")));
wG.append("text").attr("x",-weightH/2).attr("y",-36).attr("transform","rotate(-90)")
.attr("text-anchor","middle").attr("fill","#8b8fa8").attr("font-size",12).text("Training weight");
// Shared x axis
wG.append("g").attr("class","axis").attr("transform",`translate(0,${weightH})`)
.call(d3.axisBottom(x).ticks(6).tickFormat(d => d + ""));
wG.append("text").attr("x",w/2).attr("y",weightH+30).attr("text-anchor","middle")
.attr("fill","#8b8fa8").attr("font-size",12).text("Timestep");
// Color weight bars
const barW = Math.max(1, w / N - 0.5);
weights.forEach((wt, i) => {
const delta = deltas[i];
let col;
if (delta < 0) col = "#ef4444";
else if (delta > kappa) col = "#10b981";
else col = "#eab308";
wG.append("rect")
.attr("x", x(i) - barW/2).attr("y", yW(wt))
.attr("width", barW).attr("height", Math.max(0, weightH - yW(wt)))
.attr("fill", col).attr("opacity", 0.8);
});
// Progress curve background shading
for (let i = 0; i < N - 1; i++) {
const delta = deltas[i];
let col;
if (delta < 0) col = "#ef4444";
else if (delta > kappa) col = "#10b981";
else col = "#eab308";
g.append("rect")
.attr("x", x(i)).attr("y", 0)
.attr("width", Math.max(1, x(i+1) - x(i))).attr("height", progressH)
.attr("fill", col).attr("opacity", 0.07);
}
// Progress line
const line = d3.line().x((d,i) => x(i)).y(d => yP(d)).curve(d3.curveMonotoneX);
g.append("path").datum(progressRaw)
.attr("fill","none").attr("stroke","#22d3ee").attr("stroke-width",2.5).attr("opacity",0.9)
.attr("d", line);
}
render();
document.getElementById("kappa-slider").addEventListener("input", render);
window.addEventListener("resize", render);
}
if (typeof d3 !== "undefined") { _initRABC(); }
else { var s = document.createElement("script"); s.src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"; s.onload=_initRABC; document.head.appendChild(s); }
</script>
</body>
</html>