포스트

NeRF — 장면 하나를 MLP 하나에 넣기

NeRF — 장면 하나를 MLP 하나에 넣기

서론

이 시리즈의 마지막 글입니다. 그리고 앞의 여덟 편이 전부 여기로 모입니다.

NeRF는 2020년에 나와서 새로운 시점 합성 분야의 판을 바꿨습니다.1 그런데 NeRF를 이루는 부품 중에 새로 발명된 것은 거의 없습니다.

NeRF의 구성 요소이 시리즈의 어느 편
카메라 포즈3편 SfM
MLP와 역전파1편
Adam2편
볼륨 렌더링 적분6편
미분 가능성8편

전부 이미 있던 것들입니다. NeRF가 한 일은 이것들을 특정한 방식으로 조립한 것이고, 그 조립에서 새로웠던 건 사실상 두 가지 — 표현을 MLP로 둔 것위치 인코딩입니다.


1. 한 문장 정의

\[F_\Theta: (\mathbf{x}, \mathbf{d}) \;\longmapsto\; (\sigma,\; \mathbf{c})\]

3차원 위치 $\mathbf{x}$ 와 시선 방향 $\mathbf{d}$ 를 넣으면 그 지점의 밀도 $\sigma$ 와 $\mathbf{c}$ 가 나오는 함수입니다. 그리고 그 함수를 MLP 하나의 가중치 $\Theta$ 로 표현합니다.

장면이 곧 신경망이다. 점군도 메시도 복셀도 없습니다. 가중치 파일 하나가 장면 전체입니다.

한 픽셀을 그리는 과정은 이렇습니다.

NeRF 렌더링 경로와 계층적 샘플링 왼쪽: 픽셀 하나마다 광선을 쏘고, 그 위에서 점들을 뽑아 MLP에 물어보고, 6편의 볼륨 렌더링 식으로 합친다. 오른쪽: 균등하게 뽑으면 빈 공간에서 계산을 낭비하므로, 거친 단계로 어디가 중요한지 먼저 알아낸 다음 그 분포에서 다시 뽑는다. 이 예에서 세밀한 샘플의 67%가 표면 근처에 몰린다.

렌더링 식은 6편에서 유도한 그대로입니다.

\[C = \sum_{i} T_i\,\alpha_i\,\mathbf{c}_i, \qquad \alpha_i = 1 - e^{-\sigma_i \delta_i}, \qquad T_i = \prod_{j<i}(1-\alpha_j)\]

2. 왜 MLP인가

장면을 담는 자료구조로 복셀 격자를 쓰면 어떻게 될까요. 해상도 $N$ 이면 메모리가 $O(N^3)$ 입니다. $512^3$ 격자에 밀도와 색을 담으면 그것만으로 수 GB입니다. 그리고 격자 간격보다 작은 구조는 표현할 수 없습니다.

MLP는 두 가지를 바꿉니다.

  • 메모리가 해상도와 무관합니다. NeRF의 모델은 8층 × 256 폭으로, 파라미터가 약 60만 개, 5MB 남짓입니다. 이 안에 장면 전체가 들어갑니다.
  • 연속적입니다. 임의의 실수 좌표를 넣을 수 있고, 격자 해상도라는 상한이 없습니다.

물론 공짜는 아닙니다. 값 하나를 알려면 신경망을 한 번 돌려야 합니다. 격자는 메모리를 한 번 읽으면 끝인데 말이죠. 광선 하나당 192개 지점을 보고, 이미지 한 장이 수십만 픽셀이면 — 한 프레임에 MLP 호출이 수천만 번입니다. NeRF가 느린 이유의 전부가 이 한 줄에 있습니다.


3. 위치 인코딩 — 없으면 아무것도 안 된다

여기가 NeRF에서 가장 반직관적인 부분입니다. 좌표 $(x,y,z)$ 를 MLP에 그냥 넣으면 흐릿한 결과밖에 안 나옵니다.

