4-1. 파인튜닝과 LoRA의 원리
모델이 모르는 캐릭터, 화풍, 개념을 가르치는 것이 파인튜닝이다. 수십억 개의 손잡이를 전부 다시 돌리는 대신, 작은 덧붙임 하나만 학습하는 방법이 LoRA다. 몇십 MB짜리 파일로 모델에 새 지식을 붙였다 뗐다 할 수 있다.
프롬프트와 도구로 안 되는 일
3단계의 도구는 모델이 이미 아는 것을 통제했다. 모델이 모르는 것은 어떻게 해도 안 나온다.
- 내가 만든 캐릭터. 모델은 본 적이 없다.
- 특정 작가의 화풍. 학습 데이터에 없었거나 적었다.
- 학습 데이터에서 걸러진 개념. 모델은 그것이 무엇인지 모른다.
가르쳐야 한다. 이미 학습된 모델을 내 데이터로 조금 더 학습시키는 것이 파인튜닝이다.
방법들
| 방법 | 무엇을 학습하나 | 결과물의 크기 | 특징 |
|---|---|---|---|
| 전체 파인튜닝 | 디노이저의 모든 가중치 | 모델 전체 (수 GB~수십 GB) | 가장 강력하다. 그림 수만 장 이상과 큰 장비가 필요하다. Illustrious 같은 기반 모델이 이렇게 만들어진다 |
| DreamBooth | 모든 가중치를, 그림 몇 장으로 | 모델 전체 | 적은 그림으로 대상 하나를 가르친다. 다른 지식이 망가지지 않게 하는 장치가 있다 |
| Textual Inversion | 새 단어 하나의 벡터만 | 수 KB | 모델은 그대로 두고 "새 단어"만 만든다. 표현력이 약하다 |
| LoRA | 가중치에 더할 작은 행렬 | 수 MB~수백 MB | 가볍고 조합이 자유롭다. 지금의 표준 |
전체 파인튜닝은 문제가 둘이다. 장비가 크게 들고, 결과물이 모델 하나 통째다. 캐릭터 백 명이면 모델 백 개다.
LoRA의 생각
디노이저 안에는 큰 가중치 표(행렬)가 수백 개 있다. 하나가 가로세로 수천 칸이다. 파인튜닝은 이 표의 숫자들을 조금씩 바꾸는 일이다.
원래 표를 W, 학습으로 생긴 변화를 ΔW라고 하자.
새 가중치 = W + ΔW
LoRA는 이렇게 본다. ΔW는 복잡할 필요가 없다. 캐릭터 하나를 가르치는 데 수천 × 수천 칸을 전부 따로 바꿀 필요는 없다. 훨씬 단순한 변화로 충분하다.
그래서 ΔW를 작은 표 두 개의 곱으로 만든다.
ΔW = B · A
A: 가로로 긴 표. r줄 × 수천 칸B: 세로로 긴 표. 수천 줄 × r칸r: 랭크. 4, 8, 16, 32 같은 작은 수
두 표를 곱하면 원래와 같은 크기의 표가 나온다. 하지만 학습할 숫자는 훨씬 적다.
숫자로 보기
가중치 표 하나가 1024 × 1024라고 하자.
| 학습할 숫자 | |
|---|---|
| 표 전체를 바꾼다 | 1024 × 1024 = 1,048,576개 |
| LoRA, r = 16 | A: 16 × 1024, B: 1024 × 16. 합쳐 32,768개 |
32분의 1이다. 이런 표가 수백 개 있으니 차이는 더 벌어진다. 수십 GB짜리 모델의 LoRA가 수십~수백 MB인 이유다.
LoRA는 low-rank adaptation의 줄임말이다. "낮은 랭크로 적응시킨다"는 뜻이다.
왜 그걸로 충분한가
랭크 r은 "변화의 방향을 몇 가지까지 허용하는가"다. r = 16이면 그 표는 16가지 방향으로만 바뀔 수 있다.
모델은 이미 사람을 그리고, 옷을 그리고, 빛을 그릴 줄 안다. 새 캐릭터를 가르친다는 것은 그 능력을 새로 만드는 것이 아니다. 이미 있는 능력을 특정한 조합으로 살짝 돌려놓는 것이다. 그 정도 변화는 몇 가지 방향으로 충분히 표현된다.
반대로 모델이 전혀 모르는 큰 개념을 가르치려면 랭크가 더 필요하고, 그것으로도 모자라면 전체 파인튜닝을 해야 한다.
0에서 시작한다
학습을 시작할 때 B는 전부 0으로, A는 작은 랜덤값으로 채운다. 그러면 B·A = 0이다. 처음에는 원래 모델과 완전히 같다. 학습하면서 조금씩 변화가 생긴다.
3-2의 ControlNet에서 본 것과 같은 생각이다. 잘 학습된 모델을 망가뜨리지 않고 덧붙인다.
학습할 때 일어나는 일
원래 가중치 W 는 얼린다
A 와 B 만 학습한다
반복:
내 그림에 노이즈를 섞는다
(W + B·A) 로 된 디노이저가 방향을 예측한다
오차를 줄이는 쪽으로 A, B 를 조금 움직인다
학습 방법은 0-6, 1-2, 1-4와 똑같다. 노이즈를 섞고 맞히게 한다. 달라진 것은 움직이는 손잡이가 A와 B뿐이라는 점이다.
얼린 가중치는 기울기를 저장할 필요가 없다. 그래서 메모리도 적게 든다. 개인 그래픽카드로 학습할 수 있는 이유다.
쓸 때: 강도
추론할 때는 B·A를 원래 가중치에 더한다. 이때 숫자 하나를 곱할 수 있다.
새 가중치 = W + 강도 × (alpha / r) × B·A
- 강도: 쓸 때 정하는 값. 1이면 학습한 그대로, 0.7이면 70%만, 0이면 원래 모델이다.
- alpha: 학습할 때 정하는 값.
alpha / r가 변화의 기본 크기를 정한다. 4-3에서 다룬다.
강도를 조절할 수 있다는 것이 큰 장점이다. 과하게 학습된 LoRA도 0.6~0.8로 낮춰 쓰면 쓸 만해진다.
여러 개를 겹친다
LoRA는 더하는 값이다. 여러 개를 함께 더할 수 있다.
새 가중치 = W + 캐릭터 LoRA + 화풍 LoRA + 의상 LoRA
캐릭터, 화풍, 자세를 각각 LoRA로 만들어 조합한다. 전체 파인튜닝으로는 못 하는 일이다.
한계도 있다. 여러 LoRA가 같은 가중치를 서로 다른 쪽으로 밀면 충돌한다. 겹칠수록 각각의 강도를 낮춰야 한다.
어디에 붙나
디노이저의 모든 층에 붙일 필요는 없다.
- 어텐션 층: 처음에는 여기에만 붙였다. 프롬프트와 그림의 관계를 다루는 곳이라 효과가 크다.
- 그 밖의 층: 요즘은 다른 층에도 붙인다. 화풍과 질감까지 바꾸려면 필요하다.
- 텍스트 인코더: 여기에도 붙일 수 있다. 새 단어의 뜻을 가르치는 효과가 있다. 최신 모델에서는 인코더가 너무 커서 디노이저에만 붙이는 것이 보통이다.
변종들
모델 사이트에서 보이는 이름들이다.
| 이름 | 무엇이 다른가 |
|---|---|
| LoCon | 합성곱 층에도 붙인다. U-Net 모델에서 화풍 학습에 쓴다 |
| LoHa, LoKr | 작은 표를 조합하는 방법을 바꿔 같은 크기로 더 많은 변화를 담는다 |
| DoRA | 변화를 "크기"와 "방향"으로 나눠 학습한다. 전체 파인튜닝에 더 가까운 결과를 낸다 |
원리는 같다. 원래 가중치를 얼리고 작은 덧붙임을 학습한다.
호환성
LoRA는 특정 가중치 표에 더하는 값이다. 그 표를 가진 모델에서만 쓸 수 있다(2-2).
- 구조가 다른 모델에는 붙일 자리가 없다. SDXL용을 Flux에 못 쓴다.
- 구조가 같아도 가중치가 멀어진 모델에서는 효과가 달라진다. 같은 SDXL 구조인 Illustrious용과 Pony용이 서로 잘 안 통한다.
- 같은 기반 모델의 파생 모델끼리는 대체로 통한다. 그래서 기반 모델에서 학습해 두면 파생 모델들에 두루 쓸 수 있다.
확인 문제
- 2048 × 2048 가중치 표에 r = 8인 LoRA를 붙이면 학습할 숫자는 몇 개인가? 표 전체의 몇 분의 1인가?
- 학습을 시작할 때 B를 0으로 채우는 이유는?
- LoRA의 강도를 0으로 하면 무슨 일이 생기나?
풀이
- 32,768개다. A가 8 × 2048, B가 2048 × 8이다. 표 전체(약 419만 개)의 128분의 1이다.
- 처음에
B·A가 0이 되어 원래 모델과 완전히 같은 상태에서 출발하기 위해서다. - 더해지는 값이 0이 되어 원래 모델 그대로다.