<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>dirac042</title><link>https://dirac042.github.io/</link><description>dirac042's journal — notes on mathematics, computer science and building things.</description><generator>Hugo</generator><language>ko-kr</language><managingEditor>dirac042</managingEditor><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Thu, 13 Aug 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://dirac042.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Magnitude Scaling Technique — SGMSE의 Amplitude Transformation</title><link>https://dirac042.github.io/posts/magnitude-scaling-technique/</link><pubDate>Thu, 13 Aug 2026 00:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/magnitude-scaling-technique/</guid><category>Audio</category><category>Diffusion</category><category>Speech Enhancement</category><description>복소 STFT(cSTFT) 위에서 Diffusion을 돌릴 때, 유난히 큰 스펙트럼 피크 때문에 학습이 흔들리는 문제를 어떻게 다루는지에 대한 짧은 정리. SGMSE 논문(Richter, Welker, Lemercier, Lay, Gerkmann, Speech Enhancement and Dereverberation with Diffusion-based Generative Models, IEEE/ACM TASLP 2023)에서 처음 사용한 기법이다.</description><content:encoded>&lt;p>복소 STFT(cSTFT) 위에서 Diffusion을 돌릴 때, 유난히 큰 스펙트럼 피크 때문에 학습이 흔들리는 문제를 어떻게 다루는지에 대한 짧은 정리.&lt;/p>
&lt;p>&lt;a href="https://arxiv.org/abs/2208.05830" target="_blank" rel="noopener noreferrer">&lt;strong>SGMSE&lt;/strong>&lt;/a> 논문(Richter, Welker, Lemercier, Lay, Gerkmann, &lt;em>Speech Enhancement and Dereverberation with Diffusion-based Generative Models&lt;/em>, IEEE/ACM TASLP 2023)에서 처음 사용한 기법이다.&lt;/p>
&lt;p>논문에서는 Amplitude Transformation이라는 단어로 표현한다.&lt;/p>
&lt;ul>
&lt;li>STFT에서 만들어지는 Complex Coefficient를 그대로 사용하되,&lt;/li>
&lt;li>Phase는 유지하고, Magnitude를 Power-Law로 압축해 전체 Scale을 줄이자.&lt;/li>
&lt;/ul>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-amplitude-compression.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>같은 신호의 |c|(왼쪽)와 β|c|^α(가운데). 크게 울리는 배음 몇 개가 화면을 독차지하던 것이, 압축 뒤에는 조용한 마찰음 덩어리와 희미한 상승음까지 보인다. 오른쪽은 α에 따른 압축 곡선.&lt;/p>
&lt;/blockquote>&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>SGMSE의 Task: Speech Enhancement/Dereverberation을 cSTFT 도메인에서 수행.&lt;/p>
&lt;ul>
&lt;li>Pred: Clean Speech의 Real/Imaginary Spectrogram
&lt;ul>
&lt;li>왜? Magnitude-only Domain에서는 Diffusion Process가 어색해진다.&lt;/li>
&lt;li>Magnitude는 음수가 될 수 없음 → Gaussian Noise를 더하면 음수값의 Amplitude가 나옴.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">배경: 왜 하필 cSTFT인가&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>Diffusion은 &amp;ldquo;데이터에 가우시안 노이즈를 더했다가 되돌리는&amp;rdquo; 과정이라, 데이터가 실수 전체(음수 포함)에 자연스럽게 퍼져 있어야 한다. 크기(magnitude)만 쓰면 항상 0 이상이라 노이즈를 더하는 순간 정의역을 벗어나고, 위상은 따로 복원해야 한다. 실수부/허수부로 나눈 cSTFT는 두 채널이 모두 실수라 이 문제가 없다. 논문 세팅은 16 kHz, window 510(주파수 빈 256개), hop 128(75% 겹침), periodic Hann.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="amplitude-transformation">Amplitude Transformation&lt;/h2>
&lt;p>cSTFT Coefficient는 다음과 같이 정의된다:&lt;br>
&lt;/p>
&lt;div class="math math-block">\[c=|c|e^{i\angle c}\]&lt;/div>&lt;p>&lt;br>
이때, &lt;span class="math math-inline">\(|c|\)&lt;/span>는 Magnitude, &lt;span class="math math-inline">\(\angle c\)&lt;/span>는 Phase다.&lt;/p>
&lt;p>SGMSE는 위의 Coefficient를 다음과 같이 변환한다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[\tilde{c}=\beta |c|^{\alpha}e^{i\angle c}\]&lt;/div>&lt;ul>
&lt;li>&lt;span class="math math-inline">\(\alpha \in (0,1]\)&lt;/span> : Magnitude Compression Exponent&lt;/li>
&lt;li>&lt;span class="math math-inline">\(\beta &amp;gt; 0\)&lt;/span> : Scale Factor&lt;/li>
&lt;/ul>
&lt;p>위를 자세히 보면, Phase, 그리고 Complex Direction은 전혀 바뀌지 않았고, Magnitude에만 Scaling이 가해졌다.&lt;/p>
&lt;p>논문이 실험적으로 고른 값은 &lt;span class="math math-inline">\(\alpha=0.5\)&lt;/span>, &lt;span class="math math-inline">\(\beta=0.15\)&lt;/span>다. 숫자로 감을 잡아보면: 어떤 빈의 크기가 100이고 다른 빈이 1이라면 원래는 100배 차이지만, &lt;span class="math math-inline">\(\alpha=0.5\)&lt;/span>를 거치면 &lt;span class="math math-inline">\(0.15\times10=1.5\)&lt;/span> 대 &lt;span class="math math-inline">\(0.15\times1=0.15\)&lt;/span>, 즉 &lt;strong>10배&lt;/strong> 차이로 줄어든다. 큰 놈은 많이, 작은 놈은 조금 눌리는 것이 power-law 압축의 성질이다. 논문의 표현을 빌리면, α는 &amp;ldquo;에너지가 낮은 주파수 성분(예: 무성음의 마찰음)을 끌어올리는&amp;rdquo; 역할이고, β는 전체 크기를 diffusion 노이즈 스케일에 맞추는 정규화 역할이다.&lt;/p>
&lt;h2 id="inverse-amplitude-transformation">Inverse Amplitude Transformation&lt;/h2>
&lt;p>위의 Representation은 역변환도 간단하다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[c=\left(\frac{|\tilde{c}|}{\beta}\right)^{\frac{1}{\alpha}}e^{i\angle \tilde{c}}\]&lt;/div>&lt;p>주의할 점 하나: 역변환은 &lt;span class="math math-inline">\(1/\alpha\)&lt;/span> 제곱이라 &lt;strong>압축된 도메인에서의 작은 오차가 원래 도메인에서는 증폭&lt;/strong>된다. &lt;span class="math math-inline">\(\alpha\)&lt;/span>를 너무 작게 잡으면 큰 성분의 오차가 커지는 이유다. 0.5는 그 사이의 타협점.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">compress&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">beta&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.15&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># c: complex STFT (F, T)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">beta&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">abs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">alpha&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">angle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">decompress&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_tilde&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.5&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">beta&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.15&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">abs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_tilde&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">beta&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">alpha&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="n">j&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">angle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c_tilde&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="효과">효과&lt;/h2>
&lt;ol>
&lt;li>너무 큰 Spectral Peak가 지배적이지 않게 만들 수 있다.&lt;/li>
&lt;li>Low-Energy의 Speech 성분이 부각되어 숨소리 같은 소리가 잘 보존된다.&lt;/li>
&lt;li>원래 Diffusion의 Noise Scale에서 어긋나지 않는다.&lt;/li>
&lt;li>Extreme Magnitude가 덜 나와서 학습이 안정적이다.&lt;/li>
&lt;li>Perceptual Relevance가 증가한다. (결과물이 더 그럴싸해진다.)&lt;/li>
&lt;/ol>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">어디서 본 것 같다면&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>맞다. 스펙트로그램을 로그로 보는 것(dB), mel-spectrogram의 log 압축, μ-law 같은 것들이 전부 &amp;ldquo;큰 값은 세게, 작은 값은 약하게 누른다&amp;quot;는 같은 아이디어다. 논문도 이런 압축이 heavy-tailed한 음성 STFT 크기 분포를 보정하고, 음성 향상에서 지각적으로 더 의미 있다는 기존 연구를 근거로 든다. 차이라면 SGMSE는 로그가 아니라 power-law(&lt;span class="math math-inline">\(|c|^{0.5}\)&lt;/span>)를 써서 0 근처에서도 매끄럽고 역변환이 깔끔하다는 점.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>J. Richter, S. Welker, J.-M. Lemercier, B. Lay, T. Gerkmann, &lt;a href="https://arxiv.org/abs/2208.05830" target="_blank" rel="noopener noreferrer">&lt;em>Speech Enhancement and Dereverberation with Diffusion-based Generative Models&lt;/em>&lt;/a>, IEEE/ACM TASLP 31, 2023. — 변환식, α=0.5·β=0.15, OU 드리프트 + Variance Exploding 확산으로 이루어진 SDE(OUVE)까지 이 논문.&lt;/li>
&lt;li>S. Welker, J. Richter, T. Gerkmann, &lt;a href="https://arxiv.org/abs/2203.17004" target="_blank" rel="noopener noreferrer">&lt;em>Speech Enhancement with Score-Based Generative Models in the Complex STFT Domain&lt;/em>&lt;/a>, Interspeech 2022. — 같은 그룹의 앞선 버전.&lt;/li>
&lt;li>코드: &lt;a href="https://github.com/sp-uhh/sgmse" target="_blank" rel="noopener noreferrer">sp-uhh/sgmse&lt;/a> — &lt;code>spec_transform&lt;/code> 쪽을 보면 위 식이 그대로 있다.&lt;/li>
&lt;/ul></content:encoded></item><item><title>Audio의 Mid-Side Representation</title><link>https://dirac042.github.io/posts/mid-side-representation/</link><pubDate>Mon, 06 Jul 2026 10:40:00 +0900</pubDate><guid>https://dirac042.github.io/posts/mid-side-representation/</guid><category>Audio</category><category>Binaural</category><category>Notes</category><description>Binaural/Stereo 오디오를 모델에 넣을 때, 왜 Left/Right 대신 Mid/Side로 바꿔서 다루는지에 대한 짧은 메모. Left-Right Processing 기본적으로 Binaural Audio 태스크에서 오디오는 2개의 Waveform으로 주어진다:</description><content:encoded>&lt;p>Binaural/Stereo 오디오를 모델에 넣을 때, 왜 Left/Right 대신 Mid/Side로 바꿔서 다루는지에 대한 짧은 메모.&lt;/p>
&lt;h2 id="left-right-processing">Left-Right Processing&lt;/h2>
&lt;p>기본적으로 Binaural Audio 태스크에서 오디오는 2개의 Waveform으로 주어진다:&lt;/p>
&lt;ul>
&lt;li>Left Waveform: 왼쪽 귀에서 들리는 소리&lt;/li>
&lt;li>Right Waveform: 오른쪽 귀에서 들리는 소리&lt;/li>
&lt;/ul>
&lt;p>이 표현에는 문제점이 몇 가지 존재한다.&lt;/p>
&lt;ol>
&lt;li>모델의 자원 낭비: Left와 Right의 에너지와 주파수의 Correlation은 90% 이상으로 매우 높다.
&lt;ul>
&lt;li>각각을 예측하라고 하면, Semantic/Acoustic을 두 번 중복해서 학습해야 한다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Phase Error에 대한 페널티가 없다.
&lt;ul>
&lt;li>L/R의 Phase가 1ms 어긋났다고 가정하자.&lt;/li>
&lt;li>전체 Waveform의 관점에서는 둘 다 1ms 어긋났으니까, L1/MSE Loss의 변화가 없다.&lt;/li>
&lt;li>하지만 사람이 들으면 입체감이 붕괴된 안 좋은 소리가 난다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">왜 1 ms가 큰 문제인가 — 사람이 공간을 듣는 방법&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>두 귀 사이의 거리는 약 17 cm라서, 소리가 한쪽 귀에 먼저 닿는 시간차(ITD, interaural time difference)는 최대 0.6~0.7 ms 정도다. 뇌는 이 sub-millisecond 차이와 크기 차이(ILD), 주파수별 위상차(IPD)로 소리의 방향을 잡는다. 즉 1 ms의 위상 오차는 &amp;ldquo;약간 틀린&amp;rdquo; 게 아니라 &lt;strong>가능한 ITD 범위를 통째로 벗어난&lt;/strong> 오차다. 그런데 L, R을 각각 따로 L1/MSE로 비교하면 이 오차는 파형 전체가 살짝 밀린 정도로만 보여 거의 벌점을 받지 않는다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="mid-side-processing">Mid-Side Processing&lt;/h2>
&lt;p>Left/Right 신호를 간단한 Linear Combination으로 나타내는 방법.&lt;/p>
&lt;div class="math math-block">\[\text{Mid}=\frac{L&amp;#43;R}{2}\]&lt;/div>&lt;p>&lt;br>
&lt;/p>
&lt;div class="math math-block">\[\text{Side}=\frac{L-R}{2}\]&lt;/div>&lt;ul>
&lt;li>Mid: 소리의 공통 성분. (Mono Downmix)&lt;/li>
&lt;li>Side: 두 채널의 차이. (공간, 위상차, Reverb 등의 정보만 남음)&lt;/li>
&lt;/ul>
&lt;p>역변환도 간단하다: &lt;span class="math math-inline">\(L=\text{Mid}&amp;#43;\text{Side}\)&lt;/span>, &lt;span class="math math-inline">\(R=\text{Mid}-\text{Side}\)&lt;/span>.&lt;/p>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-mid-side.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>가운데서 나는 소리(공통 성분)와 왼쪽에서 조금 늦게 오른쪽 귀에 닿는 소리를 섞은 예. L과 R은 거의 똑같아 보이지만, Side에는 두 귀의 차이 — 방향을 알려주는 성분 — 만 남는다.&lt;/p>
&lt;/blockquote>&lt;p>장점&lt;/p>
&lt;ol>
&lt;li>자원 낭비가 없다.
&lt;ul>
&lt;li>Mid가 가지고 있는 정보와 Side가 가진 정보가 각각 다르다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Phase Error에 직접적인 페널티가 존재한다.
&lt;ul>
&lt;li>Side에 L1 Loss만 걸어줘도 Phase를 잡을 수 있다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>모노 호환·조절이 쉽다.
&lt;ul>
&lt;li>Mid만 남기면 그대로 모노 다운믹스이고, Side에 gain만 곱하면 스테레오 폭이 조절된다. 방송·믹싱에서 M/S를 오래 써온 이유이기도 하다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">2번을 숫자로 확인해보기&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>500 Hz 사인파가 L과 R에 똑같이 들어 있다고 하자(정중앙 소리). 모델이 R만 1 ms 늦게 냈다면, 500 Hz의 주기는 2 ms이니 1 ms는 정확히 반주기 = 위상 180°다. L/R 각각의 L1 오차는 파형이 조금 밀린 정도지만, Side = (L − R)/2 는 원래 0이어야 할 것이 &lt;strong>진폭이 원음과 같은 사인파&lt;/strong>가 되어버린다. Side에 걸린 L1이 이걸 그대로 벌점으로 만든다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">numpy&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">np&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">to_mid_side&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">):&lt;/span> &lt;span class="c1"># x: (2, T) stereo waveform&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">L&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stack&lt;/span>&lt;span class="p">([(&lt;/span>&lt;span class="n">L&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">R&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">L&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">R&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">from_mid_side&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ms&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">M&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">S&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ms&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">np&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stack&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">M&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">S&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">M&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">S&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;aside class="callout callout-note">
&lt;p class="callout-title">어디에 쓰이나&lt;/p>
&lt;div class="callout-body">
&lt;ul>
&lt;li>&lt;strong>Mono-to-binaural 연구&lt;/strong>(2.5D Visual Sound, CCStereo 등)는 정확히 이 분해를 쓴다: 입력은 mono(L+R)이고, 모델은 difference(L−R)의 spectrogram/mask를 예측한 뒤 &lt;span class="math math-inline">\(L=(M&amp;#43;D)/2\)&lt;/span>, &lt;span class="math math-inline">\(R=(M-D)/2\)&lt;/span>로 되돌린다. Mid는 이미 주어졌으니 모델은 &amp;ldquo;공간 정보&amp;quot;만 배우면 된다.&lt;/li>
&lt;li>위 정의에서 1/2 대신 &lt;span class="math math-inline">\(1/\sqrt2\)&lt;/span>를 쓰면 변환이 직교(orthonormal)가 되어 에너지가 보존된다. 손실 함수에 쓸 때는 어느 쪽이든 상관없지만, M/S를 다시 섞어 STFT를 비교할 때는 스케일을 맞춰야 한다.&lt;/li>
&lt;li>다채널(5.1, ambisonics)로 가면 같은 아이디어가 &amp;ldquo;공통 성분 + 차이 성분&amp;rdquo; 분해로 일반화된다.&lt;/li>
&lt;/ul>
&lt;/div>
&lt;/aside>&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>R. Gao, K. Grauman, &lt;a href="https://arxiv.org/abs/1812.04204" target="_blank" rel="noopener noreferrer">&lt;em>2.5D Visual Sound&lt;/em>&lt;/a>, CVPR 2019 — mono에서 L−R을 예측해 binaural을 만드는 대표 논문.&lt;/li>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Interaural_time_difference" target="_blank" rel="noopener noreferrer">Interaural time difference — Wikipedia&lt;/a>, &lt;a href="https://en.wikipedia.org/wiki/Stereophonic_sound#M/S_technique:_mid/side_stereophony" target="_blank" rel="noopener noreferrer">Mid/Side (stereophonic sound) — Wikipedia&lt;/a>.&lt;/li>
&lt;/ul></content:encoded></item><item><title>MM-DiT — 두 모달리티를 동등하게 다루는 Diffusion Transformer</title><link>https://dirac042.github.io/posts/mm-dit/</link><pubDate>Mon, 06 Jul 2026 10:30:00 +0900</pubDate><guid>https://dirac042.github.io/posts/mm-dit/</guid><category>Deep Learning</category><category>Diffusion</category><category>Paper Notes</category><description>이전 노트에서 남긴 찝찝함 — 이미지/오디오가 주(主), 텍스트가 부(副)인 구조 — 을 정면으로 다루는 MM-DiT 정리. Stable Diffusion 3 논문(Esser et al., Scaling Rectified Flow Transformers for High-Resolution Image Synthesis, 2024)에서 제안됐다.</description><content:encoded>&lt;p>&lt;a href="https://dirac042.github.io/posts/dit/">이전 노트&lt;/a>에서 남긴 찝찝함 — 이미지/오디오가 주(主), 텍스트가 부(副)인 구조 — 을 정면으로 다루는 MM-DiT 정리. Stable Diffusion 3 논문(Esser et al., &lt;a href="https://arxiv.org/abs/2403.03206" target="_blank" rel="noopener noreferrer">&lt;em>Scaling Rectified Flow Transformers for High-Resolution Image Synthesis&lt;/em>&lt;/a>, 2024)에서 제안됐다.&lt;/p>
&lt;p>기존의 DiT 구조는 2가지의 모달리티에 계층이 존재했다.&lt;/p>
&lt;ol>
&lt;li>이미지, 오디오를 메인으로 두고,&lt;/li>
&lt;li>텍스트를 보조 힌트로 사용.&lt;/li>
&lt;/ol>
&lt;p>이렇게 되면 2개의 모달리티의 깊이가 달라서, Deeper Level의 Alignment가 잘 안 되는 문제가 생긴다.&lt;/p>
&lt;p>그러나 MM-DiT는 2개의 모달리티를 완벽하게 동등한 비중으로 다루게 된다.&lt;/p>
&lt;h2 id="architecture">Architecture&lt;/h2>
&lt;ol>
&lt;li>Stream을 2개로 쪼개자!
&lt;ul>
&lt;li>Track A: Noise Token이 지나가는 길 (이미지/오디오)&lt;/li>
&lt;li>Track B: Text Token이 지나가는 길 (텍스트)
&lt;ul>
&lt;li>이때 텍스트는 힌트로 쓰이고 버려지지 않고, 이미지랑 똑같이 블록을 통과할 때마다 스스로 update된다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Joint Attention&lt;/strong>: 서로 다른 도로를 달리는 2개를 합치자!
&lt;ol>
&lt;li>이미지/텍스트는 성질이 달라서, 독립적인 Linear 신경망을 거쳐 QKV 제작&lt;/li>
&lt;li>이미지 QKV와 텍스트 QKV를 Sequential하게 이어붙이기 (매우 큰 공간)&lt;br>
→ 이 공간 안에서 토큰들이 서로 Attention (픽셀, 텍스트와의 관계 학습)&lt;br>
&amp;ldquo;사람들 4000명을 앉혀놓고, 전부 떠들게 만들기&amp;rdquo;&lt;/li>
&lt;li>정보를 가지게 된 토큰들을 다시 2개의 갈래로 나누기&lt;/li>
&lt;li>분리된 토큰들이 독립적인 MLP를 거쳐 최종적인 결과를 내리고, 다음 블럭으로 넘어가기&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-mmdit-block.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>한 블록의 흐름. 두 트랙은 가중치(adaLN, QKV, MLP)를 따로 갖고, attention 한 번만 같은 방에서 한다.&lt;/p>
&lt;/blockquote>&lt;aside class="callout callout-note">
&lt;p class="callout-title">SD3에서는 실제로 어떻게 조건을 만드나&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>텍스트 인코더를 세 개 쓴다: CLIP L/14, OpenCLIP bigG/14, T5-XXL. CLIP 두 개의 &lt;strong>pooled 출력&lt;/strong>을 이어 붙여 하나의 벡터로 만들고, 여기에 timestep 임베딩을 더해 adaLN의 조건 벡터(위 그림의 &amp;ldquo;t + pooled text&amp;rdquo;)로 쓴다. 반면 &lt;strong>토큰 단위 임베딩&lt;/strong>(CLIP의 penultimate hidden state + T5 토큰)은 Track B의 시퀀스가 되어 joint attention에 들어간다. 즉 &amp;ldquo;문장의 요약&amp;quot;은 modulation으로, &amp;ldquo;문장의 단어 하나하나&amp;quot;는 attention으로 들어가는 셈이다.&lt;/p>
&lt;p>그리고 이게 정말 나은지도 재봤다. 같은 조건에서 vanilla DiT &amp;lt; UViT &amp;lt; cross-attention DiT(CrossDiT) &amp;lt; &lt;strong>MM-DiT&lt;/strong> 순서였고, 논문은 &amp;ldquo;MM-DiT가 cross-attention과 vanilla 변형을 크게 앞선다&amp;quot;고 쓴다. 학습 목표는 DDPM 대신 rectified flow이고, 중간 timestep을 더 자주 뽑는 logit-normal 샘플링을 쓴다. 깊이 38(약 8B 파라미터)까지 키워도 validation loss가 포화 없이 계속 내려갔다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="problems">Problems&lt;/h2>
&lt;p>뭔가 데이터가 엄청나게 커지게 되면, Joint Attention이 엄청나게 느려질 것 같은 예감.&lt;/p>
&lt;ol>
&lt;li>Transformer Attention 연산은 &lt;span class="math math-inline">\(\mathcal{O}(N^2)\)&lt;/span>, 즉 데이터 길이의 제곱에 비례해 계산량이 늘어난다.
&lt;ul>
&lt;li>기존 방식은 Noise Token이 Text를 참고만 하니까, &lt;span class="math math-inline">\(\mathcal{O}(N^2)\)&lt;/span>.&lt;/li>
&lt;li>MM-DiT는 전부 다 몰아넣고 Attention을 실행하니까, &lt;span class="math math-inline">\(\mathcal{O}((N_{text}&amp;#43;N_{image})^2)\)&lt;/span>&lt;/li>
&lt;li>계산량이 매우매우 커진다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Attention 계산에서 OOM 에러&lt;/li>
&lt;li>Modality Imbalance하면 효율이 떨어진다.&lt;br>
ex. 텍스트 100개, 이미지 4만 개 → 이미지-이미지 간의 상호작용만 여러 개.&lt;/li>
&lt;/ol>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">숫자로 감 잡기&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>1024×1024 이미지를 8배 VAE로 줄이면 128×128 latent, 패치 2로 자르면 &lt;span class="math math-inline">\(64^2=4096\)&lt;/span> 토큰. 텍스트는 CLIP 77 + T5 256 정도로 수백 개. 그러면 &lt;span class="math math-inline">\((4096&amp;#43;333)^2\approx1.96\times10^7\)&lt;/span> 대 &lt;span class="math math-inline">\(4096^2\approx1.68\times10^7\)&lt;/span> — 텍스트를 같은 방에 넣어서 늘어나는 비용은 약 17%다. 걱정과 달리 병목은 &amp;ldquo;텍스트를 끼워서&amp;quot;가 아니라 애초에 이미지-이미지 attention이고, 이건 self-attention을 쓰는 이상 어떤 DiT든 똑같이 진다. 오디오는 토큰이 시간축으로 길어지기 쉬워서(수천~수만 프레임) 이 항이 더 아프다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;p>아직까지도 안 풀린 숙제로 남아 있다.&lt;/p>
&lt;ol>
&lt;li>Flash Attention 같은 최적화 기술을 영끌해서 적용하거나,&lt;/li>
&lt;li>3개의 블럭에서만 Joint Attention하고, 나머지는 분리해서 연산하는 등…&lt;/li>
&lt;/ol>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">실제로 나온 절충안들&lt;/p>
&lt;div class="callout-body">
&lt;ul>
&lt;li>FLUX.1(Black Forest Labs, 2024)은 앞쪽에 두 트랙이 분리된 MM-DiT식 &lt;strong>double-stream&lt;/strong> 블록을 두고, 뒤쪽은 두 시퀀스를 아예 하나로 합쳐 처리하는 &lt;strong>single-stream&lt;/strong> 블록으로 바꿔 파라미터를 아낀다 — 위 2번 아이디어와 같은 방향이다.&lt;/li>
&lt;li>오디오 쪽에서는 MMAudio(Cheng et al., 2024)가 비디오·텍스트·오디오 세 스트림을 joint attention으로 묶고, 비디오-오디오 프레임을 시간축에 맞춰 정렬한 위치 임베딩(aligned RoPE)을 얹어 동기화 문제를 푼다.&lt;/li>
&lt;li>계산량 자체는 FlashAttention 계열이 메모리 병목을 크게 완화하지만 &lt;span class="math math-inline">\(\mathcal{O}(N^2)\)&lt;/span> 자체가 사라지진 않는다. 그래서 latent를 더 압축하거나(패치 크기, VAE 다운샘플 비율), 윈도우/희소 attention을 섞는 연구가 이어진다.&lt;/li>
&lt;/ul>
&lt;/div>
&lt;/aside>&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>P. Esser et al., &lt;a href="https://arxiv.org/abs/2403.03206" target="_blank" rel="noopener noreferrer">&lt;em>Scaling Rectified Flow Transformers for High-Resolution Image Synthesis&lt;/em>&lt;/a>, 2024 — MM-DiT 원 논문(Stable Diffusion 3).&lt;/li>
&lt;li>W. Peebles, S. Xie, &lt;a href="https://arxiv.org/abs/2212.09748" target="_blank" rel="noopener noreferrer">&lt;em>Scalable Diffusion Models with Transformers&lt;/em>&lt;/a>, ICCV 2023 — 출발점인 DiT.&lt;/li>
&lt;li>H. K. Cheng et al., &lt;a href="https://arxiv.org/abs/2412.15322" target="_blank" rel="noopener noreferrer">&lt;em>MMAudio: Taming Multimodal Joint Training for High-Quality Video-to-Audio Synthesis&lt;/em>&lt;/a>, 2024 — 오디오에서의 multimodal joint attention.&lt;/li>
&lt;li>&lt;a href="https://github.com/black-forest-labs/flux" target="_blank" rel="noopener noreferrer">black-forest-labs/flux&lt;/a> — double/single-stream 블록 구현.&lt;/li>
&lt;/ul></content:encoded></item><item><title>DiT (Diffusion Transformer) 정리</title><link>https://dirac042.github.io/posts/dit/</link><pubDate>Mon, 06 Jul 2026 10:20:00 +0900</pubDate><guid>https://dirac042.github.io/posts/dit/</guid><category>Deep Learning</category><category>Diffusion</category><category>Paper Notes</category><description>Diffusion의 백본을 U-Net에서 Transformer로 바꾼 DiT(Peebles &amp; Xie, Scalable Diffusion Models with Transformers, ICCV 2023)를, 오디오 생성 관점에서 읽고 정리한 노트. 이전에 사용하던 U-Net 기반의 Diffusion은 이미지 생성 Task에서 많이 활용되어 왔다.</description><content:encoded>&lt;p>Diffusion의 백본을 U-Net에서 Transformer로 바꾼 DiT(Peebles &amp;amp; Xie, &lt;a href="https://arxiv.org/abs/2212.09748" target="_blank" rel="noopener noreferrer">&lt;em>Scalable Diffusion Models with Transformers&lt;/em>&lt;/a>, ICCV 2023)를, 오디오 생성 관점에서 읽고 정리한 노트.&lt;/p>
&lt;p>이전에 사용하던 U-Net 기반의 Diffusion은 이미지 생성 Task에서 많이 활용되어 왔다.&lt;/p>
&lt;ul>
&lt;li>하지만, U-Net의 구조적인 한계 때문에, 시간 간격이 긴 데이터에 약하다.&lt;/li>
&lt;li>즉, 앞의 데이터와 뒤의 데이터를 서로 연결할 수 있는 힘이 없다.&lt;/li>
&lt;/ul>
&lt;p>그래서 Transformer의 Attention 구조가 가진 Long-Term Dependency를 이용해 Transformer 기반의 Diffusion Method를 고안하게 되는데, 이것이 DiT라고 볼 수 있겠다.&lt;/p>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">논문이 실제로 내세운 주장은 조금 다르다&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>위 직관(긴 의존성)은 오디오 쪽에서 DiT를 좋아하는 이유로 맞는 말이지만, 원 논문의 핵심 메시지는 &lt;strong>&amp;ldquo;U-Net의 inductive bias는 필수가 아니고, Transformer로 바꾸면 계산량(Gflops)을 늘릴수록 성능이 착실히 좋아진다&amp;rdquo;&lt;/strong> 는 스케일링 이야기다. 12개 모델 변형에서 Gflops와 FID-50K의 상관계수가 −0.93이었고, 가장 큰 DiT-XL/2(28층, hidden 1152, 16 heads)가 ImageNet 256×256 class-conditional에서 FID 2.27로 당시 SOTA를 찍었다. 입력은 픽셀이 아니라 Stable Diffusion VAE의 latent(256² 이미지 → 32×32×4)이고, ADM처럼 노이즈 ε과 공분산 Σ를 예측한다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="architecture">Architecture&lt;/h2>
&lt;p>결국 Diffusion이 메인이라, Gaussian Noise에서 GT로 가는 방향을 예측하는 건 동일하다.&lt;/p>
&lt;p>즉, DiT의 Block은 현재 Timestep에서 입력된 Noisy Latent를 어떤 방향으로 Denoise할 것인지를 구하는 게 목표다.&lt;/p>
&lt;h3 id="patchify-latent를-토큰으로">Patchify: latent를 토큰으로&lt;/h3>
&lt;p>Transformer는 토큰의 시퀀스를 먹으니, 먼저 latent를 잘라야 한다. &lt;span class="math math-inline">\(I\times I\)&lt;/span> latent를 &lt;span class="math math-inline">\(p\times p\)&lt;/span> 패치로 자르면 토큰 수는 &lt;span class="math math-inline">\(T=(I/p)^2\)&lt;/span>. 논문은 &lt;span class="math math-inline">\(p\in\{2,4,8\}\)&lt;/span>을 실험했는데, &lt;span class="math math-inline">\(p\)&lt;/span>를 반으로 줄이면 토큰이 4배가 되고 Gflops도 최소 4배가 된다(파라미터 수는 거의 그대로). 그리고 그만큼 성능이 좋아진다 — 이것도 &amp;ldquo;계산량이 곧 성능&amp;quot;의 한 사례. 위치 정보는 ViT처럼 sine-cosine positional embedding으로 넣는다. 오디오라면 &lt;span class="math math-inline">\(I\times I\)&lt;/span> 대신 (시간 × 주파수/채널) latent를 같은 식으로 자르면 된다.&lt;/p>
&lt;h3 id="블록-안에서-일어나는-일">블록 안에서 일어나는 일&lt;/h3>
&lt;ol>
&lt;li>AdaLN (Adaptive Layer Normalization)
&lt;ul>
&lt;li>먼저 시간 &lt;span class="math math-inline">\(t\)&lt;/span>를 주입받아, 각각의 토큰들에게 &amp;lsquo;얼마나 깎아야 하는지&amp;rsquo;를 전달한다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Self-Attention
&lt;ul>
&lt;li>1에서 나온 정보들을 바탕으로, 각 토큰들은 자기 자신(Waveform) 안에서 패턴을 분석한다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Cross-Attention
&lt;ul>
&lt;li>이때 외부의 Condition(Video/Text)이 들어와 Denoising을 위한 힌트를 제공하고, 소리 생성의 방향성이 생긴다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>MLP
&lt;ul>
&lt;li>최종적으로 &amp;ldquo;이 소리는 이 방향으로 이동해야 한다!&amp;ldquo;를 구하게 된다.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-dit-block.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>원 논문에서 가장 좋았던 adaLN-Zero 블록. 조건(t, c)은 attention이 아니라 LayerNorm의 scale/shift와 residual 앞의 gate로 들어간다.&lt;/p>
&lt;/blockquote>&lt;aside class="callout callout-note">
&lt;p class="callout-title">조건을 넣는 네 가지 방법 — 그리고 승자&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>위 1~4번은 &amp;ldquo;cross-attention을 쓰는 DiT&amp;quot;의 그림이다(오디오/텍스트 조건 모델들이 실제로 이렇게 쓴다). 그런데 원 논문은 조건(timestep &lt;span class="math math-inline">\(t\)&lt;/span>, class label &lt;span class="math math-inline">\(c\)&lt;/span>)을 주입하는 방법을 네 가지 비교했다.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>방식&lt;/th>
&lt;th>어떻게&lt;/th>
&lt;th>비용&lt;/th>
&lt;th>결과&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>In-context&lt;/td>
&lt;td>&lt;span class="math math-inline">\(t\)&lt;/span>, &lt;span class="math math-inline">\(c\)&lt;/span> 임베딩을 토큰 두 개로 시퀀스 앞에 붙임&lt;/td>
&lt;td>거의 0&lt;/td>
&lt;td>가장 나쁨&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cross-attention&lt;/td>
&lt;td>조건 시퀀스에 대해 별도 cross-attn 층&lt;/td>
&lt;td>약 +15% Gflops&lt;/td>
&lt;td>중간&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>adaLN&lt;/td>
&lt;td>조건 벡터에서 LayerNorm의 scale γ, shift β를 회귀&lt;/td>
&lt;td>가장 적음&lt;/td>
&lt;td>좋음&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>adaLN-Zero&lt;/strong>&lt;/td>
&lt;td>adaLN + residual 직전의 dimension-wise gate α를 &lt;strong>0으로 초기화&lt;/strong>&lt;/td>
&lt;td>가장 적음&lt;/td>
&lt;td>&lt;strong>최고&lt;/strong> (400K step에서 FID가 in-context의 거의 절반)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>adaLN-Zero의 아이디어는 학습 초기에 각 블록이 항등함수(identity)에서 출발하게 만드는 것. 그래서 위 그림의 α가 &amp;ldquo;0으로 초기화&amp;quot;다. 정리하면 — 조건이 &amp;ldquo;짧은 벡터&amp;rdquo;(timestep, class, pooled text)라면 adaLN 계열이, 조건이 &amp;ldquo;긴 시퀀스&amp;rdquo;(문장 토큰, 비디오 프레임)라면 cross-attention이 자연스럽다. Stable Audio Open 같은 오디오 DiT가 텍스트 토큰은 cross-attention으로, timestep/타이밍 조건은 adaLN으로 넣는 이유가 여기 있다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="commentary">Commentary&lt;/h2>
&lt;p>찝찝한 부분이 있다.&lt;/p>
&lt;p>현재 DiT에서는 Self-Attention에서 Waveform의 패턴을 분석한 다음,&lt;br>
부가적으로 Condition이 들어와 Denoising을 시행한다.&lt;/p>
&lt;p>그 말인즉슨, Waveform이 주(主), Video/Text가 부(副)가 되는 형태라고 볼 수 있겠다.&lt;/p>
&lt;p>이런 식으로 이미지/오디오가 메인, 텍스트가 보조가 되면 정보 불균형이 생기지 않을까?&lt;/p>
&lt;p>이걸 Hierarchical하지 않고, Equal하게 다룰 수는 없을까?&lt;/p>
&lt;p>→ 다음 노트: &lt;a href="https://dirac042.github.io/posts/mm-dit/">MM-DiT&lt;/a>&lt;/p>
&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>W. Peebles, S. Xie, &lt;a href="https://arxiv.org/abs/2212.09748" target="_blank" rel="noopener noreferrer">&lt;em>Scalable Diffusion Models with Transformers&lt;/em>&lt;/a>, ICCV 2023. 코드: &lt;a href="https://github.com/facebookresearch/DiT" target="_blank" rel="noopener noreferrer">facebookresearch/DiT&lt;/a>.&lt;/li>
&lt;li>P. Esser et al., &lt;a href="https://arxiv.org/abs/2403.03206" target="_blank" rel="noopener noreferrer">&lt;em>Scaling Rectified Flow Transformers for High-Resolution Image Synthesis&lt;/em>&lt;/a>, 2024 (Stable Diffusion 3) — DiT를 두 모달리티 동등 구조로 확장한 MM-DiT.&lt;/li>
&lt;li>Z. Evans et al., &lt;a href="https://arxiv.org/abs/2407.14358" target="_blank" rel="noopener noreferrer">&lt;em>Stable Audio Open&lt;/em>&lt;/a>, 2024 — 오디오 latent 위에서 돌아가는 DiT의 실제 예 (T5 텍스트는 cross-attention, 타이밍 조건은 adaLN).&lt;/li>
&lt;/ul></content:encoded></item><item><title>DAC (Descript Audio Codec) 정리</title><link>https://dirac042.github.io/posts/dac/</link><pubDate>Mon, 06 Jul 2026 10:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/dac/</guid><category>Audio</category><category>Codec</category><category>Paper Notes</category><description>Descript Audio Codec: Neural Audio Codec (오디오를 작게 압축하고, 원본에 가까운 음질로 복원). 오디오 생성 모델들이 Latent를 만들 때 자주 쓰는 코덱이라 구조를 짧게 정리해 둔다. 논문은 Kumar et al., High-Fidelity Audio Compression with Improved RVQGAN (NeurIPS 2023). 숫자로 요약하면 44.1 kHz 오디오를 8 kbps, 약 90배 압축하면서 음성·음악·환경음을 모델 하나로 다룬다.</description><content:encoded>&lt;p>Descript Audio Codec: Neural Audio Codec (오디오를 작게 압축하고, 원본에 가까운 음질로 복원). 오디오 생성 모델들이 Latent를 만들 때 자주 쓰는 코덱이라 구조를 짧게 정리해 둔다. 논문은 Kumar et al., &lt;a href="https://arxiv.org/abs/2306.06546" target="_blank" rel="noopener noreferrer">&lt;em>High-Fidelity Audio Compression with Improved RVQGAN&lt;/em>&lt;/a> (NeurIPS 2023). 숫자로 요약하면 &lt;strong>44.1 kHz 오디오를 8 kbps, 약 90배 압축&lt;/strong>하면서 음성·음악·환경음을 모델 하나로 다룬다.&lt;/p>
&lt;h2 id="구조">구조&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>Encoder: Waveform을 CNN에 태우기 → Continuous Latent Representation 생성&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>RVQ (Residual Vector Quantization)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>연속적인 값을 Discrete한 Token으로 바꾸기 → Quantization&lt;/li>
&lt;li>첫 번째 층: 전체적 뼈대만 잡아서 토큰화 → Residual이 크다&lt;/li>
&lt;li>두 번째 ~ n번째 층: 이전 층의 오차(Residual)만 받아와서 Token화 → 반복…&lt;/li>
&lt;li>오차가 0에 수렴 → 적은 Token으로 디테일한 소리 정보 저장.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>Decoder: RVQ의 Discrete Token을 입력받아, Waveform으로 만들기&lt;br>
→ 훈련을 GAN으로 함. (그래서 이름이 RVQGAN)&lt;/p>
&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-rvq.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>RVQ 한 장 요약. 각 단계는 &amp;ldquo;남은 오차&amp;quot;만 양자화하므로, 뒤 코드북일수록 미세한 디테일을 담당한다.&lt;/p>
&lt;/blockquote>&lt;aside class="callout callout-note">
&lt;p class="callout-title">비트레이트를 직접 계산해보면&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>Encoder의 stride가 512라서 44.1 kHz 파형이 초당 약 86 프레임(44100/512 ≈ 86.1)의 latent가 된다. 프레임마다 코드북 9개가 각각 10비트(1024개 코드 중 하나) 인덱스를 내놓으니 86 × 9 × 10 ≈ 7,750 bps ≈ &lt;strong>8 kbps&lt;/strong>. 원본 16-bit PCM(705.6 kbps)과 비교하면 약 91배 압축이다. 코드북 개수를 줄이면(예: 앞 4개만) 그대로 낮은 비트레이트 모델이 되는데, 이게 되도록 학습 때 &lt;strong>quantizer dropout&lt;/strong>(예시마다 p=0.5 확률로 코드북 개수를 랜덤하게 자름)을 쓴다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;aside class="callout callout-note">
&lt;p class="callout-title">코드북이 죽지 않게 하는 두 가지 트릭&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>VQ의 고질병은 코드북의 일부만 쓰이고 나머지는 죽어버리는 것(codebook collapse). DAC는 이미지 쪽 Improved VQGAN에서 두 가지를 가져왔다. &lt;strong>Factorized codes&lt;/strong>: 코드 lookup은 8차원(또는 32차원)의 낮은 공간에서 하고, 실제 임베딩은 1024차원에 둔다 — 찾기는 쉽게, 표현력은 크게. &lt;strong>L2-normalized codes&lt;/strong>: 인코더 출력과 코드북 벡터를 정규화해 유클리드 거리 대신 코사인 유사도로 매칭 → 안정성과 품질이 좋아진다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="구조적-특징">구조적 특징&lt;/h2>
&lt;ol>
&lt;li>Fully Convolutional Network(FCN, 1차원 CNN)을 Encoder/Decoder에 사용&lt;/li>
&lt;li>Snake Activation Function을 전 Layer에 사용 (주기가 있는 함수에 good)&lt;/li>
&lt;li>Dilated Convolution으로 듬성듬성 넘어가서 Receptive Field 넓히기&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-snake.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>Snake: &lt;span class="math math-inline">\(x&amp;#43;\frac{1}{\alpha}\sin^2(\alpha x)\)&lt;/span>. 항등함수에 주기적인 굴곡이 들어가 있어서, ReLU로는 잘 못 배우는 주기 신호(= 소리)를 표현하기 좋다. 논문에서는 ReLU를 Snake로 바꾸는 것만으로 SI-SDR이 눈에 띄게 올랐다.&lt;/p>
&lt;/blockquote>&lt;aside class="callout callout-note">
&lt;p class="callout-title">어떻게 학습시키나 (loss 구성)&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>Decoder는 GAN으로 학습하는데, 판별자가 세 종류다: &lt;strong>multi-period&lt;/strong> 파형 판별자(주기 2, 3, 5, 7, 11로 파형을 접어서 봄), &lt;strong>multi-scale STFT&lt;/strong> 판별자(window 2048/1024/512), 그리고 STFT를 sub-band로 쪼개 고주파와 앨리어싱을 잡는 &lt;strong>multi-band multi-scale STFT&lt;/strong> 판별자. 손실은 multi-scale mel reconstruction(가중치 15), feature matching(2), adversarial(HingeGAN, 1), codebook(1), commitment(0.25)의 합이다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="다음-이야기">다음 이야기&lt;/h2>
&lt;p>→ Discrete Token을 생성하는 RVQ를 버리고, Continuous한 VAE를 쓰자 → DAC-VAE (Semantic-VAE)&lt;/p>
&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>R. Kumar, P. Seetharaman, A. Luebs, I. Kumar, K. Kumar, &lt;a href="https://arxiv.org/abs/2306.06546" target="_blank" rel="noopener noreferrer">&lt;em>High-Fidelity Audio Compression with Improved RVQGAN&lt;/em>&lt;/a>, NeurIPS 2023. 코드/가중치: &lt;a href="https://github.com/descriptinc/descript-audio-codec" target="_blank" rel="noopener noreferrer">descriptinc/descript-audio-codec&lt;/a>.&lt;/li>
&lt;li>N. Zeghidour et al., &lt;a href="https://arxiv.org/abs/2107.03312" target="_blank" rel="noopener noreferrer">&lt;em>SoundStream: An End-to-End Neural Audio Codec&lt;/em>&lt;/a>, 2021 — RVQ를 오디오 코덱에 처음 쓴 논문. A. Défossez et al., &lt;a href="https://arxiv.org/abs/2210.13438" target="_blank" rel="noopener noreferrer">&lt;em>High Fidelity Neural Audio Compression&lt;/em>&lt;/a> (EnCodec), 2022 — DAC가 주로 비교하는 상대.&lt;/li>
&lt;li>L. Ziyin, T. Hartwig, M. Ueda, &lt;a href="https://arxiv.org/abs/2006.08195" target="_blank" rel="noopener noreferrer">&lt;em>Neural networks fail to learn periodic functions and how to fix it&lt;/em>&lt;/a>, NeurIPS 2020 — Snake activation의 출처. BigVGAN도 같은 활성함수를 쓴다.&lt;/li>
&lt;/ul></content:encoded></item><item><title>인스타 릴스에서 본 방정식 x^(x+1) = 16, 끝까지 풀어보기</title><link>https://dirac042.github.io/posts/solving-x-to-the-x-plus-1-equals-16/</link><pubDate>Thu, 09 Oct 2025 00:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/solving-x-to-the-x-plus-1-equals-16/</guid><category>Math</category><category>Numerical Analysis</category><description>1. Motivation 문제의 릴스. “Can you solve this?” 인스타 릴스에서 누가 이런 문제를 올려놨다. 안 그래도 할 거 없어서 풀어볼까 하고 샤프로 끄적거려봤는데, 내가 가진 ‘상식’으로는 풀 수 없었다.</description><content:encoded>&lt;h2 id="1-motivation">1. Motivation&lt;/h2>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/KakaoTalk_Photo_2025-10-09-23-48-51.jpeg" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>문제의 릴스. &amp;ldquo;Can you solve this?&amp;rdquo;&lt;/p>
&lt;/blockquote>&lt;p>인스타 릴스에서 누가 이런 문제를 올려놨다.&lt;br>
안 그래도 할 거 없어서 풀어볼까 하고 샤프로 끄적거려봤는데, 내가 가진 &amp;lsquo;상식&amp;rsquo;으로는 풀 수 없었다.&lt;/p>
&lt;div class="math math-block">\[(x&amp;#43;1)\ln x=\ln 16\]&lt;/div>&lt;p>여기서 더 할 게 없다.&lt;br>
댓글을 봐도 &amp;lsquo;2&amp;rsquo;라고 하는 사람들과 &amp;lsquo;3&amp;rsquo;이라고 하는 사람들이 많았다.&lt;br>
넣어보면 딱 봐도 아닌데. (&lt;span class="math math-inline">\(2^3=8\)&lt;/span>, &lt;span class="math math-inline">\(3^4=81\)&lt;/span>. 답은 2와 3 사이 어딘가에 있고, 둘 다 아니다.)&lt;/p>
&lt;p>성격상 이런 거 못 참아서, 리서치(?)한 내용을 간략하게 올려본다.&lt;/p>
&lt;h2 id="2-lamberts-w-introduction">2. Lambert&amp;rsquo;s W (Introduction)&lt;/h2>
&lt;p>사실 진짜 별거 아니다.&lt;br>
&lt;span class="math math-inline">\(f(x)=xe^x\)&lt;/span> 이 함수의 역함수를 &lt;span class="math math-inline">\(W(x)\)&lt;/span> 함수라고 표기하는 방식이다.&lt;/p>
&lt;p>즉, &lt;span class="math math-inline">\(z=W(z)e^{W(z)}\)&lt;/span>를 만족하는 함수 &lt;span class="math math-inline">\(W(z)\)&lt;/span>를&lt;br>
&lt;strong>Lambert W Function&lt;/strong> 이라고 부른다.&lt;br>
일종의 표기법을 만들어낸 것뿐이지, 뭔가 거창한 풀이에 대한 내용은 없다.&lt;/p>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-lambert-w.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>왼쪽: &lt;span class="math math-inline">\(y=we^w\)&lt;/span>. 이 그래프를 옆으로 뒤집은 것이 &lt;span class="math math-inline">\(W\)&lt;/span>다. 오른쪽: 우리 문제에 해당하는 &lt;span class="math math-inline">\(we^w&amp;#43;w\)&lt;/span>. 단조증가라 해가 딱 하나다.&lt;/p>
&lt;/blockquote>&lt;aside class="callout callout-note">
&lt;p class="callout-title">왜 &amp;lsquo;함수&amp;rsquo;가 아니라 &amp;lsquo;가지(branch)&amp;lsquo;를 이야기하나&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>&lt;span class="math math-inline">\(y=we^w\)&lt;/span>는 &lt;span class="math math-inline">\(w=-1\)&lt;/span>에서 최솟값 &lt;span class="math math-inline">\(-1/e\)&lt;/span>를 찍고 다시 올라간다. 그래서 &lt;span class="math math-inline">\(-1/e&amp;lt;y&amp;lt;0\)&lt;/span> 구간에서는 역함수 값이 두 개다 — 오른쪽 가지를 &lt;span class="math math-inline">\(W_0\)&lt;/span>(principal branch), 왼쪽 가지를 &lt;span class="math math-inline">\(W_{-1}\)&lt;/span>라고 부른다. &lt;span class="math math-inline">\(y&amp;lt;-1/e\)&lt;/span>면 실수 해가 없다. &lt;span class="math math-inline">\(e^x\)&lt;/span>, &lt;span class="math math-inline">\(\ln x\)&lt;/span> 같은 초등함수(elementary function)로는 &lt;span class="math math-inline">\(W\)&lt;/span>를 쓸 수 없다는 것이 증명되어 있어서, 컴퓨터에서는 &lt;code>scipy.special.lambertw&lt;/code> 같은 함수로 수치적으로 계산한다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;p>위의 문제는 다음과 같이 적을 수 있다.&lt;br>
&lt;span class="math math-inline">\((x&amp;#43;1)\ln x=\ln 16\)&lt;/span>&lt;br>
이때, &lt;span class="math math-inline">\(x=e^{\ln x}\)&lt;/span> 이므로&lt;br>
&lt;span class="math math-inline">\(x\ln x&amp;#43;\ln x=\ln 16\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(e^{\ln x}\ln x&amp;#43;\ln x = \ln 16\)&lt;/span>&lt;/p>
&lt;p>이제 &lt;span class="math math-inline">\(\ln x = w\)&lt;/span> 라고 치환하면, 다음의 형태로 변형된다.&lt;/p>
&lt;div class="math math-block">\[we^w&amp;#43;w=\ln 16\]&lt;/div>&lt;p>이는 아까 봤던 &lt;span class="math math-inline">\(we^w=z\)&lt;/span> 꼴의 형태와 다르다.&lt;br>
그래서 좀 더 &amp;lsquo;일반화된&amp;rsquo; 람베르트 W를 정의한다.&lt;/p>
&lt;p>&lt;span class="math math-inline">\(we^w&amp;#43;pw=z\)&lt;/span> 형태의 방정식의 해를 &lt;span class="math math-inline">\(w=W_p(z)\)&lt;/span> 라고 정의하자.&lt;/p>
&lt;p>그럼 위 식은 &lt;span class="math math-inline">\(p=1\)&lt;/span>, &lt;span class="math math-inline">\(z=\ln 16\)&lt;/span> 인 식이므로&lt;/p>
&lt;div class="math math-block">\[x=e^{W_1(\ln 16)}\]&lt;/div>&lt;p>다음과 같이 표현할 수 있다.&lt;br>
근데 사실 우리는 그냥 기호를 쓴 것뿐이라, 여기에서 더 계산할 수는 없다. 값을 실제로 얻으려면 결국 수치적으로 풀어야 한다.&lt;/p>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">이 &amp;lsquo;일반화&amp;rsquo;는 실제로 있는 개념이다 — r-Lambert 함수&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>나중에 찾아보니 &lt;span class="math math-inline">\(xe^x&amp;#43;rx=a\)&lt;/span>의 해를 &lt;span class="math math-inline">\(W_r(a)\)&lt;/span>로 쓰는 &lt;strong>r-Lambert function&lt;/strong>이 Mező와 Baricz(2017)에 의해 정의되어 있었다. 위에서 내가 &lt;span class="math math-inline">\(p\)&lt;/span>라고 쓴 게 딱 &lt;span class="math math-inline">\(r\)&lt;/span>이다. 재미있는 건 가지의 개수가 &lt;span class="math math-inline">\(r\)&lt;/span>에 따라 달라진다는 것: &lt;span class="math math-inline">\(r&amp;gt;1/e^2\)&lt;/span>이면 함수 &lt;span class="math math-inline">\(xe^x&amp;#43;rx\)&lt;/span>가 단조증가라 실수 가지가 하나뿐이고, &lt;span class="math math-inline">\(0&amp;lt;r&amp;lt;1/e^2\)&lt;/span>이면 세 개, &lt;span class="math math-inline">\(r&amp;lt;0\)&lt;/span>이면 두 개가 된다. 우리 문제는 &lt;span class="math math-inline">\(r=1&amp;gt;1/e^2\approx0.135\)&lt;/span>라서 위 그림의 오른쪽처럼 해가 정확히 하나다 — 릴스 댓글에서 &amp;lsquo;2냐 3이냐&amp;rsquo; 싸울 일이 애초에 아니었던 것.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="3-newton-raphson-method">3. Newton-Raphson Method&lt;/h2>
&lt;p>인공지능을 배우면서 Gradient Descent와 같이 배운 게 기억난다.&lt;br>
방법은 단순하다.&lt;/p>
&lt;ol>
&lt;li>어떤 그래프 위의 추측값에서 접선을 긋는다.&lt;/li>
&lt;li>그 접선이 x축과 만나는 점을 다음 추측값으로 삼는다.&lt;/li>
&lt;li>일정 횟수 동안 1과 2를 반복한다.&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-newton.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>그림으로 보면 이게 전부다. 시작점을 일부러 멀리(&lt;span class="math math-inline">\(x_0=1.9\)&lt;/span>) 잡아도 세 번 만에 답 근처에 도착한다.&lt;/p>
&lt;/blockquote>&lt;p>우리의 목표는 &lt;span class="math math-inline">\(x^{x&amp;#43;1}=16\)&lt;/span>의 해를 찾는 것이므로, 이는 &lt;span class="math math-inline">\(x^{x&amp;#43;1}-16=0\)&lt;/span>의 해를 찾는 것과 동치다.&lt;/p>
&lt;p>함수 &lt;span class="math math-inline">\(f(x)=x^{x&amp;#43;1}-16\)&lt;/span>이라고 정의하자.&lt;br>
일단 1번(어떤 그래프 위의 추측값에서 접선 긋기) 과정에서 접선을 그어야 하니까, &lt;span class="math math-inline">\(f(x)\)&lt;/span>의 도함수 &lt;span class="math math-inline">\(f&amp;#39;(x)\)&lt;/span>를 구해야겠다.&lt;br>
고등학교 미적 시간에 배운 로그미분법을 활용하면 쉽게 미분이 가능하다.&lt;/p>
&lt;p>&lt;span class="math math-inline">\(y=x^{x&amp;#43;1}\)&lt;/span>이면 &lt;span class="math math-inline">\(\ln y=(x&amp;#43;1)\ln x\)&lt;/span>이므로,&lt;/p>
&lt;p>&lt;span class="math math-inline">\(\frac{y&amp;#39;}{y}=\ln x&amp;#43;(x&amp;#43;1)\frac{1}{x}\)&lt;/span>&lt;/p>
&lt;p>&lt;span class="math math-inline">\(y&amp;#39;=y\left(\ln x&amp;#43;(x&amp;#43;1)\frac{1}{x}\right)=x^{x&amp;#43;1}\left(\ln x&amp;#43;1&amp;#43;\frac{1}{x}\right)\)&lt;/span>&lt;/p>
&lt;p>즉 &lt;span class="math math-inline">\(f&amp;#39;(x)=x^{x&amp;#43;1}\left(\ln x&amp;#43;1&amp;#43;\frac{1}{x}\right)\)&lt;/span> 가 된다.&lt;/p>
&lt;p>이제 1번은 끝났으니, 2번을 보자.&lt;br>
2번에 따르면, 우리의 다음 추측값 &lt;span class="math math-inline">\(x_{n&amp;#43;1}\)&lt;/span>은 현재 추측값 &lt;span class="math math-inline">\(x_n\)&lt;/span>에 대한 식으로 나타낼 수 있겠다.&lt;/p>
&lt;p>&lt;span class="math math-inline">\(x_n\)&lt;/span>에서 그은 접선이 &lt;span class="math math-inline">\(x\)&lt;/span>축과 만나는 곳이 &lt;span class="math math-inline">\(x_{n&amp;#43;1}\)&lt;/span>이므로,&lt;br>
접선과 &lt;span class="math math-inline">\(x\)&lt;/span>축이 이루는 각을 &lt;span class="math math-inline">\(\theta\)&lt;/span> 라고 두면&lt;br>
&lt;/p>
&lt;div class="math math-block">\[\tan\theta = f&amp;#39;(x_n)=\frac{f(x_n)-0}{x_n-x_{n&amp;#43;1}}\]&lt;/div>&lt;p>&lt;br>
이 식을 정리하면:&lt;br>
&lt;/p>
&lt;div class="math math-block">\[x_{n&amp;#43;1}=x_n-\frac{f(x_n)}{f&amp;#39;(x_n)}\]&lt;/div>&lt;p>&lt;br>
다음과 같은 점화식을 얻을 수 있다. (이게 Newton-Raphson의 정수다.)&lt;/p>
&lt;p>1번과 2번 알고리즘을 제대로 정의했으니, 이제 직접 구해보자.&lt;br>
사람들의 댓글로 보아 일단 해는 &lt;span class="math math-inline">\(x=2\)&lt;/span>와 &lt;span class="math math-inline">\(x=3\)&lt;/span> 사이에 존재한다.&lt;br>
(너무나도 당연하게도. &lt;span class="math math-inline">\(f(2)=-8&amp;lt;0\)&lt;/span>, &lt;span class="math math-inline">\(f(3)=65&amp;gt;0\)&lt;/span>이고 &lt;span class="math math-inline">\(f\)&lt;/span>는 연속이니, 중간값 정리에 의해 그 사이 어딘가에서 0을 지난다.)&lt;/p>
&lt;p>한 2.3 정도로 시작해보자. &lt;span class="math math-inline">\(x_0=2.3\)&lt;/span>.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[f(2.3)=2.3^{3.3}-16\approx-0.3793\]&lt;/div>&lt;p>&lt;br>
&lt;/p>
&lt;div class="math math-block">\[f&amp;#39;(2.3)=2.3^{3.3}\left(\ln 2.3&amp;#43;1&amp;#43;2.3^{-1}\right)\approx35.4230\]&lt;/div>&lt;p>&lt;br>
&lt;/p>
&lt;div class="math math-block">\[x_1=2.3-\frac{-0.3793}{35.4230}\approx2.3107\]&lt;/div>&lt;p>&lt;br>
처음 한 번 돌렸을 때의 결과는 2.3107이 나왔다.&lt;br>
&lt;span class="math math-inline">\(f(2.3)\)&lt;/span>이 음수였으니, 2.3보다는 조금 더 큰 쪽으로 움직인 셈이다.&lt;/p>
&lt;p>귀찮으니 파이썬으로 후딱 계산을 때리면 다음과 같은 결과가 나온다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">f&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">fp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">2.3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">fp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">round&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1 2.310711&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2 2.310572&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3 2.310572&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4 2.310572&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;span class="math math-inline">\(x_1=2.31071\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(x_2=2.31057\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(x_3=2.31057\)&lt;/span>&lt;/p>
&lt;p>두 번 만에 소수점 다섯째 자리까지 딱 멈춰버린다. (Newton-Raphson은 해 근처에서 자릿수가 매 단계 두 배씩 늘어나는 &amp;lsquo;이차 수렴&amp;rsquo;을 한다.)&lt;br>
이로써 위 문제의 답은 &lt;span class="math math-inline">\(x\approx2.3106\)&lt;/span> 이라고 근사할 수 있다.&lt;/p>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">Gradient Descent와 뭐가 다른가&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>둘 다 &amp;lsquo;기울기를 보고 다음 위치를 정한다&amp;rsquo;는 점은 같다. 하지만 GD는 손실 &lt;span class="math math-inline">\(L\)&lt;/span>을 &lt;strong>최소화&lt;/strong>하려고 &lt;span class="math math-inline">\(-\eta L&amp;#39;(x)\)&lt;/span>만큼 조금씩 내려가고(학습률 &lt;span class="math math-inline">\(\eta\)&lt;/span>를 사람이 정한다), Newton은 &lt;span class="math math-inline">\(f=0\)&lt;/span>이 되는 점을 &lt;strong>찾으려고&lt;/strong> &lt;span class="math math-inline">\(f/f&amp;#39;\)&lt;/span>만큼 한 번에 뛴다(보폭을 접선이 알아서 정한다). GD를 최적화 문제 &lt;span class="math math-inline">\(L&amp;#39;(x)=0\)&lt;/span>에 Newton으로 풀면 &lt;span class="math math-inline">\(x_{n&amp;#43;1}=x_n-L&amp;#39;(x_n)/L&amp;#39;&amp;#39;(x_n)\)&lt;/span>이 되는데, 이게 딥러닝에서 말하는 2차 최적화(Newton&amp;rsquo;s method for optimization)다. 이차 미분(Hessian)이 너무 비싸서 잘 안 쓸 뿐이다.&lt;/p>
&lt;p>대신 Newton은 시작점을 잘못 잡으면(예: &lt;span class="math math-inline">\(f&amp;#39;(x_n)\approx0\)&lt;/span>인 곳) 엉뚱한 곳으로 튀거나 발산할 수 있다. 위 문제처럼 함수가 단조증가하고 볼록하면 아무 데서 시작해도 잘 간다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="4-fixed-point-iteration-method">4. Fixed-Point Iteration Method&lt;/h2>
&lt;p>전에는 미분과 도함수를 사용했다면, 이번에는 우리에게 주어진 방정식 자체를 변형시키는 방법을 써보자.&lt;/p>
&lt;p>핵심은 이렇다.&lt;br>
우리에게 주어진 방정식은 &lt;span class="math math-inline">\(f(x)=0\)&lt;/span>.&lt;br>
이 식을 어떤 방법이든 &lt;span class="math math-inline">\(x=g(x)\)&lt;/span>의 꼴로 변형시킨다.&lt;br>
만약 &lt;span class="math math-inline">\(x=g(x)\)&lt;/span>의 해를 찾을 수 있으면, 이 해 &lt;span class="math math-inline">\(x^*\)&lt;/span>를 &amp;lsquo;고정점 (Fixed Point)&amp;lsquo;이라고 칭한다.&lt;br>
(즉, 이 고정점에서 &lt;span class="math math-inline">\(g(x^*)\)&lt;/span>의 값을 계산하면 자기 자신인 &lt;span class="math math-inline">\(x^*\)&lt;/span>가 나오는 것.)&lt;/p>
&lt;p>이를 이용해 다음과 같은 과정을 거친다.&lt;/p>
&lt;ol>
&lt;li>적절한 &lt;span class="math math-inline">\(x_0\)&lt;/span>에서 시작한다.&lt;/li>
&lt;li>점화식 &lt;span class="math math-inline">\(x_{n&amp;#43;1}=g(x_n)\)&lt;/span>을 계속 반복한다.&lt;/li>
&lt;li>2번 과정이 수렴하면, 이 수렴값은 고정점이며, 그 고정점은 우리가 찾는 해다.&lt;/li>
&lt;/ol>
&lt;p>여기에서 중요한 건, 변형시킨 &lt;span class="math math-inline">\(g(x)\)&lt;/span>의 형태다.&lt;br>
이 &lt;span class="math math-inline">\(g(x)\)&lt;/span>를 어떻게 만드느냐에 따라 이 방법이 성공하느냐 실패하느냐가 갈린다.&lt;/p>
&lt;p>예를 들면, 엄청 간단하게 &lt;span class="math math-inline">\(x=\frac{16}{x^x}\)&lt;/span> 라고 뒀다고 생각해보자.&lt;br>
그럼 점화식은 다음과 같다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[x_{n&amp;#43;1}=\frac{16}{x_n^{x_n}}\]&lt;/div>&lt;p>&lt;br>
그러나 이 점화식을 계속 사용해보면, 값은 수렴하지 않고 발산해버린다. (&lt;span class="math math-inline">\(2.3 \to 2.36 \to 2.13 \to 3.22 \to \cdots\)&lt;/span>)&lt;br>
이유는 해 근처에서 &lt;span class="math math-inline">\(|g&amp;#39;(x)|&amp;lt;1\)&lt;/span>이라는 조건을 만족하지 않기 때문이다.&lt;br>
이를 &lt;strong>축소사상원리(Contraction Mapping Principle)&lt;/strong> 라고 부른다.&lt;br>
(4.1에서 설명한다.)&lt;/p>
&lt;p>이번엔 좀 더 적절한 방식으로 변형해보자.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[x_{n&amp;#43;1}=e^{\frac{\ln 16}{x_n&amp;#43;1}}\]&lt;/div>&lt;p>아까와 같이 &lt;span class="math math-inline">\(x_0=2.3\)&lt;/span>에서 시작해보자.&lt;br>
&lt;span class="math math-inline">\(x_1\approx2.3168\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(x_2\approx2.3070\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(x_3\approx2.3127\)&lt;/span>&lt;br>
&lt;span class="math math-inline">\(x_4\approx2.3093\)&lt;/span>&lt;/p>
&lt;p>뭔가 2.31 근처를 빙빙 도는 느낌이다.&lt;br>
(이렇게 위아래로 진동하며 수렴하는 것을 &amp;lsquo;나선형 수렴&amp;rsquo;이라고 부른다. Newton-Raphson보다 훨씬 느리지만, 계속 돌리면 결국 같은 값 2.3106으로 간다.)&lt;/p>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-cobweb.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>고정점 반복을 그림으로 그리면 &amp;lsquo;거미줄(cobweb) 다이어그램&amp;rsquo;이 된다. &lt;span class="math math-inline">\(x_n\)&lt;/span>에서 위로 올라가 &lt;span class="math math-inline">\(g\)&lt;/span>를 만나고, 옆으로 가서 &lt;span class="math math-inline">\(y=x\)&lt;/span>를 만나면 그게 &lt;span class="math math-inline">\(x_{n&amp;#43;1}\)&lt;/span>. 왼쪽은 &lt;span class="math math-inline">\(g&amp;#39;\)&lt;/span>의 기울기가 &lt;span class="math math-inline">\(y=x\)&lt;/span>보다 완만해서 안으로 말려 들어가고, 오른쪽은 가팔라서 튕겨 나간다.&lt;/p>
&lt;/blockquote>&lt;p>즉, &lt;span class="math math-inline">\(x\approx2.31\)&lt;/span>로 근사할 수 있다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">math&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">lambda&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">math&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">2.3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">g&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">round&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1 2.3168 / 2 2.3070 / 3 2.3127 / 4 2.3093 / 5 2.3113 / 6 2.3101 / 7 2.3108&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="41-contraction-mapping-principle">4.1. Contraction Mapping Principle&lt;/h3>
&lt;p>&lt;span class="math math-inline">\(x=g(x)\)&lt;/span>에서 왜 &lt;span class="math math-inline">\(x^*\)&lt;/span>를 구하는 조건이 &lt;span class="math math-inline">\(|g&amp;#39;(x^*)|&amp;lt;1\)&lt;/span>일까?&lt;/p>
&lt;p>&lt;strong>1. 먼저 직관적으로, 기하학적으로 분석해보자.&lt;/strong>&lt;/p>
&lt;p>&lt;span class="math math-inline">\(x=g(x)\)&lt;/span>의 해가 &lt;span class="math math-inline">\(x^*\)&lt;/span>라는 것은 &lt;span class="math math-inline">\(y=x\)&lt;/span>, &lt;span class="math math-inline">\(y=g(x)\)&lt;/span>의 교점의 &lt;span class="math math-inline">\(x\)&lt;/span>좌표가 &lt;span class="math math-inline">\(x^*\)&lt;/span>라는 뜻이기도 하다.&lt;/p>
&lt;p>이때, &lt;span class="math math-inline">\(|g&amp;#39;(x^*)|&amp;lt;1\)&lt;/span>의 의미는 &lt;span class="math math-inline">\(g(x)\)&lt;/span> 그래프의 &lt;span class="math math-inline">\(x^*\)&lt;/span>에서의 접선의 기울기가 1보다 작다는 뜻.&lt;br>
즉, &lt;span class="math math-inline">\(y=x\)&lt;/span>의 기울기보다 완만하다는 뜻.&lt;br>
그래서 점화식의 과정을 그래프로 나타내보면 점점 &lt;span class="math math-inline">\(x^*\)&lt;/span>와의 거리가 줄어드는 것이다.&lt;/p>
&lt;p>반대로, &lt;span class="math math-inline">\(|g&amp;#39;(x^*)|&amp;gt;1\)&lt;/span>이면 &lt;span class="math math-inline">\(y=x\)&lt;/span>의 기울기보다 가파르게 되어서&lt;br>
점화식의 과정 그래프가 &lt;span class="math math-inline">\(x^*\)&lt;/span>에서 튕겨나가게 된다.&lt;br>
즉 발산하게 된다.&lt;/p>
&lt;p>&lt;strong>2. 직관에서 좀 더 나아가, 평균값 정리를 이용해 축소사상원리를 증명할 수 있다.&lt;/strong>&lt;/p>
&lt;p>평균값 정리를 기억하는가?&lt;/p>
&lt;blockquote>
&lt;p>어떤 그래프가 &lt;span class="math math-inline">\([a, b]\)&lt;/span>에서 연속이고 &lt;span class="math math-inline">\((a, b)\)&lt;/span>에서 미분가능하다면 &lt;span class="math math-inline">\(\frac{f(b)-f(a)}{b-a}=f&amp;#39;(c)\)&lt;/span>를 만족하는 &lt;span class="math math-inline">\(c \in (a,b)\)&lt;/span> 가 적어도 하나 존재한다.&lt;/p>
&lt;/blockquote>&lt;p>결국 미분가능한 함수에서, 그래프 위의 두 점을 이은 선(할선)과 평행한 접선이 반드시 존재한다는 정리다.&lt;/p>
&lt;p>어떤 단계 &lt;span class="math math-inline">\(n\)&lt;/span>에서의 추측값 &lt;span class="math math-inline">\(x_n\)&lt;/span>과 &lt;span class="math math-inline">\(x^*\)&lt;/span> 사이의 오차를&lt;br>
&lt;span class="math math-inline">\(e_n=x_n-x^*\)&lt;/span>라고 정의하자.&lt;br>
그럼 다음 단계의 오차 &lt;span class="math math-inline">\(e_{n&amp;#43;1}\)&lt;/span>은 다음과 같이 정의된다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[e_{n&amp;#43;1}=x_{n&amp;#43;1}-x^*=g(x_n)-g(x^*)\]&lt;/div>&lt;p>이때, 평균값 정리에 따라 &lt;span class="math math-inline">\(x_n\)&lt;/span>과 &lt;span class="math math-inline">\(x^*\)&lt;/span> 사이의 어떤 점 &lt;span class="math math-inline">\(c\)&lt;/span>에 대해 다음이 성립한다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[g(x_n)-g(x^*)=g&amp;#39;(c)(x_n-x^*)\]&lt;/div>&lt;p>이를 위의 오차에 대입하면,&lt;br>
&lt;/p>
&lt;div class="math math-block">\[e_{n&amp;#43;1}=g&amp;#39;(c)\cdot e_n\]&lt;/div>&lt;p>&lt;br>
마지막으로 위 식의 양변에 절댓값을 취하면&lt;br>
&lt;/p>
&lt;div class="math math-block">\[|e_{n&amp;#43;1}|=|g&amp;#39;(c)|\cdot |e_n|\]&lt;/div>&lt;p>이게 무슨 뜻이냐.&lt;br>
만약 &lt;span class="math math-inline">\(|g&amp;#39;(x)|&amp;lt;1\)&lt;/span>이라면, &lt;span class="math math-inline">\(|g&amp;#39;(c)|\)&lt;/span> 는 1보다 작은 어떤 &lt;span class="math math-inline">\(k\)&lt;/span>가 된다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[|e_{n&amp;#43;1}| = k\cdot |e_n|\]&lt;/div>&lt;p>&lt;br>
즉 위와 같은 관계가 되어 오차가 매 단계 &lt;span class="math math-inline">\(k\)&lt;/span>배씩 줄어든다.&lt;/p>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">숫자로 확인해보기&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>우리 &lt;span class="math math-inline">\(g(x)=e^{\ln 16/(x&amp;#43;1)}\)&lt;/span>의 도함수는 &lt;span class="math math-inline">\(g&amp;#39;(x)=-\frac{\ln 16}{(x&amp;#43;1)^2}\,g(x)\)&lt;/span>이고, 해 근처에서 &lt;span class="math math-inline">\(g&amp;#39;(x^*)\approx-0.58\)&lt;/span>이다. 절댓값이 1보다 작으니 수렴하고, &lt;strong>부호가 음수&lt;/strong>라서 매번 반대편으로 넘어간다 — 그래서 위에서 본 것처럼 2.3168, 2.3070, 2.3127, … 하고 위아래로 진동(나선형 수렴)한 것이다. 오차가 매 단계 약 0.58배씩만 줄어드니(선형 수렴), 자릿수가 매 단계 두 배가 되는 Newton과 속도 차이가 어마어마하다. 아래 그림이 그 차이다.&lt;/p>
&lt;p>이 원리를 완비거리공간에서 일반화한 것이 &lt;strong>바나흐 고정점 정리(Banach fixed-point theorem)&lt;/strong> 이고, 미분방정식 해의 존재성 증명(Picard 반복)부터 강화학습의 Bellman 연산자 수렴 증명까지 온갖 곳에서 같은 논리가 반복된다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/fig-convergence.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>세 방법 모두 같은 답으로 가지만, 오차가 줄어드는 속도는 전혀 다르다. 로그 축에서 직선이면 선형 수렴, 아래로 꺾여 떨어지면 이차 수렴.&lt;/p>
&lt;/blockquote>&lt;h2 id="5-conclusion">5. Conclusion&lt;/h2>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/CleanShot%202025-10-10%20at%2001.11.19@2x.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>Desmos로 그려본 &lt;span class="math math-inline">\(y=x^{x&amp;#43;1}\)&lt;/span>과 &lt;span class="math math-inline">\(y=16\)&lt;/span>의 교점. &lt;span class="math math-inline">\(x\approx2.31057\)&lt;/span>.&lt;/p>
&lt;/blockquote>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>방법&lt;/th>
&lt;th>필요한 것&lt;/th>
&lt;th>반복 몇 번에 소수 5자리?&lt;/th>
&lt;th>한 줄 요약&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Lambert W (&lt;span class="math math-inline">\(W_1\)&lt;/span>)&lt;/td>
&lt;td>표기법&lt;/td>
&lt;td>— (닫힌 식은 나오지만 계산은 못 함)&lt;/td>
&lt;td>답의 &amp;lsquo;이름&amp;rsquo;을 붙여줌&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Newton-Raphson&lt;/td>
&lt;td>&lt;span class="math math-inline">\(f\)&lt;/span>, &lt;span class="math math-inline">\(f&amp;#39;\)&lt;/span>&lt;/td>
&lt;td>2번&lt;/td>
&lt;td>접선의 &lt;span class="math math-inline">\(x\)&lt;/span>절편으로 점프, 이차 수렴&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>고정점 반복&lt;/td>
&lt;td>잘 고른 &lt;span class="math math-inline">\(g\)&lt;/span>&lt;/td>
&lt;td>약 15번&lt;/td>
&lt;td>축소사상이면 수렴, 선형 수렴&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>이분법&lt;/td>
&lt;td>부호가 바뀌는 구간&lt;/td>
&lt;td>약 18번&lt;/td>
&lt;td>느리지만 절대 안 망함&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Newton-Raphson도, 고정점 반복도, Desmos도 전부 같은 곳(&lt;span class="math math-inline">\(x\approx2.3106\)&lt;/span>)을 가리킨다.&lt;br>
모르는 걸 알게 되어서 기분은 좋았다.&lt;br>
근데 내 두 시간은 어디 갔지?&lt;/p>
&lt;h2 id="참고-자료">참고 자료&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Lambert_W_function" target="_blank" rel="noopener noreferrer">Lambert W function — Wikipedia&lt;/a>: 가지 구조, 급수 전개, 어디에 쓰이는지 총정리.&lt;/li>
&lt;li>István Mező, Árpád Baricz, &lt;a href="https://arxiv.org/abs/1408.3999" target="_blank" rel="noopener noreferrer">&lt;em>On the generalization of the Lambert W function&lt;/em>&lt;/a>, Trans. Amer. Math. Soc. 369 (2017). &lt;span class="math math-inline">\(xe^x&amp;#43;rx=a\)&lt;/span>의 해 &lt;span class="math math-inline">\(W_r(a)\)&lt;/span> — 이 글의 &lt;span class="math math-inline">\(W_p\)&lt;/span>가 정확히 이것.&lt;/li>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/Newton%27s_method" target="_blank" rel="noopener noreferrer">Newton&amp;rsquo;s method — Wikipedia&lt;/a>, &lt;a href="https://en.wikipedia.org/wiki/Fixed-point_iteration" target="_blank" rel="noopener noreferrer">Fixed-point iteration — Wikipedia&lt;/a>, &lt;a href="https://en.wikipedia.org/wiki/Banach_fixed-point_theorem" target="_blank" rel="noopener noreferrer">Banach fixed-point theorem — Wikipedia&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.lambertw.html" target="_blank" rel="noopener noreferrer">&lt;code>scipy.special.lambertw&lt;/code>&lt;/a>: 표준 Lambert W를 파이썬에서 바로 계산할 때. (&lt;span class="math math-inline">\(x^x=a\)&lt;/span> 같은 문제는 &lt;span class="math math-inline">\(x=\ln a/W(\ln a)\)&lt;/span>로 닫힌 식이 나온다.)&lt;/li>
&lt;/ul></content:encoded></item><item><title>선형대수학 1강. 벡터 공간</title><link>https://dirac042.github.io/posts/linear-algebra-1.-vector-spaces/</link><pubDate>Thu, 17 Jul 2025 00:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/linear-algebra-1.-vector-spaces/</guid><category>LinAlg</category><description>벡터 벡터란 크기(Magnitude)와 방향(Direction)이 정의된 값을 말합니다. ex. 왼쪽(Direction)으로 2만큼(Magnitude) 움직였다 = 벡터</description><content:encoded>&lt;h2 id="벡터">벡터&lt;/h2>
&lt;p>벡터란 크기(Magnitude)와 방향(Direction)이 정의된 값을 말합니다.&lt;/p>
&lt;p>&lt;em>ex. 왼쪽(Direction)으로 2만큼(Magnitude) 움직였다 = 벡터&lt;/em>&lt;/p>
&lt;p>모든 벡터는 다음 두 성질을 지닙니다.&lt;/p>
&lt;h3 id="1-벡터의-합-vector-addition">1. 벡터의 합 (Vector Addition)&lt;/h3>
&lt;div class="math math-block">\[\vec{z} = \vec{x} &amp;#43; \vec{y}\]&lt;/div>&lt;p>&lt;br>
벡터끼리 서로 더할 수 있으며, 주로 평행사변형을 그려 계산합니다.&lt;/p>
&lt;h3 id="2-스칼라와-벡터의-곱-scalar-multiplication">2. 스칼라와 벡터의 곱 (Scalar Multiplication)&lt;/h3>
&lt;div class="math math-block">\[t\vec{a}=t\cdot \vec{a}\]&lt;/div>&lt;p>&lt;br>
벡터는 스칼라와 곱해질 수 있습니다. 이 때, &lt;span class="math math-inline">\(t\)&lt;/span> 가 음수이면 벡터의 방향이 반대가 됩니다.&lt;/p>
&lt;hr>
&lt;h2 id="벡터선형-공간">벡터(선형) 공간&lt;/h2>
&lt;p>정의: 장 &lt;span class="math math-inline">\(F\)&lt;/span> 위의 공간 &lt;span class="math math-inline">\(V\)&lt;/span> 가 다음과 같은 성질을 만족할 때, 이를 벡터 공간이라고 합니다.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;span class="math math-inline">\(V\)&lt;/span> 안의 임의의 원소 &lt;span class="math math-inline">\(\vec{x}\)&lt;/span>, &lt;span class="math math-inline">\(\vec{y}\)&lt;/span> 가 &lt;span class="math math-inline">\(\vec{x} &amp;#43; \vec{y}\)&lt;/span> 가 &lt;span class="math math-inline">\(V\)&lt;/span> 안에 존재한다.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;span class="math math-inline">\(V\)&lt;/span> 안의 임의의 원소 &lt;span class="math math-inline">\(\vec{x}\)&lt;/span> 와 &lt;span class="math math-inline">\(F\)&lt;/span> 안의 임의의 원소 &lt;span class="math math-inline">\(t\)&lt;/span> 에 대해 &lt;span class="math math-inline">\(t\vec{x}\)&lt;/span> 가 &lt;span class="math math-inline">\(V\)&lt;/span> 안에 존재한다.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>(위에서 본 벡터의 두가지 성질과 일치합니다.)&lt;/p>
&lt;p>즉, 우리는 이렇게 다시 말할 수 있습니다.&lt;/p>
&lt;p>&lt;strong>벡터 공간이란, 벡터합과 스칼라곱에 대해 닫혀있는 (Closed) 모든 집합을 말한다.&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>Q. &amp;lsquo;닫혀있다 (Closed)&amp;lsquo;라는건 무슨 뜻일까요?&lt;br>
A. 어떤 집합에서 임의의 원소를 이용해 계산을 했을 때, 그 &lt;strong>계산 결과가 집합 안에 포함되어 있을 때&lt;/strong>, 이를 &amp;lsquo;닫혀있다&amp;rsquo; 라고 표현합니다.&lt;br>
ex. &lt;span class="math math-inline">\(\mathbb{R}\)&lt;/span> : 실수 전체의 집합이라고 했을 때 모든 &lt;span class="math math-inline">\(a, b \in \mathbb{R}\)&lt;/span> 에 대해 &lt;span class="math math-inline">\(a&amp;#43;b \in \mathbb{R}\)&lt;/span>, 즉 두 수를 더했을 때 그 결과를 &lt;span class="math math-inline">\(\mathbb{R}\)&lt;/span> 안에서 찾을 수 있습니다.&lt;br>
이 때, 공간 &lt;span class="math math-inline">\(\mathbb{R}\)&lt;/span>은 &lt;span class="math math-inline">\(a&amp;#43;b\)&lt;/span> 연산(덧셈)에 대해 &lt;strong>닫혀있다&lt;/strong> 라고 합니다.&lt;/p>
&lt;/blockquote>&lt;p>벡터 공간에는 다음과 같은 성질이 존재합니다. (복잡해보이지만 매우 간단하고 자명합니다.)&lt;/p>
&lt;ol>
&lt;li>모든 &lt;span class="math math-inline">\(x, y \in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\(x&amp;#43;y = y&amp;#43;x\)&lt;/span>. (덧셈의 교환법칙)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(x, y, z \in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\((x&amp;#43;y)&amp;#43;z = x&amp;#43;(y&amp;#43;z)\)&lt;/span>. (덧셈의 결합법칙)&lt;/li>
&lt;li>&lt;span class="math math-inline">\(x&amp;#43;\mathbb{0}=x\)&lt;/span>를 만족하는 &lt;span class="math math-inline">\(\mathbb{0}\)&lt;/span>이 &lt;span class="math math-inline">\(V\)&lt;/span>에 존재. (원소 0)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(x \in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\(x&amp;#43;y = \mathbb{0}\)&lt;/span>을 만족하는 &lt;span class="math math-inline">\(y\)&lt;/span>가 &lt;span class="math math-inline">\(V\)&lt;/span>에 존재. (음수인 원소)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(x\in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\(1x=x\)&lt;/span>. (1과의 곱셈)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(a, b \in F\)&lt;/span>와 &lt;span class="math math-inline">\(x \in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\((ab)x=a(bx)\)&lt;/span>. (곱셈의 결합법칙)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(a \in F\)&lt;/span>와 &lt;span class="math math-inline">\(x, y\in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\(a(x&amp;#43;y) = ax &amp;#43; ay\)&lt;/span>. (스칼라의 분배법칙)&lt;/li>
&lt;li>모든 &lt;span class="math math-inline">\(a, b \in F\)&lt;/span>와 &lt;span class="math math-inline">\(x \in V\)&lt;/span>에 대해 &lt;span class="math math-inline">\((a&amp;#43;b)x = ax &amp;#43; bx\)&lt;/span>. (벡터의 분배법칙)&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>Q. 장 &lt;span class="math math-inline">\(F\)&lt;/span>란 무엇인가요?&lt;br>
A. 수학에서 &lt;span class="math math-inline">\(F\)&lt;/span>(Field)란, &lt;strong>연산 가능한 모든 수의 집합&lt;/strong>을 말합니다. &lt;span class="math math-inline">\(\mathbb{R}\)&lt;/span>라고 생각하셔도 괜찮습니다.&lt;br>
부가설명: &lt;span class="math math-inline">\(F\)&lt;/span>는 &amp;lsquo;모든 스칼라들의 세계&amp;rsquo;라고 표현할 수 있습니다.&lt;br>
ex. &lt;span class="math math-inline">\(\mathbb{R} \in F\)&lt;/span>, &lt;span class="math math-inline">\(\mathbb{C}\in F\)&lt;/span> (복소수), &lt;span class="math math-inline">\(\mathbb{F}_{p}\in F\)&lt;/span> (유한체)&lt;/p>
&lt;/blockquote>&lt;hr>
&lt;h2 id="벡터-공간의-예시">벡터 공간의 예시&lt;/h2>
&lt;p>지금부터는 대표적인 벡터 공간들과 그 특징들에 대해 알아보겠습니다.&lt;/p>
&lt;p>사실상 제일 중요한 부분이며, 우리의 목표는&lt;br>
&lt;strong>&amp;lsquo;대부분의 문제는 벡터 공간으로 표현 가능하다&amp;rsquo;&lt;/strong>&lt;br>
는 것을 이해하는 것입니다.&lt;/p>
&lt;hr>
&lt;h3 id="n-tuples-n-튜플">n-tuples (n-튜플)&lt;/h3>
&lt;p>n-tuple이란, n개의 실수가 모여있는 집합을 말합니다.&lt;/p>
&lt;div class="math math-block">\[\mathbb{R}^n = \{x_1,x_2, \dots,x_n\}\]&lt;/div>&lt;p>이 때, &lt;strong>n-tuple은 벡터 공간&lt;/strong>입니다.&lt;/p>
&lt;p>Proof:&lt;/p>
&lt;ol>
&lt;li>&lt;span class="math math-inline">\((x_1, \dots, x_n) &amp;#43; (y_1, \dots, y_n) = (x_1&amp;#43;y_1, \dots , x_n&amp;#43;y_n)\)&lt;/span>&lt;/li>
&lt;li>&lt;span class="math math-inline">\(c(x_1, \dots, x_n) = (cx_1, \dots, cx_n)\)&lt;/span>&lt;br>
즉, 덧셈과 스칼라곱에 대해 닫혀있습니다.&lt;/li>
&lt;/ol>
&lt;p>우리는 선형대수학을 배우면서 이 n-tuples에 대한 계산을 많이 다루게 될 것입니다.&lt;/p>
&lt;p>특히, 이 n-tuples들은 모든 원소를 가로로 적은 Column Vector의 형태로 표현합니다.&lt;br>
&lt;/p>
&lt;div class="math math-block">\[\mathbb{R}^n=(x_1, x_2, \dots,x_n)^T\]&lt;/div>&lt;hr>
&lt;h3 id="복소수집합-complex-numbers">복소수집합 (Complex Numbers)&lt;/h3>
&lt;p>모든 복소수 &lt;span class="math math-inline">\(a&amp;#43;bi\)&lt;/span> 가 모인 집합 &lt;span class="math math-inline">\(\mathbb{C}\)&lt;/span>은 벡터공간입니다.&lt;/p>
&lt;p>Proof:&lt;br>
1. &lt;span class="math math-inline">\((a&amp;#43;bi) &amp;#43; (c&amp;#43;di) = (a&amp;#43;c) &amp;#43; (b&amp;#43;d)i\)&lt;/span>&lt;br>
2. &lt;span class="math math-inline">\(t(a&amp;#43;bi) = at&amp;#43;bti\)&lt;/span>&lt;br>
즉, 덧셈과 스칼라곱에 대해 닫혀있습니다.&lt;/p>
&lt;p>여기서 중요한 것은, &lt;strong>&lt;span class="math math-inline">\(\mathbb{C}\)&lt;/span>는 특히 &lt;span class="math math-inline">\(\mathbb{R}^2\)&lt;/span> 위의 벡터 공간&lt;/strong>이라는 점입니다.&lt;/p>
&lt;p>즉, 모든 복소수는 벡터의 형태로 표현할 수 있습니다.&lt;br>
&lt;strong>복소평면(Argand Plane)&lt;/strong> 은 이 특징에서 시작됩니다.&lt;/p>
&lt;hr>
&lt;h3 id="다항식-polynomials">다항식 (Polynomials)&lt;/h3>
&lt;h4 id="1-최고차가-n차인-다항식">1. 최고차가 n차인 다항식&lt;/h4>
&lt;p>&lt;span class="math math-inline">\(x\)&lt;/span>를 변수로 가지는, 최고차가 n차인 다항식의 집합을 &lt;span class="math math-inline">\(P_n(\mathbb{R})\)&lt;/span>이라고 정의합시다. 즉,&lt;/p>
&lt;div class="math math-block">\[P_n({\mathbb{R}}) = a_nx^n&amp;#43;a_{n-1}x^{n-1}&amp;#43;\dots&amp;#43;a_1x&amp;#43;a_0\]&lt;/div>&lt;p>이 때, &lt;strong>&lt;span class="math math-inline">\(P_n(\mathbb{R})\)&lt;/span>은 벡터공간&lt;/strong>입니다. 즉, 덧셈과 스칼라곱에 대해 닫혀있습니다.&lt;br>
(증명은 생략하겠습니다. 직접 해보시기 바랍니다.)&lt;/p>
&lt;p>여기서 중요한 점은, &lt;strong>&lt;span class="math math-inline">\(P_n(\mathbb{R})\)&lt;/span>는 &lt;span class="math math-inline">\(\mathbb{R}^{n&amp;#43;1}\)&lt;/span>과 동형(Isomorphic)&lt;/strong> 이라는 것입니다.&lt;/p>
&lt;p>즉, 모든 n차 다항식은 (n+1)차원 벡터라고 생각해도 된다는 뜻입니다.&lt;/p>
&lt;p>(선형대수의 꽃인 행렬을 소개할 때 연립방정식이 나오는 이유가 이 곳에 있습니다.)&lt;/p>
&lt;blockquote>
&lt;p>Q. 동형(Isomorphic)이 무엇인가요?&lt;br>
A. 쉽게 설명하자면, 서로 같은(동) 형태(형)를 가진다는 뜻입니다.&lt;br>
정확한 정의를 보면 이러합니다:&lt;br>
어떤 벡터공간 &lt;span class="math math-inline">\(V\)&lt;/span>, &lt;span class="math math-inline">\(W\)&lt;/span>가 서로 일대일대응이며, 덧셈과 스칼라곱에 대해 닫혀있는 선형변환이 두 공간 사이에 존재할 때, 이 두 공간이 서로 &amp;lsquo;동형&amp;rsquo;이라고 말합니다.&lt;br>
즉, &lt;span class="math math-inline">\(v \in V\)&lt;/span>, &lt;span class="math math-inline">\(w \in W\)&lt;/span>, &lt;span class="math math-inline">\(c\in \mathbb{R}\)&lt;/span>에 대해:&lt;br>
1. &lt;span class="math math-inline">\(f(v&amp;#43;w)=f(v)&amp;#43;f(w)\)&lt;/span>, &lt;span class="math math-inline">\(f(cu)=cf(u)\)&lt;/span> (Linear)&lt;br>
2. 서로 Bijection (Surjective + Injective)가 성립 &lt;br>
다음 두 조건이 성립하면 &lt;span class="math math-inline">\(V\)&lt;/span>와 &lt;span class="math math-inline">\(W\)&lt;/span>는 동형입니다.&lt;/p>
&lt;/blockquote>&lt;h4 id="2-차수의-상관-없이-모든-형태의-다항식">2. (차수의 상관 없이) 모든 형태의 다항식&lt;/h4>
&lt;p>최고차에 상관없이 모든 다항식 종류의 집합을 &lt;span class="math math-inline">\(P(\mathbb{R})\)&lt;/span>라고 정의합시다. 즉,&lt;/p>
&lt;div class="math math-block">\[P(\mathbb{R})=\bigcup\limits_{n=0}^{\infty}P_n(\mathbb{R})\]&lt;/div>&lt;p>&lt;br>
이 때, &lt;span class="math math-inline">\(P(\mathbb{R})\)&lt;/span>은 벡터공간입니다.&lt;/p>
&lt;p>(물론 &lt;span class="math math-inline">\(P_n(\mathbb{R})\)&lt;/span> 보다는 사이즈가 훨씬 큰, 무한한 벡터공간(차수가 무한대일 수 있으므로)입니다.)&lt;/p>
&lt;hr>
&lt;h3 id="함수">함수&lt;/h3>
&lt;p>위에서는 함수의 굉장히 작은 예시에 불과한 다항식이 벡터공간임을 보였습니다.&lt;/p>
&lt;p>이제는 더욱 더 넓은, &lt;span class="math math-inline">\(x&amp;#43;\text{sin}(x)\)&lt;/span> 같은 모든 함수를 기준으로 벡터공간인지 확인해봅시다.&lt;/p>
&lt;h4 id="1-모든-연속함수의-집합">1. 모든 연속함수의 집합&lt;/h4>
&lt;p>모든 연속함수가 모인 집합을 &lt;span class="math math-inline">\(C(\mathbb{R})\)&lt;/span>라고 정의합시다. 이 때, 이 집합은 벡터공간입니다.&lt;/p>
&lt;p>(증명: 일반화로 증명하는 것은 어렵기에, &lt;span class="math math-inline">\(x&amp;#43;\text{sin}(x)\)&lt;/span>와 같은 예시로 확인해보는 것을 추천드립니다.)&lt;/p>
&lt;p>이 또한 &lt;span class="math math-inline">\(P(\mathbb{R})\)&lt;/span>와 마찬가지로 무한한 벡터공간입니다. (하지만 크기는 더욱 더 큽니다)&lt;/p>
&lt;p>이를 &lt;em>셀 수 있는 무한함 (Countably Infinite)&lt;/em> 이라고 표현합니다.&lt;/p>
&lt;h4 id="2-정의역이-정의된-모든-연속함수의-집합">2. 정의역이 정의된 모든 연속함수의 집합&lt;/h4>
&lt;p>모든 연속함수의 집합은 벡터공간이므로, 정의역이 특수하게 정의된 연속함수들은 어떨까요?&lt;/p>
&lt;p>예를 들어, &lt;span class="math math-inline">\(y=x\)&lt;/span>와 &lt;span class="math math-inline">\(y=|x|\)&lt;/span>는 엄연히 다른 함수입니다. 그러나 두 함수의 정의역이 &lt;span class="math math-inline">\(0 \lt x \lt 1\)&lt;/span>라면, 두 함수는 완전히 동일해집니다.&lt;/p>
&lt;p>정의역이 &lt;span class="math math-inline">\(a \lt x \lt b\)&lt;/span>으로 주어진 모든 연속함수의 집합을 &lt;span class="math math-inline">\(C([a, b])\)&lt;/span>라고 표현합시다.&lt;/p>
&lt;p>이 때, &lt;span class="math math-inline">\(C([a, b])\)&lt;/span>는 벡터공간입니다.&lt;/p>
&lt;h4 id="3-모든-함수의-집합">3. 모든 함수의 집합&lt;/h4>
&lt;p>2번을 통해 우리는 모든 함수 (연속이든 아니든)를 정의할 수 있습니다.&lt;/p>
&lt;p>모든 함수들의 집합을 &lt;span class="math math-inline">\(\mathcal{F}(\mathbb{R}, \mathbb{R})\)&lt;/span> 라고 정의합시다.&lt;/p>
&lt;p>이 집합은 이런 이상한 함수도 들어갈 수 있습니다.&lt;/p>
&lt;div class="math math-block">\[f(x) = 1 \text{ if }x\in\mathbb{Q}\text{, 0 if }x\notin\mathbb{Q}\]&lt;/div></content:encoded></item><item><title>나만의 블로그 만들기 1. HUGO와 친해지기</title><link>https://dirac042.github.io/posts/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1.-hugo%EC%99%80-%EC%B9%9C%ED%95%B4%EC%A7%80%EA%B8%B0/</link><pubDate>Wed, 16 Jul 2025 00:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-1.-hugo%EC%99%80-%EC%B9%9C%ED%95%B4%EC%A7%80%EA%B8%B0/</guid><category>Blog</category><category>Coding</category><description>Preparation 이 블로그 포스트는 다음 패키지를 설치되었다는 가정 하에 작성되었습니다. Git (2.50.0) Go (1.24.5) (MacOS에서는 homebrew를 통해 쉽게 설치가 가능합니다.) HUGO 소개 HUGO 메인 페이지</description><content:encoded>&lt;h2 id="preparation">Preparation&lt;/h2>
&lt;p>이 블로그 포스트는 다음 패키지를 설치되었다는 가정 하에 작성되었습니다.&lt;/p>
&lt;ul>
&lt;li>Git (2.50.0)&lt;/li>
&lt;li>Go (1.24.5)&lt;/li>
&lt;/ul>
&lt;p>(MacOS에서는 homebrew를 통해 쉽게 설치가 가능합니다.)&lt;/p>
&lt;h2 id="hugo-소개">HUGO 소개&lt;/h2>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/Pasted%20image%2020250716150210.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>HUGO 메인 페이지&lt;/p>
&lt;/blockquote>&lt;p>.md 파일을 자동으로 .html로 만드는 것은 굉장히 힘든 작업입니다. 이 작업을 쉽게 만들기 위해 우리는 정적 웹사이트 생성기 중 하나인 HUGO를 사용합니다.&lt;/p>
&lt;p>HUGO는 .md 포스트들을 .html로 변환하는 일 뿐만 아니라 다양한 블로그 테마를 쉽게 다운로드하여 수정할 수 있게 합니다. 또한 블로그의 Deploy나 기타 작업이 굉장히 빠르고 단순하여 프로그래밍을 모르는 사람들도 나만의 블로그를 쉽게 만들 수 있습니다.&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>Hugo를 직접 다운로드 해봅시다.&lt;/p>
&lt;h4 id="1-windows">1. Windows&lt;/h4>
&lt;p>(Youtube 참고)&lt;/p>
&lt;h4 id="2-macos">2. MacOS&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-zsh" data-lang="zsh">&lt;span class="line">&lt;span class="cl">brew install hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>homebrew 패키지 매니저를 이용해 다운로드 받습니다.&lt;/p>
&lt;h4 id="3-linux">3. Linux&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">sudo apt install hugo &lt;span class="c1"># Debian&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo pacman install hugo &lt;span class="c1"># Arch&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>사용하는 Distro의 패키지 매니저를 이용해 다운로드 받습니다.&lt;/p>
&lt;p>(Linux를 사용하신다면 더 이상의 설명은 필요 없으리라 생각합니다.)&lt;/p>
&lt;h2 id="create-blog-folder">Create Blog Folder&lt;/h2>
&lt;p>진행하기 전, HUGO가 제대로 설치되었는지 확인해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">hugo version &lt;span class="c1"># 버전명이 나오면 정상적으로 설치됨.&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 우리가 블로그 포스트 등을 저장할 폴더로 shell을 이동해줍니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 저는 macos를 사용중이며, 저장하기 쉽게 Desktop에 파일을 저장해두었습니다.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/Desktop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이제 HUGO를 이용해 블로그 웹사이트를 만들어봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># hugo new site [블로그 이름]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hugo new site dirac042
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>블로그가 생성되었습니다! 이제 파일이 어떤 구조로 이루어져 있는지 확인해봅시다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> dirac042 &lt;span class="c1"># 방금 생성한 블로그 이름&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ls
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="blog-folders">Blog Folders&lt;/h2>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/Pasted%20image%2020250716151913.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>필자의 블로그 폴더&lt;/p>
&lt;/blockquote>&lt;p>생성된 블로그 폴더의 역할을 간략하게 알아봅시다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>archetypes&lt;/strong>: 마크다운 타입의 문서에서 읽어오는 기본 틀에 대한 정의파일이 있습니다.&lt;/li>
&lt;li>&lt;strong>content&lt;/strong>: 제일 중요한 파일이며, 여러분들이 obsidian으로 만드는 문서들이 이 곳으로 .md 형태로 들어갑니다.&lt;/li>
&lt;li>&lt;strong>public&lt;/strong>: 웹사이트의 중요한 파일들이 이곳에 들어갑니다.&lt;/li>
&lt;li>&lt;strong>static&lt;/strong>: obsidian에서 첨부된 이미지들이 이곳으로 들어갑니다.&lt;/li>
&lt;li>&lt;strong>themes&lt;/strong>: hugo에서 설치한 테마들이 이곳으로 들어갑니다.&lt;/li>
&lt;/ol>
&lt;h2 id="git-init">Git Init&lt;/h2>
&lt;p>블로그의 테마를 설치하기 전에, git의 initialization을 해줘야합니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>(이 블로그 포스트는 여러분들이 이미 git의 설정을 완료했다는 가정하에 서술됩니다. 만약 여러분이 git 사용이 처음이시라면, git 사용법을 읽고 따라해 보시는 것을 권장드립니다.)&lt;/p>
&lt;p>&lt;strong>!주의: 이 커맨드는 현재 shell이 블로그 폴더 안에 들어가있어야 합니다!&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">pwd&lt;/span> &lt;span class="c1"># 현재 shell 위치 확인&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ex. ~/Desktop/dirac042&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="installing-hugo-themes">Installing HUGO Themes&lt;/h2>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/CleanShot%202025-07-16%20at%2015.35.36@2x.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>HUGO Themes 웹사이트&lt;/p>
&lt;/blockquote>&lt;p>&lt;a href="https://themes.gohugo.io/" target="_blank" rel="noopener noreferrer">HUGO Themes&lt;/a>에서는 유저들이 HUGO로 만든 다양한 웹사이트 테마를 제공합니다.&lt;br>
이 곳에서 마음에 드는 테마를 다운로드 받으면 곧바로 내 블로그에서 사용할 수 있습니다.&lt;/p>
&lt;p>마음에 드는 테마를 발견했다면 download 아이콘을 눌러봅시다.&lt;br>
대부분의 모드는 github submodule을 이용한 설치를 지원합니다.&lt;/p>
&lt;aside class="callout callout-note">
&lt;p class="callout-title">Github Submodule이란?&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>git에서 제공하는 모듈 중 하나로, 어떤 특정 파일을 git 안에 넣고, 그 파일을 git을 통해 계속 업데이트 시킬 수 있는 방법 중 하나다.&lt;/p>
&lt;/div>
&lt;/aside>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 예시 테마: Papermod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git submodule add --depth&lt;span class="o">=&lt;/span>&lt;span class="m">1&lt;/span> https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>이렇게 submodule을 이용하면, 테마 제작자가 업데이트를 진행할 때, 쉽게 커맨드 하나로 업데이트 시켜줄 수 있습니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">git submodule update --init --recursive
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;aside class="callout callout-warning">
&lt;p class="callout-title">주의: Submodule를 받으면 안 되는 사람들&lt;br>&lt;/p>
&lt;div class="callout-body">
&lt;p>만약 내가 다운로드 받은 블로그 테마를 수정하고 싶으면, submodule를 이용하는 것을 추천하지 않는다. (나중에 submodule로 받은 파일을 해제하고 다시 넣어야할 수 있음.)&lt;br>
필자는 블로그의 색 테마 수정을 위해 submodule를 해제하는 작업을 거쳤는데, 매우 귀찮은 작업이었다.&lt;br>
이런 사람들은 github 사이트에서 직접 release된 파일을 다운로드 받아 옮겨주거나 (제일 확실함), git으로 clone해서 rm -rf git을 통해 git을 해제하는 방법으로 테마를 다운로드 받아주자.&lt;/p>
&lt;/div>
&lt;/aside>&lt;h2 id="deploy">Deploy&lt;/h2>
&lt;p>HUGO와 테마까지 모두 받았으면, 이제 테스트를 위해 한번 Deploy를 시켜봅시다.&lt;br>
shell이 블로그 폴더에 있는 상태에서 다음의 명령어를 사용하면 됩니다.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">hugo server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>그러면 굉장히 빠른 속도로 localhost에서 로컬파일을 이용해 블로그가 만들어집니다.&lt;br>
기본적으로 1313포트에서 생성되므로, http://localhost:1313 에 들어가 자신의 블로그를 확인해보도록 합시다.&lt;/p>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/CleanShot%202025-07-16%20at%2015.47.55@2x.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>필자의 블로그 구동 화면 (localhost)&lt;/p>
&lt;/blockquote>&lt;p>이런 식으로 테마와 블로그가 제대로 나온다면, 축하드립니다!&lt;br>
여러분만의 블로그가 성공적으로 제작되었습니다.&lt;/p></content:encoded></item><item><title>나만의 블로그 만들기 0. 내가 블로그를 만드는 이유</title><link>https://dirac042.github.io/posts/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-0.-%EB%82%98%EC%9D%98-%EC%83%9D%EA%B0%81%EC%9D%84-%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A1%9C-%ED%91%9C%ED%98%84%ED%95%B4%EB%B3%B4%EC%9E%90/</link><pubDate>Wed, 16 Jul 2025 00:00:00 +0900</pubDate><guid>https://dirac042.github.io/posts/%EB%82%98%EB%A7%8C%EC%9D%98-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-0.-%EB%82%98%EC%9D%98-%EC%83%9D%EA%B0%81%EC%9D%84-%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A1%9C-%ED%91%9C%ED%98%84%ED%95%B4%EB%B3%B4%EC%9E%90/</guid><category>Blog</category><category>Coding</category><description>Motivation Second Brain 혹시 Tiago Forte의 Second Brain이라는 책을 읽어본 적이 있나요? 티아고 포르테의 &lt;세컨드 브레인> 한국에서는 &lt;세컨드 브레인>이라는 제목으로 번역되었습니다. 사실 한국보다는 미국권에서 굉장히 유명한 책입니다. 지식, 공부 관련 유튜버가 소개하는 내용들이 거의 모두 이 책에서 왔다고 해도 과언이 아닐 것입니다. 그 정도로 정보 정리에 있어서는 거의 ‘바이블’이라고 불릴 정도로 유명하고 유용한 책입니다.</description><content:encoded>&lt;h2 id="motivation">Motivation&lt;/h2>
&lt;h3 id="second-brain">Second Brain&lt;/h3>
&lt;p>혹시 Tiago Forte의 Second Brain이라는 책을 읽어본 적이 있나요?&lt;br>
&lt;img src="https://dirac042.github.io/images/9791165347048.jpg" alt="Image Description" loading="lazy" decoding="async">&lt;/p>
&lt;blockquote>
&lt;p>티아고 포르테의 &amp;lt;세컨드 브레인&amp;gt;&lt;/p>
&lt;/blockquote>&lt;p>한국에서는 &amp;lt;세컨드 브레인&amp;gt;이라는 제목으로 번역되었습니다. 사실 한국보다는 미국권에서 굉장히 유명한 책입니다. 지식, 공부 관련 유튜버가 소개하는 내용들이 거의 모두 이 책에서 왔다고 해도 과언이 아닐 것입니다. 그 정도로 정보 정리에 있어서는 거의 &amp;lsquo;바이블&amp;rsquo;이라고 불릴 정도로 유명하고 유용한 책입니다.&lt;/p>
&lt;p>이 책에서 나오는 &amp;lsquo;제 2의 뇌&amp;rsquo;를 만드는 방법으로 저자는 4단계의 방식을 소개합니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Capture&lt;/strong>: 내가 중요하다고 생각되는 것을 적기&lt;/li>
&lt;li>&lt;strong>Organize&lt;/strong>: 적은 메모들을 정리하기&lt;/li>
&lt;li>&lt;strong>Distill&lt;/strong>: 메모들에서 중요한 정보(Essence)를 찾기&lt;/li>
&lt;li>&lt;strong>Express&lt;/strong>: 이해한 정보들을 설명하며 창조하기&lt;/li>
&lt;/ol>
&lt;p>이 4가지 단계 중에서 1단계 ~ 3단계는 책을 읽기 전에도 실천하고 있었습니다. 특히 저는 Obsidian(옵시디언)이라는 앱에 흥미를 느끼게 되었고, 내가 생각하고 느낀 모든 것들은 이 프로그램을 통해 관리되고 있습니다. (추후에 옵시디언 사용법과 관련해 블로그 포스트를 적어볼 예정입니다.)&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Capture&lt;/strong>: 살면서 갑자기 떠오르는 아이디어나, 대화를 통해 얻은 지식들은 노트와 연필로 직접 적는다.&lt;/li>
&lt;li>&lt;strong>Organize&lt;/strong>: 노트에 적은 것들을 Obsidian으로 옮긴다. 만들어진 문서는 카테고리화 되어 정리된다.&lt;/li>
&lt;li>&lt;strong>Distill&lt;/strong>: 옵시디언에 정리된 것들을 읽어보며 위에 Summary 칸을 만들어 미래의 내가 한눈에 볼 수 있도록 요약한다.&lt;/li>
&lt;/ol>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/CleanShot%202025-07-16%20at%2022.10.40@2x.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>필자의 Obsidian 작업 환경. 포스트를 적을 때에는 왼쪽과 오른쪽 툴바를 넣고 쓴다.&lt;/p>
&lt;/blockquote>&lt;h3 id="express">Express&lt;/h3>
&lt;p>그러나 4가지 단계 중 네번째 단계가 빠져있습니다.&lt;/p>
&lt;p>실제로 블로그 포스트를 이용해 공부나 내가 생각했던 것을 적어보자고 학창시절 수차례 생각해보았지만, 시도들은 전부 귀찮아서 그만두게 되었습니다.&lt;/p>
&lt;p>그러한 이유를 생각해보자면 이 정도가 있겠습니다.&lt;/p>
&lt;ol>
&lt;li>블로그 포스트를 적는 것은 생각보다 시간이 오래 걸린다.&lt;/li>
&lt;li>블로그 사이트를 만드는 것은 어렵고 상당히 귀찮다.&lt;/li>
&lt;/ol>
&lt;p>그러다가 지금(2025년 7월 16일)에서야 블로그를 만들어야겠다는 생각이 들었고, 블로그를 적으면서 내가 더 성장할 수 있을 것 같다는 확신이 들었습니다. 블로그를 만들기 위해 많은 조사를 했고 그 과정에서 수많은 에러들을 만나며 고군분투한 결과, 만족할만한 웹사이트를 직접 제작할 수 있었습니다.&lt;/p>
&lt;p>여러분들은 조금 더 쉽게, 버그가 적은 환경에서 블로그를 만들 수 있도록 이 포스트를 적어봅니다.&lt;/p>
&lt;h2 id="blog-pipeline">Blog Pipeline&lt;/h2>
&lt;p>이 포스트를 시작으로 이어지는 &amp;lsquo;나만의 블로그 만들기&amp;rsquo; 시리즈는 저처럼 Obsidian을 주로 사용하는 사람들이 간단하게 블로그를 관리할 수 있는 시스템을 만드는 것을 목표로 합니다.&lt;/p>
&lt;p>코딩을 한번도 배워보지 않은 사람도 따라할 수 있도록 최대한 쉽게 포스트를 적어보려고 노력해보겠습니다.&lt;/p>
&lt;figure class="post-figure">
&lt;img src="https://dirac042.github.io/images/Pasted%20image%2020250716145644.png" alt="Image Description" loading="lazy" decoding="async">
&lt;/figure>&lt;blockquote>
&lt;p>블로그 시스템 개요도&lt;/p>
&lt;/blockquote>&lt;p>우리가 구현할 시스템의 개요도는 이러합니다.&lt;/p>
&lt;ol>
&lt;li>Obsidian에 노트 형식으로 저장.&lt;/li>
&lt;/ol>
&lt;p>모든 Obsidian 노트는 마크다운(.md) 형식으로 저장됩니다. 그러나 우리가 이 마크다운을 곧바로 블로그에 사용할 수는 없습니다. 마크다운을 마크업(.html) 언어로 바꿔야하기 때문입니다.&lt;/p>
&lt;ol start="2">
&lt;li>블로그에 .html 형식으로 포스트 작성&lt;/li>
&lt;/ol>
&lt;p>그러므로 우리는 HUGO라는 프로그램을 사용해 블로그의 토대를 만들고 마크다운 파일을 쉽게 변환해볼 것입니다. 설치 과정도 다소 단순하고 굉장히 미학적인 블로그를 만들 수 있을 것입니다.&lt;/p>
&lt;ol start="3">
&lt;li>Github Pages를 이용해 블로그에 실시간 업로드&lt;/li>
&lt;/ol>
&lt;p>믈론 각자만의 도메인을 구매하여 사용하고 있는 사람들은 이 단계가 필요하지 않습니다. 그러나 도메인이 없는 우리도 Github 계정을 이용해 자신만의 블로그 도메인을 만들 수 있습니다. HUGO로 만들어진 블로그를 어떻게 Github Pages와 연동시켜 모든 사람이 볼 수 있도록 할 수 있을지 알아봅시다.&lt;/p>
&lt;h2 id="disclaimer">Disclaimer&lt;/h2>
&lt;p>&amp;lsquo;나만의 블로그 만들기&amp;rsquo; 포스트는 대부분 NetworkChunk의 &lt;a href="https://youtu.be/dnE7c0ELEH8?si=ttcK3pt7a943LC0K" target="_blank" rel="noopener noreferrer">&amp;lsquo;I started a blog&amp;hellip;..in 2024 (why you should do)&amp;rsquo;&lt;/a>에서 만들어진 것임을 밝힙니다.&lt;/p>
&lt;p>그러나 코드를 그대로 사용하지는 않았으며, branch 구현 등 코드의 일부분을 수정하여 소개하려고 합니다.&lt;/p>
&lt;p>이 블로그의 포스트보다 더 자세한 설명을 원한다면 꼭 이 유튜브 링크를 통해 더 알아보기를 권합니다.&lt;/p></content:encoded></item></channel></rss>