<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>AI 반도체 노트</title>
    <link>https://g1g11.tistory.com/</link>
    <description>인공지능으로 반도체를 설계해봐요.
블로그에서는 기본적인 이론과 내용부터 다룹니다.</description>
    <language>ko</language>
    <pubDate>Fri, 17 Jul 2026 08:06:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>인공지능과 반도체</managingEditor>
    <image>
      <title>AI 반도체 노트</title>
      <url>https://tistory1.daumcdn.net/tistory/8393121/attach/4cb8008134b64ba8a738d7c33dc709bc</url>
      <link>https://g1g11.tistory.com</link>
    </image>
    <item>
      <title>디퓨전 모델 설명 04. DDPM: 역확산을 학습. ELBO에서 Noise 예측까지</title>
      <link>https://g1g11.tistory.com/entry/04-DDPM-%EC%97%AD%ED%99%95%EC%82%B0%EC%9D%84-%ED%95%99%EC%8A%B5%ED%95%9C%EB%8B%A4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 한눈에 &amp;mdash; DDPM이란 (요약)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM(Denoising Diffusion Probabilistic Models)은 03장의 '분포들의 경로를 거꾸로 내려오기'를 실제로 학습 가능한 형태로 만든 모델입니다. 출발점은 likelihood의 하한인 ELBO(= 분포를 맞추는 문제)지만, 그것이 놀랄 만큼 단순한 'noise 맞추기 MSE'로 정리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 장은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;① 고정된 forward,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;② 학습하는 reverse(어떤 Gaussian을, 무슨 '정답'에 맞추는지),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;③ 왜 noise를 예측하는지와 ELBO와의 연결,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;④ noise&amp;middot;$x_0$&amp;middot;score&amp;middot;$v$가 사실 한 대상임,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⑤ 학습과 샘플링 알고리즘(코드),&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⑥ 그 네 좌표를 차례로 봅니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Forward process는 고정되어 있다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM의 forward는 학습하지 않는 고정 과정입니다(왜 이 형태이고 왜 한 번에 점프되는지는 03장 &amp;sect;2&amp;ndash;3).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 $\sqrt{\alpha_t}$는 03장의 $\sqrt{1-\beta_t}$와 같은 표기입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_{t-1}) = \mathcal{N}\big(x_t;\ \sqrt{\alpha_t}\,x_{t-1},\ \beta_t I\big), \qquad \alpha_t = 1 - \beta_t&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 step을 누적하면 임의의 $t$로 한 번에 가는 닫힌 형태가 됩니다. (단 $\bar{\alpha}t = \prod{s=1}^{t}\alpha_s$)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_0) = \mathcal{N}\big(x_t;\ \sqrt{\bar{\alpha}_t}\,x_0,\ (1 - \bar{\alpha}_t)I\big), \qquad x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1 - \bar{\alpha}_t}\,\epsilon&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 점프 식이 학습의 핵심입니다. 임의의 $t$를 뽑아 $x_0$에서 곧장 $x_t$를 만들 수 있어, 긴 체인을 시뮬레이션하지 않아도 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Reverse process: 무엇을, 어떤 '정답'에 맞춰 배우나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성은 경로를 거꾸로 내려옵니다. 모델은 각 한 칸 전이를 Gaussian으로 둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x_{t-1} \mid x_t) = \mathcal{N}\big(x_{t-1};\ \mu_\theta(x_t, t),\ \Sigma_\theta(x_t, t)\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reverse를 Gaussian으로 두는 근거는 03장 &amp;sect;4입니다(스텝이 작으면 한 칸 전이가 Gaussian에 가깝다). 기본 DDPM에서는 분산을 학습하지 않고 아래의 $\sigma_t^2 = \tilde{\beta}t$(또는 $\beta_t$)로 고정한 뒤 평균 $\mu\theta$만 학습합니다(분산까지 학습하는 건 Improved DDPM의 개선).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그 평균을 무엇에 맞출까요? 진짜 reverse $q(x_{t-1}\mid x_t)$는 데이터 분포에 의존해 모르지만, $x_0$를 조건으로 넣은 posterior는 forward가 Gaussian이라 정확히 계산됩니다(03장 &amp;sect;5). 그 평균과 분산은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_{t-1}\mid x_t, x_0) = \mathcal{N}\big(x_{t-1};\ \tilde{\mu}_t,\ \tilde{\beta}_t I\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\tilde{\mu}t = \frac{\sqrt{\bar{\alpha}{t-1}}\,\beta_t}{1-\bar{\alpha}t}\,x_0 + \frac{\sqrt{\alpha_t}\,(1-\bar{\alpha}{t-1})}{1-\bar{\alpha}_t}\,x_t, \qquad \tilde{\beta}t = \frac{1-\bar{\alpha}{t-1}}{1-\bar{\alpha}_t}\,\beta_t&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽는 법: 한 칸 되돌린 평균 $\tilde{\mu}_t$는 '추정한 원본 $x_0$'와 '지금 $x_t$'를 noise 정도에 따라 가중평균한 자리이고, 분산 $\tilde{\beta}t$는 그 한 칸의 남은 불확실성입니다. 그래서 학습은 모델의 $\mu\theta$를 이 계산 가능한 $\tilde{\mu}t$에 맞추는 일이 됩니다(이미지에서는 보통 $\mu\theta$를 U-Net으로 냅니다 &amp;mdash; 왜 U-Net인지는 09-0 참고).&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 왜 noise를 예측하는가 &amp;mdash; 그리고 ELBO와의 연결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 $\tilde{\mu}_t$를 $x_0$ 대신 noise $\epsilon$로 바꿔 써 봅시다(&amp;sect;1의 점프 식을 $x_0$에 대해 풀어 대입). 그러면 평균은 'noise를 한 번 덜어내는' 깔끔한 꼴이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}}\Big(x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}t}}\,\epsilon\theta(x_t, t)\Big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$\mu_\theta$가 $\epsilon_\theta$ 하나로 정해지니, 모델은 그냥 $x_t$에 섞인 noise $\epsilon$를 예측하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;L_{\text{simple}} = \mathbb{E}{x_0,\,\epsilon,\,t}\,\big\lVert \epsilon - \epsilon\theta(x_t, t) \big\rVert^2&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 loss만 보면 &quot;그냥 noise MSE&quot;처럼 보입니다. 하지만 02장에서 봤듯 같은 $x_t$가 여러 $(x_0, \epsilon)$에서 오므로, MSE의 최적해는 평균 $\mathbb{E}[\epsilon \mid x_t]$이고, 이를 알면 원본도 곧장 추정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\hat{x}_0 = \frac{x_t - \sqrt{1 - \bar{\alpha}t}\,\epsilon\theta(x_t, t)}{\sqrt{\bar{\alpha}_t}}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ELBO와의 연결도 보이게 짚어 봅시다. ELBO를 풀면 각 $t$마다 'KL( 정답 posterior $q(x_{t-1}\mid x_t,x_0)$ ‖ 모델 $p_\theta$ )' 항이 나옵니다. 그런데 두 분포는 분산이 같은 Gaussian이라, 그 KL은 평균 차이의 제곱으로 깔끔하게 줄어듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;D_{\mathrm{KL}}\big(q \,\|\, p_\theta\big) = \frac{1}{2\sigma_t^2}\,\big\lVert \mu_\theta - \tilde{\mu}_t \big\rVert^2 + \text{const}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &quot;$\mu_\theta$를 $\tilde{\mu}t$에 맞춰라&quot;이고, 위의 $\epsilon$ 매개화를 넣으면 이는 $t$마다 가중치가 붙은 $\lVert \epsilon - \epsilon\theta \rVert^2$가 됩니다. DDPM은 그 가중치를 1로 둔 단순형 $L_{\text{simple}}$을 씁니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가중치를 버려도 되는 이유: ELBO의 정확한 가중치는 오히려 noise가 작은($t$가 작은) 항의 비중을 크게 키웁니다. 가중치를 1로 두면 그 저-noise 항들의 과한 비중을 덜어내고, 지각적으로 중요한 거친 구조가 만들어지는 고-noise 구간에 상대적으로 힘이 실립니다. 이 재조정이 실전 샘플 품질에 유리해서, 단순하면서도 잘 작동합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Score와의 연결: 사실은 같은 대상이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$x_t$가 Gaussian noising으로 만들어졌으므로, noise 예측은 score와 상수배로 이어집니다(02&amp;middot;03장).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\sigma_t = \sqrt{1 - \bar{\alpha}t}, \qquad s_t(x_t) \approx -\frac{\epsilon\theta(x_t, t)}{\sqrt{1 - \bar{\alpha}_t}}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02장의 Tweedie를 떠올리면 그림이 완성됩니다 &amp;mdash; denoiser의 출력 $\mathbb{E}[x_0 \mid x_t]$, score $\nabla \log p_t$, noise $\epsilon$는 서로 변환되는 하나의 대상입니다. DDPM이 무엇을 예측하든 사실은 분포 $p_t$의 score 하나를 다른 좌표로 읽는 셈이고, 그래서 denoising diffusion과 score-based model이 깊게 이어집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 학습과 샘플링 알고리즘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습은 단순한 회귀입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;실제 데이터 $x_0$를 뽑는다.&lt;/li&gt;
&lt;li&gt;시간 $t$를 랜덤하게 뽑는다.&lt;/li&gt;
&lt;li&gt;Gaussian noise $\epsilon \sim \mathcal{N}(0, I)$을 뽑는다.&lt;/li&gt;
&lt;li&gt;$x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1 - \bar{\alpha}_t}\,\epsilon$ 을 만든다.&lt;/li&gt;
&lt;li&gt;모델이 $\epsilon_\theta(x_t, t)$를 예측한다.&lt;/li&gt;
&lt;li&gt;$\lVert \epsilon - \epsilon_\theta \rVert^2$를 줄인다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;# 학습 (개념용 pseudo-code)
x0 = sample_data()
t  = sample_time()
eps = torch.randn_like(x0)
xt = sqrt_ab[t] * x0 + sqrt_one_minus_ab[t] * eps
loss = ((eps - model(xt, t)) ** 2).mean()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성(샘플링)은 $x_T \sim \mathcal{N}(0, I)$에서 시작해 한 칸씩 되돌립니다. 한 스텝은 &amp;sect;2&amp;middot;&amp;sect;3의 $\mu_\theta$에 약간의 새 noise를 더한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x_{t-1} = \frac{1}{\sqrt{\alpha_t}}\Big(x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}t}}\,\epsilon\theta(x_t, t)\Big) + \sigma_t\,z, \qquad z \sim \mathcal{N}(0, I)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &quot;지금 위치에서 예측한 noise를 조금 덜어내고($\mu_\theta$), 아직 갈 길이 남았으니 약간의 새 noise $\sigma_t z$를 더한다&quot;입니다. 여기서 $\sigma_t^2 = \tilde{\beta}_t$(또는 $\beta_t$, &amp;sect;2)이고, 마지막 스텝 $t=1$에서는 $z=0$입니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;flowchart LR
  A[&quot;x_t (현재)&quot;] --&amp;gt; B[&quot;&amp;epsilon;_&amp;theta;(x_t, t) 예측&quot;]
  B --&amp;gt; C[&quot;x0 추정 (Tweedie)&quot;]
  C --&amp;gt; D[&quot;reverse 평균 &amp;mu;_&amp;theta;&quot;]
  D --&amp;gt; E[&quot;x_(t-1) = &amp;mu;_&amp;theta; + &amp;sigma;_t z&quot;]
  E --&amp;gt;|&quot;t-1로 반복&quot;| A
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;# 샘플링 (개념용 pseudo-code)
x = torch.randn(shape)                 # x_T ~ N(0, I)
for t in reversed(range(1, T + 1)):
    eps = model(x, t)
    mu = (x - beta[t] / sqrt_one_minus_ab[t] * eps) / sqrt_alpha[t]
    z = torch.randn_like(x) if t &amp;gt; 1 else 0
    x = mu + sigma[t] * z
# x &amp;asymp; x_0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 짧지만, 그 배경에는 &quot;분포들의 경로를 거꾸로 내려오는 reverse process를 학습&amp;middot;실행한다&quot;는 관점이 있습니다. 이 순차 샘플링이 느리다는 점은 06&amp;middot;06-1장(DDIM&amp;middot;solver&amp;middot;distillation)에서 다룹니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 예측 대상은 '하나의 다른 좌표들'이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM을 구현하다 보면 모델이 무엇을 예측하는지가 여러 방식으로 나타납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예측 대상 의미 왜 쓰는가&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;예측 대상&lt;/td&gt;
&lt;td&gt;의미&amp;nbsp;&lt;/td&gt;
&lt;td&gt;왜 쓰는가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\epsilon$&lt;/td&gt;
&lt;td&gt;$x_t$에 섞인 noise&lt;/td&gt;
&lt;td&gt;DDPM의 대표적이고 단순한 좌표&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x_0$&lt;/td&gt;
&lt;td&gt;원본 sample 추정 $\mathbb{E}[x_0\mid x_t]$&lt;/td&gt;
&lt;td&gt;denoising 결과를 직접 다룰 때 직관적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$v$&lt;/td&gt;
&lt;td&gt;data와 noise 축을 회전한 좌표&lt;/td&gt;
&lt;td&gt;모든 $t$에서 균형이 좋아 few-step&amp;middot;distillation에 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;score&lt;/td&gt;
&lt;td&gt;$\nabla \log p_t(x_t)$&lt;/td&gt;
&lt;td&gt;Score SDE 관점과 직접 연결(05장)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 표현들은 서로 다른 목표가 아니라, 같은 reverse 방향을 어떤 좌표로 적느냐의 차이입니다. 각 $(x_t, t)$에서 서로 되돌릴 수 있는 affine 변환으로 연결됩니다(&amp;sect;4의 Tweedie가 그 변환).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 $v$는 비유가 아니라 진짜 '회전한 좌표'입니다. $\sqrt{\bar{\alpha}_t} = \cos\phi$, $\sqrt{1-\bar{\alpha}_t} = \sin\phi$로 두면($\bar{\alpha}_t + (1-\bar{\alpha}_t) = 1$이라 가능),&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x_t = \cos\phi\,x_0 + \sin\phi\,\epsilon, \qquad v \equiv \sqrt{\bar{\alpha}_t}\,\epsilon - \sqrt{1-\bar{\alpha}_t}\,x_0 = \cos\phi\,\epsilon - \sin\phi\,x_0&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 $(x_0, \epsilon)$ 축을 각도 $\phi$만큼 돌린 새 좌표가 $(x_t, v)$입니다. $t \to 0$이면 $v \approx \epsilon$, $t \to T$이면 $v \approx -x_0$입니다. 이게 이득인 이유는 회귀 target의 조건 때문입니다 &amp;mdash; $\epsilon$-예측은 $t \to 0$에서 $x_t$에 noise가 거의 없어 target이 흐릿해지고, $x_0$-예측은 $t \to T$에서 원본이 거의 안 남아 흐릿해지는데, $v$는 양끝 모두에서 정보가 살아 있어 전 구간에서 고르게 학습됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. DDPM이 남긴 중요한 관점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;adversarial training 없이도 고품질 이미지를 생성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;학습 objective가 안정적입니다(고정된 손실 하나를 내려갈 뿐, 01장의 적대적 게임과 대조).&lt;/li&gt;
&lt;li&gt;denoising &amp;middot; score matching &amp;middot; variational inference가 하나로 연결됩니다.&lt;/li&gt;
&lt;li&gt;sampling은 느리지만, 이후 DDIM과 다양한 sampler 연구로 이어집니다(06&amp;middot;06-1장).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM은 고정된 forward 경로와 학습된 reverse step을 결합하고, ELBO에서 출발한 목표를 noise prediction MSE로 단순화합니다. 그 noise&amp;middot;$x_0$&amp;middot;score&amp;middot;$v$는 결국 분포 $p_t$의 score라는 하나의 대상을 읽는 네 가지 좌표이고, 생성은 그 score로 평균이 정해지는 Gaussian 전이를 $x_T$에서 $x_0$까지 반복하는 일입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 논문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2006.11239&quot;&gt;Ho et al., 2020, Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1503.03585&quot;&gt;Sohl-Dickstein et al., 2015, Deep Unsupervised Learning using Nonequilibrium Thermodynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2102.09672&quot;&gt;Nichol &amp;amp; Dhariwal, 2021, Improved Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2202.00512&quot;&gt;Salimans &amp;amp; Ho, 2022, Progressive Distillation (v-prediction)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/31</guid>
      <comments>https://g1g11.tistory.com/entry/04-DDPM-%EC%97%AD%ED%99%95%EC%82%B0%EC%9D%84-%ED%95%99%EC%8A%B5%ED%95%9C%EB%8B%A4#entry31comment</comments>
      <pubDate>Wed, 1 Jul 2026 13:35:46 +0900</pubDate>
    </item>
    <item>
      <title>디퓨전 모델 설명 03: Diffusion의 기본 구조</title>
      <link>https://g1g11.tistory.com/entry/03-Diffusion%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%A1%B0</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 한눈에 &amp;mdash; Diffusion의 기본 구조 (요약)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion 모델의 기본 구조는 두 과정으로 이뤄집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forward process는 데이터 분포를 정해진 규칙으로 Gaussian noise 분포까지 '보내고',&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reverse process는 그 길을 거꾸로 내려오며 데이터를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 reverse가 실제로 배우는 것은 각 noise level 분포의 score(= log 밀도의 기울기, 02장)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 장은 그 구조를 근본부터 풀어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;① forward가 왜 하필 그런 형태인지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;② $x_0$에서 임의의 $x_t$로 한 번에 점프하는 방법과 그 이득,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;③ reverse가 정확히 어떤 확률 분포를 모델링하는지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;④ score를 학습하는 구체적 과정,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⑤ autoregressive 모델과 무엇이 다른지(데이터에 '새로운 축'을 하나 뚫는 관점)를 차례로 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_0 = p_{\text{data}} \;\to\; p_1 \;\to\; \cdots \;\to\; p_T \approx \mathcal{N}(0, I)&lt;br /&gt;$$&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcIh7O/dJMcaijzrcT/q8wKfEEwTQhrBad1v8TQH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcIh7O/dJMcaijzrcT/q8wKfEEwTQhrBad1v8TQH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcIh7O/dJMcaijzrcT/q8wKfEEwTQhrBad1v8TQH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcIh7O%2FdJMcaijzrcT%2Fq8wKfEEwTQhrBad1v8TQH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;442&quot; height=&quot;325&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 기본부터 &amp;mdash; Diffusion은 '분포를 옮기는' 두 과정이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 &quot;노이즈를 넣었다 뺀다&quot;로 소개하지만, 더 정확히는 분포를 옮기는 일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forward는 복잡한 데이터 분포 $p_{\text{data}}$를 다루기 쉬운 $\mathcal{N}(0, I)$로 옮기는 고정된 경로이고(우리가 손으로 정함), reverse는 그 경로를 거꾸로 내려오며 데이터를 만드는, 모델이 배우는 경로입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;02장에서 본 각 level의 분포 $p_t$가 이 경로 위의 점들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 '한 장의 이미지'가 아니라 '분포 전체'가 이동한다는 관점입니다. 이 관점이 04&amp;ndash;05장에서 DDPM과 SDE로 구체화됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Forward process: 데이터 분포를 noise로 '보내는' 고정 경로 &amp;mdash; 왜 이 형태인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 스텝은 현재 샘플의 신호를 살짝 줄이고 약간의 Gaussian noise를 더합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_{t-1}) = \mathcal{N}\big(x_t;\ \sqrt{1 - \beta_t}\,x_{t-1},\ \beta_t I\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 하필 이런 형태일까요? 세 가지 설계 이유가 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수렴: 매 스텝 신호를 $\sqrt{1-\beta_t}$배로 0 쪽으로 살짝 당기고 noise를 더하는 이 과정을 반복하면, 어떤 출발 분포든 표준정규 $\mathcal{N}(0, I)$로 수렴합니다. 그래서 끝점 $p_T$를 우리가 아는 단순한 분포로 확정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;스케일 보존: $\sqrt{1-\beta_t}$와 $\sqrt{\beta_t}$는 제곱합이 1이라, 분산이 폭발하거나 사라지지 않고 신호 대 noise 비율만 바뀝니다(02장 forward 식과 같은 원리).&lt;/li&gt;
