<?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>Audio on dirac042</title><link>https://dirac042.github.io/tags/audio/</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/tags/audio/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>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></channel></rss>