위치 인코딩 유무에 따른 차이 좌표 $(x,y)$ 를 넣어 색을 뱉는 MLP로 영상 하나를 외우게 한 실험. 신경망 구조도 학습 방법도 완전히 같고 입력 표현만 다르다. 좌표를 그대로 넣으면 큰 얼룩만 배우고 질감은 통째로 놓친다(15.9dB). 좌표를 여러 주파수의 sin·cos 으로 펼쳐 넣으면 같은 신경망이 세밀한 질감까지 잡아낸다(31.5dB).

인코딩은 이렇게 정의합니다.

\[\gamma(p) = \big(\sin(2^0\pi p),\, \cos(2^0\pi p),\, \dots,\, \sin(2^{L-1}\pi p),\, \cos(2^{L-1}\pi p)\big)\]

숫자 하나를 $2L$ 개로 펼치는 것뿐입니다. 새 정보는 없습니다. $\sin$ 은 $x$ 의 함수일 뿐이니 원리적으로 MLP가 스스로 만들 수 있는 것이기도 합니다. 그런데도 결과가 이렇게 다릅니다.

이유는 MLP가 저주파를 먼저, 훨씬 쉽게 배우기 때문입니다. 신경 탄젠트 커널(NTK) 관점에서 보면 ReLU MLP의 커널은 저주파 성분에 큰 고윳값을, 고주파 성분에 아주 작은 고윳값을 줍니다. 경사하강은 고윳값이 큰 방향부터 빠르게 수렴하므로, 고주파는 학습이 사실상 멈춰 있는 것처럼 보입니다. 이걸 스펙트럴 편향(spectral bias)이라고 부릅니다.2

위치 인코딩은 이 편향을 입력 쪽에서 미리 상쇄합니다. 고주파 성분을 이미 입력 차원으로 만들어 주면, MLP는 그 차원에 대해 선형에 가까운 일만 하면 됩니다.

NeRF의 선택은 위치에 $L=10$, 방향에 $L=4$ 입니다. 방향에 낮은 $L$ 을 쓰는 이유는 7편에서 SH 차수를 낮게 쓰는 이유와 정확히 같습니다. 시점에 따른 색 변화는 대체로 완만하고, 고주파를 허용하면 기하가 아니라 색으로 오차를 흡수해 버립니다.


4. 구조로 강제한 제약 — $\sigma$ 는 방향을 모른다

NeRF의 MLP는 두 갈래로 나뉩니다.

\[\sigma = \sigma(\mathbf{x}) \quad\text{(위치만)}, \qquad \mathbf{c} = \mathbf{c}(\mathbf{x}, \mathbf{d}) \quad\text{(위치와 방향)}\]

방향 $\mathbf{d}$ 는 신경망의 뒷부분에만 들어갑니다. 밀도를 계산하는 층들은 방향을 아예 보지 못합니다.

이건 구현 편의가 아니라 의도된 제약입니다. 만약 $\sigma$ 도 방향에 의존한다면, 신경망은 “이 시점에서는 여기 물체가 있고, 저 시점에서는 없다”고 말할 수 있게 됩니다. 그러면 모든 학습 이미지를 완벽히 재현하면서도 3차원 기하는 아무 의미가 없는 해에 도달합니다. 학습 손실은 0인데 새 시점에서는 완전히 무너지죠.

밀도가 방향과 무관해야 한다는 제약 하나가 “여러 시점이 하나의 3차원 구조에 동의해야 한다”는 요구를 신경망 구조에 새겨 넣습니다. 이건 에피폴라 기하가 대응점에 걸었던 제약과 성격이 같습니다. 방식만 다를 뿐, 둘 다 여러 관측이 하나의 3차원을 공유하도록 묶는 장치입니다.

3DGS도 같은 분업을 합니다. 기하(위치·공분산·불투명도)는 방향과 무관하고, SH 계수만 방향을 봅니다.


