Files
llm-atlas/src/components/DeepSeekLab.astro
T
2026-07-29 11:17:53 +08:00

624 lines
49 KiB
Plaintext
Raw 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.
<figure class="ds-lab" data-deepseek-lab>
<div class="ds-lab-head">
<div>
<p>INTERACTIVE / DEEPSEEK SYSTEM ATLAS</p>
<h3>四本账,把“模型创新”拆回可计算对象</h3>
</div>
<p>
这里混合精确计数与显式 toy model:参数组合和 KV 元素按公式计算;通信、bubble 与梯度权重只展示方向。
每个面板都标出证据边界,不能拿来替代真实 checkpoint 或集群复跑。
</p>
</div>
<div class="ds-tabs" role="tablist" aria-label="选择 DeepSeek 技术实验">
<button type="button" role="tab" data-ds-tab="capacity" aria-selected="true">
<span>01</span><b>稀疏容量账</b><small>MoE · shared · communication</small>
</button>
<button type="button" role="tab" data-ds-tab="cache" aria-selected="false" tabindex="-1">
<span>02</span><b>MLA 缓存账</b><small>MHA · GQA · latent · RoPE</small>
</button>
<button type="button" role="tab" data-ds-tab="codesign" aria-selected="false" tabindex="-1">
<span>03</span><b>V3 协同账</b><small>FP8 · DualPipe · MTP</small>
</button>
<button type="button" role="tab" data-ds-tab="rl" aria-selected="false" tabindex="-1">
<span>04</span><b>RL 偏差镜</b><small>GRPO · DAPO · Dr.GRPO</small>
</button>
</div>
<section class="ds-panel" data-ds-panel="capacity">
<div class="panel-intro">
<div><span>WORKBENCH 01 / SPARSE CAPACITY</span><h4>总参数很大,不代表每个 Token 都经过全部专家</h4></div>
<p>切换架构或自定义专家配置,分开观察总容量、激活计算和跨设备通信;组合数只是可选路径,不是能力分数。</p>
</div>
<div class="preset-row" role="group" aria-label="选择容量预设">
<button type="button" data-capacity-preset="dense"><b>DENSE</b><small>一条完整 FFN</small></button>
<button type="button" data-capacity-preset="coarse"><b>COARSE MOE</b><small>8 选 2</small></button>
<button type="button" data-capacity-preset="deepseekmoe"><b>DEEPSEEKMOE</b><small>细粒度 + shared</small></button>
<button type="button" data-capacity-preset="v3" class="active"><b>V3</b><small>256 routed · 8 active</small></button>
</div>
<div class="control-grid five">
<label><span>routed experts E <output data-experts-label>256</output></span><input data-experts type="range" min="1" max="384" value="256" /></label>
<label><span>routed top-k <output data-topk-label>8</output></span><input data-topk type="range" min="0" max="16" value="8" /></label>
<label><span>shared experts <output data-shared-label>1</output></span><input data-shared type="range" min="0" max="4" value="1" /></label>
<label><span>expert width <output data-expert-width-label>0.125×</output></span><input data-expert-width type="range" min="1" max="100" value="12.5" step=".5" /></label>
<label><span>EP nodes <output data-ep-label>4</output></span><input data-ep-nodes type="range" min="1" max="16" value="4" /></label>
</div>
<div class="capacity-stage">
<div class="router-box">
<span>TOKEN</span><b>h<sub>t</sub></b><small>router scores</small>
</div>
<i>→</i>
<div class="expert-map" data-expert-map aria-label="教学专家池"></div>
<i>→</i>
<div class="router-box output"><span>COMBINE</span><b>Σ gᵢEᵢ(h)</b><small>shared + routed</small></div>
</div>
<div class="metric-grid four">
<article><span>TOTAL EXPERT CAPACITY</span><b data-total-capacity>33.0× FFN</b><p>按 expert width 折算,不含 attention</p></article>
<article><span>ACTIVE EXPERT COMPUTE</span><b data-active-compute>2.0× FFN</b><p>每 Token 的教学 FFN 单位</p></article>
<article><span>ROUTE COMBINATIONS</span><b data-combinations>≈ 10¹⁵</b><p>只表示可组合路径,不代表专长质量</p></article>
<article class="dark"><span>COMMUNICATION PRESSURE</span><b data-communication>HIGH</b><p>教学指标;不是 GB/s 实测</p></article>
</div>
<div class="evidence-boundary">
<b data-capacity-name>DEEPSEEK-V3 / CAPACITY CONTRACT</b>
<p data-capacity-explain>V3 每层含 1 个 shared 与 256 个 routed experts,每 Token 激活 8 个 routed;理论稀疏计算仍需要 expert dispatch/combine 与负载均衡。</p>
</div>
</section>
<section class="ds-panel" data-ds-panel="cache" hidden>
<div class="panel-intro">
<div><span>WORKBENCH 02 / INFERENCE STATE</span><h4>MLA 省的不是模型权重,而是每个请求不断增长的历史状态</h4></div>
<p>所有方案都与当前 MHA 基线比较;MLA 的缓存必须包含 joint latent 和 decoupled RoPE key,不能只报 latent。</p>
</div>
<div class="control-grid four">
<label><span>layers L <output data-cache-layers-label>60</output></span><input data-cache-layers type="range" min="12" max="96" step="12" value="60" /></label>
<label><span>context T</span><select data-context-length><option value="4096">4K</option><option value="32768">32K</option><option value="131072" selected>128K</option><option value="1048576">1M</option></select></label>
<label><span>batch B <output data-batch-label>4</output></span><input data-batch type="range" min="1" max="32" value="4" /></label>
<label><span>storage</span><select data-cache-bytes><option value="1">FP8 / 1 byte</option><option value="2" selected>BF16 / 2 bytes</option><option value="4">FP32 / 4 bytes</option></select></label>
</div>
<div class="control-grid five">
<label><span>MHA heads <output data-heads-label>128</output></span><input data-heads type="range" min="8" max="160" step="8" value="128" /></label>
<label><span>head dim dₕ <output data-head-dim-label>128</output></span><input data-head-dim type="range" min="32" max="256" step="32" value="128" /></label>
<label><span>GQA KV groups <output data-kv-groups-label>8</output></span><input data-kv-groups type="range" min="1" max="32" value="8" /></label>
<label><span>MLA latent d꜀ <output data-latent-label>512</output></span><input data-latent type="range" min="128" max="2048" step="128" value="512" /></label>
<label><span>RoPE key dᴿ <output data-rope-dim-label>64</output></span><input data-rope-dim type="range" min="0" max="128" step="16" value="64" /></label>
</div>
<div class="cache-comparison">
<article data-cache-card="mha">
<span>MHA</span><b data-mha-elements>32,768</b><small>elements / token / layer</small>
<div><i data-mha-bar></i></div><p>完整 K 与 V,所有 heads 分开缓存。</p>
</article>
<article data-cache-card="gqa">
<span>GQA</span><b data-gqa-elements>2,048</b><small>elements / token / layer</small>
<div><i data-gqa-bar></i></div><p>Query heads 分组共享 K/V。</p>
</article>
<article class="selected" data-cache-card="mla">
<span>MLA / V2-LIKE</span><b data-mla-elements>576</b><small>d꜀ + dᴿ elements</small>
<div><i data-mla-bar></i></div><p>joint latent + decoupled RoPE key。</p>
</article>
</div>
<div class="absorption-grid">
<div class="absorb-flow">
<span>CONTENT PATH / ASSOCIATIVITY</span>
<code>qᵀ(W<sub>UK</sub>c) = (W<sub>UK</sub>ᵀq)ᵀc</code>
<div><b>q</b><i>× absorbed W</i><b>c<sup>KV</sup></b><i>→</i><b>score</b></div>
<p>固定线性上投影可吸收到 query/output 权重,不必先物化完整多头 content K/V。</p>
</div>
<div class="rope-flow">
<span>POSITION PATH / DECOUPLED</span>
<code>q<sup>R</sup>ᵀ R(j−i) k<sup>R</sup></code>
<div><b>qᴿ</b><i>rotate</i><b>kᴿ</b><i>cache</i><b data-rope-cache>64</b></div>
<p>RoPE 是位置相关运算,无法作为固定矩阵吸收;因此 key 的小位置分支仍要缓存。</p>
</div>
</div>
<div class="metric-grid four">
<article><span>SELECTED MLA CACHE</span><b data-selected-cache>32.96 GiB</b><p>当前 L × T × B × bytes</p></article>
<article><span>MHA BASELINE</span><b data-mha-cache>1.88 TiB</b><p>同一配置,不是报告基线</p></article>
<article><span>REDUCTION VS MHA</span><b data-cache-reduction>98.2%</b><p>由当前滑条计算</p></article>
<article class="dark"><span>REPORT ≠ TOY</span><b>93.3%</b><p>V2 报告相对 DeepSeek 67B</p></article>
</div>
<div class="evidence-boundary">
<b>EXACT ELEMENT COUNT / CONFIGURATION-DEPENDENT BYTES</b>
<p data-cache-boundary>元素公式是精确账;GiB 只按所选 dtype 计算,没有加入 allocator、page、quantization metadata 或 kernel workspace。</p>
</div>
</section>
<section class="ds-panel" data-ds-panel="codesign" hidden>
<div class="panel-intro">
<div><span>WORKBENCH 03 / V3 CO-DESIGN</span><h4>FP8、DualPipe 与 MTP 改的是三种不同成本</h4></div>
<p>调度台只显示方向:bubble 与通信是 toy schedule;精度角色和 MTP 生命周期来自 V3 报告。</p>
</div>
<div class="codesign-grid">
<div class="schedule-workbench">
<div class="subhead"><span>PIPELINE</span><h5>依赖等待怎样暴露设备空闲?</h5></div>
<div class="choice-row" role="group" aria-label="选择教学 pipeline schedule">
<button type="button" data-schedule="onef1b" class="active"><b>1F1B-LIKE</b><small>单向填充</small></button>
<button type="button" data-schedule="dual"><b>DUAL-ENDED TOY</b><small>两端注入 + overlap</small></button>
</div>
<div class="control-grid three compact">
<label><span>PP stages <output data-stages-label>8</output></span><input data-stages type="range" min="2" max="16" step="2" value="8" /></label>
<label><span>micro-batches <output data-micro-label>20</output></span><input data-micro type="range" min="4" max="64" step="2" value="20" /></label>
<label><span>comm / compute <output data-comm-label>0.60×</output></span><input data-comm-ratio type="range" min="0" max="150" value="60" /></label>
</div>
<div class="pipeline-strip" data-pipeline-strip aria-label="教学流水线时隙"></div>
<div class="metric-grid two">
<article><span>TOY BUBBLE</span><b data-bubble>25.9%</b><p>只由 stages / micro-batches 构造</p></article>
<article class="dark"><span>EXPOSED COMM</span><b data-exposed-comm>45.0%</b><p>重叠假设后的教学比例</p></article>
</div>
</div>
<div class="precision-workbench">
<div class="subhead"><span>PRECISION CONTRACT</span><h5>一个“FP8”标签不够描述训练</h5></div>
<div class="choice-row" role="group" aria-label="选择精度配方">
<button type="button" data-precision="bf16"><b>BF16</b><small>统一高精度基线</small></button>
<button type="button" data-precision="naive"><b>NAIVE FP8</b><small>错误的一键强转</small></button>
<button type="button" data-precision="mixed" class="active"><b>V3 MIXED</b><small>角色分治</small></button>
</div>
<div class="dtype-contract">
<article><span>GEMM INPUTS</span><b data-gemm-dtype>FP8 / tiled scale</b></article>
<article><span>ACCUMULATION</span><b data-accum-dtype>FP32-assisted</b></article>
<article><span>MASTER / OPTIMIZER</span><b data-master-dtype>FP32 / BF16 roles</b></article>
<article><span>SENSITIVE OPS</span><b data-sensitive-dtype>BF16 / FP32</b></article>
</div>
<div class="risk-meter"><span>NUMERICAL RISK</span><div><i data-risk-bar></i></div><b data-risk-label>MANAGED</b></div>
<p data-precision-explain>V3 把主要 GEMM、缩放、累加、master state、敏感算子和通信分别设计;“混合精度”才是完整对象。</p>
</div>
</div>
<div class="mtp-workbench">
<div class="subhead"><span>MULTI-TOKEN PREDICTION</span><h5>同一模块在生命周期中有三种角色</h5></div>
<div class="choice-row mtp" role="group" aria-label="选择 MTP 角色">
<button type="button" data-mtp-role="off"><b>OFF</b><small>只做 NTP</small></button>
<button type="button" data-mtp-role="train" class="active"><b>TRAIN</b><small>额外未来监督</small></button>
<button type="button" data-mtp-role="draft"><b>SPECULATIVE</b><small>候选草稿</small></button>
</div>
<div class="mtp-flow" data-mtp-flow></div>
<div class="metric-grid three">
<article><span>SUPERVISION DEPTH</span><b data-mtp-supervision>2 token targets</b><p>主 NTP + 一层 V3-style MTP</p></article>
<article><span>MAIN MODEL COST</span><b data-mtp-main-cost>TRAIN + MODULE</b><p>推理可丢弃额外 module</p></article>
<article class="dark"><span>AUTOREGRESSIVE?</span><b data-mtp-ar>YES</b><p>草稿仍需验证,不取代主模型</p></article>
</div>
<p class="boundary-copy" data-mtp-explain>V3 的顺序 MTP 首先增加训练信号;报告明确推理可直接丢弃,也可复用于 speculative decoding。</p>
</div>
<div class="evidence-boundary">
<b>TOY SCHEDULE / SOURCE-GROUNDED ROLE CONTRACT</b>
<p data-codesign-boundary>本台没有复跑 DualPipe 或 FP8 kernel;它只阻止把三个独立机制压成“V3 训练便宜”一句话。</p>
</div>
</section>
<section class="ds-panel" data-ds-panel="rl" hidden>
<div class="panel-intro">
<div><span>WORKBENCH 04 / POLICY GRADIENT</span><h4>奖励相同、回答长度和归一方式都会改变“谁被学得更多”</h4></div>
<p>DAPO 与 Dr.GRPO 是 R1 之后的公开研究,不是 DeepSeek 已披露的 R1 内部配方;这里用 toy weight 暴露目标函数偏差。</p>
</div>
<div class="preset-row rl-presets" role="group" aria-label="选择 rollout 奖励预设">
<button type="button" data-reward-preset="mixed" class="active"><b>MIXED</b><small>0 · 1 · .7 · .2</small></button>
<button type="button" data-reward-preset="same"><b>ALL SAME</b><small>零组内信号</small></button>
<button type="button" data-reward-preset="longwrong"><b>LONG WRONG</b><small>长度偏差探针</small></button>
</div>
<div class="rollout-controls">
{[
["1", "0", "512"],
["2", "1", "768"],
["3", ".7", "1536"],
["4", ".2", "3072"],
].map(([index, reward, length]) => (
<label>
<span>y{index}</span>
<small>reward</small><input data-rollout-reward type="number" min="-1" max="1" step=".1" value={reward} />
<small>tokens</small><input data-rollout-length type="number" min="64" max="8192" step="64" value={length} />
</label>
))}
</div>
<div class="choice-row algorithm-row" role="group" aria-label="选择策略梯度教学算法">
<button type="button" data-rl-algorithm="grpo" class="active"><b>GRPO</b><small>std norm · response avg</small></button>
<button type="button" data-rl-algorithm="dapo"><b>DAPO-STYLE</b><small>token loss · dynamic filter</small></button>
<button type="button" data-rl-algorithm="dr"><b>Dr.GRPO</b><small>no std · fixed denominator</small></button>
</div>
<div class="control-grid three compact">
<label><span>clip low <output data-clip-low-label>0.20</output></span><input data-clip-low type="range" min="5" max="40" value="20" /></label>
<label><span>clip high <output data-clip-high-label>0.20</output></span><input data-clip-high type="range" min="5" max="80" value="20" /></label>
<label><span>overlong threshold <output data-overlong-label>4096</output></span><input data-overlong type="range" min="512" max="8192" step="512" value="4096" /></label>
</div>
<div class="rl-stage">
<div class="advantage-table">
<div class="head"><span>ROLLOUT</span><span>R</span><span>LENGTH</span><span>Â</span><span>TOY WEIGHT</span></div>
<div data-advantage-rows></div>
</div>
<div class="rl-diagnosis">
<span data-algorithm-name>GRPO / ORIGINAL FAMILY</span>
<h5 data-signal-state>GROUP-RELATIVE SIGNAL</h5>
<p data-algorithm-explain>奖励按组均值和标准差归一;response-level loss 再按各自长度平均,可能改变长短回答的 Token 权重。</p>
<dl>
<div><dt>reward mean</dt><dd data-reward-mean>0.475</dd></div>
<div><dt>reward std</dt><dd data-reward-std>0.396</dd></div>
<div><dt>effective samples</dt><dd data-effective>4 / 4</dd></div>
<div><dt>provenance</dt><dd data-provenance>DeepSeekMath / R1</dd></div>
</dl>
</div>
</div>
<div class="pipeline-switch">
<div class="subhead"><span>TRAINING IDENTITY</span><h5>R1-Zero、R1 与 Distill 不是三个名字相近的同一步</h5></div>
<div class="choice-row" role="group" aria-label="选择 R1 训练身份">
<button type="button" data-r1-mode="zero" class="active"><b>R1-ZERO</b><small>base → rule RL</small></button>
<button type="button" data-r1-mode="r1"><b>R1</b><small>cold start → multi-stage</small></button>
<button type="button" data-r1-mode="distill"><b>DISTILL</b><small>teacher traces → SFT</small></button>
</div>
<div class="r1-mode-flow" data-r1-mode-flow></div>
<p data-r1-mode-explain>R1-Zero 从 V3 Base 直接进行规则奖励 GRPO;“无 reasoning SFT”不等于“无预训练知识”。</p>
</div>
<div class="evidence-boundary">
<b data-rl-boundary-title>TOY GRADIENT WEIGHT / NOT A TRAINING REPLAY</b>
<p data-rl-boundary>优势公式与论文定义对齐;权重只用来显示归一和长度方向,没有 policy ratio、真实 token probability、KL 或 optimizer。</p>
</div>
</section>
<figcaption>
<span>证据分层</span>
KV 元素与组合参数按公式;FP8/MTP/R1 角色来自官方报告;bubble、通信、数值风险和梯度 weight 为本站教学模型。
</figcaption>
</figure>
<script>
const roots = document.querySelectorAll<HTMLElement>("[data-deepseek-lab]");
roots.forEach((root) => {
const one = <T extends Element>(selector: string) => root.querySelector<T>(selector);
const all = <T extends Element>(selector: string) => [...root.querySelectorAll<T>(selector)];
const value = (selector: string) => Number(one<HTMLInputElement | HTMLSelectElement>(selector)?.value ?? 0);
const set = (selector: string, text: string) => {
const node = one<HTMLElement>(selector);
if (node) node.textContent = text;
};
const compact = (number: number) => {
if (number >= 1024 ** 4) return `${(number / 1024 ** 4).toFixed(2)} TiB`;
if (number >= 1024 ** 3) return `${(number / 1024 ** 3).toFixed(2)} GiB`;
if (number >= 1024 ** 2) return `${(number / 1024 ** 2).toFixed(2)} MiB`;
return `${number.toLocaleString()} B`;
};
const tabs = all<HTMLButtonElement>("[data-ds-tab]");
const panels = all<HTMLElement>("[data-ds-panel]");
const selectTab = (tab: HTMLButtonElement) => {
tabs.forEach((candidate) => {
const selected = candidate === tab;
candidate.setAttribute("aria-selected", String(selected));
candidate.tabIndex = selected ? 0 : -1;
});
panels.forEach((panel) => panel.hidden = panel.dataset.dsPanel !== tab.dataset.dsTab);
};
tabs.forEach((tab, index) => {
tab.addEventListener("click", () => selectTab(tab));
tab.addEventListener("keydown", (event) => {
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
event.preventDefault();
let target = index;
if (event.key === "ArrowRight") target = (index + 1) % tabs.length;
if (event.key === "ArrowLeft") target = (index - 1 + tabs.length) % tabs.length;
if (event.key === "Home") target = 0;
if (event.key === "End") target = tabs.length - 1;
tabs[target].focus();
selectTab(tabs[target]);
});
});
const capacityPresets: Record<string, [number, number, number, number, number, string, string]> = {
dense: [1, 1, 0, 100, 1, "DENSE / ONE ACTIVE PATH", "Dense FFN 让总容量与每 Token 激活计算绑定;没有 expert dispatch,但容量增长会直接增加计算。"],
coarse: [8, 2, 0, 100, 2, "COARSE MOE / 8 CHOOSE 2", "少数大专家提供条件计算;每个专家仍覆盖较宽知识,跨节点路由开始产生通信。"],
deepseekmoe: [63, 7, 1, 25, 4, "DEEPSEEKMOE / FINE-GRAINED", "论文代表配置把标准专家切为 0.25×,使用 1 shared + 63 routed、激活 7 routed;具体规模随实验变化。"],
v3: [256, 8, 1, 12.5, 4, "DEEPSEEK-V3 / CAPACITY CONTRACT", "V3 每层含 1 个 shared 与 256 个 routed experts,每 Token 激活 8 个 routed;理论稀疏计算仍需要 expert dispatch/combine 与负载均衡。"],
};
const logChoose = (n: number, k: number) => {
const safeK = Math.min(k, n - k);
if (safeK <= 0) return 0;
let result = 0;
for (let index = 1; index <= safeK; index += 1) result += Math.log10(n - safeK + index) - Math.log10(index);
return result;
};
const renderCapacity = () => {
const experts = Math.max(1, Math.round(value("[data-experts]")));
const topk = Math.min(experts, Math.round(value("[data-topk]")));
const shared = Math.round(value("[data-shared]"));
const width = value("[data-expert-width]") / 100;
const nodes = Math.round(value("[data-ep-nodes]"));
const total = (experts + shared) * width;
const active = (topk + shared) * width;
const logComb = logChoose(experts, topk);
const remoteShare = nodes <= 1 ? 0 : (nodes - 1) / nodes;
const communication = topk * remoteShare;
const level = communication === 0 ? "NONE" : communication < .8 ? "LOW" : communication < 2 ? "MEDIUM" : "HIGH";
set("[data-experts-label]", String(experts));
set("[data-topk-label]", String(topk));
set("[data-shared-label]", String(shared));
set("[data-expert-width-label]", `${width.toFixed(3).replace(/0+$/, "").replace(/\.$/, "")}×`);
set("[data-ep-label]", String(nodes));
set("[data-total-capacity]", `${total.toFixed(1)}× FFN`);
set("[data-active-compute]", `${active.toFixed(2)}× FFN`);
set("[data-combinations]", topk === 0 ? "1 route" : logComb < 6 ? Math.round(10 ** logComb).toLocaleString() : `≈ 10^${Math.floor(logComb)}`);
set("[data-communication]", level);
const map = one<HTMLElement>("[data-expert-map]");
if (map) {
const visible = Math.min(24, experts);
map.innerHTML = [
...Array.from({ length: shared }, (_, index) => `<i class="shared active"><b>S${index + 1}</b><small>shared</small></i>`),
...Array.from({ length: visible }, (_, index) => `<i class="${index < topk ? "active" : ""}"><b>E${index + 1}</b><small>${index < topk ? "route" : "idle"}</small></i>`),
].join("");
}
};
all<HTMLButtonElement>("[data-capacity-preset]").forEach((button) => button.addEventListener("click", () => {
const preset = capacityPresets[button.dataset.capacityPreset ?? "v3"];
const selectors = ["[data-experts]", "[data-topk]", "[data-shared]", "[data-expert-width]", "[data-ep-nodes]"];
selectors.forEach((selector, index) => {
const input = one<HTMLInputElement>(selector);
if (input) input.value = String(preset[index]);
});
set("[data-capacity-name]", preset[5]);
set("[data-capacity-explain]", preset[6]);
all("[data-capacity-preset]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderCapacity();
}));
all<HTMLInputElement>("[data-experts],[data-topk],[data-shared],[data-expert-width],[data-ep-nodes]").forEach((input) => input.addEventListener("input", renderCapacity));
const renderCache = () => {
const layers = value("[data-cache-layers]");
const context = value("[data-context-length]");
const batch = value("[data-batch]");
const bytes = value("[data-cache-bytes]");
const heads = value("[data-heads]");
const headDim = value("[data-head-dim]");
const groups = Math.min(value("[data-kv-groups]"), heads);
const latent = value("[data-latent]");
const rope = value("[data-rope-dim]");
const mha = 2 * heads * headDim;
const gqa = 2 * groups * headDim;
const mla = latent + rope;
const total = (elements: number) => elements * layers * context * batch * bytes;
const max = Math.max(mha, gqa, mla);
set("[data-cache-layers-label]", String(layers));
set("[data-batch-label]", String(batch));
set("[data-heads-label]", String(heads));
set("[data-head-dim-label]", String(headDim));
set("[data-kv-groups-label]", String(groups));
set("[data-latent-label]", String(latent));
set("[data-rope-dim-label]", String(rope));
set("[data-mha-elements]", mha.toLocaleString());
set("[data-gqa-elements]", gqa.toLocaleString());
set("[data-mla-elements]", mla.toLocaleString());
set("[data-rope-cache]", String(rope));
set("[data-selected-cache]", compact(total(mla)));
set("[data-mha-cache]", compact(total(mha)));
set("[data-cache-reduction]", `${((1 - mla / mha) * 100).toFixed(1)}%`);
const bars: [string, number][] = [["[data-mha-bar]", mha], ["[data-gqa-bar]", gqa], ["[data-mla-bar]", mla]];
bars.forEach(([selector, number]) => {
const node = one<HTMLElement>(selector);
if (node) node.style.width = `${Math.max(2, number / max * 100)}%`;
});
set("[data-cache-boundary]", `当前是 ${layers} 层 × ${context.toLocaleString()} Token × batch ${batch} × ${bytes} byte;GiB 未加入 allocator、page、quantization metadata 或 kernel workspace。`);
};
all<HTMLInputElement | HTMLSelectElement>("[data-cache-layers],[data-context-length],[data-batch],[data-cache-bytes],[data-heads],[data-head-dim],[data-kv-groups],[data-latent],[data-rope-dim]").forEach((control) => control.addEventListener("input", renderCache));
let schedule = "onef1b";
let precision = "mixed";
let mtpRole = "train";
const renderSchedule = () => {
const stages = value("[data-stages]");
const micro = value("[data-micro]");
const comm = value("[data-comm-ratio]") / 100;
const effectiveStages = schedule === "dual" ? Math.max(1, stages / 2) : stages;
const bubble = (effectiveStages - 1) / (micro + effectiveStages - 1);
const overlap = schedule === "dual" ? .78 : .25;
const exposed = Math.max(0, comm * (1 - overlap));
set("[data-stages-label]", String(stages));
set("[data-micro-label]", String(micro));
set("[data-comm-label]", `${comm.toFixed(2)}×`);
set("[data-bubble]", `${(bubble * 100).toFixed(1)}%`);
set("[data-exposed-comm]", `${(exposed * 100).toFixed(1)}%`);
const strip = one<HTMLElement>("[data-pipeline-strip]");
if (strip) strip.innerHTML = Array.from({ length: 30 }, (_, index) => {
const warm = index < effectiveStages - 1 || index >= 30 - (effectiveStages - 1);
const commSlot = !warm && index % (schedule === "dual" ? 7 : 4) === 0;
return `<i class="${warm ? "bubble" : commSlot ? "comm" : "compute"}"><small>${warm ? "idle" : commSlot ? "a2a" : index % 2 ? "B" : "F"}</small></i>`;
}).join("");
};
const precisionDetails: Record<string, [string, string, string, string, number, string, string]> = {
bf16: ["BF16", "BF16/FP32", "FP32", "BF16/FP32", 28, "LOWER", "BF16 基线保留更宽动态范围,但增加存储、带宽与高密度算术成本。"],
naive: ["FP8 / one scale", "FP8", "FP8", "FP8", 96, "CRITICAL", "一键把输入、累加、master state 和敏感算子全转 FP8 会暴露溢出、舍入与更新失真;这不是 V3 配方。"],
mixed: ["FP8 / tiled scale", "FP32-assisted", "FP32 / BF16 roles", "BF16 / FP32", 46, "MANAGED", "V3 把主要 GEMM、缩放、累加、master state、敏感算子和通信分别设计;“混合精度”才是完整对象。"],
};
const renderPrecision = () => {
const detail = precisionDetails[precision];
set("[data-gemm-dtype]", detail[0]);
set("[data-accum-dtype]", detail[1]);
set("[data-master-dtype]", detail[2]);
set("[data-sensitive-dtype]", detail[3]);
set("[data-risk-label]", detail[5]);
set("[data-precision-explain]", detail[6]);
const bar = one<HTMLElement>("[data-risk-bar]");
if (bar) bar.style.width = `${detail[4]}%`;
};
const renderMtp = () => {
const flow = one<HTMLElement>("[data-mtp-flow]");
const details: Record<string, [string, string, string, string, string]> = {
off: ["1 token target", "MAIN ONLY", "YES", "hₜ → next token", "关闭 MTP 后只有主 next-token loss;这不是 V3 报告采用的预训练目标。"],
train: ["2 token targets", "TRAIN + MODULE", "YES", "hₜ → t+1 · MTP₁(hₜ,t+1) → t+2", "V3 的顺序 MTP 首先增加训练信号;报告明确推理可直接丢弃,也可复用于 speculative decoding。"],
draft: ["draft + verify", "EXTRA DRAFT COST", "YES", "MTP draft → main model verify → accept/reject", "把 MTP module 当草稿器仍需主模型验证;验收率与 kernel 决定是否真实加速。"],
};
const detail = details[mtpRole];
set("[data-mtp-supervision]", detail[0]);
set("[data-mtp-main-cost]", detail[1]);
set("[data-mtp-ar]", detail[2]);
set("[data-mtp-explain]", detail[4]);
if (flow) flow.innerHTML = detail[3].split("→").map((item, index, array) => `<b>${item.trim()}</b>${index < array.length - 1 ? "<i>→</i>" : ""}`).join("");
};
all<HTMLButtonElement>("[data-schedule]").forEach((button) => button.addEventListener("click", () => {
schedule = button.dataset.schedule ?? "onef1b";
all("[data-schedule]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderSchedule();
}));
all<HTMLInputElement>("[data-stages],[data-micro],[data-comm-ratio]").forEach((control) => control.addEventListener("input", renderSchedule));
all<HTMLButtonElement>("[data-precision]").forEach((button) => button.addEventListener("click", () => {
precision = button.dataset.precision ?? "mixed";
all("[data-precision]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderPrecision();
}));
all<HTMLButtonElement>("[data-mtp-role]").forEach((button) => button.addEventListener("click", () => {
mtpRole = button.dataset.mtpRole ?? "train";
all("[data-mtp-role]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderMtp();
}));
let algorithm = "grpo";
let r1Mode = "zero";
const rewardPresets: Record<string, [number[], number[]]> = {
mixed: [[0, 1, .7, .2], [512, 768, 1536, 3072]],
same: [[1, 1, 1, 1], [512, 768, 1536, 3072]],
longwrong: [[1, .7, .2, 0], [384, 768, 2048, 6144]],
};
const renderRl = () => {
const rewards = all<HTMLInputElement>("[data-rollout-reward]").map((input) => Number(input.value));
const lengths = all<HTMLInputElement>("[data-rollout-length]").map((input) => Math.max(1, Number(input.value)));
const mean = rewards.reduce((sum, number) => sum + number, 0) / rewards.length;
const variance = rewards.reduce((sum, number) => sum + (number - mean) ** 2, 0) / rewards.length;
const std = Math.sqrt(variance);
const threshold = value("[data-overlong]");
const centered = rewards.map((reward) => reward - mean);
const advantages = centered.map((number) => algorithm === "dr" ? number : std > 1e-8 ? number / std : 0);
const weights = advantages.map((advantage, index) => {
if (algorithm === "dr") return advantage / threshold * 1024;
if (algorithm === "dapo") return lengths[index] > threshold ? 0 : advantage * lengths[index] / Math.max(...lengths);
return advantage / lengths[index] * 1024;
});
const effective = algorithm === "dapo" ? rewards.filter((reward, index) => Math.abs(reward - mean) > 1e-8 && lengths[index] <= threshold).length : rewards.length;
const rows = one<HTMLElement>("[data-advantage-rows]");
if (rows) rows.innerHTML = rewards.map((reward, index) => {
const width = Math.min(100, Math.abs(weights[index]) / Math.max(...weights.map(Math.abs), .001) * 100);
return `<div><b>y${index + 1}</b><span>${reward.toFixed(2)}</span><span>${lengths[index].toLocaleString()}</span><span>${advantages[index].toFixed(2)}</span><span class="${weights[index] >= 0 ? "positive" : "negative"}"><i style="width:${width}%"></i>${weights[index].toFixed(2)}</span></div>`;
}).join("");
const details: Record<string, [string, string, string]> = {
grpo: ["GRPO / ORIGINAL FAMILY", "奖励按组均值和标准差归一;response-level loss 再按各自长度平均,可能改变长短回答的 Token 权重。", "DeepSeekMath / R1"],
dapo: ["DAPO-STYLE / FOLLOW-UP", "这里用 token-level 聚合方向和 overlong filter 展示 DAPO 的两个修正;真实 DAPO 还包含 Clip-Higher 与 Dynamic Sampling。", "DAPO · arXiv:2503.14476"],
dr: ["Dr.GRPO / FOLLOW-UP", "去掉组 std normalization,并用固定全局长度分母,暴露原 GRPO 的 response-length 与 question-difficulty 尺度问题。", "Dr.GRPO · arXiv:2503.20783"],
};
const detail = details[algorithm];
set("[data-algorithm-name]", detail[0]);
set("[data-algorithm-explain]", detail[1]);
set("[data-provenance]", detail[2]);
set("[data-reward-mean]", mean.toFixed(3));
set("[data-reward-std]", std.toFixed(3));
set("[data-effective]", `${effective} / ${rewards.length}`);
set("[data-signal-state]", std < 1e-8 ? "ZERO GROUP SIGNAL" : algorithm === "dapo" && effective < rewards.length ? "FILTER / RESAMPLE" : "GROUP-RELATIVE SIGNAL");
set("[data-clip-low-label]", (value("[data-clip-low]") / 100).toFixed(2));
set("[data-clip-high-label]", (value("[data-clip-high]") / 100).toFixed(2));
set("[data-overlong-label]", String(threshold));
set("[data-rl-boundary]", std < 1e-8
? "四条奖励完全相同:组内中心化后优势为零。DAPO Dynamic Sampling 会过滤此类无梯度组并补采,但 rollout 成本不会消失。"
: "优势公式与论文定义对齐;weight 只显示归一和长度方向,没有 policy ratio、真实 token probability、KL 或 optimizer。");
};
all<HTMLButtonElement>("[data-reward-preset]").forEach((button) => button.addEventListener("click", () => {
const preset = rewardPresets[button.dataset.rewardPreset ?? "mixed"];
all<HTMLInputElement>("[data-rollout-reward]").forEach((input, index) => { input.value = String(preset[0][index]); });
all<HTMLInputElement>("[data-rollout-length]").forEach((input, index) => { input.value = String(preset[1][index]); });
all("[data-reward-preset]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderRl();
}));
all<HTMLInputElement>("[data-rollout-reward],[data-rollout-length],[data-clip-low],[data-clip-high],[data-overlong]").forEach((control) => control.addEventListener("input", renderRl));
all<HTMLButtonElement>("[data-rl-algorithm]").forEach((button) => button.addEventListener("click", () => {
algorithm = button.dataset.rlAlgorithm ?? "grpo";
all("[data-rl-algorithm]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderRl();
}));
const r1Details: Record<string, [string[], string]> = {
zero: [["V3 BASE", "RULE REWARD", "GRPO", "R1-ZERO"], "R1-Zero 从 V3 Base 直接进行规则奖励 GRPO;“无 reasoning SFT”不等于“无预训练知识”。"],
r1: [["V3 BASE", "COLD START", "REASONING RL", "SFT MIX", "GENERAL RL"], "正式 R1 用 cold start 修可读性与语言,再经 reasoning RL、rejection/SFT mix 和通用 RL;它不是纯 RL 单阶段。"],
distill: [["R1 TEACHER", "≈800K FILTERED TRACES", "SFT", "1.5B–70B STUDENTS"], "报告中的蒸馏学生主要学习 R1 生成/筛选轨迹,没有重演同一大规模 RL 探索过程。"],
};
const renderR1 = () => {
const detail = r1Details[r1Mode];
const flow = one<HTMLElement>("[data-r1-mode-flow]");
if (flow) flow.innerHTML = detail[0].map((item, index) => `<b>${item}</b>${index < detail[0].length - 1 ? "<i>→</i>" : ""}`).join("");
set("[data-r1-mode-explain]", detail[1]);
};
all<HTMLButtonElement>("[data-r1-mode]").forEach((button) => button.addEventListener("click", () => {
r1Mode = button.dataset.r1Mode ?? "zero";
all("[data-r1-mode]").forEach((candidate) => candidate.classList.toggle("active", candidate === button));
renderR1();
}));
renderCapacity();
renderCache();
renderSchedule();
renderPrecision();
renderMtp();
renderRl();
renderR1();
});
</script>
<style>
.ds-lab { max-width:100%; margin:36px 0; overflow:hidden; box-sizing:border-box; border:1px solid var(--line-strong); background:var(--paper); box-shadow:0 24px 70px rgba(8,18,30,.16); }
.ds-lab-head { display:grid; grid-template-columns:1fr 1fr; gap:38px; align-items:end; padding:30px; color:#f4efe7; background:linear-gradient(135deg,#172437,#263b52); }
.ds-lab-head p:first-child,.panel-intro span,.subhead span { margin:0 0 9px; color:#d49a68; font:600 .55rem var(--mono); letter-spacing:.13em; }
.ds-lab-head h3 { margin:0; color:#fff; font:650 clamp(1.3rem,2.6vw,2.05rem) var(--serif); }
.ds-lab-head > p { margin:0; color:#b7c1cc; font-size:.65rem; line-height:1.8; }
.ds-tabs { display:grid; grid-template-columns:repeat(4,1fr); border-bottom:1px solid var(--line-strong); }
.ds-tabs button { min-height:94px; display:grid; grid-template-columns:32px 1fr; grid-template-rows:auto auto; gap:4px 8px; padding:18px; border:0; border-right:1px solid var(--line); color:var(--ink); background:var(--paper-raised); text-align:left; cursor:pointer; }
.ds-tabs button:last-child { border-right:0; }.ds-tabs button[aria-selected="true"] { color:#fff; background:var(--navy); }
.ds-tabs span { grid-row:1/3; color:var(--copper); font:600 .6rem var(--mono); }.ds-tabs b { font:650 .84rem var(--serif); }.ds-tabs small { color:var(--muted); font:.49rem var(--mono); }
.ds-tabs button[aria-selected="true"] small { color:#aab7c5; }
.ds-panel { padding:30px; }.panel-intro { display:grid; grid-template-columns:1.1fr .9fr; gap:34px; align-items:end; margin-bottom:24px; }
.panel-intro h4 { margin:0; font:650 clamp(1.2rem,2.5vw,1.85rem) var(--serif); }.panel-intro > p { margin:0; color:var(--muted); font-size:.65rem; line-height:1.8; }
.preset-row,.choice-row { display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin:18px 0; }
.preset-row button,.choice-row button { min-height:63px; padding:12px; border:1px solid var(--line); color:var(--ink); background:var(--paper-raised); text-align:left; cursor:pointer; }
.preset-row button.active,.choice-row button.active { color:#fff; border-color:var(--navy); background:var(--navy); }
.preset-row b,.choice-row b { display:block; font:.59rem var(--mono); }.preset-row small,.choice-row small { display:block; margin-top:7px; color:var(--muted); font:.48rem var(--mono); }
.preset-row button.active small,.choice-row button.active small { color:#b6c2ce; }
.control-grid { display:grid; gap:9px; margin:16px 0 22px; }.control-grid.five { grid-template-columns:repeat(5,1fr); }.control-grid.four { grid-template-columns:repeat(4,1fr); }.control-grid.three { grid-template-columns:repeat(3,1fr); }
.control-grid label { display:flex; flex-direction:column; justify-content:space-between; gap:9px; min-height:72px; padding:12px; border:1px solid var(--line); background:var(--paper-raised); color:var(--muted); font:.52rem var(--mono); }
.control-grid label > span { display:flex; justify-content:space-between; gap:6px; }.control-grid input[type="range"] { width:100%; accent-color:var(--copper); }.control-grid select { min-height:31px; border:1px solid var(--line); color:var(--ink); background:var(--paper); font:.55rem var(--mono); }
.capacity-stage { display:grid; grid-template-columns:130px 25px 1fr 25px 145px; gap:12px; align-items:center; margin:24px 0; padding:22px; background:#172437; color:#fff; }
.capacity-stage > i { color:#d49a68; text-align:center; font-style:normal; }.router-box { padding:18px; border:1px solid #405269; }.router-box span { color:#d49a68; font:.5rem var(--mono); }.router-box b { display:block; margin:10px 0; font:650 1.2rem var(--serif); }.router-box small { color:#98a9ba; font:.48rem var(--mono); }
.expert-map { display:grid; grid-template-columns:repeat(8,1fr); gap:5px; }.expert-map i { min-height:43px; display:flex; flex-direction:column; justify-content:center; align-items:center; border:1px solid #405269; color:#7d8fa3; font-style:normal; }.expert-map i.active { color:#fff; border-color:#d49a68; background:rgba(212,154,104,.18); }.expert-map i.shared { background:#8c5538; }
.expert-map b { font:.5rem var(--mono); }.expert-map small { margin-top:4px; font:.4rem var(--mono); }
.metric-grid { display:grid; border-top:1px solid var(--line); border-left:1px solid var(--line); margin:20px 0; }.metric-grid.four { grid-template-columns:repeat(4,1fr); }.metric-grid.three { grid-template-columns:repeat(3,1fr); }.metric-grid.two { grid-template-columns:repeat(2,1fr); }
.metric-grid article { min-height:125px; padding:18px; border-right:1px solid var(--line); border-bottom:1px solid var(--line); }.metric-grid span { color:var(--copper); font:.49rem var(--mono); letter-spacing:.08em; }.metric-grid b { display:block; margin:14px 0 9px; font:650 1.12rem var(--serif); }.metric-grid p { margin:0; color:var(--muted); font-size:.53rem; line-height:1.55; }.metric-grid .dark { color:#fff; background:var(--navy); }.metric-grid .dark p { color:#9fb0c2; }
.evidence-boundary { margin-top:18px; padding:18px 20px; border-left:3px solid var(--copper); background:rgba(193,124,68,.08); }.evidence-boundary b { font:.57rem var(--mono); letter-spacing:.08em; }.evidence-boundary p { margin:8px 0 0; color:var(--muted); font-size:.61rem; line-height:1.7; }
.cache-comparison { display:grid; grid-template-columns:repeat(3,1fr); border:1px solid var(--line); }.cache-comparison article { padding:20px; border-right:1px solid var(--line); }.cache-comparison article:last-child { border-right:0; }.cache-comparison article.selected { background:rgba(193,124,68,.08); }.cache-comparison span { color:var(--copper); font:.54rem var(--mono); }.cache-comparison b { display:block; margin:12px 0 4px; font:650 1.2rem var(--serif); }.cache-comparison small { color:var(--muted-light); font:.48rem var(--mono); }.cache-comparison article > div { height:9px; margin:16px 0; background:var(--line); }.cache-comparison i { display:block; height:100%; background:var(--copper); }.cache-comparison p { color:var(--muted); font-size:.57rem; line-height:1.6; }
.absorption-grid { display:grid; grid-template-columns:1fr 1fr; margin-top:18px; border:1px solid var(--line); }.absorption-grid > div { padding:22px; }.absorption-grid > div:first-child { border-right:1px solid var(--line); }.absorption-grid span { color:var(--copper); font:.5rem var(--mono); }.absorption-grid code { display:block; margin:14px 0; color:var(--ink); font:.73rem var(--mono); }.absorption-grid div > div { display:flex; align-items:center; gap:8px; }.absorption-grid div > div b { padding:9px; border:1px solid var(--line); font:.58rem var(--mono); }.absorption-grid div > div i { color:var(--copper); font:.48rem var(--mono); font-style:normal; }.absorption-grid p { color:var(--muted); font-size:.57rem; line-height:1.65; }
.codesign-grid { display:grid; grid-template-columns:1.15fr .85fr; gap:16px; }.schedule-workbench,.precision-workbench,.mtp-workbench { padding:22px; border:1px solid var(--line); background:var(--paper-raised); }.subhead h5 { margin:0; font:650 1.05rem var(--serif); }.choice-row { grid-template-columns:repeat(2,1fr); }.choice-row.mtp { grid-template-columns:repeat(3,1fr); }
.control-grid.compact label { min-height:62px; padding:10px; }.pipeline-strip { display:grid; grid-template-columns:repeat(15,1fr); gap:3px; min-height:92px; margin:18px 0; }.pipeline-strip i { display:flex; justify-content:center; align-items:center; min-height:36px; font-style:normal; }.pipeline-strip i.compute { color:#fff; background:#314a62; }.pipeline-strip i.comm { color:#fff; background:#b36c45; }.pipeline-strip i.bubble { color:#8a96a3; border:1px dashed var(--line-strong); }.pipeline-strip small { font:.4rem var(--mono); }
.dtype-contract { display:grid; grid-template-columns:1fr 1fr; border-top:1px solid var(--line); border-left:1px solid var(--line); }.dtype-contract article { min-height:85px; padding:13px; border-right:1px solid var(--line); border-bottom:1px solid var(--line); }.dtype-contract span { color:var(--copper); font:.45rem var(--mono); }.dtype-contract b { display:block; margin-top:13px; font:.61rem var(--mono); }.risk-meter { margin:18px 0; }.risk-meter > span { color:var(--muted); font:.48rem var(--mono); }.risk-meter > div { height:9px; margin:8px 0; background:var(--line); }.risk-meter i { display:block; height:100%; background:var(--copper); }.risk-meter > b { font:.56rem var(--mono); }.precision-workbench > p,.boundary-copy { color:var(--muted); font-size:.57rem; line-height:1.65; }
.mtp-workbench { margin-top:16px; }.mtp-flow,.r1-mode-flow { display:flex; align-items:center; flex-wrap:wrap; gap:8px; padding:18px; background:#172437; color:#fff; }.mtp-flow b,.r1-mode-flow b { padding:10px; border:1px solid #405269; font:.53rem var(--mono); }.mtp-flow i,.r1-mode-flow i { color:#d49a68; font-style:normal; }
.rollout-controls { display:grid; grid-template-columns:repeat(4,1fr); gap:8px; }.rollout-controls label { display:grid; grid-template-columns:38px 1fr; gap:7px; padding:12px; border:1px solid var(--line); background:var(--paper-raised); }.rollout-controls span { grid-row:1/5; color:var(--copper); font:650 .75rem var(--serif); }.rollout-controls small { color:var(--muted); font:.45rem var(--mono); }.rollout-controls input { min-width:0; width:100%; border:1px solid var(--line); background:var(--paper); color:var(--ink); font:.54rem var(--mono); }.algorithm-row { grid-template-columns:repeat(3,1fr); }
.rl-stage { display:grid; grid-template-columns:1.15fr .85fr; border:1px solid var(--line); }.advantage-table { overflow:auto; }.advantage-table .head,.advantage-table [data-advantage-rows] > div { min-width:590px; display:grid; grid-template-columns:70px 60px 80px 60px 1fr; gap:8px; align-items:center; padding:12px 15px; border-bottom:1px solid var(--line); }.advantage-table .head { color:#fff; background:#172437; font:.45rem var(--mono); }.advantage-table [data-advantage-rows] > div { font:.55rem var(--mono); }.advantage-table [data-advantage-rows] > div:last-child { border-bottom:0; }.advantage-table [data-advantage-rows] span:last-child { position:relative; min-height:25px; display:flex; align-items:center; padding-left:7px; overflow:hidden; }.advantage-table [data-advantage-rows] span:last-child i { position:absolute; inset:0 auto 0 0; opacity:.18; }.advantage-table .positive i { background:#2e876a; }.advantage-table .negative i { background:#b1504c; }
.rl-diagnosis { padding:22px; color:#fff; background:#172437; }.rl-diagnosis > span { color:#d49a68; font:.5rem var(--mono); }.rl-diagnosis h5 { margin:14px 0; font:650 1.15rem var(--serif); }.rl-diagnosis > p { color:#b7c1cc; font-size:.58rem; line-height:1.7; }.rl-diagnosis dl { margin:18px 0 0; }.rl-diagnosis dl div { display:flex; justify-content:space-between; gap:12px; padding:8px 0; border-top:1px solid #405269; }.rl-diagnosis dt { color:#8fa2b5; font:.45rem var(--mono); }.rl-diagnosis dd { margin:0; font:.52rem var(--mono); text-align:right; }
.pipeline-switch { margin-top:18px; padding:22px; border:1px solid var(--line); }.pipeline-switch > p { color:var(--muted); font-size:.6rem; line-height:1.7; }
.ds-lab figcaption { display:flex; gap:18px; padding:16px 22px; border-top:1px solid var(--line); color:var(--muted); font-size:.54rem; line-height:1.6; }.ds-lab figcaption span { color:var(--copper); font:.49rem var(--mono); }
@media (max-width:1000px) {
.control-grid.five { grid-template-columns:repeat(3,1fr); }.codesign-grid { grid-template-columns:1fr; }.capacity-stage { grid-template-columns:110px 20px 1fr; }.capacity-stage > i:nth-of-type(2),.capacity-stage .output { display:none; }
}
@media (max-width:720px) {
.ds-lab-head,.panel-intro { grid-template-columns:1fr; }.ds-tabs { grid-template-columns:1fr; }.ds-tabs button { min-height:74px; border-right:0; border-bottom:1px solid var(--line); }
.ds-panel { padding:16px; }.preset-row,.control-grid.five,.control-grid.four,.control-grid.three,.cache-comparison,.absorption-grid,.metric-grid.four,.metric-grid.three,.metric-grid.two,.rollout-controls,.algorithm-row,.rl-stage { grid-template-columns:1fr; }
.capacity-stage { grid-template-columns:1fr; }.capacity-stage > i { transform:rotate(90deg); }.capacity-stage > i:nth-of-type(2),.capacity-stage .output { display:block; }.expert-map { grid-template-columns:repeat(6,1fr); }
.cache-comparison article,.absorption-grid > div:first-child { border-right:0; border-bottom:1px solid var(--line); }.pipeline-strip { grid-template-columns:repeat(10,1fr); }.choice-row { grid-template-columns:1fr 1fr; }
.rl-stage { border:0; gap:12px; }.advantage-table,.rl-diagnosis { border:1px solid var(--line); }.ds-lab figcaption { flex-direction:column; }
}
</style>