Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"/> | |
| <title>21. Diffusion language models β LM Playground</title> | |
| <link rel="stylesheet" href="/platform/platform.css"/> | |
| <script type="module" src="/platform/platform.js"></script> | |
| <style> | |
| :root{ | |
| --bg:#0f1117; --panel:#181b24; --panel-2:#1f2330; --border:#2a2f3d; | |
| --text:#e6e8ee; --muted:#9aa3b2; --accent:#7c8cff; --accent-2:#5be0c0; | |
| --good:#5be08a; --warn:#ffc06b; --bad:#ff9090; | |
| --ar:#7c8cff; --diff:#5be0c0; --mask:#3a3f4d; | |
| --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace; | |
| } | |
| *{box-sizing:border-box} | |
| html,body{margin:0;padding:0 20px 80px;background:radial-gradient(1200px 600px at 50% -10%,#1a1f2e 0%,var(--bg) 55%);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;line-height:1.5;-webkit-font-smoothing:antialiased} | |
| header{max-width:980px;margin:0 auto;padding:34px 0 0} | |
| .header-inner{display:flex;justify-content:space-between;align-items:flex-start;padding-bottom:12px} | |
| h1{font-size:30px;margin:0 0 6px;letter-spacing:-.5px} | |
| .sub{color:var(--muted);max-width:780px;margin:0;font-size:14.5px;line-height:1.6} | |
| .sub b{color:var(--text);font-weight:600} | |
| .page-tabs{display:flex;border-bottom:1px solid var(--border)} | |
| .page-tab{background:none;border:none;color:var(--muted);padding:11px 22px 10px;font-size:14px;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;transition:.12s} | |
| .page-tab:hover{color:var(--text)}.page-tab.active{color:var(--accent);border-bottom-color:var(--accent)} | |
| .tab-panel{display:none}.tab-panel.active{display:block} | |
| .guide{max-width:980px;margin:0 auto;padding:30px 0 80px;display:grid;grid-template-columns:1fr 220px;gap:0 48px} | |
| .guide-toc{grid-column:2;grid-row:1/20;position:sticky;top:64px;align-self:start;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:4px} | |
| .toc-label{font-size:10px;text-transform:uppercase;letter-spacing:1px;color:var(--muted);font-weight:700;margin-bottom:6px} | |
| .guide-toc a{color:var(--muted);text-decoration:none;font-size:12.5px;padding:5px 8px;border-radius:6px;transition:.1s} | |
| .guide-toc a:hover{color:var(--text);background:var(--panel-2)} | |
| .chapter{grid-column:1;padding:0 0 48px;border-bottom:1px solid var(--border);margin-bottom:48px} | |
| .chapter:last-of-type{border-bottom:none} | |
| .chapter h2{font-size:22px;margin:0 0 18px;display:flex;align-items:center;gap:12px;letter-spacing:-.3px} | |
| .ch-num{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:99px;background:var(--accent-2);color:#0b0d14;font-size:14px;font-weight:800;flex-shrink:0} | |
| .chapter h3{font-size:15px;margin:24px 0 8px;color:var(--accent-2);font-weight:700} | |
| .chapter p{margin:0 0 14px;line-height:1.7;color:#ced3de;font-size:15px} | |
| .chapter strong{color:var(--text)}.chapter em{font-style:italic} | |
| code{background:var(--panel-2);border:1px solid var(--border);border-radius:5px;padding:1px 5px;font-family:var(--mono);font-size:12.5px;color:var(--accent-2)} | |
| .callout{border-radius:10px;padding:14px 16px;margin:20px 0;font-size:14px;line-height:1.65;color:#ced3de} | |
| .callout strong{display:block;margin-bottom:5px;font-size:12px;text-transform:uppercase;letter-spacing:.6px} | |
| .callout.insight{background:#7c8cff18;border-left:3px solid var(--accent)}.callout.insight strong{color:var(--accent)} | |
| .callout.warn{background:#ffc06b18;border-left:3px solid var(--warn)}.callout.warn strong{color:var(--warn)} | |
| .try-it{display:inline-block;margin-top:10px;padding:10px 18px;border-radius:9px;background:var(--panel-2);border:1px solid var(--border);color:var(--accent);font-size:13.5px;font-weight:600;cursor:pointer;transition:.14s;font-family:inherit} | |
| .try-it:hover{background:#7c8cff22;border-color:var(--accent)} | |
| .try-it.large{font-size:15px;padding:14px 28px;background:var(--accent-2);color:#0b0d14;border-color:var(--accent-2)} | |
| .try-it.large:hover{filter:brightness(1.08)} | |
| .guide-end{text-align:center;padding:18px 0 0}.guide-end p{color:var(--muted);margin-bottom:14px} | |
| .panel-guide-item{display:flex;gap:12px;align-items:baseline;padding:9px 0;border-bottom:1px dashed var(--border)} | |
| .panel-guide-item:last-child{border-bottom:none} | |
| .pgi-label{font-size:13px;font-weight:800;color:var(--accent-2);min-width:20px;font-family:var(--mono)} | |
| .panel-guide-item p{margin:0;font-size:13.5px;color:#ced3de;line-height:1.55} | |
| .wrap{max-width:980px;margin:20px auto 0} | |
| .panel{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:16px 18px;margin-bottom:16px} | |
| .panel-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;flex-wrap:wrap;gap:8px} | |
| .panel-label{font-size:13px;font-weight:700;color:var(--text)}.panel-note{color:var(--muted);font-size:12px} | |
| .ctrl-row{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-end;margin:4px 0 6px} | |
| .ctrl{display:flex;flex-direction:column;gap:6px} | |
| .ctrl .lab{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);font-weight:600} | |
| .ctrl .lab b{color:var(--text);font-family:var(--mono)} | |
| input[type=range]{accent-color:var(--accent);width:140px} | |
| .btn{border:1px solid var(--border);background:var(--panel-2);color:var(--text);font-size:13px;font-weight:600;padding:9px 16px;border-radius:9px;cursor:pointer;font-family:inherit} | |
| .btn:hover{border-color:var(--accent)}.btn.primary{background:var(--accent-2);color:#0b0d14;border-color:var(--accent-2)} | |
| svg{display:block;width:100%;height:auto;overflow:visible} | |
| .gencol{background:var(--panel-2);border:1px solid var(--border);border-radius:11px;padding:14px} | |
| .gencol.ar{border-top:2px solid var(--ar)}.gencol.diff{border-top:2px solid var(--diff)} | |
| .gencol h4{margin:0 0 2px;font-size:13px}.gencol h4.ar{color:var(--ar)}.gencol h4.diff{color:var(--diff)} | |
| .gencol .sub{font-size:11px;color:var(--muted);margin:0 0 10px} | |
| .seq{display:flex;flex-wrap:wrap;gap:5px;min-height:120px;align-content:flex-start} | |
| .tok{font-family:var(--mono);font-size:13px;padding:5px 8px;border-radius:6px;border:1px solid var(--border);background:var(--bg);transition:.18s} | |
| .tok.mask{color:var(--muted);background:var(--mask);border-color:#4a4f5d} | |
| .tok.ar{color:var(--ar);border-color:var(--ar);background:#7c8cff15} | |
| .tok.diff{color:var(--diff);border-color:var(--diff);background:#5be0c015} | |
| .tok.just{background:#5be0c035;transform:scale(1.06)} | |
| .stepline{font-family:var(--mono);font-size:12px;color:var(--muted);margin-top:8px} | |
| .stepline b{color:var(--text)} | |
| .grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start} | |
| .card{background:var(--panel-2);border:1px solid var(--border);border-radius:11px;padding:14px} | |
| .card h4{margin:0 0 4px;font-size:13px}.card .cap{color:var(--muted);font-size:11.5px;margin:0 0 8px;line-height:1.5} | |
| .cmptable{width:100%;border-collapse:collapse;font-size:12.5px} | |
| .cmptable td{padding:7px 8px;border-bottom:1px solid var(--border);vertical-align:top} | |
| .cmptable td:first-child{color:var(--muted);width:34%} | |
| .cmptable .ar{color:var(--ar)}.cmptable .diff{color:var(--diff)} | |
| .hint{color:var(--muted);font-size:12.5px;margin-top:10px;line-height:1.5} | |
| .fig{margin:22px 0;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 16px 12px} | |
| .fig svg{display:block;width:100%;height:auto;overflow:visible} | |
| .fig figcaption{margin-top:10px;font-size:12px;color:var(--muted);text-align:center;line-height:1.55} | |
| footer{max-width:980px;margin:30px auto 0;color:var(--muted);font-size:12px;text-align:center;line-height:1.6} | |
| @media(max-width:760px){.guide{grid-template-columns:1fr}.guide-toc{grid-column:1;grid-row:auto;position:static;display:grid;grid-template-columns:1fr 1fr}.toc-label{grid-column:1/-1}.grid2{grid-template-columns:1fr}} | |
| </style> | |
| </head> | |
| <body data-chapter="diffusion-lm"> | |
| <header> | |
| <div class="header-inner"> | |
| <div> | |
| <h1>Diffusion language models</h1> | |
| <p class="sub"> | |
| Every model so far writes the same way: one token at a time, strictly left to right. But | |
| that's a choice, not a law. Image generators don't paint pixel by pixel β they start from | |
| noise and refine the <b>whole canvas at once</b>, over a handful of steps. Diffusion | |
| language models ask whether text can be written the same way: all positions in parallel, | |
| sharpened step by step from a blank, fully-masked sequence. | |
| </p> | |
| </div> | |
| </div> | |
| <nav class="page-tabs" role="tablist"> | |
| <button class="page-tab active" data-tab="guide">β Guide</button> | |
| <button class="page-tab" data-tab="playground">β‘ Playground</button> | |
| </nav> | |
| </header> | |
| <!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ GUIDE --> | |
| <section id="guide-tab" class="tab-panel active"> | |
| <article class="guide"> | |
| <nav class="guide-toc"> | |
| <span class="toc-label">Contents</span> | |
| <a href="#ch1">1 Β· The left-to-right habit</a> | |
| <a href="#ch2">2 Β· Noise, for discrete text</a> | |
| <a href="#ch3">3 Β· Refine in parallel</a> | |
| <a href="#ch4">4 Β· vs autoregressive</a> | |
| <a href="#ch5">5 Β· Why AR still rules</a> | |
| <a href="#ch6">6 Β· Reading the playground</a> | |
| </nav> | |
| <!-- 1 --> | |
| <section class="chapter" id="ch1"> | |
| <h2><span class="ch-num">1</span> The left-to-right habit</h2> | |
| <p> | |
| Autoregression β predict the next token, append, repeat β has been the only game in this | |
| course, and for good reason: it's simple, it trains on an exact likelihood, and it matches | |
| the way text seems to unfold. But it bakes in two constraints. Generation is strictly | |
| sequential, one token per forward pass, so a thousand-token output takes a thousand passes. | |
| And it only ever looks left β a token, once written, can never be revised in light of what | |
| comes after. | |
| </p> | |
| <figure class="fig"><svg viewBox="0 0 700 180" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,Segoe UI,Roboto,sans-serif"><defs><marker id="ardl" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="var(--muted)"/></marker></defs><rect x="40" y="50" width="108" height="56" rx="8" fill="var(--panel-2)" stroke="var(--border)"/><rect x="46" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="66" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="86" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="106" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="126" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="46" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="66" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="86" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="106" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="126" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="46" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="66" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="86" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="106" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="126" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><text x="94" y="128" text-anchor="middle" fill="var(--muted)" font-size="9.5">all noise</text><line x1="148" y1="78" x2="172" y2="78" stroke="var(--accent)" stroke-width="2" marker-end="url(#ardl)"/><rect x="172" y="50" width="108" height="56" rx="8" fill="var(--panel-2)" stroke="var(--border)"/><rect x="178" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="198" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="218" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="238" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="258" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="178" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="198" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="218" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="238" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="258" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="178" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="198" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="218" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="238" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="258" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><text x="226" y="128" text-anchor="middle" fill="var(--muted)" font-size="9.5"></text><line x1="280" y1="78" x2="304" y2="78" stroke="var(--accent)" stroke-width="2" marker-end="url(#ardl)"/><rect x="304" y="50" width="108" height="56" rx="8" fill="var(--panel-2)" stroke="var(--border)"/><rect x="310" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="330" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="350" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="370" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="390" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="310" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="330" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="350" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="370" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="390" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="310" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="330" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="350" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="370" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="390" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><text x="358" y="128" text-anchor="middle" fill="var(--muted)" font-size="9.5"></text><line x1="412" y1="78" x2="436" y2="78" stroke="var(--accent)" stroke-width="2" marker-end="url(#ardl)"/><rect x="436" y="50" width="108" height="56" rx="8" fill="var(--panel-2)" stroke="var(--border)"/><rect x="442" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="462" y="56" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="482" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="502" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="522" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="442" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="462" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="482" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="502" y="72" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><rect x="522" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="442" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="462" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="482" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="502" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="522" y="88" width="17" height="13" rx="2" fill="var(--accent-2)" opacity="0.85"/><text x="490" y="128" text-anchor="middle" fill="var(--muted)" font-size="9.5"></text><line x1="544" y1="78" x2="568" y2="78" stroke="var(--accent)" stroke-width="2" marker-end="url(#ardl)"/><rect x="568" y="50" width="108" height="56" rx="8" fill="var(--panel-2)" stroke="var(--border)"/><rect x="574" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="594" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="614" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="634" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="654" y="56" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="574" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="594" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="614" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="634" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="654" y="72" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="574" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="594" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="614" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="634" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><rect x="654" y="88" width="17" height="13" rx="2" fill="var(--muted)" opacity="0.3"/><text x="622" y="128" text-anchor="middle" fill="var(--muted)" font-size="9.5">clean text</text> | |
| <text x="350" y="26" text-anchor="middle" fill="var(--accent)" font-size="11.5" font-weight="700">iterative denoising β refine the whole sequence in parallel</text> | |
| </svg><figcaption>Diffusion language models generate differently from left-to-right transformers: they start from pure noise over the whole sequence and denoise it in a handful of parallel steps, sharpening every position at once. It trades the autoregressive token-by-token loop for a small number of full-sequence refinement passes.</figcaption></figure> | |
| <p> | |
| Other domains long ago abandoned this. Diffusion models β the technology behind modern image, | |
| audio, and video generators β don't produce their output in order at all. They start from | |
| pure noise and run a small, fixed number of refinement steps, each one improving the entire | |
| output simultaneously. The question this chapter asks is whether the same recipe works for | |
| language. | |
| </p> | |
| <div class="callout insight"> | |
| <strong>Autoregression is a default, not a requirement.</strong> | |
| Sequential, left-to-right generation is one way to turn a model into text β the one that | |
| won β but diffusion shows there's a fundamentally different shape the same goal can take. | |
| </div> | |
| <button class="try-it" data-action="open">βΆ Watch both ways write the same sentence</button> | |
| </section> | |
| <!-- 2 --> | |
| <section class="chapter" id="ch2"> | |
| <h2><span class="ch-num">2</span> What "noise" means for discrete text</h2> | |
| <p> | |
| Image diffusion has it easy: pixels are continuous, so you can add a little Gaussian noise, | |
| then a little more, until the picture dissolves into static β and train a model to reverse | |
| each step. Text is discrete. There's no "slightly noisy" version of the word | |
| <em>cat</em>. So discrete diffusion uses a different corruption: <strong>masking</strong>. | |
| </p> | |
| <p> | |
| The forward process progressively replaces tokens with a special <code>[MASK]</code> symbol β | |
| a few at first, then more, until the whole sequence is masked. The model is trained to run | |
| that backwards: given a partly-masked sequence, predict what the masked tokens should be. | |
| Generation then starts from an all-masked sequence and unmasks its way to text. | |
| </p> | |
| <div class="callout insight"> | |
| <strong>For text, the noise is the mask.</strong> | |
| Corrupting toward a fully-masked sequence and learning to reverse it is the discrete analogue | |
| of dissolving an image into static and denoising it back. You met this exact masking objective | |
| in Chapter 8 β diffusion turns it into a multi-step generator. | |
| </div> | |
| </section> | |
| <!-- 3 --> | |
| <section class="chapter" id="ch3"> | |
| <h2><span class="ch-num">3</span> Refine the whole sequence in parallel</h2> | |
| <p> | |
| Here's the part that makes it interesting. Each denoising step looks at the entire sequence | |
| at once β every position, masked or not β and predicts all the masked tokens together. It | |
| then <em>commits</em> the predictions it's most confident about, leaves the uncertain | |
| positions masked, and moves to the next step. Over a handful of steps, the sequence sharpens | |
| from all-mask to finished text. | |
| </p> | |
| <p> | |
| Two things fall out of this. The number of steps is <strong>fixed and small</strong> β a few | |
| dozen, not one per token β so a long sequence doesn't cost proportionally more steps. And | |
| every step has <strong>bidirectional</strong> context: a token can be filled in based on | |
| words to its right that don't exist yet under autoregression. The model can lay down anchor | |
| words first and fill the gaps around them, in any order it likes. | |
| </p> | |
| <div class="callout insight"> | |
| <strong>Steps decouple from length, and context goes both ways.</strong> | |
| Diffusion trades "one pass per token, left to right" for "a few passes over everything, in | |
| any order." That parallelism and the ability to revise are its whole appeal. | |
| </div> | |
| <button class="try-it" data-action="steps">βΆ Change the step count and re-denoise</button> | |
| </section> | |
| <!-- 4 --> | |
| <section class="chapter" id="ch4"> | |
| <h2><span class="ch-num">4</span> Diffusion vs autoregressive</h2> | |
| <p> | |
| Line them up and the trade is clear. Autoregression takes <code>N</code> sequential steps for | |
| <code>N</code> tokens, sees only the left context, can't revise, but trains on an exact | |
| likelihood and is, today, the strongest approach for text. Diffusion takes a fixed | |
| <code>T</code> steps regardless of length, sees the whole sequence, can revise earlier tokens | |
| as later ones firm up β but each of those <code>T</code> steps is a <em>full</em> forward pass | |
| over the entire sequence, and its training objective is a looser bound, not the exact | |
| likelihood. | |
| </p> | |
| <p> | |
| So "fewer steps" doesn't automatically mean "faster" β a diffusion step costs more than an | |
| autoregressive one, and you need enough steps for quality. The honest framing is that they | |
| occupy different points on the speed/quality/flexibility surface, and which wins depends on | |
| the sequence length, the hardware, and how much revision the task rewards. | |
| </p> | |
| <button class="try-it" data-action="cost">βΆ Compare the step counts vs length</button> | |
| </section> | |
| <!-- 5 --> | |
| <section class="chapter" id="ch5"> | |
| <h2><span class="ch-num">5</span> Why autoregression still rules text</h2> | |
| <p> | |
| Despite the appeal, the frontier of language modelling is still overwhelmingly autoregressive, | |
| and there are real reasons. Left-to-right factorization matches the causal grain of language | |
| and gives an exact, easy-to-optimize training loss; the KV cache makes AR generation cheap per | |
| step; and decades of tooling and scaling know-how are built around it. Diffusion's looser | |
| objective and full-sequence steps have, so far, left it a step behind on raw quality. | |
| </p> | |
| <p> | |
| But it's an active, fast-moving frontier β recent diffusion and masked-generation language | |
| models have closed much of the gap, and the parallelism is genuinely attractive for long | |
| outputs and controllable, infilling-style generation. Diffusion already owns image, audio, and | |
| video; whether it takes a real share of text is one of the open questions of the field. | |
| </p> | |
| <div class="callout warn"> | |
| <strong>Don't mistake "less common" for "settled."</strong> | |
| Autoregression leads text today on the strength of likelihood, caching, and momentum β not | |
| because diffusion can't work. This is one of the places the architecture story is still being | |
| written. | |
| </div> | |
| </section> | |
| <!-- 6 --> | |
| <section class="chapter" id="ch6"> | |
| <h2><span class="ch-num">6</span> Reading the playground</h2> | |
| <p> | |
| The two columns illustrate the generation <em>processes</em> on the same target sentence: | |
| autoregressive fills left to right, one token per step; diffusion starts fully masked and | |
| unmasks confident tokens across the whole sequence over a few steps. It shows the mechanism | |
| and the step counts, not a trained model's samples. | |
| </p> | |
| <div class="panel-guide-item"><span class="pgi-label">βΆ</span> | |
| <p>Step or play both generators side by side: autoregressive marches left to right; diffusion | |
| lays down anchor words anywhere and fills the gaps.</p></div> | |
| <div class="panel-guide-item"><span class="pgi-label">β·</span> | |
| <p>Set the number of diffusion steps and re-run β fewer steps, coarser passes; more steps, a | |
| gentler reveal.</p></div> | |
| <div class="panel-guide-item"><span class="pgi-label">βΏ</span> | |
| <p>The steps-versus-length comparison β autoregressive grows with the sequence, diffusion stays | |
| flat β and the full trade-off table.</p></div> | |
| <div class="guide-end"> | |
| <p>The reading is the setup. The playground is the point.</p> | |
| <button class="try-it large" data-action="open">βΆ Open the Playground</button> | |
| </div> | |
| </section> | |
| </article> | |
| </section> | |
| <!-- βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ PLAYGROUND --> | |
| <section id="playground-tab" class="tab-panel"> | |
| <div class="wrap"> | |
| <div class="panel"> | |
| <div class="panel-head"><span class="panel-label">Two ways to write a sentence</span> | |
| <span class="panel-note">same target, two generation processes</span></div> | |
| <div class="ctrl-row"> | |
| <button class="btn primary" id="stepBtn">βΆ Step</button> | |
| <button class="btn" id="playBtn">βΆβΆ Play</button> | |
| <button class="btn" id="resetBtn">βΊ Reset</button> | |
| <div class="ctrl"><span class="lab">Diffusion steps: <b id="tVal">6</b></span> | |
| <input type="range" id="tSteps" min="2" max="12" value="6"></div> | |
| </div> | |
| <div class="grid2"> | |
| <div class="gencol ar"> | |
| <h4 class="ar">Autoregressive</h4> | |
| <p class="sub">one token per step, strictly left β right</p> | |
| <div class="seq" id="arSeq"></div> | |
| <div class="stepline" id="arLine"></div> | |
| </div> | |
| <div class="gencol diff"> | |
| <h4 class="diff">Diffusion</h4> | |
| <p class="sub">all positions at once, masked β unmasked over a few steps</p> | |
| <div class="seq" id="diffSeq"></div> | |
| <div class="stepline" id="diffLine"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="panel" id="panelCost"> | |
| <div class="panel-head"><span class="panel-label">Steps, length & the trade-off</span> | |
| <span class="panel-note">generation steps vs sequence length</span></div> | |
| <div class="grid2"> | |
| <div class="card"> | |
| <h4>Generation steps vs length</h4> | |
| <p class="cap">Autoregressive needs one step per token (linear). Diffusion uses a fixed step | |
| budget regardless of length (flat) β though each step is a heavier pass.</p> | |
| <svg id="costPlot" viewBox="0 0 420 210"></svg> | |
| </div> | |
| <div class="card"> | |
| <h4>Side by side</h4> | |
| <table class="cmptable"> | |
| <tr><td>order</td><td class="ar">left β right</td><td class="diff">any order</td></tr> | |
| <tr><td>steps</td><td class="ar">N (one per token)</td><td class="diff">fixed T</td></tr> | |
| <tr><td>context</td><td class="ar">left only</td><td class="diff">bidirectional</td></tr> | |
| <tr><td>revise?</td><td class="ar">never</td><td class="diff">yes, until committed</td></tr> | |
| <tr><td>per-step cost</td><td class="ar">cheap (KV cache)</td><td class="diff">full pass</td></tr> | |
| <tr><td>training loss</td><td class="ar">exact likelihood</td><td class="diff">looser bound</td></tr> | |
| <tr><td>text quality today</td><td class="ar">leads</td><td class="diff">catching up</td></tr> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <footer> | |
| An illustration of the two generation processes on a fixed target sentence β autoregressive | |
| left-to-right vs diffusion's parallel masked refinement. It shows the mechanism and step counts, | |
| not samples from a trained model. | |
| </footer> | |
| </div> | |
| </section> | |
| <script> | |
| ; | |
| /* ββ tabs / toc / try-it ββ */ | |
| function switchTab(name){document.querySelectorAll(".page-tab").forEach(b=>{const on=b.dataset.tab===name;b.classList.toggle("active",on);b.setAttribute("aria-selected",on);});document.querySelectorAll(".tab-panel").forEach(p=>p.classList.toggle("active",p.id===name+"-tab"));} | |
| document.querySelectorAll(".page-tab").forEach(b=>b.addEventListener("click",()=>switchTab(b.dataset.tab))); | |
| document.querySelectorAll(".guide-toc a").forEach(a=>a.addEventListener("click",e=>{e.preventDefault();document.querySelector(a.getAttribute("href"))?.scrollIntoView({behavior:"smooth",block:"start"});})); | |
| document.querySelectorAll(".try-it[data-action]").forEach(b=>b.addEventListener("click",()=>{const a=b.dataset.action;switchTab("playground");window.scrollTo({top:0,behavior:"smooth"});const t=(a==="cost")?"panelCost":(a==="open"?null:null);if(t)setTimeout(()=>document.getElementById(t)?.scrollIntoView({behavior:"smooth",block:"start"}),350);})); | |
| /* ββββββββββββββββ ENGINE ββββββββββββββββ */ | |
| const TARGET="the quiet river flowed past the old stone bridge at dawn".split(" "); | |
| const N=TARGET.length; | |
| const STOP=new Set("the a an of to in on at by is was and or for".split(" ")); | |
| // diffusion unmask order: most "confident" first β short/common words as anchors, then the rest. | |
| function confidence(tok){return (STOP.has(tok)?2:0) + 1/tok.length;} | |
| const ORDER=[...TARGET.keys()].sort((a,b)=>confidence(TARGET[b])-confidence(TARGET[a])); | |
| // cumulative tokens revealed by diffusion step s (cosine-ish schedule) | |
| function revealedBy(s,T){if(s<=0)return 0;if(s>=T)return N;return Math.round(N*(1-Math.cos(Math.PI*s/T))/2);} | |
| /* ββββββββββββββββ UI ββββββββββββββββ */ | |
| const $=id=>document.getElementById(id); | |
| const css=v=>getComputedStyle(document.documentElement).getPropertyValue(v).trim(); | |
| const S={T:6,arStep:0,diffStep:0,playing:false,raf:0,last:0,justAR:-1,justDiff:[]}; | |
| function reset(){S.arStep=0;S.diffStep=0;S.justAR=-1;S.justDiff=[];stop();render();} | |
| function done(){return S.arStep>=N&&S.diffStep>=S.T;} | |
| function step(){ | |
| if(S.arStep<N){S.justAR=S.arStep;S.arStep++;}else S.justAR=-1; | |
| if(S.diffStep<S.T){const before=revealedBy(S.diffStep,S.T);S.diffStep++;const after=revealedBy(S.diffStep,S.T); | |
| S.justDiff=ORDER.slice(before,after);}else S.justDiff=[]; | |
| render(); | |
| } | |
| function render(){ | |
| // AR: positions 0..arStep-1 revealed, rest masked | |
| let ar="";for(let i=0;i<N;i++){const shown=i<S.arStep;const cls="tok "+(shown?(i===S.justAR?"ar just":"ar"):"mask"); | |
| ar+='<span class="'+cls+'">'+(shown?TARGET[i]:'β')+'</span>';} | |
| $('arSeq').innerHTML=ar; | |
| $('arLine').innerHTML='step <b>'+S.arStep+' / '+N+'</b> Β· '+(S.arStep>=N?'done':'next: position '+S.arStep+' (leftβright)'); | |
| // diffusion: ORDER[0..revealed-1] revealed | |
| const rev=revealedBy(S.diffStep,S.T),revealedSet=new Set(ORDER.slice(0,rev)),justSet=new Set(S.justDiff); | |
| let df="";for(let i=0;i<N;i++){const shown=revealedSet.has(i);const cls="tok "+(shown?(justSet.has(i)?"diff just":"diff"):"mask"); | |
| df+='<span class="'+cls+'">'+(shown?TARGET[i]:'[mask]')+'</span>';} | |
| $('diffSeq').innerHTML=df; | |
| $('diffLine').innerHTML='step <b>'+S.diffStep+' / '+S.T+'</b> Β· '+rev+' / '+N+' tokens committed'+(S.diffStep>=S.T?' Β· done':''); | |
| drawCost(); | |
| } | |
| function drawCost(){ | |
| const W=420,H=210,padL=40,padR=14,padT=14,padB=30,maxN=64; | |
| const X=n=>padL+(n/maxN)*(W-padL-padR),Y=v=>H-padB-(v/maxN)*(H-padT-padB); | |
| let s=""; | |
| s+='<line x1="'+padL+'" y1="'+(H-padB)+'" x2="'+(W-padR)+'" y2="'+(H-padB)+'" stroke="'+css('--border')+'"/>'; | |
| // AR: steps = n | |
| s+='<line x1="'+X(0)+'" y1="'+Y(0)+'" x2="'+X(maxN)+'" y2="'+Y(maxN)+'" stroke="'+css('--ar')+'" stroke-width="2"/>'; | |
| // diffusion: flat at T | |
| s+='<line x1="'+X(0)+'" y1="'+Y(S.T)+'" x2="'+X(maxN)+'" y2="'+Y(S.T)+'" stroke="'+css('--diff')+'" stroke-width="2"/>'; | |
| s+='<text x="'+(W-padR)+'" y="'+(Y(maxN)+12)+'" font-size="9" text-anchor="end" fill="'+css('--ar')+'">autoregressive Β· N steps</text>'; | |
| s+='<text x="'+(W-padR)+'" y="'+(Y(S.T)-4)+'" font-size="9" text-anchor="end" fill="'+css('--diff')+'">diffusion Β· '+S.T+' steps (fixed)</text>'; | |
| // current N marker | |
| s+='<line x1="'+X(N)+'" y1="'+padT+'" x2="'+X(N)+'" y2="'+(H-padB)+'" stroke="'+css('--muted')+'" stroke-dasharray="3 3" opacity="0.4"/>'; | |
| s+='<text x="'+X(N)+'" y="'+(H-padB+13)+'" font-size="8.5" text-anchor="middle" fill="'+css('--muted')+'">N='+N+'</text>'; | |
| [0,16,32,48,64].forEach(t=>{if(Math.abs(t-N)>3)s+='<text x="'+X(t)+'" y="'+(H-padB+13)+'" font-size="8.5" text-anchor="middle" fill="'+css('--muted')+'">'+t+'</text>';}); | |
| s+='<text x="'+((padL+W-padR)/2)+'" y="'+(H-2)+'" font-size="9" text-anchor="middle" fill="'+css('--muted')+'">sequence length β</text>'; | |
| s+='<text x="8" y="'+(padT+30)+'" font-size="8.5" fill="'+css('--muted')+'" transform="rotate(-90 12 '+(padT+40)+')">generation steps</text>'; | |
| $('costPlot').innerHTML=s; | |
| } | |
| function stop(){S.playing=false;$('playBtn').textContent="βΆβΆ Play";cancelAnimationFrame(S.raf);} | |
| function play(){if(S.playing){stop();return;}if(done())reset();S.playing=true;$('playBtn').textContent="βΈ Pause";S.last=0; | |
| const loop=(ts)=>{if(!S.playing)return;if(ts-S.last>520){S.last=ts;step();}if(!done())S.raf=requestAnimationFrame(loop);else stop();}; | |
| S.raf=requestAnimationFrame(loop);} | |
| /* ββ events ββ */ | |
| $('stepBtn').addEventListener('click',()=>{stop();if(done())reset();step();}); | |
| $('playBtn').addEventListener('click',play); | |
| $('resetBtn').addEventListener('click',reset); | |
| $('tSteps').addEventListener('input',e=>{S.T=+e.target.value;$('tVal').textContent=S.T;reset();}); | |
| reset(); | |
| </script> | |
| </body> | |
| </html> | |