&lt;li&gt;닫힌 형태: 이 Gaussian 스텝들을 합치면 다시 Gaussian이라, 임의의 $t$로 한 번에 가는 식이 닫힌 형태로 나옵니다(&amp;sect;3) &amp;mdash; 학습 효율의 핵심.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분포 관점으로 보면 이건 한 점이 아니라, 분포 전체가 매 스텝 조금씩 퍼지며 $\mathcal{N}(0, I)$ 쪽으로 흘러가는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 $t$의 $p_t$가 이 경로의 한 지점이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 forward는 학습되지 않습니다 &amp;mdash; $\beta_t$ 스케줄을 우리가 정한, 학습 파라미터 0의 고정 경로입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 한 번에 $x_t$ 만들기 (closed-form)와 그 이득&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forward 스텝을 $t$번 누적하면, $x_0$에서 임의의 $t$로 한 번에 점프하는 식이 닫힌 형태로 나옵니다. (단 $\alpha_s = 1-\beta_s$, $\bar{\alpha}t = \prod{s=1}^{t}\alpha_s$)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_0) = \mathcal{N}\big(x_t;\ \sqrt{\bar{\alpha}_t}\,x_0,\ (1-\bar{\alpha}_t)I\big), \qquad x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 항의 의미(남은 신호 vs 채운 noise, 분산 보존, $\bar{\alpha}_t$ 누적)는 02장 &amp;sect;4에 자세합니다. 여기서는 이게 왜 큰 이득인지가 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습할 때 특정 $t$의 $x_t$가 필요한데, 닫힌 형태가 없다면 $x_0$부터 $t$번 순차적으로 noise를 더해야 합니다($O(t)$). 닫힌 형태 덕분에 $(x_0, t, \epsilon)$만 뽑으면 단 한 번의 계산으로 $x_t$를 만들 수 있습니다($O(1)$). 그래서:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매 학습 step에서 임의의 noise level $t$를 균등하게 골라 바로 학습할 수 있고(전 구간을 편향 없이 커버),&lt;/li&gt;
&lt;li&gt;긴 체인을 시뮬레이션하지 않아 학습이 빠르고 메모리도 적게 듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 한 줄이 Diffusion 학습을 현실적으로 만든 결정적 장치입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 왜 여러 단계로 나누는가 (한 칸은 Gaussian)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 분포를 단순 분포에서 한 번에 만드는 건 어렵습니다.&amp;nbsp; 점프가 너무 크니까요(01장에서 본 GAN one-shot의 난이도와 같은 이유).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 경로를 잘게 쪼개면 이웃한 두 분포 $p_t$와 $p_{t-1}$은 거의 같아서, 한 칸 이동은 훨씬 쉬운 문제가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스텝이 충분히 작으면 그 한 칸 전이는 Gaussian으로 잘 근사되고(다음 절에서 reverse를 Gaussian으로 두는 근거), 이 작은 전이를 score&amp;middot;noise prediction으로 학습할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Reverse process: 정확히 어떤 확률 분포를 모델링하나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성은 $x_T \sim \mathcal{N}(0, I)$에서 시작해, 매 스텝 한 칸 더 데이터다운 $x_{t-1}$로 가는 전이분포를 따라 내려옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x_T \to x_{T-1} \to \cdots \to x_0, \qquad x_{t-1} \sim p_\theta(x_{t-1} \mid x_t)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 모델이 모델링하는 분포는 정확히 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 층위로 보면 분명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 스텝 층위에서, 모델은 각 전이 $p_\theta(x_{t-1}\mid x_t)$를 Gaussian으로 둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x_{t-1} \mid x_t) = \mathcal{N}\big(x_{t-1};\ \mu_\theta(x_t, t),\ \Sigma_t\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 스텝이라 한 칸 전이가 Gaussian으로 근사되기 때문입니다(&amp;sect;4). 모델이 배우는 건 그 평균 $\mu_\theta$이고(분산 $\Sigma_t$는 기본 DDPM에서 보통 고정), 이 평균은 score로 정해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 층위에서, 이 스텝들을 이으면 모델은 다음 결합분포를 정의하고, 그 $x_0$ 주변분포가 $p_{\text{data}}$에 가까워지도록 학습합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x_0) = \int p(x_T)\prod_{t=1}^{T} p_\theta(x_{t-1} \mid x_t)\,dx_{1:T}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습의 '정답'은 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 reverse $q(x_{t-1}\mid x_t)$는 데이터 분포에 의존해 직접 못 구합니다. 그러나 $x_0$를 조건으로 넣은 posterior는, forward가 Gaussian이라 정확히 계산되는 Gaussian입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_{t-1} \mid x_t, x_0) = \mathcal{N}\big(x_{t-1};\ \tilde{\mu}_t(x_t, x_0),\ \tilde{\beta}_t I\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 학습은 모델의 $p_\theta(x_{t-1}\mid x_t)$를 이 계산 가능한 정답 $q(x_{t-1}\mid x_t, x_0)$에 맞추고(이것이 04장 ELBO의 핵심 항), 생성 때는 $x_0$를 모르므로 그렇게 배운 $p_\theta$가 그 자리를 대신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확한 $\tilde{\mu}_t$ 형태와 ELBO 유도는 04장에서 다룹니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 줄 요약: reverse는 각 스텝을 Gaussian 전이로 모델링하고, 그 평균을 $x_0$-조건 posterior에 맞춰 배웁니다. 그 결과 전체 reverse 체인의 $x_0$ 분포가 $p_{\text{data}}$를 근사합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. score를 학습하는 과정 (구체적으로)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 Gaussian 평균 $\mu_\theta$는 결국 score로 환원됩니다(02장: score&amp;middot;noise&amp;middot;denoiser는 한 대상). 그래서 실제 학습은 score(또는 그와 동치인 noise $\epsilon$)를 맞히는 단순한 회귀로 돌아갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀어 쓰면 한 step은 이렇습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be9tWp/dJMcabY5XPV/SIvcM16lq7GayWRL0wlxU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be9tWp/dJMcabY5XPV/SIvcM16lq7GayWRL0wlxU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be9tWp/dJMcabY5XPV/SIvcM16lq7GayWRL0wlxU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe9tWp%2FdJMcabY5XPV%2FSIvcM16lq7GayWRL0wlxU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1002&quot; height=&quot;230&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터에서 $x_0$ 하나, 시간 $t$ 하나(균등), noise $\epsilon \sim \mathcal{N}(0, I)$ 하나를 뽑는다.&lt;/li&gt;
&lt;li&gt;닫힌 형태로 $x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon$를 만든다(&amp;sect;3).&lt;/li&gt;
&lt;li&gt;신경망에 $x_t, t$를 주고 섞인 noise를 예측($\epsilon_\theta(x_t, t)$)하게 한다.&lt;/li&gt;
&lt;li&gt;$\lVert \epsilon - \epsilon_\theta(x_t, t) \rVert^2$를 줄인다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 MSE로 학습하면 최적해는 $\epsilon_\theta \approx \mathbb{E}[\epsilon \mid x_t]$이고, 02장의 관계 $s_\theta = -\epsilon_\theta/\sqrt{1-\bar{\alpha}t}$로 곧장 score가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 noise를 맞히는 이 단순한 회귀가 사실은 모든 level의 score field를 배우는 denoising score matching입니다. 생성 때는 이 score로 reverse 스텝의 평균 $\mu\theta$를 만들어 한 칸씩 내려옵니다(04장).&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Autoregressive와 무엇이 다른가 &amp;mdash; 데이터에 '새로운 축'을 뚫는다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 고차원 분포 $p_{\text{data}}$를 모델링하는 또 다른 큰 갈래가 autoregressive(AR)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘을 비교하면 Diffusion의 관점이 선명해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AR은 결합분포를 기존 차원들의 순서로 분해합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p(x) = \prod_{i} p(x_i \mid x_{&amp;lt;i})&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 픽셀(또는 토큰)을 정해진 순서로 하나씩, '앞의 것들이 주어졌을 때 다음 것'의 조건부 확률을 직접 모델링합니다. 생성도 그 순서대로 한 좌표씩 채워 갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion은 다릅니다. 기존 차원을 순서 매기는 대신, 데이터에 수직인 새로운 축 하나 &amp;mdash; 시간/noise level $t$ &amp;mdash; 를 뚫습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 축을 따라 분포 전체를 통째로 옮기며(데이터와 noise 사이), 각 level에서 분포의 score를 배웁니다. 생성은 이 새 축을 따라(noise&amp;rarr;data) 모든 좌표를 동시에 조금씩 갱신합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AR이 모델링하는 한 스텝의 대상은 조건부 확률 그 자체($p(x_i\mid x_{&amp;lt;i})$)입니다.&lt;/li&gt;
&lt;li&gt;Diffusion이 모델링하는 한 스텝의 대상은 분포의 score(방향)이고, reverse 전이는 그 score로 평균이 정해지는 Gaussian입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 같은 분포를 다른 방식으로 분해할 뿐입니다. AR은 데이터 좌표축을 따라 조건부로, Diffusion은 새로 뚫은 noise 축을 따라 score로. (둘을 섞은 모델도 있습니다. 최신 트렌드 장의 autoregressive &amp;middot; 토큰 단위 diffusion 참고.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion의 기본 구조는 분포들의 경로입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forward는 데이터 분포를 닫힌 형태로 Gaussian까지 보내는 고정 경로이고(한 번에 $x_t$로 점프 가능), reverse는 각 스텝을 score로 평균이 정해지는 Gaussian 전이로 모델링해 그 경로를 거꾸로 내려옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;autoregressive가 기존 좌표축을 조건부로 훑는다면, Diffusion은 새로 뚫은 noise 축을 따라 전체 분포의 score를 배웁니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 논문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://proceedings.mlr.press/v37/sohl-dickstein15.html&quot;&gt;Sohl-Dickstein et al., 2015, Deep Unsupervised Learning using Nonequilibrium Thermodynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2006.11239&quot;&gt;Ho et al., 2020, Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2011.13456&quot;&gt;Song et al., 2020, Score-Based Generative Modeling through SDEs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/30</guid>
      <comments>https://g1g11.tistory.com/entry/03-Diffusion%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%A1%B0#entry30comment</comments>
      <pubDate>Tue, 30 Jun 2026 13:16:53 +0900</pubDate>
    </item>
    <item>
      <title>페이지 테스트</title>
      <link>https://g1g11.tistory.com/pages/%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;test&lt;/p&gt;</description>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/pages/%ED%8E%98%EC%9D%B4%EC%A7%80-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
      <pubDate>Wed, 24 Jun 2026 20:54:59 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조 00-1] 자료구조는 무엇을 최적화하는가?</title>
      <link>https://g1g11.tistory.com/entry/00-1-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%84-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EB%8A%94%EA%B0%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 이 장의 질문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 왜 배울까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람은 자료구조를 처음 만날 때 이렇게 생각합니다.&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;배열을 배운다.
연결 리스트를 배운다.
스택과 큐를 배운다.
트리와 그래프를 배운다.
각 구조의 시간복잡도를 외운다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식으로도 시험 문제는 어느 정도 풀 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 문제를 만나면 금방 막힙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 자료구조의 본질은 이름 암기가 아니라 &amp;ldquo;무엇을 빠르게 만들 것인가&amp;rdquo;를 판단하는 일이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 장의 질문은 하나입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 정확히 무엇을 최적화하는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답은 아래처럼 정리할 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 데이터를 어떤 연산에 맞춰, 어떤 비용 모델 위에 배치할지 정하는 표현 전략입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문장은 길지만, 핵심 단어는 네 개입니다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;데이터: 저장하고 다룰 대상
연산: 그 데이터에 반복해서 하는 질문과 수정
비용 모델: 무엇을 비싸다고 볼지 정하는 기준
표현 전략: 데이터를 어떤 모양으로 둘지 정하는 선택
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 데이터를 예쁘게 담는 그릇이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 자주 할 일을 빠르게 하기 위해, 어떤 일을 싸게 만들고 어떤 일은 조금 비싸게 감수할지 정하는 선택입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 프로그램은 결국 데이터를 묻고 고친다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램은 겉으로는 다양해 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쇼핑몰, 메신저, 게임, 검색엔진, AI 시스템은 전혀 다른 것처럼 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 안쪽에서는 대부분 데이터를 묻고 고칩니다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;쇼핑몰
- 상품을 찾는다.
- 장바구니에 넣는다.
- 주문을 저장한다.
- 사용자별 구매 이력을 조회한다.

메신저
- 새 메시지를 추가한다.
- 최근 대화를 읽는다.
- 읽지 않은 메시지 수를 센다.
- 특정 사용자를 찾는다.

게임
- 캐릭터 위치를 갱신한다.
- 충돌을 검사한다.
- 가장 가까운 적을 찾는다.
- 아이템 목록을 관리한다.

검색엔진
- 단어로 문서를 찾는다.
- 링크 관계를 따라간다.
- 점수 높은 문서를 우선순위로 정렬한다.

AI 시스템
- token id 배열을 처리한다.
- embedding vector를 저장한다.
- 가까운 벡터를 찾는다.
- KV cache를 재사용한다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 적을 때는 아무렇게나 저장해도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연락처가 10개라면 종이에 적어도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 연락처가 1,000만 개이고, 매초 수천 번 이름으로 사람을 찾아야 한다면 저장 방식이 성능을 좌우합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은&amp;nbsp;그 데이터에 반복해서 던지는 질문입니다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터를 어떻게 저장할까?
보다 먼저 물어야 할 질문은
이 데이터로 무엇을 자주 할까?
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 연산을 먼저 봐야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조 이름부터 외우면 헷갈립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 연산을 봐야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산은 데이터에 대해 하는 작업입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연산&lt;/td&gt;
&lt;td&gt;뜻&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;접근&lt;/td&gt;
&lt;td&gt;특정 위치의 값을 읽는다.&lt;/td&gt;
&lt;td&gt;10번째 메시지 보기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;탐색&lt;/td&gt;
&lt;td&gt;조건에 맞는 값을 찾는다.&lt;/td&gt;
&lt;td&gt;이름이 지민인 사용자 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삽입&lt;/td&gt;
&lt;td&gt;새 값을 넣는다.&lt;/td&gt;
&lt;td&gt;새 댓글 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삭제&lt;/td&gt;
&lt;td&gt;기존 값을 제거한다.&lt;/td&gt;
&lt;td&gt;할 일 목록에서 항목 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;갱신&lt;/td&gt;
&lt;td&gt;기존 값을 바꾼다.&lt;/td&gt;
&lt;td&gt;상품 재고 수량 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순회&lt;/td&gt;
&lt;td&gt;전체를 차례대로 훑는다.&lt;/td&gt;
&lt;td&gt;모든 주문 금액 합계 계산&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;범위 질의&lt;/td&gt;
&lt;td&gt;어떤 구간에 속한 값을 찾는다.&lt;/td&gt;
&lt;td&gt;1월 1일부터 1월 31일까지의 로그 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최우선 값 추출&lt;/td&gt;
&lt;td&gt;가장 작거나 큰 값을 꺼낸다.&lt;/td&gt;
&lt;td&gt;가장 급한 작업 먼저 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;관계 탐색&lt;/td&gt;
&lt;td&gt;연결을 따라간다.&lt;/td&gt;
&lt;td&gt;친구의 친구 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;근사 탐색&lt;/td&gt;
&lt;td&gt;정확히 같지는 않아도 가까운 값을 찾는다.&lt;/td&gt;
&lt;td&gt;비슷한 의미의 문서 찾기&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 이 연산들의 비용을 바꿉니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 연산은 빠르게 만들고, 다른 연산은 느려질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 trade-off입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 모든 일을 동시에 빠르게 만들 수는 없다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 처음 배울 때 가장 중요한 감각은 이것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 자료구조는 모든 일을 빠르게 하는 구조가 아니라, 중요한 일을 빠르게 하기 위해 다른 비용을 감수하는 구조입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 배열은 i번째 값을 바로 읽는 데 강합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작 주소와 원소 크기를 알면 위치를 바로 계산할 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 중간에 값을 끼워 넣으려면 뒤 원소들을 밀어야 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 리스트는 이미 위치를 알고 있을 때 연결을 바꾸는 삽입/삭제가 유연합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 100번째 값으로 바로 점프하기는 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 다음 포인터를 따라가야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블은 정확한 key 조회에 강합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 정렬 순서나 범위 질의에는 약합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 정렬 순서와 범위 질의에 강합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 단순 exact lookup만 보면 해시 테이블보다 무거울 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;원하는 일&lt;/td&gt;
&lt;td&gt;잘 맞는 구조&lt;/td&gt;
&lt;td&gt;대신 감수하는 것&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;번호로 바로 접근&lt;/td&gt;
&lt;td&gt;배열&lt;/td&gt;
&lt;td&gt;중간 삽입/삭제가 비쌀 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;앞뒤에서만 넣고 빼기&lt;/td&gt;
&lt;td&gt;Stack, Queue, Deque&lt;/td&gt;
&lt;td&gt;임의 위치 접근을 포기하거나 약하게 만든다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;key로 빠르게 찾기&lt;/td&gt;
&lt;td&gt;Hash Table&lt;/td&gt;
&lt;td&gt;순서와 범위 질의에는 약하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정렬된 순서 유지&lt;/td&gt;
&lt;td&gt;Balanced Tree, B+tree&lt;/td&gt;
&lt;td&gt;구현과 갱신 비용이 더 무거울 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;최솟값 반복 추출&lt;/td&gt;
&lt;td&gt;Heap&lt;/td&gt;
&lt;td&gt;전체 정렬 순서를 제공하지 않는다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대규모 근사 검색&lt;/td&gt;
&lt;td&gt;ANN Index&lt;/td&gt;
&lt;td&gt;정확도를 일부 양보할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 자료구조 선택은 &amp;ldquo;무엇이 제일 빠른가?&amp;rdquo;가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 정확한 질문은 아래입니다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;내 문제에서 가장 자주 일어나는 연산은 무엇인가?
그 연산을 빠르게 하기 위해 무엇을 포기할 수 있는가?
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 자료구조는 표현을 바꾼다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 데이터라도 표현 방식이 달라지면 가능한 질문이 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 숫자 목록이 있습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;10, 20, 30, 40, 50
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 배열로 표현하면 몇 번째 값인가?에 강합니다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;index: 0   1   2   3   4
value: 10  20  30  40  50
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 리스트로 표현하면 다음 값은 무엇인가?라는 연결이 중요해집니다.&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;10 -&amp;gt; 20 -&amp;gt; 30 -&amp;gt; 40 -&amp;gt; 50
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬된 배열로 표현하면 이 값보다 큰 첫 위치는 어디인가? 같은 질문이 가능해집니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;[10, 20, 30, 40, 50]
Binary Search 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블로 표현하면 key로 바로 찾기가 중요해집니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&quot;user:17&quot; -&amp;gt; profile
&quot;user:29&quot; -&amp;gt; profile
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프로 표현하면 값 자체보다 관계가 중요해집니다.&lt;/p&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;A -- B -- C
|         |
D -------E
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 단순히 저장 위치를 바꾸는 것이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 어떤 관점으로 볼지 바꿉니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 비용 모델까지 함께 봐야 한다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조가 최적화하는 것은 연산 비용입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 비용이 무엇인지는 상황에 따라 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 보통 RAM model로 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RAM model에서는 기본 연산과 메모리 접근을 비슷한 비용으로 보고, 입력 크기가 커질 때 연산 횟수가 어떻게 자라는지 분석합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 O(1), O(log n), O(n) 같은 Big-O 표기가 등장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 시스템에서는 비용이 더 다양합니다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;CPU cache miss가 비싼가?
SSD block I/O가 비싼가?
네트워크 왕복이 비싼가?
GPU memory 이동이 비싼가?
여러 스레드가 동시에 접근해서 lock 비용이 생기는가?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 같은 Big-O라도 실제 성능이 다를 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 순회와 연결 리스트 순회는 둘 다 O(n)일 수 있지만, 배열은 cache locality가 좋아 실제로 훨씬 빠를 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B+tree가 데이터베이스에서 중요한 이유도 단순 비교 횟수 때문만은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스크나 SSD가 block/page 단위로 데이터를 읽기 때문에, 한 번의 I/O로 많은 key를 가져오도록 구조를 설계합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM serving에서 KV cache가 중요한 것도 같은 이유입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산식만 맞는다고 충분하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 token들의 Key/Value를 어떻게 저장하고 재사용하며, GPU 메모리 낭비를 어떻게 줄일지가 throughput을 좌우할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 자료구조를 고를 때 묻는 질문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 문제를 만나면 아래 순서로 묻는 것이 좋습니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 데이터는 무엇인가?
2. 데이터는 얼마나 많은가?
3. 가장 자주 하는 연산은 무엇인가?
4. 읽기가 많은가, 쓰기가 많은가?
5. 순서가 중요한가?
6. 범위 질의가 필요한가?
7. 정확한 답이 필요한가, 근사 답이면 되는가?
8. 데이터가 메모리에 다 들어가는가?
9. cache, disk, GPU 같은 하드웨어 특성이 중요한가?
10. 여러 스레드나 요청이 동시에 접근하는가?
11. 최악 시간 보장이 필요한가, 평균 성능이면 충분한가?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문에 답하면 자료구조 선택이 암기가 아니라 판단이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &amp;ldquo;사용자 ID로 사용자 정보를 찾는다&amp;rdquo;는 문제는 Map이나 Hash Table이 자연스럽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &amp;ldquo;가입일 기준으로 특정 기간의 사용자 목록을 찾는다&amp;rdquo;면 정렬 구조나 데이터베이스 인덱스가 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;가장 가까운 embedding을 찾는다&amp;rdquo;는 문제에서 데이터가 작으면 전체 비교도 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 embedding이 1억 개라면 exact search는 비싸고, HNSW나 IVF/PQ 같은 ANN index를 고려해야 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 기본 축으로 전체 자료구조를 보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 많은 구조가 나오지만, 큰 축으로 보면 아래 질문들이 반복됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;축&lt;/td&gt;
&lt;td&gt;핵심 질문&lt;/td&gt;
&lt;td&gt;대표 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위치&lt;/td&gt;
&lt;td&gt;몇 번째 값을 바로 찾고 싶은가?&lt;/td&gt;
&lt;td&gt;Array, Dynamic Array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;끝 연산&lt;/td&gt;
&lt;td&gt;앞뒤에서만 넣고 빼면 되는가?&lt;/td&gt;
&lt;td&gt;Stack, Queue, Deque&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;key&lt;/td&gt;
&lt;td&gt;이름이나 ID로 찾고 싶은가?&lt;/td&gt;
&lt;td&gt;Map, Set, Hash Table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순서&lt;/td&gt;
&lt;td&gt;정렬 상태와 범위가 중요한가?&lt;/td&gt;
&lt;td&gt;BST, AVL, Red-Black Tree, B+tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;우선순위&lt;/td&gt;
&lt;td&gt;가장 중요한 값만 반복해서 꺼내는가?&lt;/td&gt;
&lt;td&gt;Heap, Priority Queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;연결&lt;/td&gt;
&lt;td&gt;관계와 경로가 중요한가?&lt;/td&gt;
&lt;td&gt;Graph, Union-Find&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;문자열&lt;/td&gt;
&lt;td&gt;prefix나 substring이 중요한가?&lt;/td&gt;
&lt;td&gt;Trie, Suffix Array, FM-index&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크기&lt;/td&gt;
&lt;td&gt;전체를 정확히 저장하기 너무 큰가?&lt;/td&gt;
&lt;td&gt;Compressed Structure, Sketch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;하드웨어&lt;/td&gt;
&lt;td&gt;cache, disk, GPU 비용이 중요한가?&lt;/td&gt;
&lt;td&gt;Cache-aware, B-tree, GPU-friendly layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 검색&lt;/td&gt;
&lt;td&gt;비슷한 의미를 빠르게 찾는가?&lt;/td&gt;
&lt;td&gt;Vector Index, ANN, HNSW&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 자주 하는 오해&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;ldquo;자료구조는 구현을 외우는 과목이다&amp;rdquo;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현은 중요하지만 핵심은 &amp;ldquo;어떤 연산을 빠르게 하려고 이런 모양이 되었는가&amp;rdquo;입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;ldquo;Big-O가 제일 좋은 구조를 고르면 된다&amp;rdquo;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Big-O는 출발점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 성능에는 cache, 메모리 배치, 상수 비용, 데이터 분포, 언어 런타임도 영향을 줍니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;ldquo;최신 구조가 항상 더 좋다&amp;rdquo;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 경우 단순한 배열이나 해시 테이블이 가장 좋은 선택입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 구조는 특정 조건에서 기존 구조의 한계를 해결하기 위해 등장합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;ldquo;자료구조는 알고리즘 문제 풀이용이다&amp;rdquo;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python의 list, dict, set, database index, OS scheduler, 검색엔진, vector DB, LLM KV cache 모두 자료구조의 문제입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 데이터를 저장하는 이름 목록이 아니라, 자주 하는 연산과 비용 모델에 맞춰 빠른 질문과 느린 질문을 의도적으로 선택하는 표현 전략입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다음 장으로 연결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 장에서는 비용을 말하는 언어를 배웁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(1), O(n), O(log n) 같은 표기는 암기표가 아니라 &amp;ldquo;데이터가 커질 때 비용이 어떻게 자라는가&amp;rdquo;를 말하는 언어입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://opendatastructures.org/&quot;&gt;Open Data Structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/&quot;&gt;Introduction to Algorithms, MIT Press&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>비전공자도 이해하는 기초 CS/비전공자도 이해하는 자료구조</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/43</guid>
      <comments>https://g1g11.tistory.com/entry/00-1-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%84-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EB%8A%94%EA%B0%80#entry43comment</comments>
      <pubDate>Wed, 24 Jun 2026 20:21:30 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조 00-0] AI 딸깍 시대에 왜 자료구조를 알아야 하는가?</title>
      <link>https://g1g11.tistory.com/entry/00-0-AI-%EB%94%B8%EA%B9%8D-%EC%8B%9C%EB%8C%80%EC%97%90-%EC%99%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;1294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Ol0v/dJMcahLEZ6X/8kOtZAbNUpCHIVx0yiVATk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Ol0v/dJMcahLEZ6X/8kOtZAbNUpCHIVx0yiVATk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Ol0v/dJMcahLEZ6X/8kOtZAbNUpCHIVx0yiVATk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Ol0v%2FdJMcahLEZ6X%2F8kOtZAbNUpCHIVx0yiVATk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1216&quot; height=&quot;1294&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;1294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 이 장의 질문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 코드를 직접 한 줄씩 쓰지 않아도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude code, Codex.. 등등에게 &amp;ldquo;로그 처리 코드를 짜줘&amp;rdquo;, &amp;ldquo;RAG 검색 API를 만들어줘&amp;rdquo;, &amp;ldquo;캐시를 붙여줘&amp;rdquo;라고 말하면 꽤 그럴듯한 코드가 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 자료구조는 덜 중요해졌을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니라고 생각합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 코드를 더 쉽게 만들어 줄수록, 사람은 &amp;ldquo;어떤 데이터 표현이 이 문제에 맞는가&amp;rdquo;를 더 잘 판단해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 문법 지식이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 데이터가 어떤 질문을 자주 받을지, 어떤 연산이 반복될지, 어떤 하드웨어 위에서 움직일지, 어떤 비용을 감수할지 정하는 판단 체계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 코드를 만들어 주는 시대에는 단순 구현 노동은 줄어들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 구조 선택의 책임은 사라지지 않습니다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;AI가 할 수 있는 일