5. 계층적 샘플링

6편의 마지막 그림에서 봤던 문제 — 샘플이 성기면 얇은 표면을 통째로 놓친다 — 를 NeRF는 두 단계로 풉니다.

  1. 거친(coarse) 네트워크. 광선을 64등분해 균등하게 뽑고 렌더링한다. 이때 나오는 가중치 $w_i = T_i\alpha_i$ 가 “빛이 어디서 멈췄는가”의 분포다.
  2. 세밀한(fine) 네트워크. 그 분포를 확률밀도로 보고 역 CDF 표본추출로 128개를 더 뽑는다. 표면 근처에 몰린다.

최종 이미지는 fine 네트워크로 만들지만, 손실은 두 이미지 모두에 겁니다. coarse가 정확한 그림을 못 그려도 되지만, 어디가 중요한지는 제대로 짚어야 하니까요.

1
2
3
4
5
6
7
8
def sample_pdf(bins, weights, n_fine):
    """거친 단계의 가중치를 확률밀도로 보고 역 CDF 표본추출."""
    pdf = weights / weights.sum()
    cdf = np.concatenate([[0.0], np.cumsum(pdf)])
    u = np.random.rand(n_fine)
    i = np.clip(np.searchsorted(cdf, u) - 1, 0, len(pdf) - 1)
    frac = (u - cdf[i]) / np.maximum(pdf[i], 1e-12)     # 구간 안에서의 위치
    return bins[i] + frac * (bins[i + 1] - bins[i])

광선당 총 192번의 MLP 호출이 여기서 나옵니다. 그리고 이게 학습 시간의 대부분입니다.


6. 학습

놀랍도록 단순합니다. 손실은 그냥 렌더된 색과 사진 색의 제곱오차입니다.

\[L = \sum_{\mathbf{r} \in \mathcal{R}} \Big( \|\hat{C}_{\text{coarse}}(\mathbf{r}) - C(\mathbf{r})\|^2 + \|\hat{C}_{\text{fine}}(\mathbf{r}) - C(\mathbf{r})\|^2 \Big)\]

한 스텝의 미니배치는 이미지가 아니라 광선 4096개입니다. 여러 이미지에서 픽셀을 무작위로 섞어 뽑습니다. 2편에서 이야기한 SGD 그대로이고, 옵티마이저는 Adam입니다.

정규화도, 사전학습도, 특별한 트릭도 없습니다. 미분 가능한 렌더러 하나와 $L_2$ 손실만으로 3차원이 나옵니다. NeRF가 인상적이었던 이유의 절반은 이 단순함이었습니다.

대신 장면 하나에 100~300k 반복, GPU 하루 이상이 걸립니다.


7. 무엇이 좋고 무엇이 문제인가

좋은 점문제
화질이 압도적이었다학습에 하루, 렌더링에 수 초
모델이 5MB 남짓장면마다 처음부터 다시 학습
반투명·미세 구조도 담긴다장면 일부를 떼거나 옮길 수 없다
구현이 단순하다밀도장에서 깨끗한 표면을 뽑기 어렵다

가운데 두 줄이 실용화의 벽이었습니다. 표현이 암시적이라는 것 — 즉 장면이 신경망 가중치에 녹아 있다는 것 — 이 메모리 효율의 원천이면서 동시에 편집 불가능성의 원인입니다. 어떤 가중치가 어느 의자를 담당하는지 알 방법이 없으니까요.


8. 그 뒤에 일어난 일

