Diffusion denoising

디퓨전 디노이징

The process of starting from pure noise and having a model repeatedly guess and remove a little of it until a picture emerges.

Also known as: Denoising diffusionForward and reverse diffusion
···
html
<div class="wrap">
  <canvas id="cv"></canvas>
  <div class="panel" id="panel"></div>
</div>
css
.wrap{position:relative;width:100%;height:100%}
#cv{position:absolute;inset:0;width:100%;height:100%;image-rendering:pixelated}
.panel{position:absolute;bottom:10px;left:10px;right:10px;z-index:2;padding:7px 10px;border-radius:10px;
  background:rgba(13,13,18,0.55);backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,0.15);
  font-size:11px;font-weight:600;color:#f1f0ec}
js
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');
const panel = document.getElementById('panel');
const SW = 48, SH = 30;
const small = document.createElement('canvas'); small.width = SW; small.height = SH;
const sctx = small.getContext('2d');
function fit() { const dpr = Math.min(devicePixelRatio || 1, 2); cv.width = innerWidth * dpr; cv.height = innerHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.imageSmoothingEnabled = false; }
addEventListener('resize', fit); fit();

function mulberry32(a) { return function () { a |= 0; a = a + 0x6D2B79F5 | 0; let t = Math.imul(a ^ a >>> 15, 1 | a); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; }

function paintTarget() {
  const r = mulberry32(31);
  const g = sctx.createLinearGradient(0, 0, 0, SH);
  g.addColorStop(0, 'hsl(280 45% 60%)'); g.addColorStop(1, 'hsl(320 40% 30%)');
  sctx.fillStyle = g; sctx.fillRect(0, 0, SW, SH);
  sctx.beginPath(); sctx.arc(SW * 0.3, SH * 0.22, SH * 0.12, 0, Math.PI * 2); sctx.fillStyle = 'hsl(50 90% 75%)'; sctx.fill();
  for (let l = 0; l < 2; l++) {
    sctx.beginPath(); sctx.moveTo(0, SH);
    for (let i = 0; i <= 6; i++) { const x = SW * i / 6; const y = SH * (0.55 + l * 0.16) - r() * SH * 0.12; sctx.lineTo(x, y); }
    sctx.lineTo(SW, SH); sctx.closePath();
    sctx.fillStyle = 'hsl(300 30% ' + (16 + l * 12) + '%)'; sctx.fill();
  }
}
function noiseCanvas(seed) {
  const r = mulberry32(seed);
  const tmp = document.createElement('canvas'); tmp.width = SW; tmp.height = SH;
  const tctx = tmp.getContext('2d');
  const id = tctx.createImageData(SW, SH);
  for (let i = 0; i < id.data.length; i += 4) { const v = Math.floor(r() * 255); id.data[i] = v; id.data[i + 1] = v; id.data[i + 2] = v; id.data[i + 3] = 255; }
  tctx.putImageData(id, 0, 0);
  return tmp;
}
function drawFrame(t) {
  paintTarget();
  if (t > 0.01) { sctx.globalAlpha = t; sctx.drawImage(noiseCanvas(500 + Math.floor(t * 40)), 0, 0); sctx.globalAlpha = 1; }
  ctx.clearRect(0, 0, innerWidth, innerHeight);
  ctx.drawImage(small, 0, 0, innerWidth, innerHeight);
}
let t = 0.95, dir = -1, label = '역방향(생성): 노이즈에서 이미지를 복원합니다';
function loop() {
  drawFrame(t); panel.textContent = label;
  t += dir * 0.012;
  if (t <= 0) { t = 0; dir = 1; label = '정방향(학습): 이미지에 노이즈를 더합니다'; }
  if (t >= 1) { t = 1; dir = -1; label = '역방향(생성): 노이즈에서 이미지를 복원합니다'; }
  setTimeout(loop, 30);
}
loop();

Diffusion models are trained on two processes. The forward process adds a tiny bit of noise to a real image, repeated over many steps, until it becomes pure static — this is a fixed mathematical procedure that needs no learning. What the model actually learns is the reverse: guessing, from a noisy image, what noise was just added.

Generation only ever runs the reverse process. Starting from pure noise, the model predicts "the noise mixed in here" and a bit of it is removed, repeated a set number of times, and the structure of a statistically plausible image gradually surfaces out of the static. This is why it takes many steps rather than one forward pass the way a GAN does — asking the model to remove all the noise in one shot is a much harder problem.

This iterative structure is exactly where the step count (sampling steps) comes from as a tunable parameter, and the rule for how much noise to remove at each step is the sampler algorithm.

The demo below blends a target picture with seeded noise by alpha, cycling forward (adding noise) and reverse (removing it), instead of an actual model's noise prediction.

When to use

Useful for understanding why parameters like sampling steps and seed exist in the first place. It is the mechanism those knobs rest on, more than something you tune directly.