gpt-lab / data.mjs
ai-testack's picture
Upload folder using huggingface_hub
feb3f26 verified
Raw History Blame Contribute Delete
4.44 kB
// Pure data helpers. Preserve sparse histories; never invent missing counters.
export const COLORS = ['#e47745', '#4c8b80', '#697fb6', '#b08bca', '#b79c4c', '#819ba7'];
export const finite = value => typeof value === 'number' && Number.isFinite(value);
export const metricKey = key => /^(train|eval|core|optim)\//.test(key) || ['lrm', 'muon_momentum', 'weight_decay', '_runtime', 'step'].includes(key);
export function validateSnapshot(data) {
if (!data || data.schema_version !== 1 || !Array.isArray(data.runs)) throw new Error('Expected schema_version: 1 and a runs array.');
if (data.runs.length > 100) throw new Error('Please load at most 100 runs at once.');
const ids = new Set();
for (const run of data.runs) {
if (!run || typeof run.id !== 'string' || !run.id || ids.has(run.id)) throw new Error('Every run needs a unique, non-empty string id.');
ids.add(run.id);
if (run.group != null && typeof run.group !== 'string') throw new Error('Run group must be a string.');
if (!Array.isArray(run.history) || run.history.length > 100000) throw new Error('Each run needs a history array with at most 100,000 rows.');
if (!run.history.every(row => row && typeof row === 'object' && !Array.isArray(row) && finite(row.step))) throw new Error('Every history row needs a numeric step.');
if (run.config != null && (typeof run.config !== 'object' || Array.isArray(run.config))) throw new Error('Run config must be an object.');
}
return data;
}
export function points(run, key, axis = 'step', smoothing = 0) {
const scale = axis === '_runtime' || axis === 'train/total_training_time' ? 3600 : 1;
const rows = run.history.filter(row => finite(row[key]) && finite(row[axis])).map(row => [row[axis] / scale, row[key]]).sort((a, b) => a[0] - b[0]);
let previous;
return rows.map(([x, raw]) => {
previous = previous === undefined ? raw : smoothing * previous + (1 - smoothing) * raw;
return [x, previous, raw];
});
}
export function last(run, key) {
const rows = run.history.filter(row => finite(row[key])).sort((a, b) => a.step - b.step);
return rows.length ? rows.at(-1)[key] : null;
}
export function extrema(run, key, direction = 'min') {
const values = run.history.map(row => row[key]).filter(finite);
return values.length ? values.reduce((a, b) => direction === 'min' ? Math.min(a, b) : Math.max(a, b)) : null;
}
export function evaluationSeconds(run) {
// Deduplicate repeated records of the same evaluation at a logged step.
const durations = new Map();
for (const row of run.history) for (const key of ['core/step_time_ms', 'eval/step_time_ms']) {
if (finite(row[key]) && row[key] >= 0) durations.set(`${row.step}:${key}`, row[key] / 1000);
}
return durations.size ? [...durations.values()].reduce((a, b) => a + b, 0) : null;
}
export function configJSON(value, space = 0) {
// Object key order is not a configuration difference; array order is.
return JSON.stringify(value, (_, child) => child && typeof child === 'object' && !Array.isArray(child)
? Object.fromEntries(Object.entries(child).sort(([a], [b]) => a.localeCompare(b))) : child, space);
}
export function demoSnapshot() {
const runs = ['A', 'B'].map((letter, index) => ({
id: `synthetic-${letter}`, label: `Example run ${letter}`, status: 'synthetic', group: `Example experiment ${letter}`,
config: {model: {layers: 8, width: 512, context: 1024}, optimizer: {name: 'illustrative', learning_rate: index ? 0.0015 : 0.001}, training: {seed: 42, global_batch_tokens: 65536}, evaluation: {examples_per_task: 100, protocol: 'synthetic-preview'}},
history: Array.from({length: 51}, (_, i) => {
const row = {step: i * 20, 'train/total_tokens': i * 20 * 65536, 'train/total_training_time': i * 55, _runtime: i * 70, 'train/raw_loss': 3.2 + 3.9 * Math.exp(-i / 12) + Math.sin(i * 1.7 + index) * 0.05, 'train/tokens_per_sec': 23500 + Math.sin(i + index) * 1500, lrm: Math.min(1, (i + 1) / 3) * Math.max(0.05, (51 - i) / 35)};
row['train/mfu'] = 28 + Math.sin(i + index) * 2;
if (i && i % 10 === 0) Object.assign(row, {'eval/bpb': 1.3 + Math.exp(-i / 15) * 0.8, 'eval/step_time_ms': 12000, 'core/core': 0.08 + i / 500, 'core/step_time_ms': 110000 + i * 100, 'core/max_per_task': 100, 'core/example-task-1/accuracy': 0.3 + i / 400, 'core/example-task-2/accuracy': 0.4 + i / 450});
return row;
}),
}));
return {schema_version: 1, synthetic: true, runs};
}