<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://optimisticompound.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://optimisticompound.github.io/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-08-10T10:10:55+00:00</updated><id>https://optimisticompound.github.io/feed.xml</id><title type="html">blank</title><subtitle>Yong Zhong&apos;s personal site for machine learning, representation learning, parameter generation, publications, and notes. </subtitle><entry><title type="html">A New Home for My Notes</title><link href="https://optimisticompound.github.io/blog/2026/new-home-for-my-notes/" rel="alternate" type="text/html" title="A New Home for My Notes"/><published>2026-08-04T01:00:00+00:00</published><updated>2026-08-04T01:00:00+00:00</updated><id>https://optimisticompound.github.io/blog/2026/new-home-for-my-notes</id><content type="html" xml:base="https://optimisticompound.github.io/blog/2026/new-home-for-my-notes/"><![CDATA[<p>I rebuilt this site to make technical writing easier to maintain and easier to find. It now uses the <code class="language-plaintext highlighter-rouge">al-folio</code> Jekyll starter, with content stored as Markdown and deployment handled automatically by GitHub Actions.</p> <p>The plan is simple:</p> <ul> <li>write durable notes about systems, NLP, and large language models;</li> <li>document projects with enough context to be useful later;</li> <li>keep the site lightweight, reproducible, and version controlled.</li> </ul> <p>Older notes remain available in my <a href="https://quilted-lift-9d9.notion.site/Yong-Zhong-s-Blog-2997954e6e44800987f8f12a13143308">Notion archive</a>. New writing will live here.</p>]]></content><author><name></name></author><category term="updates"/><category term="projects"/><category term="systems"/><category term="nlp"/><category term="llm"/><summary type="html"><![CDATA[Rebuilding this site as a durable home for technical notes and projects.]]></summary></entry><entry><title type="html">Cross-Entropy、KL、NLL 与 MLE：同一个目标的四种写法</title><link href="https://optimisticompound.github.io/blog/2026/cross-entropy-loss-and-more/" rel="alternate" type="text/html" title="Cross-Entropy、KL、NLL 与 MLE：同一个目标的四种写法"/><published>2026-05-25T04:00:00+00:00</published><updated>2026-05-25T04:00:00+00:00</updated><id>https://optimisticompound.github.io/blog/2026/cross-entropy-loss-and-more</id><content type="html" xml:base="https://optimisticompound.github.io/blog/2026/cross-entropy-loss-and-more/"><![CDATA[<p>Cross-entropy（CE）、KL divergence、negative log-likelihood（NLL）和 maximum likelihood estimation（MLE）经常被当成独立的几个概念，本文将从CE讲起，揭示四者的同一性。</p> <h2 id="1-从最小情形开始one-hot-分类问题">1. 从最小情形开始：One-hot 分类问题</h2> <p>考虑一个 $C$ 类分类问题。对输入 $x$，模型输出各类别的概率</p> \[p_c=p_\theta(y=c\mid x), \qquad p_c\ge 0, \qquad \sum_{c=1}^{C}p_c=1.\] <p>假设正确标签为 $j$。我们的目标是让输出正确标签的概率 $p_j$ 越大越好。于是想到可以最小化它的负对数损失，因为 $p_j$ 的负对数在 $p_j=0$ 时取正无穷，在 $p_j=1$ 时取 0：</p> \[\mathcal L(x,j) = -\log p_j\] <p>这个标签的分布是一个很简单的分布，只在标签正确的时候是 1，其他都是 0。我们把标签写成 one-hot 分布：</p> \[q_c=\mathbb 1\{c=j\},\] <p>改写一下原来的负对数损失：</p> \[\begin{aligned} \mathcal L(x,j) &amp;=-\log p_j\\ &amp;=-\sum_{c=1}^{C}\mathbb 1\{c=j\}\log p_c\\ &amp;=-\sum_{c=1}^{C}q_c\log p_c\\ &amp;=H(q,p_\theta). \end{aligned}\] <p>这样就得到了我们熟悉的 cross-entropy loss 形式。</p> <h2 id="2-统一目标目标分布下的-expected-log-loss">2. 统一目标：目标分布下的 expected log loss</h2> <p>更一般地，$q(y\mid x)$ 可以是任意分布对固定输入 $x$，定义</p> \[H\!\left(q(\cdot\mid x),p_\theta(\cdot\mid x)\right) =-\sum_y q(y\mid x)\log p_\theta(y\mid x).\] <p>再对输入分布取期望，得到总体目标</p> \[\begin{aligned} \mathcal L_{\mathrm{CE}}(\theta) &amp;=\mathbb E_{x\sim q(x)} \left[H\!\left(q(\cdot\mid x),p_\theta(\cdot\mid x)\right)\right]\\ &amp;=\mathbb E_{(x,y)\sim q} \left[-\log p_\theta(y\mid x)\right]. \end{aligned}\] <p>这就是贯穿全文的目标：在目标数据分布下，最小化模型赋给实际标签的 negative log-probability。CE、KL 和 NLL 的联系都可以从这个式子得到。</p> <h3 id="为什么它的最优解是-pq">为什么它的最优解是 $p=q$？</h3> <p>对固定的 $x$，考虑带概率归一化约束的优化问题：</p> \[\min_{p_1,\ldots,p_C} -\sum_{c=1}^{C}q_c\log p_c, \qquad \text{s.t.}\quad \sum_{c=1}^{C}p_c=1.\] <p>暂设所有 $q_c&gt;0$。引入 Lagrange multiplier $\lambda$：</p> \[\mathcal J(p,\lambda) =-\sum_{c=1}^{C}q_c\log p_c +\lambda\left(\sum_{c=1}^{C}p_c-1\right).\] <p>驻点满足</p> \[\frac{\partial\mathcal J}{\partial p_c} =-\frac{q_c}{p_c}+\lambda=0,\] <p>因此 $p_c=q_c/\lambda$。结合 $\sum_c p_c=\sum_c q_c=1$，可得 $\lambda=1$，从而</p> \[p_c=q_c.\] <p>当某些 $q_c=0$ 时，可以通过边界条件或连续性得到相同结论。这个推导说明：cross-entropy 的最优预测正是目标分布本身；它不只适用于 one-hot 标签。</p> <h2 id="3-分布视角ce-与-kl-散度">3. 分布视角：CE 与 KL 散度</h2> <p>先来看经典的 KL divergence 定义</p> \[D_{\mathrm{KL}}(q\|p_\theta) =\sum_y q(y\mid x) \log\frac{q(y\mid x)}{p_\theta(y\mid x)}.\] <p>展开 log 后，并用信息熵改写一下，则有</p> \[\begin{aligned} D_{\mathrm{KL}}(q\|p_\theta) &amp;=\sum_y q(y\mid x)\log q(y\mid x) -\sum_y q(y\mid x)\log p_\theta(y\mid x)\\ &amp;=-H(q)+H(q,p_\theta). \end{aligned}\] <p>细心的读者已经注意到了，式中的第二项就是我们的交叉熵，将其移项到等式左边，有</p> \[H(q,p_\theta) =H(q)+D_{\mathrm{KL}}(q\|p_\theta).\] <p>这里目标分布 $q$ 是固定的，所以 $H(q)$ 对 $\theta$ 求导后是常数。因此</p> \[\arg\min_\theta H(q,p_\theta) =\arg\min_\theta D_{\mathrm{KL}}(q\|p_\theta).\] <p>所以说，最小化 CE loss 和最小化 KL 散度是同一个优化目标。</p> <h2 id="4-数据视角经验-ce-与-nll">4. 数据视角：经验 CE 与 NLL</h2> <p>现实中我们不知道总体分布 $q(x,y)$，只有数据集</p> \[\mathcal D=\{(x_i,y_i)\}_{i=1}^{n}.\] <p>我们用数据集的经验分布近似总体分布，并把每个观测标签视为 one-hot target，得到 empirical cross-entropy：</p> \[\widehat{\mathcal L}_{\mathrm{CE}}(\theta) =-\frac{1}{n}\sum_{i=1}^{n} \log p_\theta(y_i\mid x_i).\] <p>另一方面，在给定各自输入后标签条件独立的假设下，conditional likelihood 是所有样本条件概率的乘积</p> \[p_\theta(y_{1:n}\mid x_{1:n}) =\prod_{i=1}^{n}p_\theta(y_i\mid x_i).\] <p>把它改写成 negative log-likelihood，首先套对数符号不改变单调性，然后再加负数变成 loss 的形式</p> \[\mathcal L_{\mathrm{NLL}}(\theta) =-\log p_\theta(y_{1:n}\mid x_{1:n}) =-\sum_{i=1}^{n}\log p_\theta(y_i\mid x_i).\] <p>不难看出</p> \[\widehat{\mathcal L}_{\mathrm{CE}}(\theta) =\frac{1}{n}\mathcal L_{\mathrm{NLL}}(\theta).\] <p>不少实现把 CE 取 batch mean，把 NLL 写成全数据 sum，所以二者数值一般不想等；但依然是相同的优化目标。</p> <h2 id="5-参数估计视角最小化-nll-就是-mle">5. 参数估计视角：最小化 NLL 就是 MLE</h2> <p>maximum likelihood estimation 定义为</p> \[\hat\theta_{\mathrm{MLE}} =\arg\max_\theta p_\theta(y_{1:n}\mid x_{1:n}) =\arg\max_\theta \sum_{i=1}^{n}\log p_\theta(y_i\mid x_i).\] <p>乘以 $-1$ 后，最大化变成最小化：</p> \[\hat\theta_{\mathrm{MLE}} =\arg\min_\theta \mathcal L_{\mathrm{NLL}}(\theta) =\arg\min_\theta \widehat{\mathcal L}_{\mathrm{CE}}(\theta).\] <p>因此在有限数据集上，有</p> \[\boxed{ \text{MLE} \Longleftrightarrow \min \text{NLL} \Longleftrightarrow \min \text{empirical CE} }\] <p>而在固定总体分布 $q$ 的意义下，有另一组等价关系：</p> \[\boxed{ \min \text{expected CE} \Longleftrightarrow \min D_{\mathrm{KL}}(q\|p_\theta) }\] <p>empirical CE 是 expected CE 的有限样本估计。这一步连接的是经验目标与总体目标，而不是两个有限样本量之间的恒等式。</p> <h2 id="6-从-logits-计算-ce为什么要用-log-sum-exp">6. 从 logits 计算 CE：为什么要用 log-sum-exp？</h2> <p>考虑 softmax 分类器。若模型输出 logits $z_1,\ldots,z_C$，softmax 概率为</p> \[p_c=\frac{e^{z_c}}{\sum_{k=1}^{C}e^{z_k}}.\] <p>对正确类别 $j$，one-hot cross-entropy 可以改写为</p> \[\begin{aligned} \mathcal L_{\mathrm{CE}} &amp;=-\log p_j\\ &amp;=-z_j+\log\sum_{k=1}^{C}e^{z_k}. \end{aligned}\] <p>在实现中，如果直接计算 $e^{z_k}$ 数值特别大，可能 overflow。利用 softmax 对所有 logits 同加减一个常数保持不变，令 $m=\max_k z_k$，可得稳定形式</p> \[\mathcal L_{\mathrm{CE}} =-z_j+m+\log\sum_{k=1}^{C}e^{z_k-m}.\] <p>这也是实践中应直接使用 <code class="language-plaintext highlighter-rouge">cross_entropy</code> 或 <code class="language-plaintext highlighter-rouge">log_softmax</code>，而不是先算 softmax、再手动取 logarithm 的原因。</p> <h2 id="7-结论">7. 结论</h2> <table> <thead> <tr> <th>视角</th> <th>对象</th> <th>与统一目标的关系</th> </tr> </thead> <tbody> <tr> <td>分布匹配</td> <td>$D_{\mathrm{KL}}(q|p_\theta)$</td> <td>与 CE 相差固定的 $H(q)$</td> </tr> <tr> <td>损失函数</td> <td>$H(q,p_\theta)$</td> <td>目标分布下的 expected negative log-probability</td> </tr> <tr> <td>有限数据</td> <td>NLL</td> <td>one-hot empirical CE 的总和形式</td> </tr> <tr> <td>参数估计</td> <td>MLE</td> <td>与最小化 NLL 完全等价</td> </tr> </tbody> </table> <hr/> <p><em>Migrated from the <a href="https://quilted-lift-9d9.notion.site/Cross-Entropy-Loss-and-More-36b7954e6e4480a490b3dea674c50774">original Notion post</a>.</em></p>]]></content><author><name></name></author><category term="notes"/><category term="machine-learning"/><category term="probability"/><category term="chinese"/><summary type="html"><![CDATA[从一个统一目标出发，推导 cross-entropy、forward KL divergence、negative log-likelihood 与 maximum likelihood estimation 的关系及成立条件。]]></summary></entry><entry><title type="html">证据下界的推导和解释 What Can We Know from ELBO?</title><link href="https://optimisticompound.github.io/blog/2026/what-can-we-know-from-elbo/" rel="alternate" type="text/html" title="证据下界的推导和解释 What Can We Know from ELBO?"/><published>2026-05-25T03:00:00+00:00</published><updated>2026-05-25T03:00:00+00:00</updated><id>https://optimisticompound.github.io/blog/2026/what-can-we-know-from-elbo</id><content type="html" xml:base="https://optimisticompound.github.io/blog/2026/what-can-we-know-from-elbo/"><![CDATA[<p>这篇笔记记录 Evidence Lower Bound（ELBO）的推导过程，以及它在 variational autoencoder（VAE）中的含义。</p> <h3 id="为什么需要-elbo">为什么需要 ELBO？</h3> <p>在 VAE 中，我们希望最大化模型对观测 $x$ 的 marginal likelihood：</p> \[p_\theta(x)=\int p_\theta(x,z)\,dz.\] <p>隐变量 $z$ 往往是连续且高维的，上述积分难以直接计算。如果能找到 $\log p_\theta(x)$ 的一个可计算下界，就可以通过最大化这个下界来近似最大化 marginal likelihood。这个下界就是 ELBO。</p> <h3 id="preliminaries">Preliminaries</h3> <ul> <li><strong>Jensen’s inequality</strong>：当 $f$ 是凹函数时，$f(\mathbb{E}[X])\geq\mathbb{E}[f(X)]$。</li> <li><strong>KL divergence</strong>：$D_{\mathrm{KL}}(q(z\mid x)|p(z))=\mathbb{E}_{q(z\mid x)}\left[\log\frac{q(z\mid x)}{p(z)}\right]$。</li> <li><strong>Importance sampling</strong>：$\int f(z)P(z)\,dz=\int f(z)\frac{P(z)}{Q(z)}Q(z)\,dz$，用容易采样的 $Q$ 来改写对 $P$ 的积分。</li> </ul> <h3 id="推导-elbo">推导 ELBO</h3> <p>引入一个可以采样的 variational posterior $q_\phi(z\mid x)$，在分子分母同时乘以它：</p> \[\begin{aligned} p_\theta(x) &amp;=\int p_\theta(x,z)\,dz\\ &amp;=\int p_\theta(x,z)\frac{q_\phi(z\mid x)}{q_\phi(z\mid x)}\,dz\\ &amp;=\mathbb{E}_{z\sim q_\phi(z\mid x)} \left[\frac{p_\theta(x,z)}{q_\phi(z\mid x)}\right]. \end{aligned}\] <p>对两边取对数，并利用 $\log$ 是凹函数以及 Jensen’s inequality：</p> \[\begin{aligned} \log p_\theta(x) &amp;=\log\mathbb{E}_{z\sim q_\phi(z\mid x)} \left[\frac{p_\theta(x,z)}{q_\phi(z\mid x)}\right]\\ &amp;\geq\mathbb{E}_{z\sim q_\phi(z\mid x)} \left[\log\frac{p_\theta(x,z)}{q_\phi(z\mid x)}\right]\\ &amp;=: \mathcal{L}_{\mathrm{ELBO}}(x). \end{aligned}\] <h3 id="elbo-的两种形式">ELBO 的两种形式</h3> <p><strong>Joint-distribution 期望形式</strong></p> \[\mathcal{L}_{\mathrm{ELBO}}(x) =\mathbb{E}_{z\sim q_\phi(z\mid x)} \left[\log\frac{p_\theta(x,z)}{q_\phi(z\mid x)}\right].\] <p><strong>Reconstruction term + KL divergence</strong></p> <p>利用 $p_\theta(x,z)=p_\theta(x\mid z)p(z)$ 展开：</p> \[\begin{aligned} \mathcal{L}_{\mathrm{ELBO}}(x) &amp;=\mathbb{E}_{q_\phi(z\mid x)}[\log p_\theta(x\mid z)] -D_{\mathrm{KL}}\big(q_\phi(z\mid x)\|p(z)\big). \end{aligned}\] <h3 id="这两种形式告诉了我们什么">这两种形式告诉了我们什么？</h3> <ul> <li>$q_\phi(z\mid x)$ 是 encoder 给出的 approximate posterior。</li> <li>$p(z)$ 是与 $x$ 无关的 prior。</li> <li>$p_\theta(x\mid z)$ 是 decoder likelihood。</li> </ul> <p>最大化 ELBO 同时意味着：</p> <ol> <li> <p>最大化 reconstruction term</p> \[\mathbb{E}_{q_\phi(z\mid x)}[\log p_\theta(x\mid z)],\] <p>让 decoder 能够重构观测 $x$。</p> </li> <li> <p>最小化 KL divergence</p> \[D_{\mathrm{KL}}\big(q_\phi(z\mid x)\|p(z)\big),\] <p>让 encoder 产生的隐变量分布接近 prior。</p> </li> </ol> <hr/> <p><em>Migrated from the <a href="https://quilted-lift-9d9.notion.site/What-Can-We-Know-from-ELBO-36b7954e6e44806f9956ef2b01ae2b5a">original Notion post</a>.</em></p>]]></content><author><name></name></author><category term="notes"/><category term="machine-learning"/><category term="variational-inference"/><category term="chinese"/><summary type="html"><![CDATA[从 importance sampling 和 Jensen's inequality 出发推导 ELBO，并解释它在 VAE 中的两种形式。]]></summary></entry><entry><title type="html">极大似然估计的推导和期望形式 Why MLE Comes in Expectation Form?</title><link href="https://optimisticompound.github.io/blog/2026/why-mle-comes-in-expectation-form/" rel="alternate" type="text/html" title="极大似然估计的推导和期望形式 Why MLE Comes in Expectation Form?"/><published>2026-05-25T02:00:00+00:00</published><updated>2026-05-25T02:00:00+00:00</updated><id>https://optimisticompound.github.io/blog/2026/why-mle-comes-in-expectation-form</id><content type="html" xml:base="https://optimisticompound.github.io/blog/2026/why-mle-comes-in-expectation-form/"><![CDATA[<p>这篇笔记记录 maximum likelihood estimation（MLE）的推导过程，同时解释 MLE 的两种常见写法：finite-sample 形式和 expectation 形式。</p> <h3 id="mle-的推导">MLE 的推导</h3> <p>设真实数据分布是 $p_{\mathrm{data}}(x)$，模型分布是 $p_\theta(x)$。我们从 $p_{\mathrm{data}}$ 独立采样：</p> \[\{x_1,x_2,\ldots,x_n\}\overset{\mathrm{i.i.d.}}{\sim}p_{\mathrm{data}}(x).\] <p>目标是找到让这组样本在模型下出现概率最大的参数 $\theta$。由于样本相互独立，联合 likelihood 是：</p> \[P_\theta(x_1,x_2,\ldots,x_n) =\prod_{i=1}^{n}p_\theta(x_i).\] <p>因此 MLE 为：</p> \[\hat\theta_{\mathrm{MLE}} =\arg\max_\theta\prod_{i=1}^{n}p_\theta(x_i).\] <p>对数函数单调递增，所以取对数不改变 $\arg\max$ 的结果，同时将乘积变成求和：</p> \[\hat\theta_{\mathrm{MLE}} =\arg\max_\theta\sum_{i=1}^{n}\log p_\theta(x_i).\] <p>这就是 finite-sample 形式的 MLE。</p> <h3 id="期望形式的-mle">期望形式的 MLE</h3> <p>将 log-likelihood 除以样本数 $n$ 不会改变最大化的参数：</p> \[\hat\theta_{\mathrm{MLE}} =\arg\max_\theta\frac{1}{n}\sum_{i=1}^{n}\log p_\theta(x_i).\] <p>根据大数定律，当 $n\to\infty$ 时，empirical average 收敛到真实数据分布下的期望：</p> \[\frac{1}{n}\sum_{i=1}^{n}\log p_\theta(x_i) \xrightarrow[n\to\infty]{} \mathbb{E}_{x\sim p_{\mathrm{data}}} [\log p_\theta(x)].\] <p>于是 population objective 可以写成：</p> \[\theta^* =\arg\max_\theta \mathbb{E}_{x\sim p_{\mathrm{data}}} [\log p_\theta(x)].\] <p>这说明 expectation 形式不是一个新的目标，而是 finite-sample average 在样本数足够大时的 population limit。</p> <hr/> <p><em>Migrated from the <a href="https://quilted-lift-9d9.notion.site/Why-MLE-Comes-in-Expectation-Form-36b7954e6e4480baa235f23745fe7b00">original Notion post</a>.</em></p>]]></content><author><name></name></author><category term="notes"/><category term="machine-learning"/><category term="probability"/><category term="chinese"/><summary type="html"><![CDATA[从独立样本的联合概率出发推导 MLE，并解释 empirical average 为什么收敛到 expectation。]]></summary></entry><entry><title type="html">为什么你应该卖烤炉鸡蛋灌饼，而不是锅包肉？</title><link href="https://optimisticompound.github.io/blog/2025/pipeline-jianbing-vs-guobaorou/" rel="alternate" type="text/html" title="为什么你应该卖烤炉鸡蛋灌饼，而不是锅包肉？"/><published>2025-11-18T04:00:00+00:00</published><updated>2025-11-18T04:00:00+00:00</updated><id>https://optimisticompound.github.io/blog/2025/pipeline-jianbing-vs-guobaorou</id><content type="html" xml:base="https://optimisticompound.github.io/blog/2025/pipeline-jianbing-vs-guobaorou/"><![CDATA[<p>假设你准备摆一个只有两个人的小吃摊。菜单上有两个候选：烤炉鸡蛋灌饼和锅包肉。</p> <p>它们都需要五个步骤，看起来复杂度相当；但在相同的人手和设备下，鸡蛋灌饼通常能卖得更多。区别不在步骤数量，而在这些步骤能否并行，以及它们是否争抢同一个稀缺资源。</p> <h2 id="两种同为五步的流程">两种同为五步的流程</h2> <p>烤炉鸡蛋灌饼的流程是：</p> <ol> <li>擀面皮；</li> <li>往面皮里灌鸡蛋；</li> <li>下油锅煎；</li> <li>放进烤炉烤；</li> <li>加小料并出餐。</li> </ol> <p>两个人分工时，A 只负责不断擀面皮，B 负责其余步骤。</p> <p>锅包肉的流程同样可以拆成五步：</p> <ol> <li>调面糊；</li> <li>裹面糊后完成第一遍炸制；</li> <li>升高油温复炸；</li> <li>炒热糖醋汁并挂汁；</li> <li>装盒、加香菜并出餐。</li> </ol> <p>在这个小摊里，A 负责调面糊和装盒，B 负责两遍炸制和炒糖醋汁。</p> <p>如果只数步骤，两者都是五步；如果画出资源依赖，差别就出现了。</p> <h2 id="真正的区别是资源依赖">真正的区别是资源依赖</h2> <p>锅包肉的问题是：在只有一个灶台的情况下，第一遍炸、第二遍炸和炒汁都要占用同一个灶台，也都需要 B 操作。即使 B 手速再快，这三段关键流程仍然只能串行执行：上一道菜没有释放灶台，下一道菜就无法进入相同阶段。</p> <p>鸡蛋灌饼则不同。油锅和烤炉是两个独立的工作站。一个饼在烤炉里烘烤时，另一个饼可以在油锅里煎；设备自行加热的间隙，B 还可以处理下一张饼。只要油锅和烤炉的容量足够，且上锅、翻面和转移等短操作可以并入相邻时间片，多个订单就可以处在不同阶段。</p> <p>因此，鸡蛋灌饼天然形成了一条流水线：</p> <div class="table-responsive"> <table class="table table-sm text-center" style="min-width: 46rem; table-layout: fixed; border-collapse: separate; border-spacing: 0.2rem"> <colgroup> <col style="width: 6rem"/> <col span="14" style="width: 2.75rem"/> </colgroup> <thead> <tr> <th scope="col" style="white-space: nowrap">订单 / 时间</th> <th scope="col">1</th> <th scope="col">2</th> <th scope="col">3</th> <th scope="col">4</th> <th scope="col">5</th> <th scope="col">6</th> <th scope="col">7</th> <th scope="col">8</th> <th scope="col">9</th> <th scope="col">10</th> <th scope="col">11</th> <th scope="col">12</th> <th scope="col">13</th> <th scope="col">14</th> </tr> </thead> <tbody> <tr> <th scope="row" style="background: var(--global-bg-color)">订单 1</th> <td style="background: color-mix(in srgb, #c026d3 18%, transparent); border-radius: 0.25rem"><strong>灌蛋</strong></td> <td colspan="4" style="background: color-mix(in srgb, #2563eb 18%, transparent); border-radius: 0.25rem"><strong>油锅</strong></td> <td colspan="4" style="background: color-mix(in srgb, #f59e0b 22%, transparent); border-radius: 0.25rem"><strong>烤炉</strong></td> <td style="background: color-mix(in srgb, #16a34a 20%, transparent); border-radius: 0.25rem"><strong>出餐</strong></td> <td colspan="4" style="background: var(--global-bg-color)"></td> </tr> <tr> <th scope="row" style="background: var(--global-bg-color)">订单 2</th> <td colspan="2" style="background: var(--global-bg-color)"></td> <td style="background: color-mix(in srgb, #c026d3 18%, transparent); border-radius: 0.25rem"><strong>灌蛋</strong></td> <td colspan="4" style="background: color-mix(in srgb, #2563eb 18%, transparent); border-radius: 0.25rem"><strong>油锅</strong></td> <td colspan="4" style="background: color-mix(in srgb, #f59e0b 22%, transparent); border-radius: 0.25rem"><strong>烤炉</strong></td> <td style="background: color-mix(in srgb, #16a34a 20%, transparent); border-radius: 0.25rem"><strong>出餐</strong></td> <td colspan="2" style="background: var(--global-bg-color)"></td> </tr> <tr> <th scope="row" style="background: var(--global-bg-color)">订单 3</th> <td colspan="4" style="background: var(--global-bg-color)"></td> <td style="background: color-mix(in srgb, #c026d3 18%, transparent); border-radius: 0.25rem"><strong>灌蛋</strong></td> <td colspan="4" style="background: color-mix(in srgb, #2563eb 18%, transparent); border-radius: 0.25rem"><strong>油锅</strong></td> <td colspan="4" style="background: color-mix(in srgb, #f59e0b 22%, transparent); border-radius: 0.25rem"><strong>烤炉</strong></td> <td style="background: color-mix(in srgb, #16a34a 20%, transparent); border-radius: 0.25rem"><strong>出餐</strong></td> </tr> </tbody> </table> </div> <p>每个有色块代表一个 processing stage，空白表示订单尚未进入或已经离开流水线。可以看到，三个订单都要经历 1 个时间片的灌蛋、4 个时间片的油锅、4 个时间片的烤炉和 1 个时间片的出餐，总 latency 仍然是 10 个时间片；但后一行相对前一行只向右移动 2 列，因此相邻订单可以每隔 2 个时间片进入流水线。</p> <h2 id="不要混淆-latency-和-throughput">不要混淆 latency 和 throughput</h2> <p>这是流水线最容易被说错的地方。</p> <ul> <li><strong>Latency</strong>：完成一个订单从开始到结束需要多久；</li> <li><strong>Throughput</strong>：进入稳态后，单位时间能完成多少订单。</li> </ul> <p>在上面的简化模型中，单个鸡蛋灌饼的 latency 仍然是 10 个时间片。流水线没有让某一张饼瞬间成熟，而是让不同订单的等待时间互相重叠，因此稳态下每 2 个时间片就能出一个饼。</p> <p>如果从空流水线开始，完成 $N$ 个订单所需的时间是</p> \[T_{\text{pipeline}}(N)=10+2(N-1)=2N+8.\] <p>若完全串行执行，则需要</p> \[T_{\text{serial}}(N)=10N.\] <p>因此加速比为</p> \[S(N)=\frac{10N}{2N+8}.\] <p>当订单很多时，$S(N)$ 逐渐接近 5。这才是“效率提升 5 倍”的准确含义：它是稳态 throughput 的极限提升，而不是第一批订单从冷启动时立刻获得的提升。</p> <p>例如，一个时间片是 20 秒：</p> <ul> <li>单个订单的 latency 是 200 秒；</li> <li>稳态下平均每 40 秒出一个饼；</li> <li>流水线填满后，6 分钟可以连续完成 9 个饼；</li> <li>但从空流水线开始，前 9 个饼需要 26 个时间片，也就是 8 分 40 秒。</li> </ul> <p>相比之下，完全串行做 9 个饼需要 30 分钟。第一批 9 个订单的实际加速约为 $90/26\approx 3.46$ 倍；订单越多，平均效率越接近 5 倍。</p> <h2 id="卖什么其实是在选择系统结构">卖什么，其实是在选择系统结构</h2> <p>这个例子不是说锅包肉天生不能流水化。如果增加灶台、炸锅或操作人员，它同样可以获得并行度。问题在于，当资源固定为“两个人、一个灶台”时，它的关键步骤集中争抢同一个 bottleneck；鸡蛋灌饼则把工作分散到了油锅、烤炉和人工操作三个工作站。</p> <p>因此，比较两门生意时，不能只问“各有多少步骤”，还要问：</p> <ol> <li>哪个步骤占用最稀缺的资源？</li> <li>哪些等待时间可以被其他订单利用？</li> <li>相邻订单最短可以间隔多久进入流程？</li> <li>增加一个人或一台设备，是否真的能解除 bottleneck？</li> </ol> <p>步骤数量决定不了产能。真正决定单位时间出餐量的，是依赖关系、资源冲突和最慢的流水线阶段。</p> <p>所以，在这个限定条件下，你应该卖烤炉鸡蛋灌饼，而不是锅包肉。</p>]]></content><author><name></name></author><category term="notes"/><category term="systems"/><category term="performance"/><category term="pipeline"/><category term="chinese"/><summary type="html"><![CDATA[同样是五个步骤，为什么烤炉鸡蛋灌饼出餐更快？从一个小摊理解流水线、吞吐量与系统瓶颈。]]></summary></entry></feed>