NeRF 이후의 연구는 대체로 “MLP 호출을 어떻게 줄일 것인가” 로 수렴합니다.

  • Instant-NGP3 — 공간을 다중 해상도 해시 격자로 나누고, 격자에 학습 가능한 특징 벡터를 둡니다. 그러면 MLP는 아주 작아도(2층) 됩니다. 무거운 일을 신경망에서 메모리 조회로 옮긴 것이고, 학습 시간이 하루에서 수 초~수 분으로 줄었습니다.
  • Mip-NeRF4 — 광선 하나가 아니라 원뿔을 추적해 픽셀의 면적을 반영합니다. 해상도가 다른 이미지들이 섞였을 때 생기는 앨리어싱을 없앱니다.
  • 3D Gaussian Splatting5 — 방향을 아예 틀어 버립니다. 암시적 표현을 명시적 표현으로, 광선 마칭을 래스터화로 바꿉니다.

마지막이 이 시리즈의 목적지입니다.


9. 3DGS는 NeRF에서 무엇을 가져오고 무엇을 버렸나

 NeRF3DGS관련 편
장면 표현MLP 가중치 (암시적)가우시안 집합 (명시적)
색의 방향 의존성MLP 뒷부분SH 계수 48개7편
고주파 표현위치 인코딩프리미티브를 늘림 (밀도 조정)
합성볼륨 렌더링 적분같은 식, 항이 가우시안6편
렌더링 루프픽셀 → 광선 → 샘플프리미티브 → 픽셀 (래스터화)5편
미분 가능성연속 밀도장이라 자연히가우시안의 부드러운 감쇠8편
최적화AdamAdam + 이산적 밀도 조정2편
초기값무작위 가중치SfM 희소 점군3편

볼륨 렌더링 식은 그대로 가져가고, 나머지는 거의 다 바꿨습니다. 그리고 바뀐 것들의 방향이 일관됩니다 — 연속을 이산으로, 암시를 명시로, “물어보기”를 “그리기”로.

여기서 3DGS의 성격이 드러납니다. 3DGS는 NeRF보다 더 똑똑한 모델이 아닙니다. 오히려 더 단순하고 더 고전적입니다. NeRF가 발견한 학습 구조를, GPU가 원래 잘하던 표현 위에 다시 얹은 것에 가깝습니다.


10. 자주 나오는 질문들

Q1. NeRF는 이제 안 쓰나?

여전히 쓰입니다. 특히 반투명·안개·미세 구조가 많은 장면과, 모델 크기가 중요한 상황에서는 밀도장 표현이 유리합니다. 3DGS는 화질이 비슷하면서 백 배 빠르지만 메모리를 수백 배 씁니다. 그리고 NeRF 계열은 Zip-NeRF 같은 후속 연구로 화질에서 여전히 앞서는 영역이 있습니다.

Q2. 위치 인코딩 대신 활성함수를 바꾸면 안 되나?

됩니다. SIREN 처럼 활성함수 자체를 사인으로 두는 접근이 있고, 잘 동작합니다. 결국 같은 처방입니다 — 신경망 어딘가에 고주파 기저를 넣어 줘야 한다는 것이고, 입력 쪽에 넣느냐 활성함수에 넣느냐의 차이입니다.

Q3. NeRF도 SfM 포즈에 의존하는데, 포즈가 틀리면?

무너집니다. 3편에서 말한 대로 SfM은 조용히 실패하고, 그 오차를 NeRF는 흐릿함으로 흡수합니다. 여러 시점이 서로 어긋나면 그 지점의 색이 시점마다 다르게 관측되고, MLP는 그 평균을 배우니까요. 그래서 포즈를 함께 최적화하는 연구(BARF 등)가 이어졌습니다.

Q4. “장면 하나에 신경망 하나”라면 학습이 아니라 그냥 압축 아닌가?

정확한 지적이고, 실제로 그렇게 봐도 됩니다. NeRF는 일반화하지 않습니다. 학습 데이터(사진들)에 의도적으로 과적합시키는 것이 목적입니다. 2편에서 “3DGS·NeRF에는 일반화라는 개념이 거의 없다”고 했던 것이 이 뜻입니다.

