1-1. 오토인코더와 VAE
이미지 생성 모델은 그림을 직접 다루지 않는다. 그림을 작게 압축한 "잠재"를 다룬다. 그 압축과 복원을 맡는 부품이 VAE다. 이번 수업은 왜 압축하는지, 어떻게 압축하는지를 본다.
왜 압축하나
0-5에서 계산했다. 1024×1024 그림의 픽셀을 그대로 다루면 계산량이 감당이 안 된다.
그런데 그림의 숫자 314만 개는 대부분 군더더기다. 옆 픽셀끼리는 거의 같은 색이다. 하늘은 수천 픽셀이 같은 파랑이다. 중요한 정보만 남기면 훨씬 적은 숫자로 같은 그림을 나타낼 수 있다.
오토인코더: 줄였다가 되살린다
신경망 두 개를 이어 붙인다.
그림 → [인코더] → 잠재(작은 숫자 묶음) → [디코더] → 그림
- 인코더: 그림을 작은 숫자 묶음으로 줄인다.
- 디코더: 그 숫자 묶음에서 그림을 되살린다.
- 잠재(latent): 가운데의 작은 숫자 묶음. 그림의 요약본이다.
학습 목표는 하나다. 나온 그림이 넣은 그림과 같아야 한다. 가운데가 좁으니, 모델은 그림을 되살리는 데 꼭 필요한 정보만 잠재에 담게 된다. 정답을 따로 만들 필요가 없다. 입력이 곧 정답이다.
실제 압축 비율
Stable Diffusion 계열의 VAE는 가로세로를 각각 8분의 1로 줄인다.
| 크기 | 숫자 개수 | |
|---|---|---|
| 원본 그림 | 1024 × 1024 × 3채널 | 약 314만 |
| 잠재 (SD 1.5, SDXL) | 128 × 128 × 4채널 | 약 6.5만 |
| 잠재 (SD3, Flux) | 128 × 128 × 16채널 | 약 26만 |
4채널이면 48분의 1이다. 그런데 디코더로 되살리면 눈으로 구분하기 어려울 만큼 원본과 같다. 채널이 16개인 최신 VAE는 덜 압축하는 대신 작은 글자나 눈동자 같은 디테일을 더 잘 살린다.
이미지 생성 도구에서 "빈 잠재 이미지"의 크기를 1024로 넣으면 실제로는 128×128짜리 숫자 묶음이 만들어진다. 모델은 처음부터 끝까지 이 작은 묶음만 만진다. 마지막에 디코더가 한 번 돌아서 그림이 된다.
잠재 공간
잠재 하나는 "잠재 공간"의 점 하나다. 0-1에서 그림을 큰 공간의 점으로 봤던 것과 같다. 공간이 훨씬 작아졌을 뿐이다.
잠재는 그림의 축소판처럼 생겼다. 128×128의 각 칸이 원본의 8×8 영역을 요약한다. 왼쪽 위 칸은 그림의 왼쪽 위를 나타낸다. 그래서 잠재에도 합성곱과 어텐션을 그대로 쓸 수 있다.
그냥 오토인코더로는 부족하다
오토인코더로 새 그림을 만들 수 있을까. 잠재 공간에서 아무 점이나 찍어 디코더에 넣으면 될 것 같다.
안 된다. 학습한 그림의 잠재는 공간 여기저기에 흩어져 있고, 그 사이는 비어 있다. 빈 곳을 찍으면 쓰레기가 나온다. 디코더는 그 자리를 본 적이 없다.
VAE: 잠재 공간을 고르게 채운다
VAE(변분 오토인코더)는 두 가지를 바꾼다.
인코더가 점이 아니라 분포를 내놓는다. 그림 하나에 대해 평균 μ와 표준편차 σ를 내놓는다. 잠재는 그 분포에서 뽑는다.
z = μ + σ·ε
0-1의 성질 1이다. 무작위성을 ε에 몰아넣어서 학습이 가능해진다. 그림 하나가 점 하나가 아니라 작은 구름이 된다. 구름끼리 겹치면서 빈 곳이 메워진다.
잠재의 분포를 표준 가우시안에 가깝게 당긴다. 손실에 항을 하나 더한다.
손실 = 복원 오차 + β · KL( 인코더가 낸 분포 ‖ N(0, 1) )
0-2의 KL 발산이다. 인코더가 내놓는 분포가 N(0, 1)에서 멀어지면 벌점을 준다. 잠재들이 원점 주변에 고르게 모인다.
두 항은 서로 당긴다. 복원 오차는 "정보를 많이 담아라"고 하고, KL 항은 "다 비슷하게 만들어라"고 한다. β가 그 균형을 정한다.
이미지 생성 모델에서 VAE의 실제 역할
VAE만으로도 그림을 생성할 수 있다. N(0, 1)에서 뽑아 디코더에 넣으면 된다. 하지만 결과가 흐릿하다. 그래서 요즘은 VAE를 생성기로 쓰지 않는다. 압축기로만 쓴다.
- KL 항의 β를 아주 작게 둔다. 잠재의 크기가 너무 벌어지지 않게 살짝 눌러 주는 정도다.
- 복원 오차에 "사람 눈에 비슷해 보이는가"를 재는 손실과 "진짜 같은가"를 판별하는 손실을 더한다. 그래야 복원이 선명해진다.
- 진짜 생성은 이 잠재 공간 위에서 확산 모델이 한다. 이것을 잠재 확산이라고 한다.
학습: 그림 → [VAE 인코더] → 잠재 → (여기에 노이즈를 섞고 디노이저를 학습)
생성: 노이즈 → [디노이저 × 여러 번] → 잠재 → [VAE 디코더] → 그림
VAE는 한 번 학습해 두고 얼려서 쓴다. 디노이저를 학습할 때는 건드리지 않는다.
VAE 때문에 생기는 일
- 디테일의 한계는 VAE가 정한다. 디노이저가 아무리 좋아도 VAE가 못 살리는 디테일은 못 나온다. 작은 얼굴, 손가락, 글자가 뭉개지는 원인 중 하나다.
- 모델과 VAE는 짝이다. SDXL의 잠재를 SD 1.5의 VAE로 풀면 그림이 깨진다. 채널 수가 다른 계열끼리는 아예 못 쓴다.
- 고해상도에서 디코딩이 메모리를 많이 먹는다. 그래서 조각내어 디코딩하는 기능(타일 디코드)이 있다.
확인 문제
- 512×512 컬러 그림을 SD 1.5의 VAE로 인코딩하면 잠재의 크기는?
- 오토인코더의 잠재 공간에서 아무 점이나 찍어 디코딩하면 왜 쓰레기가 나오나?
z = μ + σ·ε에서 ε은 어디서 오나?
풀이
- 64 × 64 × 4채널이다. 가로세로가 8분의 1이 된다.
- 학습한 그림의 잠재 사이가 비어 있어서다. 디코더는 그 빈 자리를 본 적이 없다.
- 표준 가우시안
N(0, 1)에서 뽑는다. 0-1의 성질 1을 쓴 것이다.