Files
llm-atlas/scripts/check-numerics-browser.mjs
2026-07-29 06:07:42 +08:00

293 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { writeFileSync } from "node:fs";
const cdpPort = process.env.CDP_PORT ?? "9227";
const baseUrl = process.env.SITE_URL ?? "http://127.0.0.1:4326";
const pages = await fetch(`http://127.0.0.1:${cdpPort}/json/list`).then((response) => response.json());
const page = pages.find((entry) => entry.type === "page");
if (!page) throw new Error(`CDP ${cdpPort} 没有可用页面`);
const socket = new WebSocket(page.webSocketDebuggerUrl);
await new Promise((resolve, reject) => {
socket.addEventListener("open", resolve, { once: true });
socket.addEventListener("error", reject, { once: true });
});
let nextId = 0;
const pending = new Map();
const exceptions = [];
socket.addEventListener("message", (event) => {
const message = JSON.parse(event.data);
if (message.id && pending.has(message.id)) {
const { resolve, reject } = pending.get(message.id);
pending.delete(message.id);
if (message.error) reject(new Error(message.error.message));
else resolve(message.result);
}
if (message.method === "Runtime.exceptionThrown") {
exceptions.push(message.params.exceptionDetails.exception?.description ?? message.params.exceptionDetails.text);
}
});
const command = (method, params = {}) => new Promise((resolve, reject) => {
const id = ++nextId;
pending.set(id, { resolve, reject });
socket.send(JSON.stringify({ id, method, params }));
});
const pause = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
const evaluate = async (expression) => {
const result = await command("Runtime.evaluate", { expression, returnByValue: true, awaitPromise: true });
if (result.exceptionDetails) throw new Error(result.exceptionDetails.exception?.description ?? result.exceptionDetails.text);
return result.result.value;
};
const navigate = async (path) => {
await command("Page.navigate", { url: `${baseUrl}${path}` });
for (let attempt = 0; attempt < 50; attempt += 1) {
await pause(100);
if (await evaluate("document.readyState === 'complete'")) return;
}
throw new Error(`${path} 加载超时`);
};
const screenshot = async (path, full = false) => {
const params = { format: "png", captureBeyondViewport: full };
if (full) {
const metrics = await command("Page.getLayoutMetrics");
params.clip = {
x: 0,
y: 0,
width: metrics.cssContentSize.width,
height: metrics.cssContentSize.height,
scale: 1,
};
}
const result = await command("Page.captureScreenshot", params);
writeFileSync(path, Buffer.from(result.data, "base64"));
};
await command("Page.enable");
await command("Runtime.enable");
await command("Emulation.setDeviceMetricsOverride", {
width: 1440,
height: 1100,
deviceScaleFactor: 1,
mobile: false,
});
await navigate("/systems/numerics/");
await screenshot("/tmp/llm-atlas-numerics-desktop.png");
const format = await evaluate(`(() => {
const root = document.querySelector("[data-numerics-lab]");
const metric = (name) => root.querySelector('[data-format-metric="' + name + '"]').textContent;
const initial = {
storage: metric("storage"),
status: metric("status"),
error: metric("absolute"),
};
root.querySelector('[data-format-choice="fp16"]').click();
root.querySelector('[data-format-preset="tiny"]').click();
const tinyFp16 = { status: metric("status"), encoded: metric("encoded") };
root.querySelector('[data-format-choice="e4m3"]').click();
root.querySelector('[data-format-preset="large"]').click();
const largeE4M3 = { status: metric("status"), encoded: metric("encoded") };
root.querySelector('[data-format-choice="mxfp4"]').click();
root.querySelector('[data-format-preset="one"]').click();
const outlier = root.querySelector('[data-format-input="outlier"]');
const local = { error: metric("absolute"), encoded: metric("encoded") };
outlier.value = "64";
outlier.dispatchEvent(new Event("input", { bubbles: true }));
return {
initial,
tinyFp16,
largeE4M3,
local,
shared: {
error: metric("absolute"),
encoded: metric("encoded"),
note: root.querySelector("[data-format-scale-note]").textContent,
},
};
})()`);
const ledger = await evaluate(`(() => {
const root = document.querySelector("[data-numerics-lab]");
root.querySelector('[data-num-tab="ledger"]').click();
const read = () => ({
total: root.querySelector('[data-ledger-metric="total"]').textContent,
saving: root.querySelector('[data-ledger-metric="saving"]').textContent,
activation: root.querySelector('[data-ledger-metric="activation"]').textContent,
communication: root.querySelector('[data-ledger-metric="communication"]').textContent,
risks: root.querySelector("[data-ledger-risks]").textContent,
rows: root.querySelectorAll("[data-state-stack] > div").length,
});
root.querySelector('[data-precision-preset="bf16"]').click();
const bf16 = read();
root.querySelector('[data-precision-preset="v3"]').click();
const v3 = read();
root.querySelector('[data-precision-preset="k3"]').click();
const k3 = read();
return { bf16, v3, k3 };
})()`);
const optimizer = await evaluate(`(() => {
const root = document.querySelector("[data-numerics-lab]");
root.querySelector('[data-num-tab="optimizer"]').click();
const ratio = root.querySelector('[data-optimizer-input="ratio"]');
ratio.value = "24";
ratio.dispatchEvent(new Event("input", { bubbles: true }));
const read = () => ({
label: root.querySelector("[data-optimizer-label]").textContent,
imbalance: root.querySelector('[data-optimizer-metric="imbalance"]').textContent,
unit: root.querySelector('[data-optimizer-metric="unit"]').textContent,
note: root.querySelector("[data-optimizer-note]").textContent,
cells: root.querySelectorAll('[data-matrix="output"] i').length,
});
root.querySelector('[data-optimizer-choice="muon"]').click();
const full = read();
root.querySelector('[data-optimizer-choice="perhead"]').click();
const perHead = read();
return { full, perHead };
})()`);
const stability = await evaluate(`(() => {
const root = document.querySelector("[data-numerics-lab]");
root.querySelector('[data-num-tab="stability"]').click();
const read = () => ({
summary: root.querySelector("[data-stability-summary]").textContent,
levels: [...root.querySelectorAll("[data-gauge] b")].map((node) => node.textContent),
defenses: [...root.querySelectorAll("[data-defense]:checked")].map((node) => node.dataset.defense),
timeline: root.querySelectorAll("[data-risk-timeline] i").length,
});
root.querySelector('[data-stability-preset="k2"]').click();
const k2 = read();
root.querySelector('[data-stability-preset="v4"]').click();
const v4 = read();
const firstTab = root.querySelector('[data-num-tab="format"]');
firstTab.focus();
firstTab.dispatchEvent(new KeyboardEvent("keydown", { key: "End", bubbles: true }));
return {
k2,
v4,
keyboard: {
selected: root.querySelector('[data-num-tab][aria-selected="true"]').dataset.numTab,
visible: root.querySelector("[data-num-view]:not([hidden])").dataset.numView,
},
};
})()`);
const layout = await evaluate(`(() => {
const nav = document.querySelector(".top-nav");
const meta = document.querySelector(".header-meta");
return {
documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth,
navGap: Number((meta.getBoundingClientRect().left - nav.getBoundingClientRect().right).toFixed(1)),
navLinks: document.querySelectorAll(".top-nav a").length,
articleSections: document.querySelectorAll(".article-section").length,
paperLinks: document.querySelectorAll(".paper-chain a").length,
labTabs: document.querySelectorAll("[data-num-tab]").length,
views: document.querySelectorAll("[data-num-view]").length,
};
})()`);
await evaluate(`document.querySelector("[data-numerics-lab]").scrollIntoView({ block: "start", behavior: "instant" })`);
await pause(150);
await screenshot("/tmp/llm-atlas-numerics-lab-desktop.png");
await command("Emulation.setDeviceMetricsOverride", {
width: 390,
height: 844,
deviceScaleFactor: 1,
mobile: true,
});
await navigate("/systems/numerics/");
await evaluate(`document.querySelector("[data-numerics-lab]").scrollIntoView({ block: "start", behavior: "instant" })`);
await pause(100);
await screenshot("/tmp/llm-atlas-numerics-lab-mobile.png");
const mobile = await evaluate(`(() => {
const toggle = document.querySelector("#menu-toggle");
toggle.click();
return {
documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth,
menuVisible: getComputedStyle(toggle).display !== "none",
menuOpen: toggle.getAttribute("aria-expanded"),
mobileLinks: document.querySelectorAll("#mobile-nav a").length,
};
})()`);
await command("Emulation.setDeviceMetricsOverride", {
width: 1440,
height: 1100,
deviceScaleFactor: 1,
mobile: false,
});
await navigate("/");
const home = await evaluate(`({
documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth,
releaseCards: document.querySelectorAll(".release-card").length,
firstRelease: document.querySelector(".release-card h2").textContent,
firstHref: document.querySelector(".release-card").getAttribute("href"),
paperCount: document.querySelector(".hero-stats div:nth-child(3) b").textContent,
navLinks: document.querySelectorAll(".top-nav a").length,
})`);
await navigate("/papers/");
const papers = await evaluate(`(() => {
const optimizer = [...document.querySelectorAll("[data-filter]")].find((node) => node.dataset.filter === "优化器");
optimizer?.click();
return {
hasOptimizerFilter: Boolean(optimizer),
total: document.querySelectorAll("[data-paper]").length,
visible: [...document.querySelectorAll("[data-paper]")].filter((node) => !node.hidden).length,
};
})()`);
const report = { format, ledger, optimizer, stability, layout, mobile, home, papers, exceptions };
console.log(JSON.stringify(report, null, 2));
const numeric = (value) => Number.parseFloat(value.replaceAll(",", ""));
const failures = [];
if (format.initial.storage !== "2.000 B/value") failures.push("BF16 初始字节口径异常");
if (!["SUBNORMAL", "ROUNDED"].includes(format.tinyFp16.status)) failures.push("FP16 微小梯度未进入 subnormal/rounding 边界");
if (format.largeE4M3.status !== "OVERFLOW") failures.push("E4M3 大激活未触发 overflow");
if (numeric(format.shared.error) <= numeric(format.local.error) || !format.shared.note.includes("teaching scale")) {
failures.push("MXFP4 block outlier 没有压缩普通值格点");
}
if (ledger.bf16.rows !== 6 || ledger.v3.rows !== 6 || ledger.k3.rows !== 6) failures.push("混合精度状态栈数量异常");
if (numeric(ledger.v3.total) >= numeric(ledger.bf16.total) || numeric(ledger.k3.total) >= numeric(ledger.bf16.total)) {
failures.push("低精度预设没有降低教学状态字节");
}
if (!ledger.v3.risks.includes("1×128") || !ledger.k3.risks.includes("post-training")) failures.push("V3/K3 证据边界缺失");
if (optimizer.full.cells !== 8 || optimizer.perHead.cells !== 8) failures.push("更新矩阵没有完整渲染");
if (optimizer.perHead.unit.trim() !== "attention head" || !optimizer.perHead.label.includes("Per-Head")) {
failures.push("Per-Head Muon 逻辑单位异常");
}
if (
numeric(optimizer.perHead.imbalance) > 1.25
|| numeric(optimizer.perHead.imbalance) >= numeric(optimizer.full.imbalance) * 0.1
) failures.push("Per-Head Muon 没有显著降低两个 head 的更新失衡");
if (stability.v4.timeline !== 24 || stability.k2.timeline !== 24) failures.push("稳定性时间线数量异常");
if (!stability.v4.summary.includes("均低于 HIGH") || stability.v4.defenses.length !== 5) {
failures.push("DeepSeek-V4 防线预设没有压低四条教学风险");
}
if (stability.keyboard.selected !== "stability" || stability.keyboard.visible !== "stability") {
failures.push("实验页签键盘导航异常");
}
if (layout.articleSections !== 19 || layout.paperLinks !== 36 || layout.labTabs !== 4 || layout.views !== 4) {
failures.push("章节、论文或实验数量异常");
}
if (layout.navLinks !== 15 || mobile.mobileLinks !== 15 || home.navLinks !== 15) failures.push("全站导航未同步数值专题");
if (layout.documentOverflow > 0 || mobile.documentOverflow > 0 || home.documentOverflow > 0) failures.push("页面存在横向溢出");
if (layout.navGap < 0) failures.push(`桌面导航碰撞:${layout.navGap}px`);
if (!mobile.menuVisible || mobile.menuOpen !== "true") failures.push("移动端菜单不可用");
if (home.releaseCards !== 10 || !home.firstRelease.includes("DPO 没有") || home.firstHref !== "/post-training/alignment/") {
failures.push("首页 Transformer 新章入口异常");
}
if (home.paperCount !== "280") failures.push(`首页论文总数异常:${home.paperCount}`);
if (!papers.hasOptimizerFilter || papers.total !== 280 || papers.visible < 8) failures.push("论文库优化器标签或论文总数异常");
if (exceptions.length) failures.push(`浏览器脚本异常:${exceptions.join("; ")}`);
socket.close();
if (failures.length) {
failures.forEach((failure) => console.error(`- ${failure}`));
process.exit(1);
}
console.log("数值精度、优化器与稳定性专题真实 Chrome 断言通过。");