다만 “압축”이라고만 하기엔 하나 더 있습니다. 사진에 없던 시점을 만들어 낼 수 있다는 것. 그게 가능한 이유는 볼륨 렌더링이라는 물리적으로 옳은 구조를 통과시켰기 때문이고, 그 구조가 곧 귀납 편향입니다. 모델에 어떤 가정을 심어 두었느냐가 관측하지 못한 것을 어떻게 채울지를 정하는데, 이 이야기는 베이지안 추론 3편에서 다뤘습니다.


마치며

  • NeRF는 장면을 MLP 하나로 표현하고, 광선 위에서 그 MLP에 물어본 값을 볼륨 렌더링 식으로 합친다.
  • 새로운 부품은 사실상 둘 — 암시적 표현위치 인코딩이다. 나머지는 이미 있던 것들의 조립이다.
  • 위치 인코딩이 필요한 이유는 MLP가 고주파를 잘 못 배우기 때문이고, 이건 신경망의 근본 성질이다.
  • 밀도는 방향을 몰라야 한다. 이 구조적 제약 하나가 여러 시점을 하나의 3차원에 묶는다.
  • 느린 이유도 하나로 설명된다. 광선당 192번의 MLP 호출. 이후 연구는 거의 다 이 숫자를 줄이는 이야기다.
  • 3DGS는 볼륨 렌더링 식만 남기고 나머지를 명시적·이산적·래스터화 쪽으로 되돌렸다.

여기까지가 3D Gaussian Splatting을 읽기 위한 기초지식입니다. 아홉 편을 지나온 지금, 그 글의 문장들이 처음보다 훨씬 구체적으로 읽힐 것입니다. “SfM 점군을 초기값으로”, “투영해도 여전히 가우시안”, “앞에서 뒤로 알파 블렌딩”, “SH 계수로 view-dependent 효과”, “미분 가능한 타일 래스터라이저”, “Adam으로 갱신” — 이제 전부 뒤에 한 편씩 붙어 있는 말들입니다.


이 시리즈 — 3DGS를 읽기 위한 기초지식

  1. MLP와 역전파
  2. SGD에서 Adam까지
  3. SfM 파이프라인
  4. MVS — 밀집 복원
  5. 래스터화
  6. 알파 블렌딩과 볼륨 렌더링
  7. 구면 조화 함수
  8. 미분 가능 렌더링
  9. NeRF ← 지금 읽는 글
  10. 3D Gaussian Splatting ← 도착지

참고문헌

  1. Mildenhall, B., Srinivasan, P. P., Tancik, M., Barron, J. T., Ramamoorthi, R., & Ng, R. (2020). NeRF: Representing scenes as neural radiance fields for view synthesis. ECCV. ↩︎

  2. Tancik, M., et al. (2020). Fourier features let networks learn high frequency functions in low dimensional domains. NeurIPS. — 위치 인코딩이 왜 필요한지를 NTK로 설명한 논문. ↩︎

  3. Müller, T., Evans, A., Schied, C., & Keller, A. (2022). Instant neural graphics primitives with a multiresolution hash encoding. ACM TOG, 41(4). ↩︎

  4. Barron, J. T., Mildenhall, B., Tancik, M., Hedman, P., Martin-Brualla, R., & Srinivasan, P. P. (2021). Mip-NeRF: A multiscale representation for anti-aliasing neural radiance fields. ICCV. ↩︎

  5. Kerbl, B., Kopanas, G., Leimkühler, T., & Drettakis, G. (2023). 3D Gaussian Splatting for Real-Time Radiance Field Rendering. ACM TOG, 42(4). ↩︎

이 기사는 저작권자의 CC BY-NC-ND 4.0 라이센스를 따릅니다.

License

CC BY-NC-ND 4.0

이 포스트는 CC BY-NC-ND 4.0 라이선스로 제공됩니다. 출처 표시는 필요하며, 상업적 이용과 변경은 허용되지 않습니다.