Spaces:
Building on CPU Upgrade
Building on CPU Upgrade
Commit Β·
f838d6f
1
Parent(s): 663cec5
make verbosity analysis take data from rephrasing_metadata.json instead
Browse files
app/src/content/chapters/analyses.mdx
CHANGED
|
@@ -75,5 +75,6 @@ Different prompt formats produce wildly different output lengths. <FigRef target
|
|
| 75 |
<HtmlEmbed
|
| 76 |
id="verbosity"
|
| 77 |
src="verbosity.html"
|
|
|
|
| 78 |
desc="Output tokens per document across prompt types and model families. Hover over dots to see detailed statistics for each experiment."
|
| 79 |
/>
|
|
|
|
| 75 |
<HtmlEmbed
|
| 76 |
id="verbosity"
|
| 77 |
src="verbosity.html"
|
| 78 |
+
data="rephrasing_metadata.json"
|
| 79 |
desc="Output tokens per document across prompt types and model families. Hover over dots to see detailed statistics for each experiment."
|
| 80 |
/>
|
app/src/content/embeds/verbosity.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
<div class="d3-
|
| 2 |
<script>
|
| 3 |
(() => {
|
| 4 |
const ensureD3 = (cb) => {
|
|
@@ -16,487 +16,470 @@
|
|
| 16 |
};
|
| 17 |
|
| 18 |
const bootstrap = () => {
|
| 19 |
-
const
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
container.dataset.mounted = 'true';
|
| 26 |
}
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
//
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
['
|
| 37 |
-
['
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
['Format','FAQ','Gemma-3 1B','FW-Edu HQ',17.67,22.21,20.1,0.711,0.929,0.218,-0.346,3.416,3.762],
|
| 45 |
-
['Format','FAQ','Gemma-3 1B','FW-Edu LQ',1.84,1.75,32.9,0.690,0.719,0.029,0.369,1.275,0.905],
|
| 46 |
-
['Format','FAQ','Falcon3 1B','FW-Edu HQ',3.41,4.84,20.1,0.691,0.909,0.217,-0.249,3.512,3.762],
|
| 47 |
-
['Format','FAQ','Granite3 1B','FW-Edu HQ',2.55,4.17,20.1,0.680,0.898,0.218,-0.166,3.596,3.762],
|
| 48 |
-
['Format','FAQ','Llama-3.2 1B','FW-Edu HQ',6.29,11.62,20.1,0.735,0.952,0.217,-0.375,3.387,3.762],
|
| 49 |
-
['Format','FAQ','Qwen3 1.7B','FW-Edu HQ',2.88,4.77,20.1,0.632,0.850,0.218,-0.219,3.543,3.762],
|
| 50 |
-
['Format','FAQ','SmolLM2 1.7B','FW-Edu HQ',0.89,2.00,20.1,0.648,0.867,0.219,-0.406,3.355,3.762],
|
| 51 |
-
['Format','Math','Gemma-3 12B','FW-Edu HQ',2.51,5.93,20.1,0.755,0.972,0.217,-0.370,3.392,3.762],
|
| 52 |
-
['Format','Math','Gemma-3 1B','FW-Edu HQ',2.46,5.08,20.1,0.620,0.838,0.218,-0.174,3.587,3.762],
|
| 53 |
-
['Format','Math','Gemma-3 270M','FW-Edu HQ',1.21,1.33,20.1,0.600,0.818,0.218,-0.406,3.357,3.762],
|
| 54 |
-
['Format','Math','Gemma-3 27B','FW-Edu HQ',1.05,2.62,20.1,0.754,0.971,0.217,-0.429,3.333,3.762],
|
| 55 |
-
['Format','Math','Gemma-3 4B','FW-Edu HQ',0.68,1.75,20.1,0.743,0.960,0.217,-0.335,3.427,3.762],
|
| 56 |
-
['Format','Math','Falcon3 1B','FW-Edu HQ',1.42,2.17,20.1,0.704,0.921,0.217,-0.156,3.606,3.762],
|
| 57 |
-
['Format','Math','Granite3 1B','FW-Edu HQ',1.57,3.35,20.1,0.698,0.916,0.218,-0.324,3.438,3.762],
|
| 58 |
-
['Format','Math','Llama-3.2 1B','FW-Edu HQ',0.86,2.17,20.1,0.737,0.955,0.218,-0.384,3.378,3.762],
|
| 59 |
-
['Format','Math','Qwen3 1.7B','FW-Edu HQ',0.56,2.00,20.1,0.742,0.959,0.218,-0.310,3.452,3.762],
|
| 60 |
-
['Format','Math','SmolLM2 1.7B','FW-Edu HQ',0.64,2.28,20.1,0.657,0.875,0.218,-0.669,3.093,3.762],
|
| 61 |
-
['Format','Table','Gemma-3 12B','FW-Edu HQ',0.76,2.49,20.1,0.719,0.937,0.217,-0.774,2.988,3.762],
|
| 62 |
-
['Format','Table','Gemma-3 1B','FW-Edu HQ',1.68,5.62,20.1,0.715,0.932,0.217,-0.776,2.985,3.762],
|
| 63 |
-
['Format','Table','Falcon3 1B','FW-Edu HQ',0.65,2.00,20.1,0.722,0.940,0.218,-0.748,3.015,3.763],
|
| 64 |
-
['Format','Table','Granite3 1B','FW-Edu HQ',1.44,3.90,20.1,0.726,0.944,0.218,-0.597,3.165,3.762],
|
| 65 |
-
['Format','Table','Llama-3.2 1B','FW-Edu HQ',0.88,2.73,20.1,0.772,0.989,0.217,-0.815,2.947,3.762],
|
| 66 |
-
['Format','Table','Qwen3 1.7B','FW-Edu HQ',0.80,2.69,20.1,0.751,0.969,0.218,-0.638,3.123,3.762],
|
| 67 |
-
['Format','Table','SmolLM2 1.7B','FW-Edu HQ',0.41,1.52,20.1,0.668,0.885,0.218,-0.943,2.818,3.762],
|
| 68 |
-
['Format','Tutorial','Gemma-3 12B','FW-Edu HQ',5.33,6.57,20.1,0.398,0.553,0.155,-0.077,2.612,2.667],
|
| 69 |
-
['Format','Tutorial','Gemma-3 12B','FW-Edu LQ',2.35,2.57,32.9,0.189,0.210,0.020,0.379,0.869,0.613],
|
| 70 |
-
['Format','Tutorial','Gemma-3 1B','Cosmopedia',1.02,1.47,31.1,-0.049,0.529,0.578,-0.080,2.415,2.495],
|
| 71 |
-
['Format','Tutorial','Gemma-3 1B','DCLM',1.67,3.30,29.5,0.371,0.514,0.142,0.528,2.113,1.585],
|
| 72 |
-
['Format','Tutorial','Gemma-3 1B','FW-Edu HQ',1.51,2.70,19.4,0.074,0.112,0.038,-0.077,0.632,0.646],
|
| 73 |
-
['Format','Tutorial','Gemma-3 1B','FW-Edu LQ',1.90,2.51,32.9,0.172,0.193,0.021,0.413,0.917,0.630],
|
| 74 |
-
['Format','Tutorial','Gemma-3 270M','FW-Edu HQ',1.64,1.71,20.1,0.514,0.731,0.217,-0.337,3.425,3.762],
|
| 75 |
-
['Format','Tutorial','Gemma-3 27B','FW-Edu HQ',2.55,3.29,20.1,0.485,0.702,0.218,-0.057,3.705,3.762],
|
| 76 |
-
['Format','Tutorial','Gemma-3 4B','FW-Edu HQ',1.50,2.02,20.1,0.404,0.621,0.217,-0.049,3.713,3.762],
|
| 77 |
-
['Format','Tutorial','Falcon3 1B','FW-Edu HQ',4.97,7.58,20.1,0.447,0.665,0.218,-0.145,3.617,3.762],
|
| 78 |
-
['Format','Tutorial','Granite3 1B','FW-Edu HQ',3.51,6.42,20.1,0.449,0.666,0.218,-0.072,3.690,3.762],
|
| 79 |
-
['Format','Tutorial','Llama-3.2 1B','FW-Edu HQ',2.36,4.88,20.1,0.557,0.774,0.217,-0.031,3.731,3.762],
|
| 80 |
-
['Format','Tutorial','Qwen1.5 1.8B','FW-Edu HQ',2.22,2.40,20.1,0.647,0.864,0.218,0.072,3.834,3.762],
|
| 81 |
-
['Format','Tutorial','Qwen2 1.5B','FW-Edu HQ',3.09,8.00,20.1,0.527,0.746,0.218,-0.010,3.751,3.762],
|
| 82 |
-
['Format','Tutorial','Qwen2.5 1.5B','FW-Edu HQ',2.27,4.87,20.1,0.576,0.794,0.218,-0.083,3.678,3.762],
|
| 83 |
-
['Format','Tutorial','Qwen3 1.7B','FW-Edu HQ',3.56,5.69,20.1,0.281,0.497,0.217,0.056,3.818,3.762],
|
| 84 |
-
['Format','Tutorial','SmolLM2 1.7B','FW-Edu HQ',1.52,3.38,20.1,0.439,0.658,0.219,-0.244,3.518,3.762],
|
| 85 |
-
['Nemotron','Distill','Gemma-3 1B','FW-Edu HQ',2.12,5.37,20.1,0.331,0.549,0.217,-0.132,3.629,3.762],
|
| 86 |
-
['Nemotron','Diverse QA','Gemma-3 1B','FW-Edu HQ',1.97,7.01,20.1,0.779,0.996,0.217,-0.208,3.554,3.762],
|
| 87 |
-
['Nemotron','Extract Knowledge','Gemma-3 1B','FW-Edu HQ',2.41,6.59,20.1,0.254,0.472,0.218,0.025,3.787,3.762],
|
| 88 |
-
['Nemotron','Knowledge List','Gemma-3 1B','FW-Edu HQ',2.90,9.15,20.1,0.589,0.806,0.217,-0.193,3.569,3.762],
|
| 89 |
-
['Nemotron','Wikipedia Style','Gemma-3 1B','FW-Edu HQ',3.43,8.37,20.1,0.297,0.515,0.217,-0.193,3.568,3.762],
|
| 90 |
-
['REWIRE','Guided Rewrite+','Gemma-3 12B','FW-Edu HQ',1.45,2.14,20.1,0.222,0.439,0.217,-0.102,3.660,3.762],
|
| 91 |
-
['REWIRE','Guided Rewrite+','Gemma-3 1B','FW-Edu HQ',1.63,3.42,20.1,0.097,0.315,0.217,-0.428,3.334,3.762],
|
| 92 |
-
['REWIRE','Guided Rewrite','Gemma-3 12B','FW-Edu HQ',1.78,1.72,20.1,0.607,0.824,0.217,-1.214,2.547,3.762],
|
| 93 |
-
['REWIRE','Guided Rewrite','Gemma-3 1B','FW-Edu HQ',8.69,10.30,20.1,0.278,0.495,0.217,-1.012,2.750,3.762],
|
| 94 |
-
['REWIRE','Guided Rewrite','Gemma-3 270M','FW-Edu HQ',0.78,1.71,20.1,0.755,0.972,0.217,-2.407,1.355,3.762],
|
| 95 |
-
['REWIRE','Guided Rewrite','Gemma-3 4B','FW-Edu HQ',0.91,1.10,20.1,0.436,0.654,0.218,-0.919,2.843,3.762],
|
| 96 |
-
['REWIRE','Guided Rewrite','Gemma-3 27B','FW-Edu HQ',8.43,8.64,19.95,0.546,0.763,0.217,-1.228,2.533,3.762],
|
| 97 |
-
['Format','Tutorial','SmolLM2 135M','FW-Edu HQ',4.51,6.99,20.1,0.423,0.641,0.218,-0.572,3.190,3.762],
|
| 98 |
-
['Format','Tutorial','SmolLM2 360M','FW-Edu HQ',3.14,6.52,20.1,0.441,0.659,0.218,-0.565,3.197,3.762]
|
| 99 |
-
];
|
| 100 |
-
|
| 101 |
-
const experiments = raw.map((r, i) => ({
|
| 102 |
-
idx: i, cat: r[0], prompt: r[1], model: r[2], source: r[3],
|
| 103 |
-
compTokens: r[4], promptTokens: r[5], numDocs: r[6],
|
| 104 |
-
dclmDiff: r[7], outDclm: r[8], inDclm: r[9],
|
| 105 |
-
eduDiff: r[10], outEdu: r[11], inEdu: r[12],
|
| 106 |
-
compPerDoc: r[4] * 1000 / r[6],
|
| 107 |
-
phase: Math.random() * Math.PI * 2
|
| 108 |
-
}));
|
| 109 |
-
|
| 110 |
-
// ββββββββββββββββββββββββββββββββββββββββββββββββββββοΏ½οΏ½οΏ½ββββββ
|
| 111 |
-
// MODEL FAMILIES
|
| 112 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 113 |
-
const getFamily = (m) => {
|
| 114 |
-
if (m.includes('SmolLM')) return 'SmolLM2';
|
| 115 |
-
if (m.includes('Gemma')) return 'Gemma';
|
| 116 |
-
if (m.includes('Qwen')) return 'Qwen';
|
| 117 |
-
if (m.includes('Falcon')) return 'Falcon';
|
| 118 |
-
if (m.includes('Granite')) return 'Granite';
|
| 119 |
-
if (m.includes('Llama')) return 'Llama';
|
| 120 |
-
return 'Other';
|
| 121 |
-
};
|
| 122 |
-
const familyColors = {
|
| 123 |
-
'Gemma': '#4EA5B7',
|
| 124 |
-
'Qwen': '#8B7BE8',
|
| 125 |
-
'SmolLM2': '#E8C44A',
|
| 126 |
-
'Falcon': '#E889AB',
|
| 127 |
-
'Granite': '#5BC0A4',
|
| 128 |
-
'Llama': '#D09090',
|
| 129 |
};
|
| 130 |
-
const familyOrder = ['Gemma','Qwen','SmolLM2','Falcon','Granite','Llama'];
|
| 131 |
-
experiments.forEach(d => { d.family = getFamily(d.model); });
|
| 132 |
-
|
| 133 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 134 |
-
// FILTER: Only prompts tested across 6 model families
|
| 135 |
-
// (keep multi-source Gemma variants for Tutorial/FAQ)
|
| 136 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 137 |
-
const focusPrompts = ['Math', 'Table', 'FAQ', 'Tutorial'];
|
| 138 |
-
const filtered = experiments.filter(d => focusPrompts.includes(d.prompt));
|
| 139 |
-
|
| 140 |
-
// Sort rows by median compPerDoc (most verbose on top)
|
| 141 |
-
const promptStats = {};
|
| 142 |
-
focusPrompts.forEach(p => {
|
| 143 |
-
const vals = filtered.filter(d => d.prompt === p).map(d => d.compPerDoc).sort((a,b) => a - b);
|
| 144 |
-
const mid = Math.floor(vals.length / 2);
|
| 145 |
-
promptStats[p] = {
|
| 146 |
-
median: vals.length % 2 ? vals[mid] : (vals[mid-1] + vals[mid]) / 2,
|
| 147 |
-
count: vals.length
|
| 148 |
-
};
|
| 149 |
-
});
|
| 150 |
-
const sortedPrompts = [...focusPrompts].sort((a, b) => promptStats[b].median - promptStats[a].median);
|
| 151 |
-
|
| 152 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 153 |
-
// TOOLTIP
|
| 154 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 155 |
-
const fmtB = (v) => v >= 10 ? v.toFixed(0) + 'B' : v.toFixed(1) + 'B';
|
| 156 |
-
const fmtSign = (v, p) => (v >= 0 ? '+' : '') + v.toFixed(p || 3);
|
| 157 |
-
const dCol = (v) => v >= 0 ? '#5BC0A4' : '#E889AB';
|
| 158 |
-
const buildTip = (d) =>
|
| 159 |
-
`<div style="font-weight:800;font-size:13px;">${d.prompt}</div>` +
|
| 160 |
-
`<div style="font-size:11px;color:var(--muted-color);margin-top:-2px;margin-bottom:4px;">` +
|
| 161 |
-
`<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:${familyColors[d.family]};margin-right:4px;vertical-align:middle;"></span>` +
|
| 162 |
-
`${d.model} \u00b7 ${d.source}</div>` +
|
| 163 |
-
`<div style="padding-top:5px;border-top:1px solid var(--border-color);display:grid;grid-template-columns:auto 1fr;gap:2px 8px;font-size:11.5px;">` +
|
| 164 |
-
`<span style="color:var(--muted-color);">Total output</span><span>${fmtB(d.compTokens)}</span>` +
|
| 165 |
-
`<span style="color:var(--muted-color);">Output/doc</span><span>${Math.round(d.compPerDoc)} tokens</span>` +
|
| 166 |
-
`<span style="color:var(--muted-color);">Docs</span><span>${d.numDocs.toFixed(1)}M</span>` +
|
| 167 |
-
`</div>` +
|
| 168 |
-
`<div style="margin-top:5px;padding-top:5px;border-top:1px solid var(--border-color);display:grid;grid-template-columns:auto 1fr;gap:2px 8px;font-size:11.5px;">` +
|
| 169 |
-
`<span style="color:var(--muted-color);">DCLM</span>` +
|
| 170 |
-
`<span>${d.inDclm.toFixed(3)} \u2192 ${d.outDclm.toFixed(3)} <b style="color:${dCol(d.dclmDiff)};">${fmtSign(d.dclmDiff)}</b></span>` +
|
| 171 |
-
`<span style="color:var(--muted-color);">Edu</span>` +
|
| 172 |
-
`<span>${d.inEdu.toFixed(2)} \u2192 ${d.outEdu.toFixed(2)} <b style="color:${dCol(d.eduDiff)};">${fmtSign(d.eduDiff, 2)}</b></span>` +
|
| 173 |
-
`</div>`;
|
| 174 |
-
|
| 175 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 176 |
-
// SVG
|
| 177 |
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 178 |
-
const svg = d3.select(container).append('svg')
|
| 179 |
-
.attr('width', '100%')
|
| 180 |
-
.style('display', 'block')
|
| 181 |
-
.style('cursor', 'crosshair');
|
| 182 |
-
|
| 183 |
-
let animFrame = null;
|
| 184 |
-
|
| 185 |
-
const render = () => {
|
| 186 |
-
const width = container.clientWidth || 800;
|
| 187 |
-
const height = Math.max(260, Math.round(width / 3));
|
| 188 |
-
svg.attr('width', width).attr('height', height);
|
| 189 |
-
|
| 190 |
-
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
| 191 |
-
const textColor = isDark ? 'rgba(255,255,255,0.72)' : 'rgba(0,0,0,0.62)';
|
| 192 |
-
const mutedText = isDark ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.18)';
|
| 193 |
-
const subtleText = isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)';
|
| 194 |
-
const refLine = isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.07)';
|
| 195 |
-
const bandEven = isDark ? 'rgba(255,255,255,0.022)' : 'rgba(0,0,0,0.018)';
|
| 196 |
-
const glowColor = isDark ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.25)';
|
| 197 |
-
const smolHighlight = isDark ? 'rgba(232,196,74,0.18)' : 'rgba(232,196,74,0.12)';
|
| 198 |
-
|
| 199 |
-
const fontSize = Math.max(8, Math.min(12, width / 80));
|
| 200 |
-
|
| 201 |
-
// βββ LAYOUT βββ
|
| 202 |
-
const labelW = Math.max(68, width * 0.085);
|
| 203 |
-
const pl = labelW + 12;
|
| 204 |
-
const pr = width * 0.965;
|
| 205 |
-
const pt = height * 0.20;
|
| 206 |
-
const pb = height * 0.86;
|
| 207 |
-
const plotH = pb - pt;
|
| 208 |
-
const rowH = plotH / sortedPrompts.length;
|
| 209 |
-
|
| 210 |
-
const rowCenter = {};
|
| 211 |
-
sortedPrompts.forEach((p, i) => { rowCenter[p] = pt + (i + 0.5) * rowH; });
|
| 212 |
-
|
| 213 |
-
// βββ X SCALE: completion tokens per document (log) βββ
|
| 214 |
-
const xScale = d3.scaleLog().base(10)
|
| 215 |
-
.domain([15, 1000])
|
| 216 |
-
.range([pl, pr]);
|
| 217 |
-
|
| 218 |
-
const rBase = Math.max(3.5, Math.min(8, width * 0.007));
|
| 219 |
-
|
| 220 |
-
// βββ FORCE SIMULATION βββ
|
| 221 |
-
filtered.forEach(d => {
|
| 222 |
-
d.tx = xScale(Math.max(15, d.compPerDoc));
|
| 223 |
-
d.ty = rowCenter[d.prompt];
|
| 224 |
-
d.x = d.tx + (Math.random() - 0.5) * 6;
|
| 225 |
-
d.y = d.ty + (Math.random() - 0.5) * rowH * 0.3;
|
| 226 |
-
});
|
| 227 |
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
.force('collide', d3.forceCollide(rBase + 1.5).iterations(5))
|
| 232 |
-
.stop();
|
| 233 |
-
for (let i = 0; i < 250; i++) sim.tick();
|
| 234 |
-
|
| 235 |
-
filtered.forEach(d => {
|
| 236 |
-
d.x = Math.max(pl + rBase, Math.min(pr - rBase, d.x));
|
| 237 |
-
const yMin = rowCenter[d.prompt] - rowH * 0.46;
|
| 238 |
-
const yMax = rowCenter[d.prompt] + rowH * 0.46;
|
| 239 |
-
d.y = Math.max(yMin, Math.min(yMax, d.y));
|
| 240 |
-
});
|
| 241 |
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
|
| 263 |
-
|
| 264 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
|
|
|
| 278 |
|
| 279 |
-
//
|
| 280 |
-
const
|
| 281 |
-
|
| 282 |
-
const
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
}
|
| 288 |
|
| 289 |
-
//
|
| 290 |
-
gRows.
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 320 |
-
.
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 329 |
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
.attr('font-size', (fontSize * 0.72) + 'px')
|
| 336 |
-
.attr('font-weight', '600')
|
| 337 |
-
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 338 |
-
.text('Output tokens / document \u2192');
|
| 339 |
-
|
| 340 |
-
// "Less verbose" / "More verbose" labels
|
| 341 |
-
gRef.append('text')
|
| 342 |
-
.attr('x', pl + 6).attr('y', pt - 5)
|
| 343 |
-
.attr('text-anchor', 'start')
|
| 344 |
-
.attr('fill', subtleText)
|
| 345 |
-
.attr('font-size', (fontSize * 0.62) + 'px')
|
| 346 |
-
.attr('font-style', 'italic')
|
| 347 |
-
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 348 |
-
.text('\u2190 concise');
|
| 349 |
-
|
| 350 |
-
gRef.append('text')
|
| 351 |
-
.attr('x', pr - 6).attr('y', pt - 5)
|
| 352 |
-
.attr('text-anchor', 'end')
|
| 353 |
-
.attr('fill', subtleText)
|
| 354 |
-
.attr('font-size', (fontSize * 0.62) + 'px')
|
| 355 |
-
.attr('font-style', 'italic')
|
| 356 |
-
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 357 |
-
.text('verbose \u2192');
|
| 358 |
-
|
| 359 |
-
// βββ MODEL FAMILY LEGEND βββ
|
| 360 |
-
const gLeg = svg.selectAll('g.legend').data([0]).join('g').attr('class', 'legend');
|
| 361 |
-
gLeg.selectAll('*').remove();
|
| 362 |
-
const legDotR = Math.max(3, fontSize * 0.35);
|
| 363 |
-
const legGap = Math.max(68, width * 0.082);
|
| 364 |
-
const totalLegW = familyOrder.length * legGap;
|
| 365 |
-
const legStartX = Math.max(pl, (width - totalLegW) / 2);
|
| 366 |
-
const legY = height * 0.055;
|
| 367 |
-
|
| 368 |
-
familyOrder.forEach((fam, i) => {
|
| 369 |
-
const lx = legStartX + i * legGap;
|
| 370 |
-
gLeg.append('circle')
|
| 371 |
-
.attr('cx', lx).attr('cy', legY)
|
| 372 |
-
.attr('r', legDotR)
|
| 373 |
-
.attr('fill', familyColors[fam]).attr('fill-opacity', 0.85);
|
| 374 |
-
gLeg.append('text')
|
| 375 |
-
.attr('x', lx + legDotR + 4).attr('y', legY)
|
| 376 |
-
.attr('dominant-baseline', 'central')
|
| 377 |
-
.attr('fill', isDark ? 'rgba(255,255,255,0.48)' : 'rgba(0,0,0,0.42)')
|
| 378 |
.attr('font-size', (fontSize * 0.72) + 'px')
|
| 379 |
-
.attr('font-weight',
|
| 380 |
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 381 |
-
.text(
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 383 |
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 410 |
});
|
| 411 |
-
tip.appendChild(tipInner);
|
| 412 |
-
container.appendChild(tip);
|
| 413 |
-
} else {
|
| 414 |
-
tipInner = tip.querySelector('.d3-tooltip__inner') || tip;
|
| 415 |
-
}
|
| 416 |
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
.
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
.
|
| 448 |
-
|
| 449 |
-
.style('filter', null)
|
| 450 |
-
.transition().duration(90).ease(d3.easeCubicOut)
|
| 451 |
-
.attr('r', rBase);
|
| 452 |
-
tip.style.opacity = '0';
|
| 453 |
-
tip.style.transform = 'translate(-9999px, -9999px)';
|
| 454 |
-
};
|
| 455 |
|
| 456 |
-
|
| 457 |
-
.join(
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
.
|
| 463 |
-
.attr('
|
| 464 |
-
|
| 465 |
-
.
|
| 466 |
-
.
|
| 467 |
-
.
|
| 468 |
-
.
|
| 469 |
-
|
| 470 |
-
.attr('
|
| 471 |
-
|
| 472 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
.attr('fill-opacity', 0.82)
|
| 474 |
-
.attr('stroke',
|
| 475 |
-
|
| 476 |
-
.
|
| 477 |
-
.
|
| 478 |
-
.
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
};
|
| 491 |
-
breathe();
|
| 492 |
-
};
|
| 493 |
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
|
|
|
|
|
|
| 498 |
}
|
| 499 |
-
render();
|
| 500 |
};
|
| 501 |
|
| 502 |
if (document.readyState === 'loading') {
|
|
|
|
| 1 |
+
<div class="d3-verbosity" style="width:100%;margin:10px 0;aspect-ratio:3/1;min-height:260px;"></div>
|
| 2 |
<script>
|
| 3 |
(() => {
|
| 4 |
const ensureD3 = (cb) => {
|
|
|
|
| 16 |
};
|
| 17 |
|
| 18 |
const bootstrap = () => {
|
| 19 |
+
const scriptEl = document.currentScript;
|
| 20 |
+
let container = scriptEl ? scriptEl.previousElementSibling : null;
|
| 21 |
+
if (!(container && container.classList && container.classList.contains('d3-verbosity'))) {
|
| 22 |
+
const cs = Array.from(document.querySelectorAll('.d3-verbosity'))
|
| 23 |
+
.filter(el => !(el.dataset && el.dataset.mounted === 'true'));
|
| 24 |
+
container = cs[cs.length - 1] || null;
|
|
|
|
| 25 |
}
|
| 26 |
+
if (!container) return;
|
| 27 |
+
if (container.dataset.mounted === 'true') return;
|
| 28 |
+
container.dataset.mounted = 'true';
|
| 29 |
+
|
| 30 |
+
// Read data path from HtmlEmbed attribute
|
| 31 |
+
let mountEl = container;
|
| 32 |
+
while (mountEl && !mountEl.getAttribute?.('data-datafiles')) mountEl = mountEl.parentElement;
|
| 33 |
+
const dataAttr = mountEl?.getAttribute?.('data-datafiles');
|
| 34 |
+
const dataPaths = dataAttr
|
| 35 |
+
? [dataAttr.includes('/') ? dataAttr : `/data/${dataAttr}`]
|
| 36 |
+
: ['/data/rephrasing_metadata.json', './assets/data/rephrasing_metadata.json'];
|
| 37 |
+
|
| 38 |
+
const fetchFirst = async (paths) => {
|
| 39 |
+
for (const p of paths) {
|
| 40 |
+
try { const r = await fetch(p, { cache: 'no-cache' }); if (r.ok) return r.json(); } catch(_) {}
|
| 41 |
+
}
|
| 42 |
+
throw new Error('Data not found');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
+
fetchFirst(dataPaths).then(data => buildChart(data)).catch(err => {
|
| 46 |
+
container.innerHTML = `<pre style="color:red;padding:12px;">Error loading data: ${err.message}</pre>`;
|
| 47 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
+
function buildChart(rawData) {
|
| 50 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 51 |
+
// PARSE JSON into chart-ready objects
|
| 52 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 53 |
+
const SOURCE_MAP = {
|
| 54 |
+
'fineweb-edu-hq-20BT': 'FW-Edu HQ',
|
| 55 |
+
'fineweb-edu-lq-20BT': 'FW-Edu LQ',
|
| 56 |
+
'dclm-37BT': 'DCLM',
|
| 57 |
+
'cosmopedia-25BT': 'Cosmopedia'
|
| 58 |
+
};
|
| 59 |
+
const PROMPT_LABELS = {
|
| 60 |
+
'article': 'Article', 'commentary': 'Commentary', 'discussion': 'Discussion',
|
| 61 |
+
'faq': 'FAQ', 'math': 'Math', 'table': 'Table', 'tutorial': 'Tutorial',
|
| 62 |
+
'distill': 'Distill', 'diverse_qa_pairs': 'Diverse QA',
|
| 63 |
+
'extract_knowledge': 'Extract Knowledge', 'knowledge_list': 'Knowledge List',
|
| 64 |
+
'wikipedia_style_rephrasing': 'Wikipedia Style',
|
| 65 |
+
'guided_rewrite_improved': 'Guided Rewrite+',
|
| 66 |
+
'guided_rewrite_original': 'Guided Rewrite'
|
| 67 |
+
};
|
| 68 |
+
const CAT_MAP = { 'format': 'Format', 'nemotron': 'Nemotron', 'rewire': 'REWIRE' };
|
| 69 |
+
|
| 70 |
+
const getFamily = (m) => {
|
| 71 |
+
const ml = m.toLowerCase();
|
| 72 |
+
if (ml.includes('smollm')) return 'SmolLM2';
|
| 73 |
+
if (ml.includes('gemma')) return 'Gemma';
|
| 74 |
+
if (ml.includes('qwen')) return 'Qwen';
|
| 75 |
+
if (ml.includes('falcon')) return 'Falcon';
|
| 76 |
+
if (ml.includes('granite')) return 'Granite';
|
| 77 |
+
if (ml.includes('llama')) return 'Llama';
|
| 78 |
+
return 'Other';
|
| 79 |
+
};
|
| 80 |
|
| 81 |
+
const experiments = rawData.map((d, i) => {
|
| 82 |
+
const [cat, promptFile] = d.prompt.split('/');
|
| 83 |
+
const promptKey = promptFile.replace('.md', '');
|
| 84 |
+
return {
|
| 85 |
+
idx: i,
|
| 86 |
+
cat: CAT_MAP[cat] || cat,
|
| 87 |
+
prompt: PROMPT_LABELS[promptKey] || promptKey,
|
| 88 |
+
model: d.model.split('/').pop(),
|
| 89 |
+
source: SOURCE_MAP[d.source_dataset] || d.source_dataset,
|
| 90 |
+
family: getFamily(d.model),
|
| 91 |
+
compTokens: d.output_tokens / 1e9,
|
| 92 |
+
promptTokens: d.input_tokens / 1e9,
|
| 93 |
+
numDocs: d.num_documents / 1e6,
|
| 94 |
+
dclmDiff: d.dclm_score_difference,
|
| 95 |
+
outDclm: d.output_dclm_score,
|
| 96 |
+
inDclm: d.input_dclm_score,
|
| 97 |
+
eduDiff: d.edu_score_difference,
|
| 98 |
+
outEdu: d.output_edu_score,
|
| 99 |
+
inEdu: d.input_edu_score,
|
| 100 |
+
compPerDoc: d.output_token_count_mean,
|
| 101 |
+
phase: Math.random() * Math.PI * 2
|
| 102 |
+
};
|
| 103 |
+
});
|
| 104 |
|
| 105 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 106 |
+
// MODEL FAMILIES
|
| 107 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 108 |
+
const familyColors = {
|
| 109 |
+
'Gemma': '#4EA5B7',
|
| 110 |
+
'Qwen': '#8B7BE8',
|
| 111 |
+
'SmolLM2': '#E8C44A',
|
| 112 |
+
'Falcon': '#E889AB',
|
| 113 |
+
'Granite': '#5BC0A4',
|
| 114 |
+
'Llama': '#D09090',
|
| 115 |
+
};
|
| 116 |
+
const familyOrder = ['Gemma','Qwen','SmolLM2','Falcon','Granite','Llama'];
|
| 117 |
+
|
| 118 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 119 |
+
// FILTER: Only prompts tested across multiple model families
|
| 120 |
+
// βββββοΏ½οΏ½βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 121 |
+
const focusPrompts = ['Math', 'Table', 'FAQ', 'Tutorial'];
|
| 122 |
+
const filtered = experiments.filter(d => focusPrompts.includes(d.prompt));
|
| 123 |
+
|
| 124 |
+
// Sort rows by median compPerDoc (most verbose on top)
|
| 125 |
+
const promptStats = {};
|
| 126 |
+
focusPrompts.forEach(p => {
|
| 127 |
+
const vals = filtered.filter(d => d.prompt === p).map(d => d.compPerDoc).sort((a,b) => a - b);
|
| 128 |
+
const mid = Math.floor(vals.length / 2);
|
| 129 |
+
promptStats[p] = {
|
| 130 |
+
median: vals.length % 2 ? vals[mid] : (vals[mid-1] + vals[mid]) / 2,
|
| 131 |
+
count: vals.length
|
| 132 |
+
};
|
| 133 |
+
});
|
| 134 |
+
const sortedPrompts = [...focusPrompts].sort((a, b) => promptStats[b].median - promptStats[a].median);
|
| 135 |
+
|
| 136 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 137 |
+
// TOOLTIP
|
| 138 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 139 |
+
const fmtB = (v) => v >= 10 ? v.toFixed(0) + 'B' : v.toFixed(1) + 'B';
|
| 140 |
+
const fmtSign = (v, p) => (v >= 0 ? '+' : '') + v.toFixed(p || 3);
|
| 141 |
+
const dCol = (v) => v >= 0 ? '#5BC0A4' : '#E889AB';
|
| 142 |
+
const buildTip = (d) =>
|
| 143 |
+
`<div style="font-weight:800;font-size:13px;">${d.prompt}</div>` +
|
| 144 |
+
`<div style="font-size:11px;color:var(--muted-color);margin-top:-2px;margin-bottom:4px;">` +
|
| 145 |
+
`<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:${familyColors[d.family]};margin-right:4px;vertical-align:middle;"></span>` +
|
| 146 |
+
`${d.model} \u00b7 ${d.source}</div>` +
|
| 147 |
+
`<div style="padding-top:5px;border-top:1px solid var(--border-color);display:grid;grid-template-columns:auto 1fr;gap:2px 8px;font-size:11.5px;">` +
|
| 148 |
+
`<span style="color:var(--muted-color);">Total output</span><span>${fmtB(d.compTokens)}</span>` +
|
| 149 |
+
`<span style="color:var(--muted-color);">Output/doc</span><span>${Math.round(d.compPerDoc)} tokens</span>` +
|
| 150 |
+
`<span style="color:var(--muted-color);">Docs</span><span>${d.numDocs.toFixed(1)}M</span>` +
|
| 151 |
+
`</div>` +
|
| 152 |
+
`<div style="margin-top:5px;padding-top:5px;border-top:1px solid var(--border-color);display:grid;grid-template-columns:auto 1fr;gap:2px 8px;font-size:11.5px;">` +
|
| 153 |
+
`<span style="color:var(--muted-color);">DCLM</span>` +
|
| 154 |
+
`<span>${d.inDclm.toFixed(3)} \u2192 ${d.outDclm.toFixed(3)} <b style="color:${dCol(d.dclmDiff)};">${fmtSign(d.dclmDiff)}</b></span>` +
|
| 155 |
+
`<span style="color:var(--muted-color);">Edu</span>` +
|
| 156 |
+
`<span>${d.inEdu.toFixed(2)} \u2192 ${d.outEdu.toFixed(2)} <b style="color:${dCol(d.eduDiff)};">${fmtSign(d.eduDiff, 2)}</b></span>` +
|
| 157 |
+
`</div>`;
|
| 158 |
+
|
| 159 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 160 |
+
// SVG
|
| 161 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 162 |
+
const svg = d3.select(container).append('svg')
|
| 163 |
+
.attr('width', '100%')
|
| 164 |
+
.style('display', 'block')
|
| 165 |
+
.style('cursor', 'crosshair');
|
| 166 |
+
|
| 167 |
+
let animFrame = null;
|
| 168 |
+
|
| 169 |
+
const render = () => {
|
| 170 |
+
const width = container.clientWidth || 800;
|
| 171 |
+
const height = Math.max(260, Math.round(width / 3));
|
| 172 |
+
svg.attr('width', width).attr('height', height);
|
| 173 |
+
|
| 174 |
+
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
| 175 |
+
const textColor = isDark ? 'rgba(255,255,255,0.72)' : 'rgba(0,0,0,0.62)';
|
| 176 |
+
const mutedText = isDark ? 'rgba(255,255,255,0.22)' : 'rgba(0,0,0,0.18)';
|
| 177 |
+
const subtleText = isDark ? 'rgba(255,255,255,0.12)' : 'rgba(0,0,0,0.08)';
|
| 178 |
+
const refLine = isDark ? 'rgba(255,255,255,0.10)' : 'rgba(0,0,0,0.07)';
|
| 179 |
+
const bandEven = isDark ? 'rgba(255,255,255,0.022)' : 'rgba(0,0,0,0.018)';
|
| 180 |
+
const glowColor = isDark ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.25)';
|
| 181 |
+
const smolHighlight = isDark ? 'rgba(232,196,74,0.18)' : 'rgba(232,196,74,0.12)';
|
| 182 |
+
|
| 183 |
+
const fontSize = Math.max(8, Math.min(12, width / 80));
|
| 184 |
+
|
| 185 |
+
// βββ LAYOUT βββ
|
| 186 |
+
const labelW = Math.max(68, width * 0.085);
|
| 187 |
+
const pl = labelW + 12;
|
| 188 |
+
const pr = width * 0.965;
|
| 189 |
+
const pt = height * 0.20;
|
| 190 |
+
const pb = height * 0.86;
|
| 191 |
+
const plotH = pb - pt;
|
| 192 |
+
const rowH = plotH / sortedPrompts.length;
|
| 193 |
+
|
| 194 |
+
const rowCenter = {};
|
| 195 |
+
sortedPrompts.forEach((p, i) => { rowCenter[p] = pt + (i + 0.5) * rowH; });
|
| 196 |
+
|
| 197 |
+
// βββ X SCALE: completion tokens per document (log) βββ
|
| 198 |
+
const xScale = d3.scaleLog().base(10)
|
| 199 |
+
.domain([15, 1000])
|
| 200 |
+
.range([pl, pr]);
|
| 201 |
+
|
| 202 |
+
const rBase = Math.max(3.5, Math.min(8, width * 0.007));
|
| 203 |
+
|
| 204 |
+
// βββ FORCE SIMULATION βββ
|
| 205 |
+
filtered.forEach(d => {
|
| 206 |
+
d.tx = xScale(Math.max(15, d.compPerDoc));
|
| 207 |
+
d.ty = rowCenter[d.prompt];
|
| 208 |
+
d.x = d.tx + (Math.random() - 0.5) * 6;
|
| 209 |
+
d.y = d.ty + (Math.random() - 0.5) * rowH * 0.3;
|
| 210 |
+
});
|
| 211 |
|
| 212 |
+
const sim = d3.forceSimulation(filtered)
|
| 213 |
+
.force('x', d3.forceX(d => d.tx).strength(0.72))
|
| 214 |
+
.force('y', d3.forceY(d => d.ty).strength(0.55))
|
| 215 |
+
.force('collide', d3.forceCollide(rBase + 1.5).iterations(5))
|
| 216 |
+
.stop();
|
| 217 |
+
for (let i = 0; i < 250; i++) sim.tick();
|
| 218 |
+
|
| 219 |
+
filtered.forEach(d => {
|
| 220 |
+
d.x = Math.max(pl + rBase, Math.min(pr - rBase, d.x));
|
| 221 |
+
const yMin = rowCenter[d.prompt] - rowH * 0.46;
|
| 222 |
+
const yMax = rowCenter[d.prompt] + rowH * 0.46;
|
| 223 |
+
d.y = Math.max(yMin, Math.min(yMax, d.y));
|
| 224 |
+
});
|
| 225 |
|
| 226 |
+
// βββ BG STARS βββ
|
| 227 |
+
const bgCol = (() => {
|
| 228 |
+
const i01 = d3.interpolateRgb(d3.rgb(78,165,183), d3.rgb(206,192,250));
|
| 229 |
+
const i12 = d3.interpolateRgb(d3.rgb(206,192,250), d3.rgb(232,137,171));
|
| 230 |
+
return (v) => { const t = Math.max(0, Math.min(1, v)); return t <= 0.5 ? i01(t / 0.5) : i12((t - 0.5) / 0.5); };
|
| 231 |
+
})();
|
| 232 |
+
const gBg = svg.selectAll('g.bg').data([0]).join('g').attr('class', 'bg');
|
| 233 |
+
if (!gBg.selectAll('circle').size()) {
|
| 234 |
+
const stars = d3.range(50).map(() => ({
|
| 235 |
+
x: Math.random() * width, y: Math.random() * height,
|
| 236 |
+
z: Math.random(), r: 0.3 + Math.random() * 0.6
|
| 237 |
+
}));
|
| 238 |
+
gBg.selectAll('circle').data(stars).join('circle')
|
| 239 |
+
.attr('cx', d => d.x).attr('cy', d => d.y).attr('r', d => d.r)
|
| 240 |
+
.attr('fill', d => bgCol(d.z)).attr('fill-opacity', d => 0.03 + d.z * 0.04);
|
| 241 |
}
|
| 242 |
|
| 243 |
+
// βββ ROW BANDS & LABELS βββ
|
| 244 |
+
const gRows = svg.selectAll('g.rows').data([0]).join('g').attr('class', 'rows');
|
| 245 |
+
gRows.selectAll('*').remove();
|
| 246 |
+
|
| 247 |
+
sortedPrompts.forEach((p, i) => {
|
| 248 |
+
const y = rowCenter[p];
|
| 249 |
+
|
| 250 |
+
if (i % 2 === 0) {
|
| 251 |
+
gRows.append('rect')
|
| 252 |
+
.attr('x', pl - 6).attr('y', y - rowH / 2)
|
| 253 |
+
.attr('width', pr - pl + 12).attr('height', rowH)
|
| 254 |
+
.attr('fill', bandEven).attr('rx', 4);
|
| 255 |
+
}
|
| 256 |
+
if (i > 0) {
|
| 257 |
+
gRows.append('line')
|
| 258 |
+
.attr('x1', pl - 2).attr('x2', pr + 2)
|
| 259 |
+
.attr('y1', y - rowH / 2).attr('y2', y - rowH / 2)
|
| 260 |
+
.attr('stroke', refLine).attr('stroke-width', 0.5);
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
// SmolLM2 highlight zone
|
| 264 |
+
const smolExp = filtered.filter(d => d.prompt === p && d.family === 'SmolLM2');
|
| 265 |
+
if (smolExp.length) {
|
| 266 |
+
const smolX = smolExp[0].x;
|
| 267 |
+
gRows.append('rect')
|
| 268 |
+
.attr('x', smolX - rBase * 2.5).attr('y', y - rowH * 0.42)
|
| 269 |
+
.attr('width', rBase * 5).attr('height', rowH * 0.84)
|
| 270 |
+
.attr('fill', smolHighlight).attr('rx', rBase * 2);
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
// Label
|
| 274 |
+
gRows.append('text')
|
| 275 |
+
.attr('x', pl - 10).attr('y', y)
|
| 276 |
+
.attr('text-anchor', 'end')
|
| 277 |
+
.attr('dominant-baseline', 'central')
|
| 278 |
+
.attr('fill', textColor)
|
| 279 |
+
.attr('font-size', fontSize + 'px')
|
| 280 |
+
.attr('font-weight', '700')
|
| 281 |
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 282 |
+
.attr('letter-spacing', '-0.2px')
|
| 283 |
+
.text(p);
|
| 284 |
+
});
|
| 285 |
+
|
| 286 |
+
// βββ X AXIS TICKS βββ
|
| 287 |
+
const gRef = svg.selectAll('g.ref').data([0]).join('g').attr('class', 'ref');
|
| 288 |
+
gRef.selectAll('*').remove();
|
| 289 |
+
|
| 290 |
+
[20, 50, 100, 200, 500].forEach(v => {
|
| 291 |
+
const x = xScale(v);
|
| 292 |
+
if (x > pl && x < pr) {
|
| 293 |
+
gRef.append('line')
|
| 294 |
+
.attr('x1', x).attr('x2', x)
|
| 295 |
+
.attr('y1', pb).attr('y2', pb + 3)
|
| 296 |
+
.attr('stroke', mutedText).attr('stroke-width', 0.7);
|
| 297 |
+
gRef.append('text')
|
| 298 |
+
.attr('x', x).attr('y', pb + 5)
|
| 299 |
+
.attr('text-anchor', 'middle')
|
| 300 |
+
.attr('dominant-baseline', 'hanging')
|
| 301 |
+
.attr('fill', mutedText)
|
| 302 |
+
.attr('font-size', (fontSize * 0.65) + 'px')
|
| 303 |
+
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 304 |
+
.text(v);
|
| 305 |
+
gRef.append('line')
|
| 306 |
+
.attr('x1', x).attr('x2', x)
|
| 307 |
+
.attr('y1', pt).attr('y2', pb)
|
| 308 |
+
.attr('stroke', subtleText).attr('stroke-width', 0.4)
|
| 309 |
+
.attr('stroke-dasharray', '2,6');
|
| 310 |
+
}
|
| 311 |
+
});
|
| 312 |
|
| 313 |
+
// Axis label
|
| 314 |
+
gRef.append('text')
|
| 315 |
+
.attr('x', pr).attr('y', pb + 16)
|
| 316 |
+
.attr('text-anchor', 'end')
|
| 317 |
+
.attr('fill', mutedText)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
.attr('font-size', (fontSize * 0.72) + 'px')
|
| 319 |
+
.attr('font-weight', '600')
|
| 320 |
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 321 |
+
.text('Output tokens / document \u2192');
|
| 322 |
+
|
| 323 |
+
// "concise" / "verbose" labels
|
| 324 |
+
gRef.append('text')
|
| 325 |
+
.attr('x', pl + 6).attr('y', pt - 5)
|
| 326 |
+
.attr('text-anchor', 'start')
|
| 327 |
+
.attr('fill', subtleText)
|
| 328 |
+
.attr('font-size', (fontSize * 0.62) + 'px')
|
| 329 |
+
.attr('font-style', 'italic')
|
| 330 |
+
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 331 |
+
.text('\u2190 concise');
|
| 332 |
|
| 333 |
+
gRef.append('text')
|
| 334 |
+
.attr('x', pr - 6).attr('y', pt - 5)
|
| 335 |
+
.attr('text-anchor', 'end')
|
| 336 |
+
.attr('fill', subtleText)
|
| 337 |
+
.attr('font-size', (fontSize * 0.62) + 'px')
|
| 338 |
+
.attr('font-style', 'italic')
|
| 339 |
+
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 340 |
+
.text('verbose \u2192');
|
| 341 |
+
|
| 342 |
+
// βββ MODEL FAMILY LEGEND βββ
|
| 343 |
+
const gLeg = svg.selectAll('g.legend').data([0]).join('g').attr('class', 'legend');
|
| 344 |
+
gLeg.selectAll('*').remove();
|
| 345 |
+
const legDotR = Math.max(3, fontSize * 0.35);
|
| 346 |
+
const legGap = Math.max(68, width * 0.082);
|
| 347 |
+
const totalLegW = familyOrder.length * legGap;
|
| 348 |
+
const legStartX = Math.max(pl, (width - totalLegW) / 2);
|
| 349 |
+
const legY = height * 0.055;
|
| 350 |
+
|
| 351 |
+
familyOrder.forEach((fam, i) => {
|
| 352 |
+
const lx = legStartX + i * legGap;
|
| 353 |
+
gLeg.append('circle')
|
| 354 |
+
.attr('cx', lx).attr('cy', legY)
|
| 355 |
+
.attr('r', legDotR)
|
| 356 |
+
.attr('fill', familyColors[fam]).attr('fill-opacity', 0.85);
|
| 357 |
+
gLeg.append('text')
|
| 358 |
+
.attr('x', lx + legDotR + 4).attr('y', legY)
|
| 359 |
+
.attr('dominant-baseline', 'central')
|
| 360 |
+
.attr('fill', isDark ? 'rgba(255,255,255,0.48)' : 'rgba(0,0,0,0.42)')
|
| 361 |
+
.attr('font-size', (fontSize * 0.72) + 'px')
|
| 362 |
+
.attr('font-weight', fam === 'SmolLM2' ? '700' : '500')
|
| 363 |
+
.attr('font-family', 'system-ui, -apple-system, sans-serif')
|
| 364 |
+
.text(fam);
|
| 365 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 366 |
|
| 367 |
+
// βββ TOOLTIP βββ
|
| 368 |
+
container.style.position = container.style.position || 'relative';
|
| 369 |
+
let tip = container.querySelector('.d3-tooltip');
|
| 370 |
+
let tipInner;
|
| 371 |
+
if (!tip) {
|
| 372 |
+
tip = document.createElement('div');
|
| 373 |
+
tip.className = 'd3-tooltip';
|
| 374 |
+
Object.assign(tip.style, {
|
| 375 |
+
position: 'absolute', top: '0px', left: '0px',
|
| 376 |
+
transform: 'translate(-9999px, -9999px)',
|
| 377 |
+
pointerEvents: 'none',
|
| 378 |
+
padding: '10px 14px', borderRadius: '12px',
|
| 379 |
+
fontSize: '12px', lineHeight: '1.4',
|
| 380 |
+
border: '1px solid var(--border-color)',
|
| 381 |
+
background: 'var(--surface-bg)',
|
| 382 |
+
color: 'var(--text-color)',
|
| 383 |
+
boxShadow: '0 8px 32px rgba(0,0,0,.28), 0 2px 8px rgba(0,0,0,.12)',
|
| 384 |
+
opacity: '0', transition: 'opacity .12s ease',
|
| 385 |
+
backdropFilter: 'saturate(1.12) blur(8px)',
|
| 386 |
+
zIndex: '20', maxWidth: '320px'
|
| 387 |
+
});
|
| 388 |
+
tipInner = document.createElement('div');
|
| 389 |
+
tipInner.className = 'd3-tooltip__inner';
|
| 390 |
+
Object.assign(tipInner.style, {
|
| 391 |
+
textAlign: 'left', display: 'flex', flexDirection: 'column',
|
| 392 |
+
gap: '4px', minWidth: '220px'
|
| 393 |
+
});
|
| 394 |
+
tip.appendChild(tipInner);
|
| 395 |
+
container.appendChild(tip);
|
| 396 |
+
} else {
|
| 397 |
+
tipInner = tip.querySelector('.d3-tooltip__inner') || tip;
|
| 398 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
|
| 400 |
+
// βββ DOTS βββ
|
| 401 |
+
const gDots = svg.selectAll('g.dots').data([0]).join('g').attr('class', 'dots');
|
| 402 |
+
|
| 403 |
+
const handleEnter = function (ev, d) {
|
| 404 |
+
gDots.selectAll('circle').attr('fill-opacity', 0.12).attr('stroke-opacity', 0.05);
|
| 405 |
+
gDots.selectAll('circle')
|
| 406 |
+
.filter(c => c.family === d.family)
|
| 407 |
+
.attr('fill-opacity', 0.60).attr('stroke-opacity', 0.4);
|
| 408 |
+
d3.select(this)
|
| 409 |
+
.raise()
|
| 410 |
+
.attr('fill-opacity', 1)
|
| 411 |
+
.attr('stroke-opacity', 1)
|
| 412 |
+
.style('filter', `drop-shadow(0 0 8px ${glowColor})`)
|
| 413 |
+
.transition().duration(90).ease(d3.easeCubicOut)
|
| 414 |
+
.attr('r', rBase * 1.5);
|
| 415 |
+
tipInner.innerHTML = buildTip(d);
|
| 416 |
+
tip.style.opacity = '1';
|
| 417 |
+
};
|
| 418 |
+
const handleMove = (ev) => {
|
| 419 |
+
const [mx, my] = d3.pointer(ev, container);
|
| 420 |
+
const bw = tip.offsetWidth || 260;
|
| 421 |
+
const bh = tip.offsetHeight || 180;
|
| 422 |
+
const ox = (mx + bw + 20 > width) ? -(bw + 12) : 12;
|
| 423 |
+
const oy = (my + bh + 20 > height) ? -(bh + 12) : 14;
|
| 424 |
+
tip.style.transform = `translate(${Math.round(mx + ox)}px, ${Math.round(my + oy)}px)`;
|
| 425 |
+
};
|
| 426 |
+
const handleLeave = function () {
|
| 427 |
+
gDots.selectAll('circle')
|
| 428 |
.attr('fill-opacity', 0.82)
|
| 429 |
+
.attr('stroke-opacity', 0.30);
|
| 430 |
+
d3.select(this)
|
| 431 |
+
.style('filter', null)
|
| 432 |
+
.transition().duration(90).ease(d3.easeCubicOut)
|
| 433 |
+
.attr('r', rBase);
|
| 434 |
+
tip.style.opacity = '0';
|
| 435 |
+
tip.style.transform = 'translate(-9999px, -9999px)';
|
| 436 |
+
};
|
| 437 |
+
|
| 438 |
+
gDots.selectAll('circle').data(filtered, d => d.idx)
|
| 439 |
+
.join(
|
| 440 |
+
enter => enter.append('circle')
|
| 441 |
+
.attr('cx', d => d.x).attr('cy', d => d.y)
|
| 442 |
+
.attr('r', rBase)
|
| 443 |
+
.attr('fill', d => familyColors[d.family] || '#aaa')
|
| 444 |
+
.attr('fill-opacity', 0.82)
|
| 445 |
+
.attr('stroke', d => d.family === 'SmolLM2' ? '#fff' : (familyColors[d.family] || '#aaa'))
|
| 446 |
+
.attr('stroke-width', d => d.family === 'SmolLM2' ? 1.5 : 0.9)
|
| 447 |
+
.attr('stroke-opacity', d => d.family === 'SmolLM2' ? 0.5 : 0.30)
|
| 448 |
+
.on('mouseenter', handleEnter)
|
| 449 |
+
.on('mousemove', handleMove)
|
| 450 |
+
.on('mouseleave', handleLeave),
|
| 451 |
+
update => update
|
| 452 |
+
.attr('cx', d => d.x).attr('cy', d => d.y)
|
| 453 |
+
.attr('r', rBase)
|
| 454 |
+
.attr('fill', d => familyColors[d.family] || '#aaa')
|
| 455 |
+
.attr('fill-opacity', 0.82)
|
| 456 |
+
.attr('stroke', d => d.family === 'SmolLM2' ? '#fff' : (familyColors[d.family] || '#aaa'))
|
| 457 |
+
.attr('stroke-width', d => d.family === 'SmolLM2' ? 1.5 : 0.9)
|
| 458 |
+
.attr('stroke-opacity', d => d.family === 'SmolLM2' ? 0.5 : 0.30)
|
| 459 |
+
.on('mouseenter', handleEnter)
|
| 460 |
+
.on('mousemove', handleMove)
|
| 461 |
+
.on('mouseleave', handleLeave)
|
| 462 |
+
);
|
| 463 |
+
|
| 464 |
+
// βββ BREATHING βββ
|
| 465 |
+
if (animFrame) cancelAnimationFrame(animFrame);
|
| 466 |
+
const breathe = () => {
|
| 467 |
+
const now = Date.now() * 0.001;
|
| 468 |
+
gDots.selectAll('circle').each(function (d) {
|
| 469 |
+
d3.select(this).attr('r', rBase + Math.sin(now * 0.5 + d.phase) * rBase * 0.03);
|
| 470 |
+
});
|
| 471 |
+
animFrame = requestAnimationFrame(breathe);
|
| 472 |
+
};
|
| 473 |
+
breathe();
|
| 474 |
};
|
|
|
|
|
|
|
| 475 |
|
| 476 |
+
if (window.ResizeObserver) {
|
| 477 |
+
new ResizeObserver(() => render()).observe(container);
|
| 478 |
+
} else {
|
| 479 |
+
window.addEventListener('resize', render);
|
| 480 |
+
}
|
| 481 |
+
render();
|
| 482 |
}
|
|
|
|
| 483 |
};
|
| 484 |
|
| 485 |
if (document.readyState === 'loading') {
|