= 주어진 방향으로 코드를 빠르게 생성한다.

사람이 여전히 해야 하는 일
= 그 방향이 문제의 데이터, 연산, 비용 모델에 맞는지 판단한다.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. &amp;ldquo;딸깍하면 끝&amp;rdquo;처럼 보이는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 코딩 도구가 강력해진 이유는 분명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복적인 코드, 흔한 API 사용, boilerplate, 간단한 알고리즘 구현은 아주 빠르게 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 문법과 라이브러리 사용법을 찾느라 오래 걸리던 일들이 훨씬 쉬워졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아래 요청들은 AI가 꽤 잘 처리합니다.&lt;/p&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;CSV 파일을 읽어서 통계를 내줘.
FastAPI 서버 골격을 만들어줘.
로그를 날짜별로 묶어줘.
간단한 그래프 탐색 코드를 짜줘.
Python dict로 빈도수를 세줘.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기에는 중요한 전제가 숨어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 보통 &amp;ldquo;주어진 설명 안에서&amp;rdquo; 코드를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명에 데이터 크기, 연산 빈도, 메모리 제약, 응답 시간 목표, 동시성 조건이 빠져 있으면 AI도 그 조건을 정확히 반영하기 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 예제에서 맞는 코드는 쉽게 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 서비스에서 버티는 구조는 별개의 문제입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 돌아가는 코드와 좋은 구조는 다르다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 큐처럼 동작합니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;queue = []
queue.append(&quot;A&quot;)
queue.append(&quot;B&quot;)
queue.pop(0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 예제에서는 아무 문제가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 pop(0)은 맨 앞 원소를 제거한 뒤 뒤 원소들을 앞으로 당겨야 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 많고 이 연산이 반복되면 비용이 커집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐처럼 앞에서 꺼내는 일이 많다면 collections.deque가 더 자연스럽습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from collections import deque

queue = deque()
queue.append(&quot;A&quot;)
queue.append(&quot;B&quot;)
queue.popleft()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 코드는 모두 &amp;ldquo;큐를 구현했다&amp;rdquo;고 말할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 내부 자료구조가 다르기 때문에 데이터가 커졌을 때 비용이 달라집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 차이가 자료구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 모르면 AI가 만들어 준 코드를 &amp;ldquo;잘 실행된다&amp;rdquo;는 이유로 그대로 받아들이기 쉽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 알면 아래 질문을 던집니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;이 연산은 몇 번 반복되는가?
이 구조는 그 반복에 맞는가?
지금 빠른가, 커져도 빠른가?
평균은 빠른가, 최악에도 버티는가?
Big-O만 괜찮은가, 실제 메모리 배치도 괜찮은가?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드가 돌아가는 것은 출발점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좋은 구조는 데이터가 커지고 조건이 나빠져도 의도한 비용 안에서 동작&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 자료구조는 &amp;ldquo;미래의 질문&amp;rdquo;을 준비하는 일이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 저장한다는 말은 단순히 값을 어딘가에 넣는다는 뜻이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 어떤 질문을 받을지 예상하고, 그 질문에 빨리 답할 수 있게 미리 모양을 잡는다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 같은 사용자 데이터라도 질문에 따라 구조가 달라집니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;자주 하는 질문&lt;/td&gt;
&lt;td&gt;자연스러운 구조&lt;/td&gt;
&lt;td&gt;이유&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자 ID로 프로필을 찾는다.&lt;/td&gt;
&lt;td&gt;Hash Table / Map&lt;/td&gt;
&lt;td&gt;key로 정확히 찾는 일이 중요하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가입일 순서대로 사용자를 본다.&lt;/td&gt;
&lt;td&gt;정렬 배열, Tree, DB index&lt;/td&gt;
&lt;td&gt;순서와 범위가 중요하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;친구 관계를 따라간다.&lt;/td&gt;
&lt;td&gt;Graph&lt;/td&gt;
&lt;td&gt;개별 값보다 연결 관계가 중요하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가장 활동량 높은 사용자를 반복해서 뽑는다.&lt;/td&gt;
&lt;td&gt;Heap / Priority Queue&lt;/td&gt;
&lt;td&gt;최댓값 또는 최우선 값을 빨리 꺼내야 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중복 가입 여부만 빠르게 판단한다.&lt;/td&gt;
&lt;td&gt;Set, Bloom Filter&lt;/td&gt;
&lt;td&gt;존재 여부가 핵심이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 자료구조는 &amp;ldquo;데이터를 담는 그릇&amp;rdquo;보다 더 정확히 말하면 &amp;ldquo;미래의 질문에 대한 준비&amp;rdquo;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. AI 시대의 병목은 자주 데이터 배치에서 나온다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 컴퓨터는 계산만 빠른 기계가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 어디에서 읽고, 어디에 쓰고, 얼마나 자주 이동시키는지가 성능을 크게 좌우합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 안에는 여러 계층이 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CPU register
-&amp;gt; L1/L2/L3 cache
-&amp;gt; main memory
-&amp;gt; SSD/HDD
-&amp;gt; network
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU도 마찬가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU는 많은 연산을 동시에 처리할 수 있지만, 데이터가 규칙적으로 배치되어 있고 많은 thread가 효율적으로 읽을 수 있을 때 강합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 접근이 흩어져 있거나 이동이 많으면 계산 장치가 아무리 빨라도 병목이 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 같은 O(n)이라도 실제 성능은 다를 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;배열 순회
[10][20][30][40][50]
가까운 데이터가 연속되어 있어 cache에 유리하다.

연결 리스트 순회
[10] -&amp;gt; 멀리 있는 [20] -&amp;gt; 또 다른 곳의 [30]
다음 위치를 따라갈 때마다 cache miss가 늘 수 있다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 시스템에서도 이 원리는 그대로 나타납니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;상황&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;겉으로 보이는 문제&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;자료구조 관점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Tensor 연산&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;숫자 계산&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;다차원 배열의 layout과 memory access 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;Vector DB&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;비슷한 문서 검색&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;고차원 벡터를 전부 비교하지 않기 위한 ANN index 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;RAG&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;검색 후 생성&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;embedding 저장, metadata lookup, 후보 압축, graph 탐색 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;LLM 추론&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;token 생성&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;KV cache를 어떻게 저장하고 재사용할지의 메모리 관리 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;대규모 로그 분석&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;통계 계산&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;정확 저장과 sketch 기반 근사 요약의 선택 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FlashAttention이 중요한 이유도 단순히 &amp;ldquo;attention을 빠르게 했다&amp;rdquo;가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 GPU memory 계층 사이의 읽기와 쓰기를 줄이도록 계산 순서와 데이터 배치를 바꾼 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PagedAttention도 비슷합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LLM serving에서 KV cache는 요청마다 길이가 다르고 동적으로 커집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 cache를 큰 연속 덩어리로만 관리하면 낭비와 fragmentation이 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PagedAttention은 KV cache를 block 단위로 관리해 메모리 사용과 batching 문제를 다룹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 딥러닝만의 이야기가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조의 이야기입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. AI가 만든 코드에서 특히 조심해야 할 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 만든 코드는 매우 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 검토해야 할 지점이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1. 작은 입력에서는 드러나지 않는 비용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(n^2) 코드는 데이터가 100개일 때는 조용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 1,000,000개가 되면 갑자기 전체 시스템을 멈추게 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 예제용으로 만든 중첩 반복문은 실제 트래픽에서 병목이 될 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2. ADT와 구현의 혼동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;큐&amp;rdquo;라고 말하면 AI는 동작하는 큐 코드를 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 큐의 핵심 연산이 앞에서 꺼내기라면, list가 아니라 deque가 맞을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 ADT는 &amp;ldquo;무엇을 할 수 있어야 하는가&amp;rdquo;이고, 구현은 &amp;ldquo;그 약속을 실제로 어떻게 지키는가&amp;rdquo;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구분은 뒤에서 다시 자세히 봅니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3. 평균과 최악의 혼동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hash Table은 평균적으로 빠릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 hash function, load factor, collision 처리에 따라 최악 성능은 달라질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안, adversarial input, latency tail이 중요한 시스템에서는 평균만 보면 안 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.4. 하드웨어 비용의 누락&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Big-O가 같아도 실제 성능은 다를 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU cache, SSD block I/O, GPU memory access, network round trip은 모두 서로 다른 비용입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 생성한 코드는 이런 비용 모델을 자동으로 보장하지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.5. 정확한 답과 근사 답의 선택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색, 추천, 모니터링에서는 정확한 답이 항상 필요한 것은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 vector search에서는 ANN index가 exact search보다 실용적일 수 있고, 로그 집계에서는 sketch가 전체 저장보다 적합할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 선택은 문법 문제가 아니라 문제 이해의 영역입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 자료구조를 아는 사람은 AI를 다르게 쓴다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 모르는 사람은 AI에게 &amp;ldquo;코드를 만들어 달라&amp;rdquo;고 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조를 아는 사람은 AI에게 &amp;ldquo;연산 패턴과 비용 모델을 비교해 달라&amp;rdquo;고 말합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;상황&lt;/td&gt;
&lt;td&gt;피상적 요청&lt;/td&gt;
&lt;td&gt;자료구조를 아는 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실시간 로그 집계&lt;/td&gt;
&lt;td&gt;로그 세는 코드 짜줘&lt;/td&gt;
&lt;td&gt;정확한 Map 집계와 Count-Min Sketch를 메모리&amp;middot;오차 기준으로 비교해줘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메시지 처리&lt;/td&gt;
&lt;td&gt;큐 구현해줘&lt;/td&gt;
&lt;td&gt;FIFO, popleft 비용, backpressure를 고려해 deque 또는 broker queue로 설계해줘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DB 검색&lt;/td&gt;
&lt;td&gt;인덱스 추가해줘&lt;/td&gt;
&lt;td&gt;point lookup, range scan, write-heavy workload에 따라 hash/B+tree/LSM 계열을 비교해줘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG 검색&lt;/td&gt;
&lt;td&gt;벡터 검색 붙여줘&lt;/td&gt;
&lt;td&gt;recall, latency, memory budget에 맞춰 HNSW/IVF/PQ 인덱스 선택을 설명해줘.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM serving&lt;/td&gt;
&lt;td&gt;추론 빠르게 해줘&lt;/td&gt;
&lt;td&gt;KV cache 크기, batching, fragmentation, block layout을 기준으로 병목을 분석해줘.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 좋은 조수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 좋은 질문을 받았을 때 더 좋은 조수가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 AI에게 좋은 질문을 던지기 위한 언어입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 추구하는 설명 방향&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 블로그에선 자료구조 이름을 외우는 방식은 지양하려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열, 연결 리스트, 스택, 큐, 해시 테이블, 트리, 그래프를 당연히 설명하긴 하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표는 단순히 이것이 뭔지 목록을 완성하는 것이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 아래 순서로 생각합니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 어떤 문제가 있었는가?
2. 어떤 연산이 자주 일어나는가?
3. 그 연산을 빠르게 하려면 데이터를 어떻게 배치해야 하는가?
4. 대신 어떤 비용을 감수하는가?
5. 실제 하드웨어나 시스템에서는 무엇이 달라지는가?
6. AI와 대규모 시스템에서는 이 아이디어가 어떤 모습으로 다시 나타나는가?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 배열을 배울 때도 단순히 a[i]가 빠르다는 말에서 끝내지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열이 cache locality, tensor, GPU batch, embedding table로 이어지는 이유를 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블을 배울 때도 &amp;ldquo;빠르다&amp;rdquo;에서 끝내지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균/최악, 충돌, load factor, Bloom Filter, sketch로 이어지는 흐름을 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 배울 때도 정점과 간선 정의에서 끝내지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS/DFS에서 recommendation graph, HNSW, vector search graph까지 이어지는 이유를 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이곳에서 자료구조를 배우는 목표는 구현 암기가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목표는 &lt;b&gt;데이터와 연산을 보는 눈&lt;/b&gt;을 만드는 것입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 코드를 대신 써줄수록, 사람은 데이터의 연산 패턴, 비용 모델, 하드웨어 제약을 읽고 올바른 자료구조를 선택하는 능력을 더 잘 갖춰야 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다음 장으로 연결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 장에서는 자료구조 전체를 관통하는 가장 큰 질문으로 들어갑니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조는 정확히 무엇을 최적화하는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 질문을 잡으면 이후에 등장하는 배열, 해시 테이블, 트리, 그래프, vector index, KV cache....가 하나의 흐름으로 보이기 시작합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://dl.acm.org/doi/10.1145/1498765.1498785&quot;&gt;Williams, Waterman, Patterson, Roofline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2205.14135&quot;&gt;Dao et al., FlashAttention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2309.06180&quot;&gt;Kwon et al., PagedAttention / vLLM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1603.09320&quot;&gt;Malkov and Yashunin, HNSW&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1702.08734&quot;&gt;Johnson, Douze, Jegou, FAISS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>비전공자도 이해하는 기초 CS/비전공자도 이해하는 자료구조</category>
      <category>Ai</category>
      <category>CS</category>
      <category>llm</category>
      <category>배열</category>
      <category>인공지능</category>
      <category>자료구조</category>
      <category>최적화</category>
      <category>캐시</category>
      <category>트리</category>
      <category>해시테이블</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/42</guid>
      <comments>https://g1g11.tistory.com/entry/00-0-AI-%EB%94%B8%EA%B9%8D-%EC%8B%9C%EB%8C%80%EC%97%90-%EC%99%9C-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80#entry42comment</comments>
      <pubDate>Wed, 24 Jun 2026 20:01:48 +0900</pubDate>
    </item>
    <item>
      <title>디퓨전 모델 설명 02: 확률 분포와 Score. 노이즈 제거를 넘어 diffusion을 분포(distribution)으로 이해하기</title>
      <link>https://g1g11.tistory.com/entry/02-%ED%99%95%EB%A5%A0-%EB%B6%84%ED%8F%AC%EC%99%80-Score</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 이 장의 질문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서 왜 score라는 개념이 중요할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion을 깊게 이해하는 가장 빠른 길은 &quot;노이즈 제거&quot;가 아니라 분포에서 출발하는 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 분포는 직접 알기 어렵다. 그러니 그 분포에서 데이터다운 쪽을 가리키는 방향만 배우자. 그 방향이 score다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 '방향'이 뒤따르는 모든 장(03의 경로, 04의 DDPM, 05의 SDE/ODE)을 관통하는 실입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 확률 분포를 직접 알기는 어렵다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 $x$가 데이터 분포 $p_{\text{data}}(x)$에서 왔다고 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학습 이미지는 많지만 그 공식은 모릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://g1g11.tistory.com/entry/00-%EC%83%9D%EC%84%B1-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EB%AA%A9%ED%91%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2026.06.23 - [인공지능 이론/Diffusion] - 00. 생성 모델의 목표&lt;/a&gt;에서 봤듯 이미지 공간은 20만 차원처럼 거대하고, 자연스러운 이미지는 그 안의 아주 좁고 휘어진 manifold 위에만 놓여 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 분포에서 $p_{\text{data}}(x)$의 값 자체(&quot;이 이미지가 정확히 얼마나 높은 density인가&quot;)를 구하는 건 매우 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 생성에는 그 숫자 전체가 꼭 필요하지 않습니다. 필요한 건 &quot;지금 위치에서 어느 쪽으로 움직이면 더 데이터다운가&quot;라는 방향뿐입니다. noise에서 출발해 그 방향으로 조금씩 움직이면 되니까요. 그 방향을 담은 것이 score입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Score의 정의 &amp;mdash; 'log를 미분한다'의 의미까지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Score는 log density의 입력 $x$에 대한 gradient입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;s(x) = \nabla_x \log p(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 기호의 뜻은 이렇습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$p(x)$: 위치 $x$가 얼마나 그럴듯한지 나타내는 density.&lt;/li&gt;
&lt;li&gt;$\log p(x)$: density를 로그로 바꾼 값.&lt;/li&gt;
&lt;li&gt;$\nabla_x$: $x$를 어느 방향으로 움직이면 그 값이 가장 빨리 커지는지 가리키는 미분.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 'log를 미분한다'는 그냥 표기 편의가 아니라 의미가 있습니다. 로그의 미분은 다음처럼 풀립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_x \log p(x) = \frac{\nabla_x p(x)}{p(x)}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 score는 &quot;density가 커지는 방향 $\nabla_x p$를, 지금 density 값 $p$로 나눈 것&quot; &amp;mdash; 절대적인 높이가 아니라 상대적인 증가율입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 score는 $p$ 전체에 곱해진 상수배에 영향을 받지 않습니다(분자&amp;middot;분모에서 약분되니까요). 이 성질이 &amp;sect;3에서 결정적으로 쓰입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기하적으로 읽으면 score는 x-공간의 각 위치마다 더 그럴듯한 쪽을 가리키는 화살표(벡터장)입니다. 분포 $p$가 그 화살표들을 만들어 냅니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1D Gaussian으로 보는 score&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순한 예 $p(x) = \mathcal{N}(0, 1)$을 봅시다. 로그를 취하면 $\log p(x) = -\tfrac{x^2}{2} + \text{const}$이고, 미분하면 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_x \log p(x) = -x&lt;br /&gt;$$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$x &amp;gt; 0$이면 score는 왼쪽(&amp;minus;)을, $x &amp;lt; 0$이면 오른쪽(+)을 가리킵니다.&lt;/li&gt;
&lt;li&gt;즉 평균 $0$ 쪽으로 돌아가라는 방향이고, 크기 $|x|$는 멀수록 강합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;935&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qhI9h/dJMcaay2liP/7Adq9oxniKyCztiw4B3rb0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qhI9h/dJMcaay2liP/7Adq9oxniKyCztiw4B3rb0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qhI9h/dJMcaay2liP/7Adq9oxniKyCztiw4B3rb0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqhI9h%2FdJMcaay2liP%2F7Adq9oxniKyCztiw4B3rb0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;355&quot; height=&quot;346&quot; data-origin-width=&quot;959&quot; data-origin-height=&quot;935&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 이미지 분포에서도 직관은 같습니다 &amp;mdash; 덜 그럴듯한 위치에 있으면 score가 더 그럴듯한 영역으로 가는 방향을 알려줍니다. (2D 분포 위의 score 벡터장은 Yang Song의 블로그 그림이 직관적입니다: &lt;a href=&quot;http://yang-song.net/blog/2021/score&quot;&gt;yang-song.net/blog/2021/score&lt;/a&gt;.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 왜 density보다 score가 유용한가 &amp;mdash; 정석부터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 정석적인 이유입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;density $p(x)$를 직접 모델링하려면 반드시 정규화 조건을 지켜야 합니다 &amp;mdash; 전체 공간에 대해 적분하면 1이 되어야 하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 모델을 보통 $p(x) = \tilde{p}(x) / Z$ 꼴(정규화 안 된 $\tilde{p}$를 상수 $Z$로 나눔)로 쓰는데, 이 정규화 상수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;Z = \int \tilde{p}(x)\, dx&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 앞장에서 본 그 다루기 힘든 고차원 적분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 valid한 density를 직접 만들려면 매번 이 $Z$를 감당해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 score를 보면 $Z$가 통째로 사라집니다. $\log p = \log \tilde{p} - \log Z$인데, $Z$는 $x$와 무관한 상수라 미분하면 0이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_x \log p(x) = \nabla_x \log \tilde{p}(x) - \underbrace{\nabla_x \log Z}_{=\,0} = \nabla_x \log \tilde{p}(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 정규화되지 않은 모델 $\tilde{p}$(또는 에너지 $E$로 $\tilde{p} = e^{-E}$)만 있어도 score는 배울 수 있습니다 &amp;mdash; 불가능한 $Z$를 영영 계산하지 않고서요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&amp;sect;2에서 본 '상대적 증가율 $\nabla_x p / p$'가 정확히 이 약분을 일으킵니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게다가 score를 샘플만으로 학습하는 구체적 방법도 있습니다 &amp;mdash; score matching(Hyv&amp;auml;rinen)과, 다음 절로 이어지는 denoising score matching(Vincent)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유하자면, 지도 전체의 정확한 고도(= density 값)를 몰라도, &quot;여기서 어느 쪽이 오르막인가&quot;(= score)는 알 수 있습니다. 생성에는 바로 이 오르막 방향만 있으면 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 각 noise level은 그 자체로 하나의 분포다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion은 데이터에 noise를 점점 섞습니다. 핵심 사실 하나부터 짚죠 &amp;mdash; noise를 섞으면 뾰족하던 분포가 매끄럽게 펴집니다. 왜 그럴까요?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 noise를 섞으면 매끄러워지나&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 Gaussian noise를 더하는 일은, 수학적으로 분포를 Gaussian으로 합성곱(convolution)하는 것과 같습니다. 그리고 Gaussian 합성곱은 흐리기(blur) 연산입니다 &amp;mdash; 사진에 블러를 먹이는 것과 똑같죠. 구체적으로 보면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원본 $p_{\text{data}}$은 얇은 manifold 위에만 몰려 있어서, 데이터가 있는 곳은 뾰족하고 그 바깥은 거의 0(빈 공간)입니다.&lt;/li&gt;
&lt;li&gt;각 데이터 점을 Gaussian 덩어리로 부풀려 겹치면, 뾰족한 봉우리가 퍼지고 점들 사이 빈 골짜기가 메워집니다. 그래서 분포가 어디서나 양수인 매끈한 덩어리가 됩니다.&lt;/li&gt;
&lt;li&gt;noise를 더 많이 섞을수록($t$가 클수록) 더 흐려져, 결국 봉우리가 다 뭉개진 하나의 넓은 Gaussian에 가까워집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2640&quot; data-origin-height=&quot;1120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8KTX6/dJMcaf1liJA/enCOMHSjW6DdFEqpKCgzCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8KTX6/dJMcaf1liJA/enCOMHSjW6DdFEqpKCgzCk/img.png&quot; data-alt=&quot;그림 2 &amp;amp;mdash; 데이터에 Gaussian noise를 섞는 것은 분포를 흐리는(convolution) 일이다. 뾰족하던 데이터 분포(t=0)가 noise를 섞을수록 봉우리가 퍼지고 골짜기가 메워져, 결국 하나의 매끄러운 Gaussian(큰 t)에 가까워진다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8KTX6/dJMcaf1liJA/enCOMHSjW6DdFEqpKCgzCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8KTX6%2FdJMcaf1liJA%2FenCOMHSjW6DdFEqpKCgzCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2640&quot; height=&quot;1120&quot; data-origin-width=&quot;2640&quot; data-origin-height=&quot;1120&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 2 &amp;mdash; 데이터에 Gaussian noise를 섞는 것은 분포를 흐리는(convolution) 일이다. 뾰족하던 데이터 분포(t=0)가 noise를 섞을수록 봉우리가 퍼지고 골짜기가 메워져, 결국 하나의 매끄러운 Gaussian(큰 t)에 가까워진다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 왜 중요할까요? 원본 $p_{\text{data}}$는 빈 공간에서 사실상 0이라, 그곳의 score(방향)가 정의되지 않거나 폭발합니다 &amp;mdash; &quot;데이터가 하나도 없는 허허벌판에서 어느 쪽이 데이터다운가&quot;를 말할 수 없으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 흐려진 $p_t$는 어디서나 매끄럽고 양수라, score가 공간 전체에서 잘 정의되고 학습 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 noise를 섞는 건 단순한 망가뜨리기가 아니라, score를 배울 수 있게 만드는 장치입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;각 level의 분포 $p_t$&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 각 시간 $t$마다 그 자체로 하나의 분포 $p_t$가 생깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$t$가 작으면 원본에 가깝고(뾰족), 크면 거의 $\mathcal{N}(0, I)$입니다. 정확히 쓰면 $p_t$는 모든 원본 $x_0$를 각각 Gaussian으로 흐릿하게 만든 뒤 평균낸 분포입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_t(x_t) = \int \mathcal{N}\big(x_t;\ \sqrt{\bar{\alpha}_t}\,x_0,\ (1-\bar{\alpha}t)I\big)\,p{\text{data}}(x_0)\,dx_0&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽는 법: $x_0$ 하나를 고르고 &amp;rarr; noise를 섞으면 $x_t$가 나올 분포가 생기고 &amp;rarr; 가능한 모든 $x_0$에 대해 평균내면 시간 $t$의 전체 분포 $p_t$가 됩니다. (이 $p_t$는 03장에서 '분포들의 경로'로 다시 등장합니다.)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;forward 식이 왜 그런 모양인가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 적분 안의 Gaussian은, 샘플 한 개 수준에서 보면 다음 한 줄과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1 - \bar{\alpha}_t}\,\epsilon, \qquad \epsilon \sim \mathcal{N}(0, I)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식의 의미를 뜯어보면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$\sqrt{\bar{\alpha}_t}\,x_0$: 원본 신호를 $\sqrt{\bar{\alpha}_t}\,(&amp;lt;1)$만큼 줄여 남긴 것. $t$가 커지면 $\bar{\alpha}_t \to 0$이라 신호가 사라집니다.&lt;/li&gt;
&lt;li&gt;$\sqrt{1-\bar{\alpha}_t}\,\epsilon$: 그 줄어든 만큼을 Gaussian noise로 채운 것. $t$가 커지면 계수가 1에 가까워져 거의 순수 noise가 됩니다.&lt;/li&gt;
&lt;li&gt;두 계수는 우연이 아닙니다. 각각 제곱해 더하면 $\bar{\alpha}_t + (1 - \bar{\alpha}_t) = 1$ &amp;mdash; 신호와 noise의 '에너지 배분'이 항상 1로 유지됩니다. 그래서 (원본 분산이 1이면) $x_t$의 분산도 항상 1로, 스케일이 폭발하거나 사라지지 않고 신호 대 noise 비율(SNR)만 바뀝니다. $\sqrt{\bar{\alpha}_t}$와 $\sqrt{1-\bar{\alpha}_t}$는 $\cos$&amp;middot;$\sin$처럼 크기를 보존하며 신호를 noise로 '회전'시키는 한 쌍인 셈입니다.&lt;/li&gt;
&lt;li&gt;$\bar{\alpha}t = \prod{s \le t}(1 - \beta_s)$: 매 step 조금씩($\beta_s$) noise를 섞을 때 $t$까지 누적해 남은 신호 비율. 덕분에 중간 step을 일일이 시뮬레이션하지 않고도 임의의 $t$로 한 번에 점프할 수 있습니다 &amp;mdash; 이 닫힌 형태의 결정적 이점입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;모델이 배우는 것: 각 level의 score&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모델이 배우는 것은 각 레벨의 score field입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;s_\theta(x_t, t) \approx \nabla_{x_t} \log p_t(x_t)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 &quot;정답 이미지 하나&quot;가 아니라, 각 noise level에서 분포가 데이터 쪽으로 향하는 방향을 배웁니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tweedie 공식: 'denoise'와 'score'가 같은 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 중요한 연결이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 $x_t$는 서로 다른 (원본 $x_0$, noise $\epsilon$) 조합에서 나올 수 있습니다. 그래서 MSE로 학습한 최적 denoiser는 특정 원본 하나가 아니라, 가능한 깨끗한 원본들의 평균 $\mathbb{E}[x_0 \mid x_t]$를 내놓습니다. 그리고 이 평균이 score와 정확히 연결됩니다 &amp;mdash; Tweedie 공식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그런지, 가장 단순한 형태로 직접 유도해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;noise가 $x = x_0 + \sigma\epsilon$처럼 더해졌다고 하면, 흐려진 분포는 $p_\sigma(x) = \int \mathcal{N}(x; x_0, \sigma^2 I)\,p(x_0)\,dx_0$입니다. 이걸 $x$로 미분할 때 Gaussian의 성질 $\nabla_x \mathcal{N}(x; x_0, \sigma^2 I) = \mathcal{N}(x; x_0, \sigma^2 I)\cdot\frac{x_0 - x}{\sigma^2}$를 쓰면, 다음이 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_x \log p_\sigma(x) = \frac{\nabla_x p_\sigma(x)}{p_\sigma(x)} = \mathbb{E}\!\left[\frac{x_0 - x}{\sigma^2}\;\middle|\;x\right] = \frac{\mathbb{E}[x_0 \mid x] - x}{\sigma^2}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양변을 정리하면 Tweedie 공식이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\mathbb{E}[x_0 \mid x] = x + \sigma^2\,\nabla_x \log p_\sigma(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 옮기면 이렇습니다 &amp;mdash; 깨끗한 원본의 최선 추정치는, 지금 노이즈 낀 점 $x$에서 score 방향으로 노이즈 분산($\sigma^2$)만큼 한 걸음 옮긴 자리입니다. 즉 잘 denoise하는 것과 score를 아는 것은 같은 일입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kv0MI/dJMcajiphJ8/agNeYAeizb0CLNyDUYslBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kv0MI/dJMcajiphJ8/agNeYAeizb0CLNyDUYslBk/img.png&quot; data-alt=&quot;그림 3 &amp;amp;mdash; Tweedie 공식. 노이즈 낀 점 x_t에서 score(초록 화살표) 방향으로 노이즈 분산만큼 나아간 자리가 곧 깨끗한 원본의 평균 추정 E[x0 ❘ x_t]이고, 그 점은 data manifold 위에 놓인다. 그래서 denoise는 곧 score를 따라가기다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kv0MI/dJMcajiphJ8/agNeYAeizb0CLNyDUYslBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKv0MI%2FdJMcajiphJ8%2FagNeYAeizb0CLNyDUYslBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2400&quot; height=&quot;1280&quot; data-origin-width=&quot;2400&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3 &amp;mdash; Tweedie 공식. 노이즈 낀 점 x_t에서 score(초록 화살표) 방향으로 노이즈 분산만큼 나아간 자리가 곧 깨끗한 원본의 평균 추정 E[x0 ❘ x_t]이고, 그 점은 data manifold 위에 놓인다. 그래서 denoise는 곧 score를 따라가기다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM 표기로 옮기면 위 결과는 다음과 같고(원리는 동일), 외울 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_{x_t} \log p_t(x_t) = \frac{\sqrt{\bar{\alpha}_t}\,\mathbb{E}[x_0 \mid x_t] - x_t}{1 - \bar{\alpha}_t}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져갈 직관은 하나입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 denoise한다 = 가능한 깨끗한 원본들의 평균을 안다 = score를 안다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Noise prediction과 score, 그리고 한 가지 주의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM은 보통 noise $\epsilon$를 예측합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 forward 식 $x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon$에서, 한 학습 예시는 $x_0$와 $\epsilon$를 우리가 알고 있으니 &quot;이 $x_t$에 섞인 noise가 무엇이었는지 맞혀 봐&quot;라고 시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score와 잇는 건 의미상 자연스럽습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forward 식을 $\epsilon$에 대해 풀면 $\epsilon = (x_t - \sqrt{\bar{\alpha}_t}\,x_0)/\sqrt{1-\bar{\alpha}_t}$, 즉 noise는 &quot;$x_t$가 깨끗한 쪽에서 얼마나&amp;middot;어느 쪽으로 벗어났는가&quot;를 가리킵니다. 그러니 density가 커지는 방향(score)은 그 벗어남을 되돌리는 방향, 곧 noise의 반대쪽이어야 합니다. 실제로, 생성에 필요한 건 특정 쌍의 noise 하나가 아니라 같은 $x_t$에서 가능한 noise들의 평균이라는 점까지 반영하면 다음이 성립합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_{x_t} \log p_t(x_t) = -\frac{\mathbb{E}[\epsilon \mid x_t]}{\sqrt{1 - \bar{\alpha}_t}}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 MSE로 학습한 최적 noise predictor $\epsilon_\theta(x_t, t) \approx \mathbb{E}[\epsilon \mid x_t]$를 쓰면 score는 이렇게 근사됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;s_\theta(x_t, t) \approx -\frac{\epsilon_\theta(x_t, t)}{\sqrt{1 - \bar{\alpha}_t}}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부호 $-$가 바로 &quot;score는 섞인 noise의 반대 방향&quot;이라는 뜻이고, 분모 $\sqrt{1-\bar{\alpha}_t}$는 noise 세기로 정규화한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 noise 예측 &amp;middot; score 예측 &amp;middot; denoising은 같은 대상을 다르게 표현한 세 언어입니다 &amp;mdash; 하나는 섞인 noise를, 하나는 density가 커지는 방향을, 하나는 깨끗한 쪽 평균을 맞히는 언어이죠.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 한 가지 주의. score는 방향을 가리키는 안내 신호일 뿐, score를 한 번 따라간다고 noise가 곧장 깨끗한 이미지가 되는 건 아닙니다. 한 분포 $p_t$의 score만 계속 따라가면 그 레벨 $p_t$ 안에서 그럴듯한 쪽으로 움직일 뿐입니다. noise를 데이터로 되돌리려면 $t = T \to 0$으로 분포들의 경로 $\{p_t\}$를 거슬러 내려가야 하고(03장), 그 역방향 이동을 실제로 수행하는 것이 DDPM의 한 스텝(04장)이나 reverse SDE/ODE(05장)입니다. 한마디로, score는 &lt;b&gt;운전대&lt;/b&gt;, 경로를 따라가는 차는 &lt;b&gt;reverse process&lt;/b&gt;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 분포의 값은 정규화 상수 $Z$ 때문에 직접 알기 어려우니, 대신 그것에 무관한 방향장 score를 배웁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;noise를 섞으면 분포가 매끄러워져 각 level의 score가 학습 가능해지고, 이 score는 denoising(깨끗한 쪽 평균, Tweedie)&amp;middot;noise 예측과 같은 대상입니다. 실제 생성은 그 score를 안내 삼아 분포들의 경로를 거꾸로 내려오는 일입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 논문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://jmlr.org/papers/v6/hyvarinen05a.html&quot;&gt;Hyv&amp;auml;rinen, 2005, Estimation of Non-Normalized Statistical Models by Score Matching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://doi.org/10.1162/NECO_a_00142&quot;&gt;Vincent, 2011, A Connection Between Score Matching and Denoising Autoencoders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1907.05600&quot;&gt;Song &amp;amp; Ermon, 2019, Generative Modeling by Estimating Gradients of the Data Distribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2011.13456&quot;&gt;Song et al., 2020, Score-Based Generative Modeling through SDEs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2006.11239&quot;&gt;Ho et al., 2020, Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/29</guid>
      <comments>https://g1g11.tistory.com/entry/02-%ED%99%95%EB%A5%A0-%EB%B6%84%ED%8F%AC%EC%99%80-Score#entry29comment</comments>
      <pubDate>Wed, 24 Jun 2026 19:44:22 +0900</pubDate>
    </item>
    <item>
      <title>[파이토치 01] 환경 준비와 Quick Start</title>
      <link>https://g1g11.tistory.com/entry/01-%ED%99%98%EA%B2%BD-%EC%A4%80%EB%B9%84%EC%99%80-Quickstart</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 목표&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지의 목표는 PyTorch 코드의 전체 모양을 먼저 보는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 모든 줄을 완벽히 이해하려고 하지 않아도 됩니다. 먼저 &amp;ldquo;전체 구조가 이렇게 생겼구나&amp;rdquo;를 잡는 것이 중요합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 설치 확인&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;import torch

print(torch.__version__)
print(torch.cuda.is_available())
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;torch.cuda.is_available()가 False여도 괜찮습니다. 기본 실습은 CPU에서도 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;True라면 앞으로 큰 Tensor 계산을 GPU에서 실행할 수 있다는 뜻입니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;# 최신 PyTorch 권장 방식: CUDA / MPS(Mac) / XPU 등 사용 가능한 가속기를 자동 선택
device = torch.accelerator.current_accelerator().type if torch.accelerator.is_available() else &quot;cpu&quot;
print(device)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구버전 스타일인 &quot;cuda&quot; if torch.cuda.is_available() else &quot;cpu&quot;도 잘 동작하지만, Mac의 MPS 같은 가속기는 잡지 못합니다. torch.accelerator(PyTorch 2.6+)는 CUDA&amp;middot;MPS&amp;middot;XPU를 한 줄로 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU가 있다면 이름과 용량도 한 번 확인해둡니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;if torch.cuda.is_available():
    print(torch.cuda.get_device_name(0))
    total_gb = torch.cuda.get_device_properties(0).total_memory / (1024 ** 3)
    print(round(total_gb, 2), &quot;GB&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 이 숫자를 외울 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 나중에 batch size를 키우거나 이미지 크기를 바꿀 때, 결국 이 용량 안에서 학습이 돌아간다는 점만 기억하면 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 자주 쓰는 패키지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 역할&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;torch&lt;/td&gt;
&lt;td&gt;Tensor, Autograd, 모델 학습의 핵심&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torch.nn&lt;/td&gt;
&lt;td&gt;Layer, Loss, 모델 구조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torch.optim&lt;/td&gt;
&lt;td&gt;SGD, Adam 같은 optimizer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torch.utils.data&lt;/td&gt;
&lt;td&gt;Dataset, DataLoader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torchvision&lt;/td&gt;
&lt;td&gt;이미지 데이터셋, transform, vision 모델&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Quickstart 코드의 큰 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyTorch 공식 Quickstart는 FashionMNIST 예제로 다음 흐름을 보여줍니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 데이터셋 다운로드
2. DataLoader 생성
3. nn.Module 모델 정의
4. Loss와 Optimizer 정의
5. train loop 실행
6. test loop 실행
7. 모델 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Quickstart는 세부 API를 외우는 페이지가 아니라 PyTorch 프로젝트의 전체 골격을 보는 페이지입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 환경 관련 주의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GPU가 없어도 CPU로 실습할 수 있습니다.&lt;/li&gt;
&lt;li&gt;모델과 데이터는 같은 device에 있어야 합니다.&lt;/li&gt;
&lt;li&gt;큰 Tensor를 CPU와 GPU 사이에 자주 옮기면 시간이 들 수 있습니다.&lt;/li&gt;
&lt;li&gt;torchvision은 이미지 데이터셋 실습에서 필요합니다.&lt;/li&gt;
&lt;li&gt;이 문서의 실습은 기본적으로 CPU에서도 돌아가도록 설계합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html&quot;&gt;PyTorch Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 코딩/PyTorch</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/10</guid>
      <comments>https://g1g11.tistory.com/entry/01-%ED%99%98%EA%B2%BD-%EC%A4%80%EB%B9%84%EC%99%80-Quickstart#entry10comment</comments>
      <pubDate>Tue, 23 Jun 2026 23:33:54 +0900</pubDate>
    </item>
    <item>
      <title>디퓨전 모델 설명 01: GAN에서 Diffusion으로. 생성 모델을 바라보는 관점 (중요)</title>
      <link>https://g1g11.tistory.com/entry/01-GAN%EC%97%90%EC%84%9C-Diffusion%EC%9C%BC%EB%A1%9C</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;-1. 들어가기 전에&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion을 알기 위해서 GAN을 반드시 잘 알아야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 그럴 필요는 없습니다. 이쪽 분야는 워낙 빠르게 변하다보니, 이전 기술을 전부 follow up 하고 최신걸로 들어가는건 쉽지 않습니다. 차라리, 이전거는 대략적으로 개념만 알고, 최신 기술을 먼저 습득한다음 다시 이전걸 공부하면 더 효율적일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글도 같은 방식으로 진행합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 이 장의 질문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 Diffusion을 설명할 때 GAN과 비교하는 것이 도움이 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GAN과 Diffusion은 둘 다 생성 모델이고, 목표도 같습니다 &amp;mdash; $p_{\text{data}}(x)$와 비슷한 분포에서 새 샘플을 뽑는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이는 &lt;b&gt;그 분포를 맞추는 방식&lt;/b&gt;입니다. 그 방식의 차이를 보면, 왜 Diffusion이 지금의 형태가 되었는지가 선명해집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. GAN은 분포를 게임으로 맞춘다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GAN에는 두 모델이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Generator&lt;/b&gt; $G$: noise $z$를 받아 fake sample $G(z)$를 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Discriminator&lt;/b&gt; $D$: 입력이 real data인지 fake data인지 구분합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 $z$는 보통 Gaussian 같은 단순한 분포에서 뽑은 무작위 벡터입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 GAN은 &quot;단순한 noise를 한 번에 데이터처럼 보이는 sample로 바꾸는 함수&quot;를 학습합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 GAN의 목적 함수는 아래 minimax game으로 표현됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\min_G \max_D\ \mathbb{E}{x \sim p{\text{data}}}\big[\log D(x)\big] + \mathbb{E}_{z \sim p_z}\big[\log\big(1 - D(G(z))\big)\big]&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식이 길지만 읽는 법은 어렵지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$\max_D$: 판별자 $D$는 이 값을 크게 만들고 싶습니다.&lt;/li&gt;
&lt;li&gt;$\mathbb{E}{x \sim p{\text{data}}}[\log D(x)]$: 진짜 데이터 $x$를 보고 &quot;진짜다&quot;라고 높은 점수를 주면 커지는 항입니다.&lt;/li&gt;
&lt;li&gt;$\mathbb{E}_{z \sim p_z}[\log(1-D(G(z)))]$: 생성자가 만든 가짜 $G(z)$를 보고 &quot;가짜다&quot;라고 잘 맞히면 커지는 항입니다.&lt;/li&gt;
&lt;li&gt;$\min_G$: 반대로 생성자 $G$는 판별자가 가짜를 못 알아보게 만들어 이 게임에서 이기려 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관은 단순합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판별자 $D$는 진짜와 가짜를 더 잘 구분하려 하고, 생성자 $G$는 판별자를 속이려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상적인 균형에서는 판별자가 더 이상 진짜와 가짜를 구분하지 못하고, 생성자 분포 $p_G$가 실제 데이터 분포 $p_{\text{data}}$에 가까워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 왜 &quot;속이는 것&quot;이 &quot;분포를 맞추는 것&quot;이 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;판별자는 사실상 두 분포의 &lt;b&gt;차이 탐지기&lt;/b&gt;입니다. $p_G$가 $p_{\text{data}}$와 조금이라도 다르면, 한쪽에 확률이 더 몰린 영역이 반드시 생기고, 똑똑한 판별자는 바로 그 틈을 노려 진짜/가짜를 가려냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 생성자가 &lt;b&gt;가장 잘하는 판별자조차&lt;/b&gt; 못 속이게 만드는 길은 단 하나뿐입니다 &amp;mdash; 통계적 차이를 아예 없애는 것, 즉 $p_G = p_{\text{data}}$.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(수학적으로도, $G$를 고정했을 때 최적 판별자 $D^\ast(x) = \frac{p_{\text{data}}(x)}{p_{\text{data}}(x) + p_G(x)}$를 대입하면 생성자의 목표는 두 분포의 &lt;b&gt;Jensen&amp;ndash;Shannon divergence&lt;/b&gt;를 줄이는 것이 되고, 이 값은 $p_G = p_{\text{data}}$일 때 정확히 0입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 균형점에서 판별자는 어디서나 $\tfrac{1}{2}$를 답하고, 생성자 분포는 실제 데이터 분포와 같아집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. GAN의 강점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GAN은 오랫동안 이미지 생성의 중심이었습니다. 특히 StyleGAN 계열은 매우 선명한 이미지를 만들었습니다. 장점은 분명합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;sampling이 빠릅니다.&lt;/b&gt; noise를 넣으면 한 번의 forward로 결과가 나옵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;adversarial loss가 시각적으로 선명한 샘플&lt;/b&gt;을 만들기 좋습니다.&lt;/li&gt;
&lt;li&gt;generator가 직접 sample을 만들기 때문에 &lt;b&gt;추론 구조가 간단&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 장점들은 동시에 어려움의 뿌리이기도 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. GAN의 어려움 &amp;mdash; 그리고 '왜' 그런가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지를 짚고 갑시다. 셋은 사실 한 뿌리에서 나옵니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) GAN은 noise에서 데이터로 '한 번에' 건너뛴다.&lt;/b&gt; 생성자는 $z \sim \mathcal{N}(0, I)$ 같은 noise 한 점을 받아, 신경망 한 번 통과로 곧장 완성된 이미지를 내놓습니다: $z \to G(z) = x$. 즉 GAN도 &lt;b&gt;noise에서 출발&lt;/b&gt;하지만, noise&amp;rarr;data를 단 한 걸음에 끝냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 빠른 sampling의 비결인 동시에 학습을 어렵게 만드는 근본 원인입니다 &amp;mdash; 에서 본 그 '얇고 휘고 비볼록한' 데이터 분포로 가는 복잡한 map 전체를, 생성자가 한 함수로 한 번에 학습해야 하니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 그래서 명시적 likelihood를 직접 최적화하지 않는다 (못 한다).&lt;/b&gt; 생성자는 'noise를 이미지로 바꾸는 함수'일 뿐, 어떤 이미지가 얼마나 그럴듯한지 $p_G(x)$를 알려주는 공식을 갖고 있지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 모델을 &lt;b&gt;implicit(암묵적) 모델&lt;/b&gt;이라 부릅니다 &amp;mdash; 샘플은 뽑을 수 있어도 그 확률(density)은 계산할 수 없습니다. (억지로 계산하려 하면 다루기 힘든 적분과 정규화 상수가 다시 등장합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;likelihood를 직접 못 올리니, GAN은 그것을 &lt;b&gt;'판별자를 속이는가'라는 신호로 대체&lt;/b&gt;합니다. 즉 density를 평가하는 대신 sample을 평가하는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 두 모델이 동시에 움직이는 게임이라 학습이 민감하다.&lt;/b&gt; 보통의 학습은 정해진 손실 하나를 내려가면 됩니다. 그런데 GAN에는 고정된 목표가 없습니다 &amp;mdash; 생성자의 목표는 '지금의 판별자'에 달려 있고 판별자의 목표는 '지금의 생성자'에 달려 있어서, 둘이 서로를 쫓는 &lt;b&gt;움직이는 표적&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;균형이 미묘해서, 판별자가 너무 강해지면 생성자에게 줄 gradient가 사라지고(&quot;너무 확실히 가짜&quot;라고 해버려 '어디를 고치라'는 신호가 없어짐), 너무 약하면 생성자가 대충 속이고 넘어갑니다. 그 결과가 학습 불안정과 &lt;b&gt;mode collapse&lt;/b&gt;(판별자를 속이는 몇몇 출력에만 확률을 몰아주어 다양성을 잃는 현상)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 의미 뿌리&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 84px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;문제&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;의미&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;뿌리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;학습 불안정성&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;두 모델의 균형이 깨지면 학습이 흔들림&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;(3) 움직이는 표적 게임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;mode collapse&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;분포의 일부 mode만 반복 생성&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;(3) 속이기만 하면 되는 신호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;확률 해석의 어려움&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;$p_G(x)$의 density를 직접 다루기 어렵다&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot;&gt;(2) implicit 모델&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 어려움들은 결국 &lt;b&gt;복잡한 분포로 가는 거대한 도약을 한 번에, 그것도 적대적 게임으로&lt;/b&gt; 학습한다는 한 가지 사실에서 나옵니다. 그래서 자연스러운 질문이 따라옵니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 큰 도약을, 더 안정적으로 풀 수 있게 잘게 쪼갤 수는 없을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion이 답하는 방식이 바로 이것입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Diffusion은 다른 질문을 던진다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion은 GAN처럼 noise를 한 번에 완성된 샘플로 바꾸지 않습니다. 같은 'noise &amp;rarr; data'를, &lt;b&gt;한 걸음이 아니라 여러 작은 걸음&lt;/b&gt;으로 나눠 갑니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSyj1N/dJMcaf1lhX1/MF9EP2VHcq5KIyVkpGzjwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSyj1N/dJMcaf1lhX1/MF9EP2VHcq5KIyVkpGzjwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSyj1N/dJMcaf1lhX1/MF9EP2VHcq5KIyVkpGzjwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSyj1N%2FdJMcaf1lhX1%2FMF9EP2VHcq5KIyVkpGzjwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;238&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구체적으로는 복잡한 데이터 분포와 단순한 noise 분포 사이에 많은 중간 분포를 둡니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_{\text{data}} \;\to\; p_1 \;\to\; p_2 \;\to\; \cdots \;\to\; p_T \approx \mathcal{N}(0, I)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 수식에서 $p_1, p_2, \ldots, p_T$는 이미지 한 장이 아니라 &lt;b&gt;각 noise level에서 sample들이 이루는 분포&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 실제 데이터 분포에 가깝고, 시간이 갈수록 더 흐릿하고 단순한 Gaussian noise 분포에 가까워집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점은 &lt;b&gt;forward noising 과정은 우리가 미리 정해 둔다&lt;/b&gt;는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 처음부터 모든 경로를 마음대로 발견하는 것이 아니라, &quot;데이터에 noise를 조금씩 섞으면 결국 Gaussian에 가까워진다&quot;는 쉬운 방향을 먼저 깔아 둡니다. 모델이 배우고 써야 하는 것은 그 &lt;b&gt;반대 방향&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\mathcal{N}(0, I) \;\to\; \cdots \;\to\; p_2 \;\to\; p_1 \;\to\; p_{\text{data}}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 diffusion의 핵심은 &quot;흐릿한 sample $x_t$가 주어졌을 때, 조금 덜 흐릿한 $x_{t-1}$ 쪽으로 어떻게 이동할까?&quot;를 반복해 푸는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 보면 denoising은 단순한 이미지 복원이 아니라, 단순한 prior 분포에서 데이터 분포로 돌아오는 &lt;b&gt;작은 조건부 생성 문제들의 연쇄&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 step은 작아서 학습 신호를 만들기 쉽고, 고정된 손실 하나만 내려가면 되므로(적대적 게임이 아님) GAN보다 안정적입니다 &amp;mdash; 이것이 diffusion의 학습 안정성과 넓은 분포 커버리지로 이어집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. GAN과 Diffusion의 차이&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;관점&lt;/td&gt;
&lt;td&gt;GAN&lt;/td&gt;
&lt;td&gt;Diffusion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;생성 방식&lt;/td&gt;
&lt;td&gt;noise를 한 번에 sample로 변환&lt;/td&gt;
&lt;td&gt;noise에서 여러 단계로 sample 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;학습 신호&lt;/td&gt;
&lt;td&gt;discriminator의 판단 (적대적 게임)&lt;/td&gt;
&lt;td&gt;denoising, score, variational objective (고정된 손실)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분포 접근&lt;/td&gt;
&lt;td&gt;implicit distribution matching&lt;/td&gt;
&lt;td&gt;probability path와 reverse process 학습&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;빠른 sampling&lt;/td&gt;
&lt;td&gt;안정적 학습과 넓은 분포 커버리지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어려움&lt;/td&gt;
&lt;td&gt;학습 불안정, mode collapse&lt;/td&gt;
&lt;td&gt;sampling 비용(여러 step)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion은 GAN을 대체한다기보다, 같은 생성 문제를 다른 방식으로 푼 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 최근에는 두 관점이 다시 만나, GAN의 adversarial loss를 diffusion distillation에 활용하는 흐름(ADD, LADD 등)도 등장했습니다. (자세한 내용은 기회가 된다면 추후 다뤄보겠습니다.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GAN은 분포를 판별자와 생성자의 게임으로 맞추되 noise를 한 번에 데이터로 바꾸고, Diffusion은 데이터에 noise를 더하는 쉬운 forward 과정을 정해 둔 뒤 Gaussian noise에서 데이터 분포로 돌아오는 역방향 조건부 이동을 &lt;b&gt;여러 단계로&lt;/b&gt; 학습합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 논문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1406.2661&quot;&gt;Goodfellow et al., 2014, Generative Adversarial Networks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2105.05233&quot;&gt;Dhariwal &amp;amp; Nichol, 2021, Diffusion Models Beat GANs on Image Synthesis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2006.11239&quot;&gt;Ho et al., 2020, Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/28</guid>
      <comments>https://g1g11.tistory.com/entry/01-GAN%EC%97%90%EC%84%9C-Diffusion%EC%9C%BC%EB%A1%9C#entry28comment</comments>
      <pubDate>Tue, 23 Jun 2026 21:21:58 +0900</pubDate>
    </item>
    <item>
      <title>디퓨전 설명 00: 생성 모델의 목표 - 디퓨전은 단순 노이즈 제거로만 이해하면 안된다!</title>
      <link>https://g1g11.tistory.com/entry/00-%EC%83%9D%EC%84%B1-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EB%AA%A9%ED%91%9C</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 시작하기 전에 &amp;mdash; 왜 '큰 그림'부터 보는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion을 다룬 글은 대부분 이걸 &quot;노이즈를 넣었다가 다시 지우는 학습 기법&quot;으로 소개합니다. 그 설명만으로도 코드는 돌아갑니다. 하지만 거기서 멈추면 시야가 좁아집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 하필 noise를 쓰는지, 왜 분포가 아니라 score를 배우는지, 그 손실함수는 어디서 튀어나왔는지를 모른 채 레시피만 외우게 됩니다. 그러면 막상 응용하거나 새로운 연구로 확장하려 할 때 손에 잡히는 게 없습니다. &quot;denoise하는 과정&quot;에만 익숙해진 채로 advanced한 작업에 들어가 길을 잃는 경우가 그래서 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 작성하는 Diffusion관련 내용은 순서를 뒤집어 서술합니다.. Diffusion을 &lt;b&gt;'생성 모델'이라는 더 큰 문제의 한 가지 해법&lt;/b&gt;으로 놓고, &lt;b&gt;무슨 문제를 푸는가 &amp;rarr; 그래서 왜 이런 장치가 필요했는가&lt;/b&gt;의 순서로 풀어갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 관점에서 보면 noise schedule, score, reverse process, ELBO 같은 장치들이 임의의 트릭이 아니라, 그 문제에서 자연스럽게 따라 나온 결론으로 보이기 시작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 장은 그 출발점입니다. 먼저 생성 모델이 정확히 무엇을 목표로 하는지부터 잡습니다. (수학 기호가 아직 낯설면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://g1g11.tistory.com/entry/00-0-%EC%84%9C%EB%A1%A0-%EC%83%9D%EC%84%B1%ED%98%95-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88-%EC%88%98%ED%95%99%EC%A0%81-%EA%B0%9C%EB%85%90%EB%93%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2026.06.23 - [인공지능 이론/Diffusion] - 00-0. 서론. 생성형 모델을 이해하기 위한 기초 수학적 개념들&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 먼저 읽고 와도 좋습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 목표: 데이터 '한 장'이 아니라 '분포'를 손에 넣기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직관부터 잡고 갑시다. 친구 1,000명의 키를 모으면 하나의 '키 분포'(170cm 근처가 가장 많은 종 모양)가 생깁니다. 그 분포에서 무작위로 한 값을 뽑으면, 실제로 재본 적 없는 &lt;b&gt;새로운 사람의 키&lt;/b&gt;를 만들어낸 셈입니다. 생성(generation)이란 바로 이 &quot;분포에서 뽑기&quot;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지도 똑같습니다. 고양이 사진 100만 장이 있어도 가능한 고양이 이미지는 훨씬 많고, 우리는 그 사진들을 &lt;b&gt;어떤 알 수 없는 분포에서 뽑힌 샘플&lt;/b&gt;로 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x \sim p_{\text{data}}(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 $x$는 이미지&amp;middot;음성&amp;middot;문장 등 생성 대상이고, $p_{\text{data}}(x)$는 &quot;진짜 데이터가 나타나는 확률 구조&quot;입니다. 우리는 그 공식을 모릅니다. 가진 것은 샘플(예시 사진)뿐입니다. 그래서 생성 모델의 목표는, 이 샘플들을 보고 $p_{\text{data}}$와 비슷한 분포 $p_\theta$를 &lt;b&gt;직접 만들어&lt;/b&gt;, 거기서 새 샘플을 뽑는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x) \approx p_{\text{data}}(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 건 이게 &lt;b&gt;외우기가 아니라는&lt;/b&gt; 점입니다. 학습 사진을 그대로 복사해 내놓으면 '외운 것'이고, 학습 데이터엔 없던 '주황 줄무늬에 한쪽 귀만 접힌 고양이'를 새로 그려낼 수 있으면 개별 사진이 아니라 '고양이다움의 규칙(= 분포)'을 배운 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 생성 모델은 후자이고, 보통 아래 네 가지를 함께 봅니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;관점&lt;/td&gt;
&lt;td&gt;질문&lt;/td&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;샘플 품질&lt;/td&gt;
&lt;td&gt;그럴듯한가?&lt;/td&gt;
&lt;td&gt;이미지가 선명하고 자연스러운가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분포 커버리지&lt;/td&gt;
&lt;td&gt;다양한가?&lt;/td&gt;
&lt;td&gt;특정 모양만 반복하지 않고 분포 전체를 고루 덮는가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;조건부 생성&lt;/td&gt;
&lt;td&gt;조건을 따르는가?&lt;/td&gt;
&lt;td&gt;텍스트 prompt, class label을 반영하는가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;학습 안정성&lt;/td&gt;
&lt;td&gt;훈련이 안정적인가?&lt;/td&gt;
&lt;td&gt;mode collapse(같은 것만 반복), 불안정한 loss가 적은가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 그런데 왜 어려운가 &amp;mdash; &quot;그냥 뽑으면 되지 않나?&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 자연스러운 의문이 듭니다. &lt;b&gt;&quot;&lt;/b&gt;$p_{\text{data}}$&lt;b&gt;에서 그냥 뽑으면 되는데 왜 이렇게 복잡하게 하지?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답은 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우리에겐&lt;/b&gt; $p_{\text{data}}$&lt;b&gt;가 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손에 있는 건 유한한 샘플 몇 장뿐이고, 그 뒤에 있는 분포는 직접 주어지지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 분포를 샘플만 보고 모델로 복원해야 하는데, 이게 왜 어려운지가 Diffusion이라는 장치 전체의 출발점입니다. 세 가지 이유를 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 고차원 &amp;mdash; 차원의 저주.&lt;/b&gt; 가로&amp;middot;세로 256, 컬러 이미지 한 장은 숫자 $3 \times 256 \times 256 \approx 20$만 개짜리 벡터입니다. 이 공간은 상상하기 어려울 만큼 크고, 데이터는 그 안에서 극도로 희박합니다. &quot;공간을 칸으로 잘게 나눠 각 칸에 데이터가 몇 개 있나 세는(히스토그램)&quot; 단순한 방법은, 칸 수가 차원에 대해 지수로 폭발해 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) 데이터는 manifold 위에 몰려 있다.&lt;/b&gt; 그 거대한 공간을 실제 데이터가 채우지는 않습니다. 픽셀을 완전히 무작위로 칠하면 거의 항상 의미 없는 noise가 나오죠 &amp;mdash; 진짜 이미지는 전체 공간의 아주 얇고 휜 한 겹에만 모여 있습니다. 이 얇은 면을 **manifold(다양체)**라고 부릅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF40Gi/dJMcaiDOvgt/OpQLjWe3bmlpfI1mNIyCq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF40Gi/dJMcaiDOvgt/OpQLjWe3bmlpfI1mNIyCq1/img.png&quot; data-alt=&quot;그림1. 실제 data의 분포는 거대한 전체 공간 중에서 매우 작은 부분이다. (manifold) 출처: https://journals.aps.org/prx/abstract/10.1103/PhysRevX.10.041044&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF40Gi/dJMcaiDOvgt/OpQLjWe3bmlpfI1mNIyCq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF40Gi%2FdJMcaiDOvgt%2FOpQLjWe3bmlpfI1mNIyCq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;337&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림1. 실제 data의 분포는 거대한 전체 공간 중에서 매우 작은 부분이다. (manifold) 출처: https://journals.aps.org/prx/abstract/10.1103/PhysRevX.10.041044&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;manifold란?&lt;/b&gt; 높은 차원 공간 안에 들어 있지만, 국소적으로 보면 훨씬 낮은 차원처럼 생긴 '휘어진 면'입니다. 비유하면 3차원 방 안에 종이 한 장을 구겨 넣은 것과 같습니다 &amp;mdash; 점들은 그 2차원 종이 표면 위에만 있고 방 전체(3차원)를 채우지 않습니다. 실제 이미지의 집합도 이렇게 고차원 공간 속 얇은 manifold에 놓여 있고, 그래서 $p_{\text{data}}$는 공간 거의 전부에서 0이고 이 manifold 위에서만 큽니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 그 집합은 convex하지 않다 (비볼록).&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;convex란?&lt;/b&gt; 어떤 집합이 convex(볼록)하다는 건, 그 안의 두 점을 직선으로 이었을 때 그 선분 전체가 집합 안에 머무는 성질입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 실제 이미지의 집합은 그렇지 않습니다. 고양이 이미지 A와 또 다른 고양이 이미지 B를 픽셀 단위로 평균 내면(= 둘을 직선으로 이은 중간점), 결과는 또 다른 고양이가 아니라 &lt;b&gt;두 사진이 겹친 흐릿한 유령&lt;/b&gt;입니다. 즉 두 실제 점의 중간이 manifold를 벗어납니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2800&quot; data-origin-height=&quot;1480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb6V5g/dJMcag0eQiF/mXUqyOg8REPQkd4qjOJHc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb6V5g/dJMcag0eQiF/mXUqyOg8REPQkd4qjOJHc1/img.png&quot; data-alt=&quot;그림2. 고차원 공간 속 얇게 휘어진 data manifold 위에 실제 이미지들이 놓여 있다. 두 실제 이미지 A&amp;amp;middot;B(서로 다른 고양이)를 직선으로 이어 평균 낸 중간점은 manifold를 벗어나, 어느 쪽도 아닌 흐릿한 유령이 된다(✕). 그래서 실제 이미지의 집합은 convex하지 않다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb6V5g/dJMcag0eQiF/mXUqyOg8REPQkd4qjOJHc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb6V5g%2FdJMcag0eQiF%2FmXUqyOg8REPQkd4qjOJHc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;333&quot; data-origin-width=&quot;2800&quot; data-origin-height=&quot;1480&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림2. 고차원 공간 속 얇게 휘어진 data manifold 위에 실제 이미지들이 놓여 있다. 두 실제 이미지 A&amp;middot;B(서로 다른 고양이)를 직선으로 이어 평균 낸 중간점은 manifold를 벗어나, 어느 쪽도 아닌 흐릿한 유령이 된다(✕). 그래서 실제 이미지의 집합은 convex하지 않다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 가지가 합쳐지면 결론은 분명합니다. $p_{\text{data}}$는 &lt;b&gt;고차원 공간 속 얇고 휘고 비볼록한&lt;/b&gt; 분포라서, 직접 추정하거나 단순히 보간&amp;middot;평균하는 식으로는 잡히지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 영리한 우회가 필요하고, Diffusion이 그 우회 중 하나입니다. (이 manifold&amp;middot;convex라는 말은 앞으로도 계속 쓰입니다 &amp;mdash; 예컨대 'noise를 섞는다'는 건 데이터를 manifold 밖으로 잠깐 밀어냈다가 다시 manifold 위로 끌어오는 일로 읽을 수 있습니다.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. likelihood로 재고 싶지만, 직접 못 잰다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분포를 배운다는 걸 조금 더 정밀하게 쓰면, 모델 $p_\theta$가 데이터를 얼마나 잘 설명하는지를 &lt;b&gt;likelihood&lt;/b&gt;로 재고 그 값을 키우는 것입니다. likelihood는 &quot;모델이 실제 데이터 $x$에 얼마나 높은 확률(밀도)을 주는가&quot; 즉 $p_\theta(x)$이고, 이게 크면 좋은 모델입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는, 대부분의 쓸 만한 모델에서 $p_\theta(x)$를 &lt;b&gt;직접 계산하는 게 불가능&lt;/b&gt;하다는 점입니다. 두 가지로 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(가) 숨은 변수에 대한 적분.&lt;/b&gt; Diffusion 같은 모델은 $x$를 단번에 만들지 않고 숨은 중간 단계 $z = (x_1, \dots, x_T)$를 거쳐 만듭니다. 그래서 &quot;$x$ 하나의 확률&quot;은 그 $x$로 이어질 수 있는 모든 숨은 경로를 다 더해야 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x) = \int p_\theta(x, z)\, dz&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 적분은 고차원 잠재공간 전체에 대한 것이라 경우의 수가 천문학적이어서 정확히 계산할 수 없습니다. (한 이미지의 확률을 알려면, 모델이 그걸 만들 수 있는 &lt;b&gt;모든 방법&lt;/b&gt;의 확률을 빠짐없이 합산해야 한다는 뜻입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(나) 정규화 상수.&lt;/b&gt; 분포를 $p(x) = \frac{1}{Z}\,e^{-E(x)}$ 꼴(에너지 $E$가 낮을수록 그럴듯)로 적으면, 전체 합이 1이 되도록 나눠 주는 상수 $Z = \int e^{-E(x)}\,dx$가 또 고차원 적분입니다. $E$는 신경망으로 줄 수 있어도 $Z$는 못 구합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수치로 감만 잡자면, 1차원이면 이 적분은 구간을 잘게 나눠 더하면 끝나지만, 20만 차원에서 같은 식으로 격자를 나누면 격자점 수가 $(\text{격자 수})^{200000}$으로 폭발합니다 &amp;mdash; 우주의 모든 연산을 동원해도 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 생성 모델들은 저마다 이 벽을 &lt;b&gt;다른 방식으로 우회&lt;/b&gt;합니다. 이게 다음 절의 '여러 접근'이 생긴 이유입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;VAE&lt;/b&gt;: 직접 못 올리는 likelihood 대신 계산 가능한 하한인 &lt;b&gt;ELBO&lt;/b&gt;를 올린다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GAN&lt;/b&gt;: likelihood를 아예 포기하고, 진짜/가짜를 구분하는 판별자를 속이는 방식으로 &lt;b&gt;암묵적으로&lt;/b&gt; 분포를 맞춘다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Score 기반 / Diffusion&lt;/b&gt;: $p$ 자체 대신 그 &lt;b&gt;기울기&lt;/b&gt; $\nabla_x \log p(x)$(score)를 배운다. 결정적 이점이 있는데, $\log$를 미분하면 골치 아픈 정규화 상수 $Z$가 (상수의 미분이라) &lt;b&gt;사라진다&lt;/b&gt;. 즉 $Z$를 몰라도 score는 배울 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KL&amp;middot;ELBO의 자세한 직관(왜 log를 쓰는지, '구름에 가린 산과 깃발' 비유 등)은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://g1g11.tistory.com/entry/00-0-%EC%84%9C%EB%A1%A0-%EC%83%9D%EC%84%B1%ED%98%95-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88-%EC%88%98%ED%95%99%EC%A0%81-%EA%B0%9C%EB%85%90%EB%93%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2026.06.23 - [인공지능 이론/Diffusion] - 00-0. 서론. 생성형 모델을 이해하기 위한 기초 수학적 개념들&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에 풀어 두었습니다. 여기서는 &quot;&lt;b&gt;likelihood를 직접 못 재서 저마다 우회한다&lt;/b&gt;&quot;만 가져가면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 우회 전체를 묶어 &lt;b&gt;variational inference&lt;/b&gt;(직접 못 구하는 분포를 다루기 쉬운 분포로 근사해 푸는 방법)라 부르고, Diffusion의 대표 모델 &lt;b&gt;DDPM&lt;/b&gt;도 바로 이 ELBO에서 출발합니다 &amp;mdash; 겉보기엔 단순한 denoising loss 같지만요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 생성 모델의 여러 접근&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 봤듯, '분포를 직접 다루기 어렵다'는 같은 벽을 저마다 다르게 넘은 결과가 아래 다섯 갈래입니다. 모두 &quot;&lt;b&gt;분포를 배워 새로 뽑는다&lt;/b&gt;&quot;는 같은 목표를 향합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;접근&lt;/td&gt;
&lt;td&gt;핵심 아이디어&lt;/td&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GAN&lt;/td&gt;
&lt;td&gt;판별자(진짜/가짜 구분자)를 속이도록 생성자를 학습&lt;/td&gt;
&lt;td&gt;샘플이 선명하고 생성이 빠름&lt;/td&gt;
&lt;td&gt;학습 불안정, mode collapse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VAE&lt;/td&gt;
&lt;td&gt;latent variable과 likelihood 하한(ELBO)을 학습&lt;/td&gt;
&lt;td&gt;확률적 해석이 명확함&lt;/td&gt;
&lt;td&gt;샘플이 흐릿할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normalizing Flow&lt;/td&gt;
&lt;td&gt;invertible map(되돌릴 수 있는 변환)으로 density를 직접 계산&lt;/td&gt;
&lt;td&gt;likelihood 계산 가능&lt;/td&gt;
&lt;td&gt;구조 제약이 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diffusion&lt;/td&gt;
&lt;td&gt;data와 noise를 잇는 경로 위에서, noise를 데이터 쪽으로 되돌리는 방향/분포를 학습&lt;/td&gt;
&lt;td&gt;학습이 안정적이고 품질이 높음&lt;/td&gt;
&lt;td&gt;sampling이 느릴 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flow Matching&lt;/td&gt;
&lt;td&gt;분포 사이의 vector field(속도장)를 직접 학습&lt;/td&gt;
&lt;td&gt;경로 관점이 단순하고 확장 가능&lt;/td&gt;
&lt;td&gt;경로 설계와 solver 이해가 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표에 모르는 용어(판별자, latent, invertible map, vector field &amp;hellip;)가 보여도 괜찮습니다. 각 모델을 다루는 장에서 풀립니다. 이 문서는 GAN을 출발점으로 삼아 Diffusion을 깊게 보고, Flow Matching으로 넘어갑니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 중심 잡기 &amp;mdash; 앞으로 무엇을 붙들 것인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Diffusion이 그 벽을 어떻게 넘는지, 그리고 이 자료를 읽는 내내 무엇을 중심에 둬야 하는지를 한 번에 정리합니다. Diffusion의 노선은 한마디로 &lt;b&gt;&quot;어려운&lt;/b&gt; $p_{\text{data}}$**를 직접 건드리지 않는다&quot;**입니다. 구체적으로는 이렇습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;어려운 데이터 분포와 &lt;b&gt;다루기 쉬운 분포&lt;/b&gt;($\mathcal{N}(0, I)$)를 잇는 &lt;b&gt;고정된 경로&lt;/b&gt;를 깐다. 데이터에 noise를 조금씩 섞으면 분포가 $p_0 = p_{\text{data}} \to \cdots \to p_T \approx \mathcal{N}(0, I)$로 매끄럽게 흐른다. 각 중간 단계 $p_t$는 데이터를 그만큼 흐릿하게 만든 분포다.&lt;/li&gt;
&lt;li&gt;그 경로 위에서, 분포의 값 대신 &lt;b&gt;국소 방향(score)&lt;/b&gt; &amp;mdash; 또는 그와 같은 것인 &lt;b&gt;denoiser&lt;/b&gt; &amp;mdash; 를 배운다. (분포 값은 못 구해도 방향은 배울 수 있다는 게 핵심인데, 그 이유가 &amp;sect;3에서 본 'score는 $Z$가 사라진다'이고 02장으로 이어진다.)&lt;/li&gt;
&lt;li&gt;생성은 이 경로를 &lt;b&gt;거꾸로 걷는 것&lt;/b&gt;이다. $\mathcal{N}(0, I)$에서 한 점을 뽑아, score가 가리키는 더 데이터다운 쪽으로 조금씩 되돌아오면 $p_{\text{data}}$의 샘플이 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 자료 전체에서 붙들 &lt;b&gt;중심 네 가지&lt;/b&gt;는 이렇습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;한 장이 아니라 &lt;b&gt;분포&lt;/b&gt;의 문제다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;$p_{\text{data}}$를 &lt;b&gt;직접 건드리지 않는다&lt;/b&gt; &amp;mdash; 점점 흐려지는 &lt;b&gt;분포들의 경로&lt;/b&gt;로 우회한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;배우는 대상은 분포 값이 아니라 &lt;b&gt;방향장(score) / denoiser&lt;/b&gt;다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;생성 = 그 경로를 &lt;b&gt;거꾸로 밟기&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 말하는 &quot;노이즈를 넣었다 뺀다&quot;는 이 네 가지의 겉모습일 뿐입니다. 이후 모든 장(forward&amp;middot;reverse, DDPM과 ELBO, Score SDE, Flow Matching, guidance &amp;hellip;)은 이 네 가지를 구체화한 것이고, 길을 잃을 때마다 여기로 돌아오면 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 이 장의 한 문장 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성 모델의 목표는 좋은 이미지를 외워 찍어내는 것이 아니라, 실제 데이터가 놓인 (고차원의 얇고 비볼록한) 확률 분포와 비슷한 분포를 배워 거기서 새 샘플을 뽑는 것입니다. Diffusion은 그 어려운 분포를 직접 다루는 대신, 쉬운 분포와 잇는 경로 위에서 방향(score)을 배워 거꾸로 걸어 내려오는 방법입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 논문&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1406.2661&quot;&gt;Goodfellow et al., 2014, Generative Adversarial Networks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1312.6114&quot;&gt;Kingma &amp;amp; Welling, 2013, Auto-Encoding Variational Bayes (VAE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2006.11239&quot;&gt;Ho et al., 2020, Denoising Diffusion Probabilistic Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2210.02747&quot;&gt;Lipman et al., 2022, Flow Matching for Generative Modeling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <category>Ai</category>
      <category>Diffusion</category>
      <category>flowmatching</category>
      <category>generativeAI</category>
      <category>그림</category>
      <category>나노바나나</category>
      <category>디퓨전</category>
      <category>딥러닝</category>
      <category>생성형 모델</category>
      <category>인공지능</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/27</guid>
      <comments>https://g1g11.tistory.com/entry/00-%EC%83%9D%EC%84%B1-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EB%AA%A9%ED%91%9C#entry27comment</comments>
      <pubDate>Tue, 23 Jun 2026 21:19:37 +0900</pubDate>
    </item>
    <item>
      <title>디퓨전 모델 설명 00-0: 생성형 모델을 이해하는데 필요한 기초 수학. 필요한것만 간단히!</title>
      <link>https://g1g11.tistory.com/entry/00-0-%EC%84%9C%EB%A1%A0-%EC%83%9D%EC%84%B1%ED%98%95-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88-%EC%88%98%ED%95%99%EC%A0%81-%EA%B0%9C%EB%85%90%EB%93%A4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 이 페이지를 읽는 법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지는 Diffusion을 읽기 전에 수학 기호 때문에 막히지 않도록 만든 준비 운동입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학은 잘 모르지만, 그렇다고 선형대수학, 미적분학, 확률변수론... 등을 처음부터 시작하기에는 답이 없는 분들을 위해서 만들었습니다! (내용이 부족하다면 지속 수정 예정입니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확률, 조건부 확률, 미분, gradient를 이미 편하게 읽을 수 있다면 건너뛰어도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 수식만 보면 멈칫한다면, 이 페이지를 천천히 읽고 나서 본문으로 가면 훨씬 편합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 나오는 어려운 단어는 나오는 최대한 설명하면서 잘 읽히도록 작성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 작성한 목적:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식을 외우는 것이 아니라, 수식이 무슨 말을 짧게 적은 것인지 읽을 수 있게 되는 것.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 먼저 큰 그림부터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성형 모델을 한 문장으로 말하면 이렇습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고양이 사진 100만 장을 보여주면, 한 번도 본 적 없는 새 고양이 사진을 그려내는 기계.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러려면 &amp;lsquo;고양이다움&amp;rsquo;을 숫자로 다뤄야 합니다. 그 도구가 이 페이지에 나오는 단어들(분포, score, gradient, likelihood &amp;hellip;)입니다. 지금 이 단어들을 몰라도 됩니다. 이 글 다음에서 계속 설명할겁니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단어들은 사실 한 장의 그림의 부품일 뿐입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rk8oB/dJMcag0eLtD/BQuSagnXKlrkbzKjrYEXp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rk8oB/dJMcag0eLtD/BQuSagnXKlrkbzKjrYEXp1/img.png&quot; data-alt=&quot;그림1. Diffusion의 reverse(생성)과 forward(확산)과정. 왼쪽 순수 noise에서 score(초록 화살표)를 따라 오른쪽 데이터로 갈수록 또렷해진다. 파란 화살표(생성 &amp;amp;middot; reverse)가 score를 따라 noise&amp;amp;rarr;data로 거슬러 오르는 과정이고, 회색(확산 &amp;amp;middot; forward)은 그 반대다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rk8oB/dJMcag0eLtD/BQuSagnXKlrkbzKjrYEXp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRk8oB%2FdJMcag0eLtD%2FBQuSagnXKlrkbzKjrYEXp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;1000&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림1. Diffusion의 reverse(생성)과 forward(확산)과정. 왼쪽 순수 noise에서 score(초록 화살표)를 따라 오른쪽 데이터로 갈수록 또렷해진다. 파란 화살표(생성 &amp;middot; reverse)가 score를 따라 noise&amp;rarr;data로 거슬러 오르는 과정이고, 회색(확산 &amp;middot; forward)은 그 반대다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한쪽 끝에는 아무 의미 없는 &lt;b&gt;noise(단순)&lt;/b&gt;, 반대쪽 끝에는 진짜 데이터(복잡)가 있습니다. 둘 사이를 잇는 다리가 있고, 다리 위 매 지점마다 &amp;ldquo;&lt;b&gt;어느 쪽이 더 데이터다운가&lt;/b&gt;&amp;rdquo;를 가리키는 화살표(이걸 score라고 부릅니다)가 붙어 있습니다. noise에서 출발해 이 화살표를 따라가면, 점점 그럴듯한 데이터가 됩니다. Diffusion은 사실상 이게 전부입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지의 나머지는 전부 이 그림의 부품을 하나씩 설명하는 것입니다. 데이터가 놓인 &lt;b&gt;분포&lt;/b&gt;(&amp;sect;3), 단순한 쪽 끝의 &lt;b&gt;Gaussian&lt;/b&gt;(&amp;sect;7), 화살표 방향인 &lt;b&gt;gradient&amp;middot;score&lt;/b&gt;(&amp;sect;13&amp;ndash;14), 그 흐름을 적는 &lt;b&gt;ODE/SDE&lt;/b&gt;(&amp;sect;17), 그리고 &amp;ldquo;얼마나 잘했는지&amp;rdquo; 재는 &lt;b&gt;likelihood&amp;middot;KL&amp;middot;ELBO&lt;/b&gt;(&amp;sect;9&amp;ndash;11)입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 가장 먼저 알아야 할 기호&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 들어가기 전에, 자료 전체에서 가장 많이 나오는 기초 단어 세 개부터 짚고 갑니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;샘플(sample)&lt;/b&gt;: 데이터 하나하나를 말합니다. 고양이 사진 한 장이 샘플 하나입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;벡터(vector)&lt;/b&gt;: 숫자 여러 개를 한 줄로 늘어놓은 묶음입니다. 예를 들어 가로&amp;middot;세로 100픽셀 흑백 이미지는 픽셀 밝기 10,000개를 쭉 늘어놓은 숫자 묶음이고, 이걸 &amp;ldquo;10,000차원 벡터&amp;rdquo;라고 부릅니다. 즉 &lt;b&gt;이미지 = 숫자 묶음&lt;/b&gt;입니다. (&amp;lsquo;차원&amp;rsquo;은 그냥 &amp;ldquo;숫자의 개수&amp;rdquo;라고 보면 됩니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수 표기&lt;/b&gt; $p(x)$: 고등학교의 $f(x)$와 똑같습니다. $x$를 넣으면 어떤 값을 돌려주는 상자입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 자주 쓰는 기호를 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기호 읽는 법 뜻&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기호&lt;/td&gt;
&lt;td&gt;읽는 법&lt;/td&gt;
&lt;td&gt;뜻&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x$&lt;/td&gt;
&lt;td&gt;엑스&lt;/td&gt;
&lt;td&gt;하나의 데이터 샘플입니다. 이미지, 음성, 문장, latent vector가 될 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x_0$&lt;/td&gt;
&lt;td&gt;엑스 영&lt;/td&gt;
&lt;td&gt;Diffusion에서 보통 원본 데이터입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$x_t$&lt;/td&gt;
&lt;td&gt;엑스 티&lt;/td&gt;
&lt;td&gt;시간 $t$에서 noise가 섞인 중간 샘플입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\theta$&lt;/td&gt;
&lt;td&gt;세타&lt;/td&gt;
&lt;td&gt;모델의 학습되는 파라미터(모델이 조절하는 숫자 손잡이들)입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\epsilon$&lt;/td&gt;
&lt;td&gt;엡실론&lt;/td&gt;
&lt;td&gt;Gaussian noise를 나타낼 때 자주 씁니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\sim$&lt;/td&gt;
&lt;td&gt;에서 뽑혔다&lt;/td&gt;
&lt;td&gt;$x \sim p(x)$는 $x$가 분포 $p$에서 샘플링(무작위로 뽑힘)되었다는 뜻입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\mid$&lt;/td&gt;
&lt;td&gt;조건으로&lt;/td&gt;
&lt;td&gt;$p(x \mid y)$는 $y$가 주어졌을 때의 $x$ 분포입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\mathbb{E}[\,\cdot\,]$&lt;/td&gt;
&lt;td&gt;기댓값&lt;/td&gt;
&lt;td&gt;여러 번 평균내면 어떻게 되는지를 나타냅니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\nabla$&lt;/td&gt;
&lt;td&gt;그래디언트(나블라)&lt;/td&gt;
&lt;td&gt;어느 방향으로 움직이면 값이 가장 빨리 커지는지 알려줍니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\lVert a-b \rVert^2$&lt;/td&gt;
&lt;td&gt;제곱 거리&lt;/td&gt;
&lt;td&gt;$a$와 $b$가 얼마나 다른지 재는 값입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 데이터 하나와 분포의 차이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 한 장은 데이터 하나입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 생성형 모델이 배우려는 것은 이미지 한 장이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고양이 이미지가 수백만 장 있다면, 우리는 그 뒤에 어떤 보이지 않는 규칙이 있다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 규칙을 **분포(distribution)**라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분포가 뭔지 감이 안 오면 &lt;b&gt;사람들의 키&lt;/b&gt;를 떠올려 보세요. 키를 잔뜩 모아 그래프로 그리면, 170cm 근처에 사람이 가장 많고 아주 크거나 작은 쪽은 드뭅니다. 이렇게 &amp;ldquo;&lt;b&gt;어떤 값이 얼마나 자주(그럴듯하게) 나오는가&lt;/b&gt;&amp;rdquo;를 통째로 나타낸 것이 분포입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;x \sim p_{\text{data}}(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식은 이렇게 읽으면 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 $x$는 실제 데이터 분포 $p_{\text{data}}$에서 뽑힌 샘플이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 $\sim$는 &amp;ldquo;뽑혔다&amp;rdquo;, 아래첨자 $\text{data}$는 &amp;ldquo;진짜 세상의&amp;rdquo;라는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 $p_{\text{data}}(x)$는 &amp;ldquo;이런 데이터가 얼마나 그럴듯한가&amp;rdquo;를 나타내는 보이지 않는 지도입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 그 지도를 직접 알지 못합니다. 학습 데이터라는 점 몇 개만 보고, 모델이 그 지도를 흉내 내도록 학습합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x) \approx p_{\text{data}}(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 쓰면: 모델이 만든 분포 $p_\theta$가 실제 데이터 분포 $p_{\text{data}}$와 비슷해지게 한다. ($\approx$는 &amp;ldquo;거의 같다&amp;rdquo;는 기호입니다.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 확률과 density를 구분하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동전 던지기처럼 경우의 수가 적으면 &amp;ldquo;앞면이 나올 확률은 0.5&amp;rdquo;라고 말할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이미지는 픽셀 값이 많고 거의 &lt;b&gt;연속적인&lt;/b&gt; 숫자입니다. (&amp;lsquo;연속적&amp;rsquo;이란 키처럼 173.4, 173.41&amp;hellip;처럼 값 사이를 무한히 쪼갤 수 있다는 뜻입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때는 정확히 어떤 이미지 하나가 나올 확률보다, 그 근처가 얼마나 그럴듯한지를 **density(밀도)**로 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;density는 &lt;b&gt;인구 밀도 지도&lt;/b&gt;를 떠올리면 쉽습니다. 전국 어디에 사람이 사는지 색으로 칠한 지도에서 서울은 진하고(밀도 높음), 산속은 옅습니다(낮음). 어떤 한 점(정확한 좌표)에 사람이 딱 있을 &amp;ldquo;확률&amp;rdquo;은 0에 가깝지만, 그 동네가 얼마나 빽빽한지는 말할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키도 마찬가지입니다. 정확히 173.4cm일 확률은 0에 가깝지만, &amp;ldquo;170~175cm 근처는 빽빽하다&amp;rdquo;는 말은 됩니다. 이 &amp;ldquo;근처의 빽빽함&amp;rdquo;이 density입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 단순하게 말하면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;확률: 딱 떨어지는 사건에 얼마만큼의 가능성이 있는가&lt;/li&gt;
&lt;li&gt;density: 연속적인 공간에서 이 근처가 얼마나 빽빽한가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서 $p(x)$라고 쓸 때는 보통 density를 생각하면 됩니다. 처음 읽을 때는 너무 엄밀하게 구분하지 않아도 됩니다 &amp;mdash; $p(x)$는 &amp;ldquo;$x$가 그럴듯한 정도&amp;rdquo;라고 읽어도 충분합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 조건부 확률: $p(x \mid y)$&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건부 확률은 &amp;ldquo;어떤 정보가 주어졌을 때&amp;rdquo;의 확률입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p(x \mid y)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식은 이렇게 읽습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$y$가 주어졌을 때 $x$의 분포.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 text-to-image 모델에서는 $y$가 prompt일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p(\text{image} \mid \text{text prompt})&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말은 &amp;ldquo;아무 이미지나 만들겠다&amp;rdquo;가 아니라, &amp;ldquo;prompt가 주어졌을 때 그 조건에 맞는 이미지를 만들겠다&amp;rdquo;는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion 문서에서 조건부 확률은 아래처럼 자주 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_0), \qquad p_\theta(x_{t-1} \mid x_t), \qquad p(x \mid \text{condition})&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 말로 풀면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$q(x_t \mid x_0)$: 원본 $x_0$가 주어졌을 때 noisy sample $x_t$의 분포&lt;/li&gt;
&lt;li&gt;$p_\theta(x_{t-1} \mid x_t)$: 현재 noisy sample $x_t$가 주어졌을 때 이전 단계 $x_{t-1}$의 모델 분포&lt;/li&gt;
&lt;li&gt;$p(x \mid \text{condition})$: 조건이 주어졌을 때 생성하고 싶은 데이터 분포&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. prior, posterior, marginal&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 세 단어는 처음 보면 어렵지만, 뜻은 &amp;ldquo;&lt;b&gt;믿음의 세 종류&lt;/b&gt;&amp;rdquo;로 보면 단순합니다. 비 오는 날을 예로 셋을 한 번에 봅시다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;prior(사전 믿음)&lt;/b&gt;: 아무 정보도 보기 전의 &lt;b&gt;기본 생각&lt;/b&gt;. &amp;ldquo;오늘 비 올까?&amp;rdquo;에 대한 평소 감각.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;posterior(사후 믿음)&lt;/b&gt;: 정보를 &lt;b&gt;본 뒤 갱신된 생각&lt;/b&gt;. 길에서 우산 든 사람을 보고 &amp;ldquo;비 올 가능성 높네&amp;rdquo;로 바뀐 생각.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;marginal(주변 분포)&lt;/b&gt;: 특정 조건을 &lt;b&gt;지우고 평균낸 전체 그림&lt;/b&gt;. 우산을 봤든 안 봤든 상관없이 &amp;ldquo;그냥 평소 비 올 확률&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서도 똑같습니다. $x_t$라는 noisy sample을 보고, 그 이전 상태나 원본이 무엇이었을지 추측(갱신)합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;용어&lt;/td&gt;
&lt;td&gt;쉬운 뜻&lt;/td&gt;
&lt;td&gt;Diffusion에서의 예&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;prior&lt;/td&gt;
&lt;td&gt;정보를 보기 전의 기본 믿음&lt;/td&gt;
&lt;td&gt;$x_T \sim \mathcal{N}(0, I)$처럼 생성이 시작되는 noise 분포&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;posterior&lt;/td&gt;
&lt;td&gt;정보를 보고 갱신된 믿음&lt;/td&gt;
&lt;td&gt;$q(x_{t-1} \mid x_t, x_0)$처럼 조건을 알고 난 뒤의 이전 상태 분포&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;marginal&lt;/td&gt;
&lt;td&gt;다른 조건을 숨기고 전체적으로 본 분포&lt;/td&gt;
&lt;td&gt;$p_t(x_t)$처럼 시간 $t$에서 전체 noisy sample들이 이루는 분포&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표의 예시 기호($\mathcal{N}(0,I)$나 조건이 두 개인 $q(x_{t-1}\mid x_t, x_0)$)는 지금 당장 이해 안 돼도 됩니다. $\mathcal{N}(0,I)$는 바로 다음 &amp;sect;7에서, 두 조건짜리 식은 DDPM 장에서 자연스럽게 풀립니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Gaussian: 가운데가 높은 &amp;ldquo;종 모양 언덕&amp;rdquo;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K0dhV/dJMcai4NFQR/yz54DSfUM5UAuV6JIhjVqK/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K0dhV/dJMcai4NFQR/yz54DSfUM5UAuV6JIhjVqK/tfile.svg&quot; data-alt=&quot;그림2. 가우시안 분포.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K0dhV/dJMcai4NFQR/yz54DSfUM5UAuV6JIhjVqK/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK0dhV%2FdJMcai4NFQR%2Fyz54DSfUM5UAuV6JIhjVqK%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;276&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림2. 가우시안 분포.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서 가장 자주 나오는 분포는 Gaussian distribution, 우리말로 &lt;b&gt;정규분포&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;먼저 모양부터 그려봅시다.&lt;/b&gt; 가로축을 값, 세로축을 &amp;ldquo;그럴듯한 정도&amp;rdquo;라고 하면, Gaussian은 **가운데가 가장 높고 양옆으로 갈수록 매끄럽게 낮아지는 언덕(종 모양)**입니다. &amp;sect;3에서 본 키 분포가 바로 이 모양입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언덕의 &lt;b&gt;꼭대기 위치&lt;/b&gt;가 평균입니다.&lt;/li&gt;
&lt;li&gt;언덕이 &lt;b&gt;얼마나 넓게 퍼졌는지&lt;/b&gt;가 표준편차입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\mathcal{N}(0, I)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기호는 &amp;ldquo;평균이 0이고, 폭이 표준적인 종 모양&amp;rdquo;을 뜻합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$0$: 언덕 꼭대기가 0에 있다 = noise가 한쪽으로 치우치지 않는다.&lt;/li&gt;
&lt;li&gt;$I$: (행렬이라는 말을 몰라도 됩니다.) 이미지처럼 숫자가 여러 개일 때, &lt;b&gt;각 숫자에 똑같은 세기의 noise를 서로 영향 없이 따로따로 넣는다&lt;/b&gt;는 표시입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 하필 Gaussian일까요?&lt;/b&gt; 가장 단순하고 다루기 쉬운 분포이기 때문입니다. &amp;sect;1의 큰 그림에서 &amp;lsquo;단순한 쪽 끝&amp;rsquo;이 바로 이 Gaussian입니다. 출발점은 다루기 쉬워야 좋으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Diffusion은 실제 이미지 $x_0$에서 시작해 점점 Gaussian noise를 섞고, 생성할 때는 반대로 Gaussian noise에서 시작해 데이터다운 샘플로 거슬러 옵니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 평균, 분산, 표준편차&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian(종 모양)을 볼 때 자주 나오는 말입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어 뜻 직관&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;용어&lt;/td&gt;
&lt;td&gt;뜻&lt;/td&gt;
&lt;td&gt;직관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;평균&lt;/td&gt;
&lt;td&gt;중심 위치&lt;/td&gt;
&lt;td&gt;값들이 대체로 모이는 곳 (언덕 꼭대기)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;분산&lt;/td&gt;
&lt;td&gt;퍼진 정도의 제곱&lt;/td&gt;
&lt;td&gt;값들이 중심에서 얼마나 멀리 흩어지는가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;표준편차&lt;/td&gt;
&lt;td&gt;분산의 제곱근&lt;/td&gt;
&lt;td&gt;실제 단위로 본 흔들림 크기 (언덕의 폭)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 시험 점수가 평균 70점인데 다들 65~75점이면 분산(퍼짐)이 작고, 30~100점으로 흩어지면 분산이 큽니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서는 noise의 세기를 $\beta_t$, $\sigma_t$, $1 - \bar{\alpha}_t$ 같은 값으로 표현하고, 이 값들이 커질수록 원본보다 noise가 더 강해집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. log와 likelihood&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성 모델에서 &lt;b&gt;likelihood&lt;/b&gt;(우리말로 &amp;ldquo;그럴듯함의 정도&amp;rdquo;)는 &amp;ldquo;모델이 실제 데이터에 얼마나 높은 확률을 주는가&amp;rdquo;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;p_\theta(x_0)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값이 크면 모델이 $x_0$를 그럴듯하다고 본다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 표기 습관 하나. 확률을 여러 개 곱하면(예: 여러 픽셀, 여러 단계) 숫자가 순식간에 0에 가까워져 컴퓨터가 0으로 뭉개버립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;0.1 \times 0.1 \times 0.1 \times \cdots \;\to\; \text{아주 작은 수}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;log&lt;/b&gt;를 씌웁니다. log는 곱셈을 덧셈으로 바꿔 주고($\log(a \times b) = \log a + \log b$), 값이 커지면 같이 커지므로(단조증가) $\log p$를 최대로 만드는 것과 $p$를 최대로 만드는 것이 같은 일입니다. 그래서 논문에는 $p_\theta(x_0)$ 대신 $\log p_\theta(x_0)$가 자주 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 log로도 풀리지 않는, 더 근본적인 문제가 하나 있습니다. 모델은 $x_0$를 단번에 만드는 게 아니라 여러 단계의 &lt;b&gt;숨은 중간 상태&lt;/b&gt;($x_1, x_2, \dots, x_T$)를 거쳐 만듭니다. 그래서 &amp;ldquo;$x_0$ 하나의 확률&amp;rdquo; $p_\theta(x_0)$를 정확히 구하려면, 그 $x_0$로 이어질 수 있는 &lt;b&gt;모든 가능한 중간 경로를 빠짐없이 더해야&lt;/b&gt;(적분해야) 합니다. 그 경우의 수가 천문학적이라 사실상 계산이 불가능합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 likelihood는 **&amp;lsquo;올리고 싶지만 직접은 못 재는 값&amp;rsquo;**입니다. 바로 다음 두 절(KL, ELBO)이 이 문제를 어떻게 우회하는지를 다룹니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. KL divergence&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흐름을 정리하고 갑시다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;모델을 잘 만들었는지는 likelihood(&amp;sect;9)로 재고 싶다.&lt;/li&gt;
&lt;li&gt;그런데 방금 봤듯 likelihood는 직접 계산할 수 없다.&lt;/li&gt;
&lt;li&gt;그래서 대신 &lt;b&gt;계산 가능한 lower bound인 ELBO&lt;/b&gt;(&amp;sect;11)를 올린다. 그 ELBO는 &lt;b&gt;두 분포의 차이를 재는 KL&lt;/b&gt;(이 절)로 이루어져 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 KL을 먼저 보고 ELBO로 갑니다. KL divergence는 &lt;b&gt;두 분포가 얼마나 다른지&lt;/b&gt;를 하나의 숫자로 재는 값입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$q$라는 분포를 $p$로 흉내 내려 할 때 얼마나 어색한가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 분포가 똑같으면 0이고, 다를수록 커집니다(KL은 항상 0 이상입니다). 주의할 점은, 흉내 내는 방향을 바꾸면($p$를 $q$로) 어색함이 달라진다는 것입니다 &amp;mdash; 그래서 KL은 우리가 아는 &amp;lsquo;거리&amp;rsquo;와는 조금 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;D_{\mathrm{KL}}(q \,\|\, p) = \mathbb{E}_{q}\big[\log q(x) - \log p(x)\big]&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식이 어렵게 보여도 괜찮습니다. &amp;ldquo;&lt;b&gt;두 분포의 차이를 하나의 숫자로 잰다&lt;/b&gt;&amp;rdquo;만 가져가면 충분합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM의 ELBO에도 KL이 등장하는데, 그 의미는 &amp;ldquo;모델의 reverse step이 진짜 정답 step과 얼마나 다른가&amp;rdquo;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. ELBO&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ELBO는 Evidence Lower Bound의 약자입니다. 여기서 **bound(바운드)**는 &amp;ldquo;한계선&amp;rdquo;, **lower bound(하한)**는 &amp;ldquo;그 값보다 작거나 같다고 보장되는 값&amp;rdquo;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유로 보면 이렇습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 산 높이(likelihood)는 구름에 가려 직접 못 잽니다 &amp;mdash; 바로 &amp;sect;9에서 본 &amp;lsquo;모든 중간 경로를 더해야 하는 적분&amp;rsquo;이 그 구름입니다. 대신 &amp;ldquo;이 산은 적어도 저 깃발보다는 높다&amp;rdquo;는 깃발(lower bound)을 세울 수 있고, 그 &lt;b&gt;깃발을 최대한 높이 올리면 산 높이도 그만큼 보장&lt;/b&gt;됩니다. ELBO가 바로 그 깃발입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\log p_\theta(x_0) \;\ge\; \text{ELBO}&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 직접 못 올리는 likelihood 대신, 올릴 수 있는 ELBO를 올립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM에서 ELBO는 여러 KL 항으로 나뉘고, 그중 중요한 항들은 reverse process를 학습하는 문제로 이어집니다. 그래서 DDPM의 noise prediction MSE는 그냥 갑자기 나온 손실함수가 아니라, 이 ELBO를 실전적으로 단순화한 형태입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 미분은 변화율이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미분은 어떤 값을 조금 움직였을 때 결과가 얼마나 변하는지 보는 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 $f(x)$가 있다고 해봅시다. $x$를 아주 조금 키웠을 때 $f(x)$가 커지면 미분값(그 지점의 기울기)은 양수이고, 작아지면 음수입니다. 즉 미분은 &amp;ldquo;$x$를 늘리면 $f$가 어느 쪽으로, 얼마나 빨리 변하는가&amp;rdquo;를 알려주는 숫자입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝에서 우리가 줄이고 싶은 것은 &lt;b&gt;loss&lt;/b&gt;(모델이 틀린 정도를 나타내는 점수)입니다. 그러려면 &amp;ldquo;loss가 어느 방향으로 변하는가&amp;rdquo;를 알아야 하고, 그것을 알려주는 도구가 미분입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터를 어느 방향으로 바꾸면 loss가 줄어드는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 &amp;lsquo;방향&amp;rsquo;을 제대로 다루려면, 변수가 많을 때의 미분인 &lt;b&gt;gradient&lt;/b&gt;가 필요합니다 &amp;mdash; 다음 절입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. Gradient는 &amp;lsquo;방향&amp;rsquo;이다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미분은 변수가 하나일 때의 이야기입니다. 그런데 이미지는 픽셀이 많고, 모델 파라미터도 수백만 개입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수가 여러 개일 때는 각 변수 방향의 미분을 한꺼번에 모은 &lt;b&gt;벡터&lt;/b&gt;가 필요합니다. 그것이 gradient입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\nabla_x f(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식은 이렇게 읽습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$x$를 어느 방향으로 움직이면 $f(x)$가 가장 빨리 커지는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 미분(숫자 하나)을 여러 방향으로 확장한 것이 gradient(방향 화살표)입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &amp;sect;12에서 미뤄둔 &lt;b&gt;gradient descent&lt;/b&gt;를 말할 수 있습니다. loss를 줄이고 싶으니, gradient가 가리키는 &amp;ldquo;가장 빨리 커지는 방향&amp;rdquo;의 &lt;b&gt;반대쪽&lt;/b&gt;으로 파라미터를 한 걸음씩 옮기면 됩니다. 비유하면 안개 낀 산에서 가장 낮은 곳으로 내려가기입니다 &amp;mdash; 발밑 기울기(gradient)를 느껴 가장 가파르게 내려가는 쪽으로 한 걸음, 또 한 걸음. (여기서 &amp;lsquo;산 높이&amp;rsquo;가 loss입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서 중요한 score도 gradient입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;s(x) = \nabla_x \log p(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 score는 &amp;ldquo;확률 density가 가장 빨리 커지는 방향&amp;rdquo;입니다. (방향이라는 말이 아직 추상적이면, 바로 아래 &amp;sect;14에서 숫자로 보면 단번에 잡힙니다.)&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14. Score를 아주 쉽게 보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차원 Gaussian $\mathcal{N}(0,1)$을 생각해봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 분포는 0 근처가 가장 그럴듯합니다(언덕 꼭대기가 0).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 score는 정확히 계산되는데, $\nabla_x \log p(x) = -x$입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 위치가 $x = 3$이면 score는 $-3$, 즉 왼쪽(중심 0 방향)을 가리킵니다.&lt;/li&gt;
&lt;li&gt;현재 위치가 $x = -3$이면 score는 $+3$, 즉 오른쪽(중심 0 방향)을 가리킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 score는 항상 &amp;ldquo;더 그럴듯한 중심 쪽으로 돌아가라&amp;rdquo;는 방향을 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 이미지 분포에서는 중심 하나로 돌아가는 문제가 아니지만, 핵심은 같습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;score는 현재 sample을 더 데이터다운 곳으로 움직이는 방향 정보다. (&amp;sect;1 큰 그림의 그 &amp;lsquo;화살표&amp;rsquo;가 바로 이것입니다.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;15. $\mathbb{E}\,\lVert \epsilon - \epsilon_\theta \rVert^2$ 읽는 법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDPM에서 자주 보는 loss입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\mathbb{E}\,\big\lVert \epsilon - \epsilon_\theta(x_t, t) \big\rVert^2&lt;br /&gt;$$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;천천히 읽으면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$\epsilon$: 실제로 섞은 noise&lt;/li&gt;
&lt;li&gt;$\epsilon_\theta(x_t, t)$: 모델이 예측한 noise&lt;/li&gt;
&lt;li&gt;$\epsilon - \epsilon_\theta$: 실제 noise와 예측 noise의 차이&lt;/li&gt;
&lt;li&gt;$\lVert \cdot \rVert^2$: 차이를 제곱해서 크기를 잼&lt;/li&gt;
&lt;li&gt;$\mathbb{E}$: 여러 데이터, 여러 noise, 여러 time에 대해 평균냄&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이 식은 이렇게 읽으면 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 noisy sample을 보고 섞인 noise를 평균적으로 잘 맞추도록 학습한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 더 깊은 의미는 이것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;noise를 잘 예측하는 것은, &lt;b&gt;reverse process&lt;/b&gt;(noise에서 데이터로 거슬러 오는 과정)와 score를 학습하는 한 가지 &lt;b&gt;parameterization&lt;/b&gt;(같은 것을 표현하는 방식)이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;16. 시간 $t$는 시계 시간이 아니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Diffusion에서 $t$는 실제 초, 분, 시간이 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data에서 noise로 얼마나 이동했는지를 나타내는 인덱스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$t = 0$이면 data에 가깝고, $t = T$이면 거의 pure noise입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 $x_t$는 &amp;ldquo;시간 $t$의 이미지&amp;rdquo;라기보다 &amp;ldquo;noise level $t$의 sample&amp;rdquo;이라고 보는 편이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 기호는 아래처럼 이해하면 됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기호&lt;/td&gt;
&lt;td&gt;뜻&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\beta_t$&lt;/td&gt;
&lt;td&gt;한 step에서 추가하는 noise의 양&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\alpha_t = 1 - \beta_t$&lt;/td&gt;
&lt;td&gt;한 step에서 원본 방향이 유지되는 비율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\bar{\alpha}_t$&lt;/td&gt;
&lt;td&gt;처음부터 시간 $t$까지 누적해서 남은 signal 비율 (위의 막대 bar는 &amp;ldquo;0부터 $t$까지 누적해 곱했다&amp;rdquo;는 표시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$\sigma_t$&lt;/td&gt;
&lt;td&gt;noise scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SNR&lt;/td&gt;
&lt;td&gt;signal-to-noise ratio, 즉 신호 대 잡음비&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기호가 많아 보이지만, 전부 &amp;ldquo;&lt;b&gt;지금 얼마나 noisy한가&lt;/b&gt;&amp;rdquo;를 다른 방식으로 적은 것입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17. ODE와 SDE&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤쪽 장에서 ODE와 SDE가 나옵니다. 비유로 건너뛰기 전에, 식의 정확한 뜻부터 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ODE (Ordinary Differential Equation, 상미분방정식).&lt;/b&gt; 어떤 양 $x$가 시간 $t$에 따라 변할 때, &amp;lsquo;매 순간의 변화율&amp;rsquo;을 그 순간의 상태로 적은 식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;\frac{dx}{dt} = v_t(x)&lt;br /&gt;$$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$\frac{dx}{dt}$: 시간이 아주 조금 흐를 때 $x$가 변하는 속도(변화율).&lt;/li&gt;
&lt;li&gt;$v_t(x)$: 시간 $t$, 위치 $x$에서 &amp;ldquo;$x$가 어느 방향으로 얼마나 빨리 움직여야 하는지&amp;rdquo;를 정해 주는 함수(속도장, velocity field).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식이 하는 일은 이렇습니다. &lt;b&gt;시작점&lt;/b&gt; $x(0)$ &lt;b&gt;하나를 정하면&lt;/b&gt;, 매 순간 $v_t$가 가리키는 대로 조금씩 따라가(= 적분해) &lt;b&gt;전체 경로&lt;/b&gt; $x(t)$&lt;b&gt;가 유일하게 정해집니다.&lt;/b&gt; 그래서 ODE는 &lt;b&gt;결정론적&lt;/b&gt;입니다 &amp;mdash; 같은 시작점이면 늘 같은 경로.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(직관: 강물에 띄운 나뭇잎. 물살 $v_t$가 정해져 있으니, 같은 자리에 놓으면 늘 같은 길로 흘러갑니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SDE (Stochastic Differential Equation, 확률미분방정식).&lt;/b&gt; 위 흐름에, 매 순간 작은 무작위 흔들림을 더한 식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;dx = f(x, t)\,dt + g(t)\,dw&lt;br /&gt;$$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$f(x, t)\,dt$: ODE와 같은 &amp;lsquo;정해진 방향&amp;rsquo;으로의 변화(drift).&lt;/li&gt;
&lt;li&gt;$g(t)\,dw$: 매 순간 더해지는 무작위 noise. $dw$는 평균 0, 분산 $dt$인 아주 작은 Gaussian 증분(Brownian motion, 즉 연속시간 random walk의 변화량)이고, $g(t)$는 그 흔들림의 세기입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$dw$ 때문에 SDE는 &lt;b&gt;확률적&lt;/b&gt;입니다 &amp;mdash; 같은 시작점이어도 매번 조금씩 다른 경로가 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(직관: 같은 강물에 바람이 더해진 것. 흐름은 같아도 바람 $dw$ 때문에 나뭇잎이 매번 다른 길로 갑니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 ODE/SDE는 모두 &amp;ldquo;$x$가 시간에 따라 어떻게 흐르는가&amp;rdquo;를 적는 언어이고, 차이는 무작위 항 $dw$의 유무뿐입니다. Diffusion에서는 이 언어로 &amp;lsquo;분포가 시간에 따라 흐르는 과정&amp;rsquo;을 적습니다(05장).&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;18. 수식을 읽는 작은 습관&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분포에 관한 수식은 &amp;ldquo;&lt;b&gt;무엇을 / 어떤 조건에서 / 어떤 분포로&lt;/b&gt;&amp;rdquo; 순서로 끊어 읽으면 거의 다 읽힙니다. DDPM forward 식으로 연습해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$&lt;br /&gt;q(x_t \mid x_0) = \mathcal{N}\big(x_t;\ \sqrt{\bar{\alpha}_t}\,x_0,\ (1-\bar{\alpha}_t)I\big)&lt;br /&gt;$$&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;무엇의 분포인가?&lt;/b&gt; 왼쪽 $q(x_t \mid \cdots)$ &amp;rarr; &amp;ldquo;$x_t$가 어떻게 분포하는지&amp;rdquo;를 말하는 식.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어떤 조건에서?&lt;/b&gt; 조건 기호 $\mid$ 뒤의 $x_0$ &amp;rarr; &amp;ldquo;원본 $x_0$가 주어졌을 때&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어떤 분포인가?&lt;/b&gt; 오른쪽 $\mathcal{N}(\cdots)$ &amp;rarr; Gaussian(종 모양).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;평균과 분산은?&lt;/b&gt; $\mathcal{N}(x_t;\ \text{평균},\ \text{분산})$ 꼴이므로, 평균 $= \sqrt{\bar{\alpha}_t}\,x_0$, 분산 $= (1-\bar{\alpha}_t)I$.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;그래서 말로는?&lt;/b&gt; &amp;ldquo;$x_0$가 주어지면, $x_t$는 원본을 $\sqrt{\bar{\alpha}_t}$만큼 줄인 자리를 중심으로 $(1-\bar{\alpha}_t)$만큼 퍼진 Gaussian&amp;rdquo; &amp;rarr; 한마디로 &lt;b&gt;원본 신호 일부 + Gaussian noise&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 팁: $\mathcal{N}(x;\ \mu,\ \Sigma)$를 만나면 세미콜론 뒤 &lt;b&gt;첫 번째가 평균&lt;/b&gt; $\mu$&lt;b&gt;, 두 번째가 분산&lt;/b&gt; $\Sigma$입니다. 이 규칙 하나면 Diffusion 수식의 절반은 읽힙니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;19. 이 페이지의 최종 요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &amp;sect;1의 큰 그림으로 돌아가 봅시다. 그 한 장의 그림이 아래 부품들로 이루어져 있었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터는 보이지 않는 &lt;b&gt;분포&lt;/b&gt;에서 나온 sample이다. (&amp;sect;3)&lt;/li&gt;
&lt;li&gt;생성 모델은 $p_\theta \approx p_{\text{data}}$를 만들고 싶다. (&amp;sect;3)&lt;/li&gt;
&lt;li&gt;단순한 쪽 끝은 &lt;b&gt;Gaussian&lt;/b&gt;(종 모양 언덕)이다. (&amp;sect;7)&lt;/li&gt;
&lt;li&gt;&amp;ldquo;얼마나 잘했나&amp;rdquo;는 &lt;b&gt;likelihood&lt;/b&gt;로 재고 싶지만 직접 못 재니, 계산 가능한 &lt;b&gt;ELBO&lt;/b&gt;(KL로 이루어짐)로 우회한다. (&amp;sect;9&amp;ndash;11)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;gradient&lt;/b&gt;는 값이 커지는 방향, &lt;b&gt;score&lt;/b&gt;는 $\log p(x)$가 커지는 방향 = 큰 그림의 그 &amp;lsquo;화살표&amp;rsquo;다. (&amp;sect;13&amp;ndash;14)&lt;/li&gt;
&lt;li&gt;DDPM의 noise prediction은 단순 복원이 아니라 reverse process와 score를 배우는 방식이다. (&amp;sect;15)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ODE/SDE&lt;/b&gt;는 sample과 분포가 시간에 따라 흐르는 방식을 적는 언어다. (&amp;sect;17)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다. 오류 지적이나 내용 질문은 언제든 환영입니다.&lt;/p&gt;</description>
      <category>인공지능 이론/Diffusion</category>
      <author>인공지능과 반도체</author>
      <guid isPermaLink="true">https://g1g11.tistory.com/26</guid>
      <comments>https://g1g11.tistory.com/entry/00-0-%EC%84%9C%EB%A1%A0-%EC%83%9D%EC%84%B1%ED%98%95-%EB%AA%A8%EB%8D%B8%EC%9D%84-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EA%B8%B0%EC%B4%88-%EC%88%98%ED%95%99%EC%A0%81-%EA%B0%9C%EB%85%90%EB%93%A4#entry26comment</comments>
      <pubDate>Tue, 23 Jun 2026 21:01:18 +0900</pubDate>
    </item>
  </channel>
</rss>