1-3. 샘플러: 노이즈에서 그림까지 걸어가는 방법
디노이저는 "지금 자리에서 그림 쪽이 어느 방향인지"를 알려 준다. 샘플러는 그 방향을 따라 실제로 걸어가는 방법이다. 이미지 생성 도구의 샘플러, 스케줄러, 스텝 설정이 전부 이 수업에 나온다.
디노이저가 알려 주는 것
노이즈가 섞인 그림 x_t가 있다. 디노이저는 섞인 노이즈를 예측한다. 그 노이즈를 빼는 방향이 곧 "그림다운 그림이 몰린 쪽"이다.
0-1의 데모로 보면 이렇다. 점이 가우시안 어딘가에 떨어져 있다. 디노이저는 그 점에게 "봉우리는 저쪽이다"라고 화살표를 그려 준다. 화살표는 위치마다, 시간마다 다르다.
공간의 모든 자리에 화살표가 그려져 있다고 생각하자. 바람 지도와 같다. 생성은 노이즈 한 점을 이 바람에 실어 보내는 일이다.
걸어가는 방법이 하나가 아니다
DDPM은 1000걸음을 걸었다. 걸음마다 새 노이즈도 더했다.
뒤에 밝혀진 사실이 있다. 같은 디노이저를 가지고 노이즈를 더하지 않고 걸어도 같은 분포의 그림에 도착한다. 이때 경로는 매끈한 곡선 하나가 된다. 출발점이 정해지면 도착점도 정해진다.
수학에서는 이런 곡선을 미분방정식(ODE)의 해라고 한다. "각 자리에서 어느 쪽으로 얼마나 빨리 움직이는가"가 주어졌을 때, 그것을 따라간 경로다.
여기서 중요한 결론이 나온다. 샘플링은 미분방정식을 푸는 일이다. 미분방정식을 수치로 푸는 방법은 수백 년 동안 연구됐다. 그 방법들을 가져다 쓰면 된다. 다시 학습할 필요가 없다. 같은 모델에 샘플러만 바꿔 끼울 수 있는 이유다.
가장 단순한 방법: Euler
지금 자리에서 방향을 잰다
그 방향으로 한 걸음 직진한다
반복한다
Euler(오일러) 방법이다. 문제는 경로가 곡선이라는 것이다. 직진하면 곡선에서 조금 벗어난다. 걸음이 클수록 많이 벗어난다.
- 걸음을 작게, 많이: 정확하지만 느리다.
- 걸음을 크게, 적게: 빠르지만 경로에서 벗어난다. 그림이 뭉개지거나 깨진다.
스텝 수가 바로 이 걸음 수다. 디노이저를 그만큼 부른다.
더 똑똑한 방법들
같은 걸음 수로 더 정확하게 가는 방법이 있다.
| 방법 | 생각 | 걸음당 디노이저 호출 |
|---|---|---|
| Euler | 지금 방향으로 직진 | 1번 |
| Heun | 가 본 자리에서 방향을 한 번 더 재고, 두 방향의 평균으로 간다 | 2번 |
| DPM++ 2M | 바로 전 걸음에서 쟀던 방향을 기억해 두고, 방향이 어떻게 휘는지 짐작해서 간다 | 1번 |
DPM++ 2M이 널리 쓰이는 이유가 여기 있다. 호출은 한 번인데 정확도는 Heun 수준이다. 20~30스텝이면 충분하다.
DDIM이라는 이름도 자주 보인다. 노이즈를 더하지 않는 걸음을 처음 내놓은 방법이다. 내용은 Euler와 거의 같다.
노이즈를 다시 넣는 샘플러
이름에 a(ancestral)나 SDE가 붙은 샘플러는 걸음마다 새 노이즈를 조금 넣는다. DDPM의 방식을 이어받은 것이다.
| 노이즈를 안 넣는 샘플러 | 노이즈를 넣는 샘플러 | |
|---|---|---|
| 예 | Euler, DPM++ 2M, DDIM | Euler a, DPM++ SDE, DPM++ 2M SDE |
| 스텝을 늘리면 | 같은 그림으로 수렴한다 | 그림이 계속 달라진다 |
| 특징 | 재현성이 좋다. 스텝을 줄여도 구도가 유지된다 | 디테일이 풍부해지는 경향. 걸음마다 오차를 씻어 낸다 |
스텝 수를 20에서 30으로 올렸더니 다른 그림이 나왔다면, 노이즈를 넣는 샘플러를 쓰고 있는 것이다.
스케줄러: 걸음을 어디에 놓을까
노이즈가 가장 많은 시점에서 0인 시점까지 가야 한다. 20걸음을 그 사이 어디에 놓을지가 스케줄러다.
고르게 놓는 것이 최선이 아니다. 구간마다 하는 일이 다르기 때문이다.
- 노이즈가 많은 구간: 큰 구도가 정해진다.
- 노이즈가 적은 구간: 디테일이 정해진다.
| 스케줄러 | 걸음 배치 |
|---|---|
| normal, simple | 대체로 고르게 |
| karras | 노이즈가 적은 구간에 촘촘하게. 디테일에 걸음을 더 쓴다 |
| exponential | karras와 비슷하게 뒤쪽이 촘촘 |
| sgm_uniform, beta | 모델 계열에 맞춘 배치 |
1-2에서 말한 "노이즈 스케줄"은 학습할 때 정한 것이다. 여기의 스케줄러는 생성할 때 그 위에서 걸음을 놓는 방법이다. 이름이 비슷해서 헷갈리기 쉽다.
도구의 설정을 수식에 대응시키기
| 설정 | 뜻 |
|---|---|
| seed | 출발점. 처음 노이즈를 정한다 (0-1) |
| steps | 걸음 수. 디노이저를 부르는 횟수 |
| sampler | 걷는 방법. 미분방정식의 해법 |
| scheduler | 걸음을 시간축 어디에 놓을지 |
| cfg | 프롬프트를 얼마나 강하게 따를지 (1-6에서 다룬다) |
| denoise | 어디서 출발할지. 1이면 순수 노이즈에서 출발 (3단계에서 다룬다) |
고르는 요령
- 시작은 Euler나 DPM++ 2M에 20~30스텝. 대부분의 모델에서 무난하다.
- 스텝을 올려도 나아지지 않으면 더 올릴 필요가 없다. 이미 경로를 충분히 정확하게 따라가고 있다.
- 모델마다 권장 조합이 있다. 학습 방식에 따라 경로의 모양이 다르기 때문이다. 모델 설명서의 권장값에서 출발하자.
- 조합을 비교할 때는 시드를 고정한다. 그래야 샘플러의 차이만 보인다.
확인 문제
- 샘플러를 바꿀 때 모델을 다시 학습해야 하나? 이유는?
- 스텝을 20에서 40으로 올렸더니 구도가 완전히 달라졌다. 어떤 종류의 샘플러를 쓰고 있나?
- Heun으로 20스텝을 돌리면 디노이저를 대략 몇 번 부르나?
풀이
- 아니다. 디노이저는 방향만 알려 주고, 그 방향을 따라 걷는 방법은 따로 고를 수 있다.
- 걸음마다 노이즈를 다시 넣는 샘플러다. 이름에 a나 SDE가 붙은 것들이다.
- 약 40번이다. 걸음마다 두 번 부른다.