02 - 미세 조정 변압기: LoRA, QLoRA 및 어댑터
Llama 3, Mistral, GPT-4 및 Claude와 같은 사전 훈련된 Transformer 모델은 언어와 추론에 대한 인상적인 지식이 있지만 거의 준비가 되어 있지 않습니다. 특정 작업에 사용하기 위해. 분류라는 영역에 적용하려면 비즈니스 이메일, 독점 프레임워크에서 코드 생성 또는 질문에 답변 의료, 당신은 필요합니다 미세 조정.
문제는 이러한 모델에 수십억 개의 매개변수가 있다는 것입니다. LLaMA 2에는 70억 개의 매개변수가 있습니다. 가장 작은 버전에서는 700억, 가장 큰 버전에서는 700억입니다. LLaMA-7B의 전체 미세 조정 FP32의 가중치에만 약 28GB의 VRAM이 필요하고 최적화 상태에도 동일하게 필요합니다. Adam의 첫 번째 및 두 번째 순간), 그래디언트 및 활성화를 위한 메모리. 에서 실제로 단일 미세 조정 실행에는 4개의 80GB A100이 필요합니다.
이 시리즈의 두 번째 기사에서는 고급 딥 러닝 및 엣지 배포, 우리는 기술을 탐구할 것입니다 매개변수 효율적인 미세 조정(PEFT) 그 이를 통해 적은 리소스를 사용하여 수십억 개의 매개변수로 모델을 맞출 수 있습니다. 전체 미세 조정 문제부터 시작하여 LoRA, QLoRA, DoRA를 자세히 분석하겠습니다. HuggingFace PEFT를 사용하여 Python으로 완전히 구현된 어댑터 레이어.
시리즈 개요
| # | Articolo | 집중하다 |
|---|---|---|
| 1 | 변압기의 주의 메커니즘 | Self-attention, 멀티 헤드, 완전한 아키텍처 |
| 2 | 현재 위치 - LoRA, QLoRA 및 어댑터를 사용한 미세 조정 | 매개변수 효율적인 미세 조정 |
| 3 | 모델의 양자화 | INT8, INT4, GPTQ, AWQ |
| 4 | 가지치기 및 압축 | 매개변수 감소, 증류 |
| 5 | 지식의 증류 | 교사-학생, 지식 이전 |
| 6 | 올라마(Ollama)와 LLM 로컬 | 지역 추론, 최적화 |
| 7 | 비전 트랜스포머 | ViT, DINO, 이미지 분류 |
| 8 | 엣지 배포 | ONNX, TensorRT, 모바일 장치 |
| 9 | NAS와 AutoML | 신경 아키텍처 검색 |
| 10 | 벤치마킹 및 최적화 | 프로파일링, 메트릭, 튜닝 |
무엇을 배울 것인가
- 수십억 개의 매개변수가 있는 모델에서는 완전한 미세 조정이 지속 가능하지 않기 때문입니다.
- PEFT 기술의 전체 개요: 접두사 튜닝, 프롬프트 튜닝, 어댑터, LoRA
- LoRA의 수학: 낮은 순위 분해, 알파를 사용한 확장, 대상 모듈
- QLoRA: 소비자 GPU의 미세 조정을 위해 4비트 양자화와 LoRA를 결합하는 방법
- DoRA: LoRA를 향상시키는 크기와 방향으로의 가중치 분해
- 어댑터 레이어: 병목 현상 어댑터, 병렬 어댑터, 어댑터 융합
- HuggingFace PEFT 및 SFTtrainer를 사용한 완벽한 실제 구현
- 데이터세트 준비: 알파카 형식, 채팅 템플릿, 대화형 형식
- 초매개변수 조정: 순위, 알파, 학습률, 배치 크기
- LoRA vs QLoRA vs DoRA vs 실제 벤치마크와의 전체 미세 조정 비교
- 소비자 GPU의 하드웨어 요구 사항 및 제한 사항
1. 전체 미세 조정 문제
Il 완전한 미세 조정 업데이트에 관한 것입니다 모든 사람 매개변수 특정 데이터 세트를 훈련할 때 사전 훈련된 모델의 모든 무게부터 임베딩 레이어와 어텐션 헤드의 레이어는 다음을 통해 수정됩니다. 역전파. 이 접근 방식은 크기가 큰 모델에 효과적이었습니다. BERT(1억 1천만 매개변수)와 같이 보통이지만 수십억으로 확장하면 지속 불가능해집니다. 매개변수.
1.1 계산 비용
전체 미세 조정이 금지된 이유를 이해하기 위해 메모리 요구 사항을 살펴보겠습니다. LLaMA 2 7B의 경우:
전체 미세 조정 메모리 공간(LLaMA 2 7B)
| 요소 | 공식 | 메모리 |
|---|---|---|
| 모델 중량(FP16) | 7B * 2바이트 | 14GB |
| 그라데이션(FP16) | 7B * 2바이트 | 14GB |
| 최적화 상태(Adam FP32) | 7B * 4바이트 * 2(m, v) | 56GB |
| 활성화(batch_size=1) | 변하기 쉬운 | ~8~16GB |
| Totale | ~92-106GB |
어떤 소비자 GPU도 100GB VRAM을 처리할 수 없습니다. 80GB A100도 부족해요 그래디언트 체크포인트 및 혼합 정밀도와 같은 기술이 없습니다. LLaMA 70B의 경우 다음과 같이 말합니다. 1TB 이상의 메모리가 필요합니다.
1.2 치명적인 망각
Full Fine Tuning의 두 번째 문제는 치명적인 망각 (치명적인 건망증). 특정 데이터세트의 모든 매개변수를 업데이트하면 모델은 사전 훈련 중에 얻은 지식을 잊어버리는 경향이 있습니다. 모델 법률 문서를 세밀하게 조정하면 Python 코드를 생성하는 능력이 상실되거나 역사 질문에 답하기 위해.
이는 Full Fine-Tuning이 모든 가중치를 무분별하게 수정하기 때문에 발생하며, 일반적인 언어 지식을 인코딩하는 것을 포함합니다. 실제로 모델은 이전 지식을 새로운 지식으로 덮어씁니다.
1.3 다중 모델 저장
회사가 동일한 기본 모델을 10가지 다른 작업에 적용해야 하는 경우 (이메일 분류, 감정 분석, 의료 Q&A, 보고서 생성 등), 전체 미세 조정을 위해서는 모델의 전체 복사본 10개를 저장해야 합니다. LLaMA 7B의 경우, 140GB의 저장 공간입니다. LoRA를 사용하면 각 적응에 10-50MB만 필요합니다. 총 100-500MB입니다.
전체 미세 조정은 확장되지 않기 때문에
| 문제 | 전체 미세 조정 | PEFT (LoRA) |
|---|---|---|
| LLaMA 7B용 VRAM | ~100GB | ~16~24GB |
| 견인 가능한 매개변수 | 7,000,000,000 | ~4,000,000 (0.06%) |
| 적응을 위한 저장 | 14GB | 10-50MB |
| 치명적인 망각 | 위험 | 최소한의 위험 |
| 필수 하드웨어 | 4x A100 80GB | 1x RTX 3090 24GB |
2. 매개변수 효율적인 미세 조정(PEFT): 개요
기술 PEFT 그들은 기본 원칙을 공유합니다. 모든 모델 매개변수를 업데이트하고 사전 훈련된 가중치를 고정하고 훈련합니다. 추가 매개변수의 작은 하위 집합일 뿐입니다. 이는 획기적으로 감소합니다. 메모리 요구 사항을 충족하고 훈련 속도를 높이며 기본 모델에 대한 지식을 보존합니다.
PEFT 기술의 분류
| 기술 | 그것이 작동하는 곳 | 추가 매개변수 | 장점 |
|---|---|---|---|
| 프롬프트 튜닝 | 입력 임베딩 | 입력 시 사전 가중치가 부여된 소프트 토큰 | 매우 간단하고 매개변수가 거의 없음 |
| 접두사 튜닝 | 각 관심 레이어 | 견인 가능한 K,V 접두사 | 프롬프트 튜닝보다 표현력이 풍부함 |
| 어댑터 레이어 | Transformer의 레이어 사이 | 병목 현상 모듈이 삽입됨 | 유연한 모듈식 |
| 로라 | 기존 가중치 매트릭스 | 낮은 순위 행렬 B와 A | 추론 시 오버헤드 없음 |
| QLoRA | LoRA + 양자화처럼 | 4비트 모델의 LoRA | 소비자 GPU 미세 조정 |
| 도라 | LoRA + 분해와 유사 | 크기 + 방향 | LoRA보다 우수한 품질 |
2.1 프롬프트 튜닝
Il 신속한 튜닝 (Lester et al., 2021)은 다음 세트를 추가합니다. 소프트 토큰 입력 시작 시 견인 가능. 이 토큰은 실제 어휘와 일치하지 않으며, 그러나 이는 모델이 훈련 중에 학습하는 연속 벡터입니다. 기본 모델은 그대로 유지 완전히 동결됨: 소프트 토큰 임베딩만 훈련됩니다.
Input originale: [Classify this email: "Meeting at 3pm"]
Con prompt tuning: [T1][T2][T3]...[T20] [Classify this email: "Meeting at 3pm"]
^^^^^^^^^^^^^^^^^
20 soft tokens trainabili
(20 * d_model parametri = 20 * 4096 = 81.920 parametri)
Il modello base (7B parametri) e CONGELATO.
Solo 81.920 parametri vengono aggiornati.
신속한 조정은 매우 큰 모델(>10B 매개변수)에 놀라울 정도로 잘 작동합니다. 하지만 더 작은 모델에서는 품질이 떨어집니다. T5-XXL(11B)을 사용하면 신속한 튜닝이 가능합니다. SuperGLUE의 전체 미세 조정과 거의 동일한 성능입니다.
2.2 접두사 튜닝
Il 접두사 튜닝 (Li & Liang, 2021)은 신속한 조정 아이디어를 확장합니다. 입력에만 소프트 토큰을 추가하는 대신 학습 가능한 접두사를 입력에 추가합니다. 키(K)와 값(V) 각 레이어 관심의. 이는 모델을 제공합니다. 단순한 프롬프트 튜닝보다 표현력이 더 풍부합니다.
Prompt Tuning:
Layer 1 Attention: Q=[input], K=[input], V=[input]
Layer 2 Attention: Q=[input], K=[input], V=[input]
Solo soft tokens preposti all'input iniziale.
Prefix Tuning:
Layer 1 Attention: Q=[input], K=[prefix_1 | input], V=[prefix_1 | input]
Layer 2 Attention: Q=[input], K=[prefix_2 | input], V=[prefix_2 | input]
...
Layer L Attention: Q=[input], K=[prefix_L | input], V=[prefix_L | input]
Prefissi trainabili a OGNI layer di attention.
Parametri: L * prefix_len * 2 * d_model (2 per K e V)
Esempio: 32 layer * 20 prefix * 2 * 4096 = 5.242.880 parametri
3. LoRA: 낮은 순위 적응
로라 (Hu et al., 2021)과 가장 많이 사용되고 대표적인 PEFT 기술 대규모 언어 모델을 미세 조정하는 전환점입니다. 핵심 아이디어는 단순함의 우아함: 가중치 행렬을 직접 업데이트하는 대신 Transformer의 업데이트를 두 개의 하위 행렬로 분해합니다.
3.1 직관: 내재 순위 가설
연구(Aghajanyan et al., 2020)에 따르면 우리가 미세 조정하면 특정 작업에 대한 모델 가중치 업데이트는 저차원 부분공간. 즉, 행렬의 체중 업데이트에는 본질적인 순위 그 사람보다 훨씬 낮아 공칭 크기.
d x k 차원의 가중치 행렬 W를 고려합니다(예를 들어, 투영 LLaMA 7B 주의 쿼리 수: 4096 x 4096). 완전한 업데이트 4096 x 4096 = 16,777,216개의 매개변수 배열이 필요합니다. 하지만 업데이트가 된다면 낮은 고유 순위를 가지면 훨씬 더 작은 순위 r로 이를 근사화할 수 있습니다.
3.2 LoRA의 수학
d x k 크기의 미리 훈련된 가중치 행렬 W_0이 주어지면 LoRA는 다음을 매개변수화합니다. 두 개의 하위 행렬의 곱으로 업데이트됩니다.
LoRA 기본 공식
W = W_0 + \델타 W = W_0 + B \cdot A
어디:
- W_0 \in \mathbb{R}^{d \times k} 사전 훈련된(동결된) 가중치 행렬
- B \in \mathbb{R}^{d \times r} 하향 투영 행렬
- A \in \mathbb{R}^{r \times k} 상향 투영 행렬
- r \ll \min(d, k) 그리고 계급 (일반적으로 4, 8, 16, 32, 64)
스케일링 사용: h = W_0 x + \frac{\alpha}{r} \cdot B A x
어디 \alpha 그리고 적응의 강도를 제어하는 스케일링 인자.
Matrice originale W_0 (congelata):
k = 4096
+------------------+
| |
d = | W_0 | 16.777.216 parametri
4096| (CONGELATA) | Non viene aggiornata
| |
+------------------+
Aggiornamento LoRA (trainabile):
r = 16 k = 4096
+-----+ +------------------+
| | | |
d = | B | x r=16 | A |
4096| | | |
| | +------------------+
+-----+
65.536 65.536
B (d x r) A (r x k)
= 4096 * 16 = 16 * 4096
= 65.536 = 65.536
Totale LoRA: 131.072 parametri (0.78% di 16.777.216)
3.3 초기화
A와 B의 초기화가 중요합니다. LoRA는 다음을 초기화합니다.
- A 균일한 Kaiming 초기화(가우스 분포)
- B 모두 0으로
이를 통해 훈련 시작 시 LoRA 기여도가 정확히 0이 되도록 보장합니다. (B * A = 0)이므로 모델은 사전 훈련된 모델의 동작에서 시작됩니다. 훈련은 B와 A를 점진적으로 변경하여 모델을 특정 작업에 맞게 조정합니다.
3.4 스케일링 팩터 알파
매개변수 \alpha (알파)는 강도를 제어합니다 LoRA 적응. 실제 출력은 다음과 같습니다.
h = W_0 x + \frac{\alpha}{r} \cdot B A x
보고서 \알파 / r 학습률처럼 작동합니다. LoRA를 위해. 실무상 자주 개최되는 \알파 = 2r (예를 들어 \알파 = 32 ~와 함께 r = 16), 결과적으로 배율 인수는 2가 됩니다. 이를 통해 학습률을 재조정하지 않고도 순위를 변경할 수 있습니다.
3.5 대상 모듈
LoRA는 Transformer의 모든 레이어에 적용되지 않고 특정 매트릭스에만 적용됩니다. 무게의. 대상 모듈의 선택은 제품의 품질에 큰 영향을 미칩니다. 미세 조정:
공통 아키텍처를 위한 대상 모듈
| 기준 치수 | 유형 | 치수(LLaMA 7B) | 영향 |
|---|---|---|---|
q_proj |
주의 쿼리 | 4096x4096 | 높음 - 모델이 "찾는" 내용을 제어합니다. |
k_proj |
주의 키 | 4096x4096 | 높음 - 토큰이 색인화되는 방식을 제어합니다. |
v_proj |
주의 가치 | 4096x4096 | 높음 - 추출된 정보를 제어합니다. |
o_proj |
주의 출력 | 4096x4096 | 중간 |
gate_proj |
FFN 게이트 | 4096x11008 | 높음 - FFN의 정보 흐름을 제어합니다. |
up_proj |
FFN 업 | 4096x11008 | 중간-높음 |
down_proj |
FFN 다운 | 11008x4096 | 중간 |
3.6 견인 가능한 매개변수의 정확한 계산
q_proj 및 v_proj에 LoRA를 적용하여 LLaMA 2 7B에 대한 훈련 가능한 매개변수를 계산합니다. 32개 레이어 모두에서:
LLaMA 2 7B: 32 layer, d_model = 4096
Con r = 16, target_modules = ["q_proj", "v_proj"]:
Per ogni layer:
q_proj LoRA: B (4096 x 16) + A (16 x 4096) = 65.536 + 65.536 = 131.072
v_proj LoRA: B (4096 x 16) + A (16 x 4096) = 65.536 + 65.536 = 131.072
Totale per layer: 262.144
Totale: 32 layer * 262.144 = 8.388.608 parametri (8.4M)
Rapporto: 8.4M / 6.738M (totale LLaMA 7B) = 0.12% dei parametri
Con target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"]:
Per ogni layer: 7 moduli * 131.072 (media) = ~917.504
Totale: 32 * 917.504 = ~29.4M parametri = 0.44%
3.7 추론의 장점: 오버헤드 제로
어댑터 레이어에 비해 LoRA의 주요 장점은 추론이 없다는 것입니다. 계산 오버헤드가 없습니다. LoRA 매트릭스는 다음과 같습니다. 병합된 기본 모델의 가중치:
W_{병합} = W_0 + \frac{\alpha}{r} \cdot B \cdot A
병합 후 모델의 크기와 속도는 정확히 동일합니다. 원래 모델을 추론하지만 가중치는 업데이트됩니다. 이건 불가능하다 모델에 영구 매개변수를 추가하는 어댑터 레이어가 있습니다.
4. QLoRA: 양자화된 LoRA
QLoRA (Dettmers et al., 2023) 및 다음을 결합한 LoRA의 확장입니다. LoRA 미세 조정을 통한 기본 모델의 4비트 양자화. 이를 통해 다음을 수행할 수 있습니다. 단일 48GB GPU에서 650억 개의 매개변수로 모델을 미세 조정하고, 이전에는 불가능했던 결과입니다.
4.1 QLoRA의 세 가지 혁신
QLoRA는 세 가지 핵심 기술을 소개합니다.
QLoRA 혁신
- 4비트 NormalFloat(NF4): 새롭게 최적화된 양자화된 데이터 유형 정규 분포 가중치의 경우. 각 가중치는 16개 값(4비트) 중 하나에 매핑됩니다. 가우스 분포에서 양자화 오류를 최소화하기 위해 선택되었습니다. NF4는 신경망의 가중치가 대략 다음과 같기 때문에 INT4 및 FP4보다 성능이 뛰어납니다. 정규 분포.
- 이중 양자화: 양자화 상수(각각 하나씩 64개 가중치 블록) 자체는 8비트로 양자화됩니다. 이렇게 하면 돈이 절약됩니다 매개변수당 추가 0.37비트(65B 모델의 경우 약 3GB)
- 페이징된 최적화 프로그램: 페이징 메모리(통합 메모리) 사용 훈련, 이동 중 메모리 급증을 처리하기 위한 NVIDIA GPU 필요한 경우 자동으로 GPU와 CPU 사이의 최적화 상태를 유지합니다.
4.2 NF4의 작동 방식
NF4 양자화는 잘 훈련된 신경망의 가중치가 평균이 0인 대략 정규 분포를 따릅니다. NF4는 16개의 등확률 구간에 표준 정규 분포를 적용하고 각 간격은 예상되는 오류를 최소화하는 최적의 값입니다.
INT4 (equispaziato):
Livelli: [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
Problema: molti livelli nelle code (pochi pesi li), pochi al centro (molti pesi li)
NF4 (quantili normali):
Livelli: [-1.0, -0.6962, -0.5251, -0.3949, -0.2844, -0.1848, -0.0911, 0.0,
0.0796, 0.1609, 0.2461, 0.3379, 0.4407, 0.5626, 0.7230, 1.0]
Vantaggio: livelli densi dove ci sono più pesi (vicino a 0)
Risultato: NF4 produce errore di quantizzazione ~2x inferiore a INT4
4.3 QLoRA 메모리 공간
메모리 비교: 전체 FT, LoRA, QLoRA(LLaMA 7B)
| 요소 | 전체 FT(FP16) | LoRA(FP16) | QLoRA(NF4) |
|---|---|---|---|
| 모델 가중치 | 14GB(FP16) | 14GB(FP16) | 3.5GB(NF4) |
| 그라데이션 | 14GB | ~16MB | ~16MB |
| 최적화 상태 | 56GB | ~64MB | ~64MB |
| 활성화 | ~12GB | ~12GB | ~6GB |
| Totale | ~96GB | ~26GB | ~10GB |
QLoRA를 사용하면 단일 RTX 3090(24GB)에서 LLaMA 7B의 미세 조정이 가능해지며, 그래디언트 체크포인트가 활성화된 단일 RTX 4090(24GB)의 LLaMA 13B.
5. DoRA: 가중치 분해 낮은 순위 적응
도라 (Liu et al., 2024) 및 매트릭스를 분해하는 LoRA의 진화 두 가지 구성요소의 가중치: 크기 (크기) 전자 방향 (방향). 이 분해는 클래식에서 영감을 얻었습니다. Salimans & Kingma의 Weight Normalization(2016) 및 품질 격차 해소를 목표로 함 LoRA와 전체 미세 조정 사이.
5.1 DoRA의 직관
학습 패턴 분석은 전체 학습과 학습 패턴의 근본적인 차이를 보여줍니다. 미세 조정 및 LoRA: 전체 미세 조정은 크기와 방향을 모두 변경합니다. 가중치를 독립적으로 수정하는 반면 LoRA는 가중치를 비례적으로 수정하는 경향이 있습니다. 표현력을 제한합니다.
5.2 DoRA의 수학
DoRA는 사전 훈련된 가중치 행렬을 다음과 같이 분해합니다.
DoRA 공식
W' = m \cdot \frac{W_0 + BA}{\|W_0 + BA\|_c}
어디:
- m \in \mathbb{R}^{1 \times k} 그리고 열 노름으로 초기화된 (학습 가능한) 크기 벡터 W_0
- W_0 + BA LoRA를 통해 업데이트된 방향을 나타냅니다.
- \\|\cdot\|_c 각 열을 단위 표준으로 정규화하는 열 표준
- B e A 표준 LoRA 매트릭스입니다(학습 가능).
이러한 방식으로 DoRA에는 두 가지 독립적인 자유도가 있습니다.
- La 방향 B와 A에 의해 제어됩니다(LoRA와 정확히 동일).
- La 크기 방향에 관계없이 바뀔 수 있는 벡터 m에 의해 제어됩니다.
5.3 LoRA에 비해 DoRA의 장점
벤치마크 DoRA 대 LoRA(상식 추론, LLaMA-7B)
| 작업 | LoRA(r=32) | DoRA(r=32) | 전체 FT |
|---|---|---|---|
| 부울Q | 69.8 | 71.8 | 73.2 |
| 피카 | 82.1 | 83.2 | 83.9 |
| 위노그란데 | 79.4 | 80.6 | 81.5 |
| HellaSwag | 83.6 | 84.4 | 85.1 |
| 평균 | 78.7 | 80.0 | 80.9 |
DoRA는 오버헤드를 통해 LoRA와 전체 미세 조정 간의 격차를 약 60~70% 줄입니다. 최소 매개변수(추가 m 벡터만)
6. 어댑터 계층
그만큼 어댑터 레이어 (Houlsby et al., 2019)은 최초의 것 중 하나였습니다. PEFT 기술을 제안했습니다. 아이디어는 간단합니다. 작은 견인형 모듈을 삽입하는 것입니다. (어댑터) Transformer의 기존 레이어 사이에 원래 무게.
6.1 병목 어댑터
클래식 어댑터 및 모듈 병목 세 가지 구성 요소로:
- 하향 투영: d_model에서 d_bottleneck으로 크기를 줄입니다(예: 4096 -> 64).
- 비선형성: 일반적으로 ReLU 또는 GELU
- 상향 투영: 원래 크기를 복원합니다(예: 64 -> 4096).
- 잔여 연결: 어댑터의 출력이 입력에 추가됩니다.
Input x (dimensione d_model = 4096)
|
+----> Down-proj: W_down (4096 x 64) --> h (dimensione 64)
| |
| Non-linearita (GELU)
| |
| Up-proj: W_up (64 x 4096) <------+
| |
+------- (+) ----+ Residual Connection
|
Output (dimensione 4096)
Parametri per adapter: (4096 * 64) + (64 * 4096) = 524.288
Con 2 adapter per layer, 32 layer: 2 * 32 * 524.288 = 33.5M parametri
6.2 비교: 어댑터와 LoRA
어댑터와 LoRA: 주요 차이점
| 특성 | 어댑터 레이어 | 로라 |
|---|---|---|
| 추론 시 오버헤드 | 예(추가 레이어) | 아니요(가중치 병합) |
| 추가 대기 시간 | ~5-10% 증가 | 0% |
| 구성성 | 높음(어댑터 퓨전) | 평균(LoRA의 합) |
| 구현 용이성 | 높은 | 높은 |
| 도서관 지원 | 어댑터허브, PEFT | PEFT, 나태하지 않은, 아홀로틀 |
7. HuggingFace PEFT를 이용한 실제 구현
연습을 계속해 봅시다. 이 섹션에서는 모델의 미세 조정을 구현해 보겠습니다. HuggingFace PEFT 라이브러리와 함께 LoRA 및 QLoRA를 사용하는 Transformer입니다. 미스트랄을 사용하겠습니다. 7B를 기본 모델로 사용하고 이를 지시-응답 작업에 적용할 것입니다.
7.1 설정 및 설치
# Installazione delle librerie necessarie
# pip install torch transformers peft trl datasets accelerate bitsandbytes
import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
)
from peft import (
LoraConfig,
get_peft_model,
prepare_model_for_kbit_training,
TaskType,
)
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
# Verifica GPU disponibile
print(f"GPU: {torch.cuda.get_device_name(0)}")
print(f"VRAM: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB")
print(f"PyTorch: {torch.__version__}")
print(f"CUDA: {torch.version.cuda}")
7.2 LoRA 구성
# Configurazione LoRA per Mistral 7B
lora_config = LoraConfig(
# Rango della decomposizione low-rank
# Valori tipici: 4 (minimo), 8 (buono), 16 (ottimo), 32 (alto), 64 (massimo)
r=16,
# Alpha: fattore di scaling. Il peso effettivo e alpha/r.
# Regola pratica: alpha = 2 * r
lora_alpha=32,
# Dropout applicato ai layer LoRA durante il training
# Aiuta a prevenire l'overfitting, specialmente con dataset piccoli
lora_dropout=0.05,
# Moduli del Transformer a cui applicare LoRA
# Per Mistral/LLaMA: q_proj, k_proj, v_proj, o_proj (attention)
# gate_proj, up_proj, down_proj (FFN)
target_modules=[
"q_proj", # Query projection - impatto alto
"k_proj", # Key projection - impatto alto
"v_proj", # Value projection - impatto alto
"o_proj", # Output projection - impatto medio
"gate_proj", # FFN gate - impatto alto
"up_proj", # FFN up projection - impatto medio-alto
"down_proj", # FFN down projection - impatto medio
],
# Tipo di task
task_type=TaskType.CAUSAL_LM,
# Bias: "none" (consigliato), "all", "lora_only"
bias="none",
)
# Stampa riepilogo configurazione
print(f"Rank: {lora_config.r}")
print(f"Alpha: {lora_config.lora_alpha}")
print(f"Scaling: {lora_config.lora_alpha / lora_config.r}")
print(f"Target modules: {lora_config.target_modules}")
print(f"Dropout: {lora_config.lora_dropout}")
7.3 LoRA(FP16)를 이용한 미세 조정
model_name = "mistralai/Mistral-7B-v0.3"
# Caricamento tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# Caricamento modello in FP16
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16,
device_map="auto", # Distribuzione automatica su GPU disponibili
attn_implementation="flash_attention_2", # Flash Attention per efficienza
)
# Applica LoRA al modello
model = get_peft_model(model, lora_config)
# Mostra parametri trainabili
model.print_trainable_parameters()
# Output: trainable params: 27,262,976 || all params: 7,268,633,600 || trainable%: 0.375%
# Configurazione training
training_args = SFTConfig(
output_dir="./results/mistral-lora",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4, # Effective batch size: 4 * 4 = 16
gradient_checkpointing=True, # Risparmia VRAM scambiando con tempo
optim="adamw_torch",
learning_rate=2e-4, # LR più alto rispetto al full FT
lr_scheduler_type="cosine",
warmup_ratio=0.03, # 3% degli step come warmup
weight_decay=0.001,
max_grad_norm=0.3,
logging_steps=10,
save_strategy="steps",
save_steps=100,
max_seq_length=2048,
fp16=True,
report_to="wandb", # Logging su Weights & Biases
seed=42,
)
7.4 QLoRA(4비트)를 사용한 미세 조정
# Configurazione quantizzazione 4-bit (QLoRA)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # Carica pesi in 4-bit
bnb_4bit_quant_type="nf4", # NormalFloat 4-bit (migliore di INT4)
bnb_4bit_compute_dtype=torch.bfloat16, # Compute in BF16 (più stabile di FP16)
bnb_4bit_use_double_quant=True, # Double quantization (risparmia ~0.4 bit/param)
)
# Caricamento modello quantizzato
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
attn_implementation="flash_attention_2",
)
# Prepara il modello per il training k-bit
# Questo congela i pesi quantizzati e prepara i layer per LoRA
model = prepare_model_for_kbit_training(
model,
use_gradient_checkpointing=True,
)
# Applica LoRA (stessa configurazione di prima)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Output: trainable params: 27,262,976 || all params: 3,778,682,880 || trainable%: 0.721%
# Nota: il modello base ora occupa ~3.8GB invece di ~14GB
# Configurazione training QLoRA
training_args = SFTConfig(
output_dir="./results/mistral-qlora",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
gradient_checkpointing=True,
optim="paged_adamw_8bit", # Paged optimizer per gestire picchi di memoria
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
weight_decay=0.001,
max_grad_norm=0.3,
logging_steps=10,
save_strategy="steps",
save_steps=100,
max_seq_length=2048,
bf16=True, # BF16 per il compute (più stabile)
report_to="wandb",
seed=42,
)
8. 데이터 세트 준비
미세 조정의 품질은 데이터 세트의 품질에 따라 크게 달라집니다. 이것에는 섹션에서는 미세 조정에 사용되는 표준 형식으로 데이터를 준비하는 방법을 살펴보겠습니다. LLM의.
8.1 알파카 형식
Alpaca 형식(Stanford, 2023)은 LLM 미세 조정에 가장 널리 사용되는 형식 중 하나입니다. 지시-반응 과제에 대해. 각 예시에는 세 가지 필드가 있습니다.
def format_alpaca(example):
"""Converte un esempio nel formato Alpaca per il fine-tuning."""
if example.get("input", ""):
# Con input aggiuntivo
text = (
f"### Instruction:\n{example['instruction']}\n\n"
f"### Input:\n{example['input']}\n\n"
f"### Response:\n{example['output']}"
)
else:
# Solo istruzione e risposta
text = (
f"### Instruction:\n{example['instruction']}\n\n"
f"### Response:\n{example['output']}"
)
return {"text": text}
# Caricamento dataset
dataset = load_dataset("tatsu-lab/alpaca", split="train")
dataset = dataset.map(format_alpaca)
# Esempio di output formattato
print(dataset[0]["text"])
# ### Instruction:
# Give three tips for staying healthy.
#
# ### Response:
# 1. Eat a balanced and nutritious diet...
# 2. Exercise regularly...
# 3. Get enough sleep...
8.2 채팅 템플릿(Mistral/ChatML)
대화형 모델의 경우 채팅 템플릿 형식이 더 적합합니다. 모든 모델 고유한 특정 템플릿이 있습니다.
def format_chat_template(example, tokenizer):
"""Formatta l'esempio usando il chat template del modello."""
messages = [
{"role": "system", "content": "Sei un assistente esperto e disponibile."},
{"role": "user", "content": example["instruction"]},
{"role": "assistant", "content": example["output"]},
]
# Applica il chat template del tokenizer
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=False,
)
return {"text": text}
# Formato risultante per Mistral:
# <s>[INST] Sei un assistente esperto. [/INST]
# [INST] Give three tips for staying healthy. [/INST]
# 1. Eat a balanced diet...</s>
# Per ChatML (usato da molti modelli):
# <|im_start|>system
# Sei un assistente esperto.<|im_end|>
# <|im_start|>user
# Give three tips for staying healthy.<|im_end|>
# <|im_start|>assistant
# 1. Eat a balanced diet...<|im_end|>
8.3 SFTtrainer를 이용한 훈련
from trl import SFTTrainer
# Dataset formattato
dataset = load_dataset("tatsu-lab/alpaca", split="train")
dataset = dataset.map(
lambda x: format_chat_template(x, tokenizer)
)
# Split train/eval
dataset = dataset.train_test_split(test_size=0.05, seed=42)
# Creazione trainer
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
processing_class=tokenizer,
)
# Avvio training
trainer.train()
# Salvataggio adattatore LoRA (solo ~50MB)
trainer.save_model("./results/mistral-qlora/final")
tokenizer.save_pretrained("./results/mistral-qlora/final")
9. 가중치 병합 및 배포
훈련 후에는 동결된 기본 모델과 소형 LoRA 어댑터가 있습니다. 배포를 위해 두 가지를 별도로 유지할 수 있습니다(사이를 전환하는 데 유용함). 다른 적응) 또는 단일 모델로 병합합니다.
9.1 LoRA 가중치를 기본 모델에 병합
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
# Caricamento modello base (FP16 per il merge)
base_model = AutoModelForCausalLM.from_pretrained(
"mistralai/Mistral-7B-v0.3",
torch_dtype=torch.float16,
device_map="auto",
)
# Caricamento adattatore LoRA
model = PeftModel.from_pretrained(
base_model,
"./results/mistral-qlora/final",
)
# Merge LoRA nei pesi base
# Dopo il merge: W_merged = W_0 + (alpha/r) * B * A
model = model.merge_and_unload()
# Salvataggio modello merged
model.save_pretrained("./models/mistral-7b-finetuned")
tokenizer.save_pretrained("./models/mistral-7b-finetuned")
# Upload su HuggingFace Hub
model.push_to_hub("username/mistral-7b-finetuned")
tokenizer.push_to_hub("username/mistral-7b-finetuned")
print("Modello merged e caricato su HuggingFace Hub!")
9.2 미세 조정 모델을 사용한 추론
from transformers import pipeline
# Pipeline di generazione
pipe = pipeline(
"text-generation",
model="./models/mistral-7b-finetuned",
torch_dtype=torch.float16,
device_map="auto",
)
# Generazione
messages = [
{"role": "system", "content": "Sei un assistente esperto di programmazione."},
{"role": "user", "content": "Spiega il pattern Repository in Python."},
]
output = pipe(
messages,
max_new_tokens=512,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
print(output[0]["generated_text"][-1]["content"])
10. 하이퍼파라미터 튜닝
좋은 결과를 얻으려면 하이퍼파라미터를 선택하는 것이 중요합니다. 여기 가이드가 있습니다 커뮤니티 경험과 공개된 벤치마크를 기반으로 실습합니다.
LoRA 하이퍼파라미터 가이드
| 초매개변수 | 범위 | 조언 | 메모 |
|---|---|---|---|
| 순위(r) | 4-256 | 16-64 | 복잡한 작업의 경우 증가합니다. r=8인 경우 분류에 충분함 |
| 알파 | 8-128 | 2 * 순위 | 알파/r 및 효과적인 스케일링; r을 변경할 때 비율을 일정하게 유지 |
| 학습_속도 | 1e-5 - 5e-4 | 2e-4 | 전체 FT(10-100x)보다 높습니다. 손실이 변동하는 경우 감소 |
| 배치_크기 | 1-32 | 4-8 | Gradient_accumulation을 사용하여 대규모 배치 시뮬레이션 |
| 시대 | 1-5 | 2-3 | 과적합을 주의하세요. 평가 손실 모니터링 |
| 준비_비율 | 0.01-0.1 | 0.03 | 안정성에 중요합니다. 높은 LR로 더 높음 |
| 탈락 | 0.0-0.1 | 0.05 | 대규모 데이터 세트의 경우 0.0, 작은 데이터 세트의 경우 0.1 |
| 최대_순서_길이 | 512-8192 | 2048년 | 높을수록 더 많은 VRAM; 데이터세트에 적응하다 |
미세 조정 시 흔히 저지르는 실수
- 학습률이 너무 높음: 손실은 변동하거나 분기됩니다. 해결 방법: LR을 2~5배 줄이거나 워밍업을 늘립니다.
- 순위가 너무 낮음: 모델이 충분히 학습하지 않습니다. 해결책: r을 8에서 16 또는 32로 늘립니다.
- 순위가 너무 높음: 특히 작은 데이터 세트의 경우 과적합. 해결책: r을 줄이거나 드롭아웃을 늘리십시오.
- 몇 시대: 과소적합. 평가손실이 지속적으로 감소하는지 확인
- 시대가 너무 많습니다. 훈련 손실은 감소하지만 평가 손실은 증가합니다(과적합).
- 정리되지 않은 데이터 세트: 중복, 오류, 일관되지 않은 형식으로 인해 품질이 저하됩니다.
- 그라디언트 체크포인트는 잊어버리세요: 대형 모델의 즉각적인 OOM
11. 벤치마크 및 비교
LoRA, QLoRA, DoRA와 전체 미세 조정 중에서 선택하는 방법은 무엇입니까? 체계적인 비교는 다음과 같습니다. 공개 벤치마크 및 커뮤니티 테스트를 기반으로 합니다.
전체 비교: LoRA vs QLoRA vs DoRA vs Full FT
| 미터법 | 전체 FT | 로라 | QLoRA | 도라 |
|---|---|---|---|---|
| 품질(MT-Bench) | 7.8 | 7.5 | 7.3 | 7.6 |
| VRAM(7B 모델) | ~100GB | ~26GB | ~10GB | ~26GB |
| 훈련 속도(상대) | 1.0배 | 1.2배 | 0.8배 | 1.1배 |
| 견인 가능한 매개변수 | 100% | 0.1-0.5% | 0.1-0.5% | 0.1-0.5% + m |
| 스토리지 적응 | 14GB | 10-50MB | 10-50MB | 10-50MB |
| 추론 오버헤드 | 0% | 0% (병합) | 0% (병합) | 0% (병합) |
| 최소 GPU(7B) | A100 4개 | 1x A100 40GB | 1x RTX 3090 | 1x A100 40GB |
12. 하드웨어 요구 사항
하드웨어 선택은 미세 조정하려는 모델과 PEFT 기술에 따라 다릅니다. 당신이 사용하는. 다음은 소비자 및 전문가용 GPU를 위한 실용적인 가이드입니다.
미세 조정을 위한 GPU 요구 사항
| GPU | VRAM | LoRA(FP16) | QLoRA(4비트) | 메모 |
|---|---|---|---|---|
| RTX 3060 | 12GB | 최대 3B | 최대 7B(서열 512) | 보급형, 제한적 |
| RTX 3090 | 24GB | 최대 7B | 최대 13B | QLoRA 7B에 탁월함 |
| RTX 4090 | 24GB | 최대 7B | 최대 13B | 3090보다 빠르며 동일한 VRAM |
| A100 40GB | 40GB | 최대 13B | 최대 34B | 전문적인 표준 |
| A100 80GB | 80GB | 최대 30B | 최대 70B | 대형 모델에 이상적 |
| H100 80GB | 80GB | 최대 30B | 최대 70B | A100보다 빠름, FP8 지원 |
GPU 소비자를 위한 팁
- 제한된 예산(RTX 3060 12GB): seq_length=512,atch_size=1,gradient_accumulation=16인 7B 모델의 QLoRA
- 좋은 품질/가격 비율(RTX 3090/4090 24GB): seq_length=2048, 배치_크기=4인 7-13B 모델의 QLoRA
- 클라우드 컴퓨팅: Google Colab Pro(월 10달러)는 제한된 세션에 대해 A100 40GB를 제공합니다. 대량 사용을 위한 RunPod 및 Lambda Labs
- 항상 활성화: gradient_checkpointing=True, 페이징 최적화 프로그램, Flash Attention 2
13. 실제 사용 사례
LoRA를 통한 미세 조정이 특히 효과적인 몇 가지 구체적인 사용 사례를 살펴보겠습니다.
13.1 텍스트 분류
분류 작업(감정 분석, 주제 분류, 스팸 감지)의 경우 LoRA는 다음과 같은 이유로 선호되는 경우가 많습니다.
- 이 작업에는 몇 가지 추가 매개변수가 필요합니다(순위 r=4-8이면 충분함).
- 분류 데이터 세트는 일반적으로 작습니다(예: 1,000~50,000개)
- 높은 순위와 높은 순위에 대한 과적합 위험
13.2 코드 생성
코드 생성에 대한 미세 조정(예: 특정 언어에 모델 적용) 또는 회사 계약) 다음을 권장합니다.
- 코드의 구조와 가변성이 높기 때문에 순위가 더 높습니다(r=32-64).
- 완전한 대상 모듈(변압기 모듈 7개 모두)
- 고품질 데이터 세트: 잘 문서화된 코드, 테스트 포함, 일관된 스타일
- 전체 컨텍스트에 대한 긴 시퀀스(max_seq_length=4096-8192)
13.3 도메인별 챗봇
전문적인 챗봇(의료, 법률, 기술 지원)을 만들려면:
- 모델의 채팅 템플릿 형식의 대화 데이터 세트
- 거절의 예를 포함하십시오(“그 질문에는 대답할 수 없습니다”).
- 평균 순위(r=16-32)
- 자동 지표뿐만 아니라 도메인 전문가와의 검증
13.4 요약
요약 작업을 세부적으로 조정하려면 다음을 수행하세요.
- 고품질 쌍(문서, 요약)이 포함된 데이터 세트입니다.
- 입력을 위한 긴 시퀀스(최대 8192개 토큰)
- 중상위 (r=16-32)
- ROUGE 및 인간 평가와 같은 측정항목을 사용한 평가
14. 결론 및 의사결정나무
PEFT 기술을 통해 대규모 언어 모델의 미세 조정이 가능해졌습니다. 소비자 GPU를 사용하는 모든 사람에게 제공됩니다. LoRA, QLoRA 및 DoRA는 최신 기술을 대표합니다. 매개변수 효율적인 미세 조정을 위해 각각 고유한 장점이 있습니다.
의사결정 트리: 언제 무엇을 사용할 것인가
| 상황 | 권장 기술 | 동기 부여 |
|---|---|---|
| < 16GB VRAM을 갖춘 GPU | QLoRA | 소비자 하드웨어의 7B+ 모델에 대한 유일한 옵션 |
| 24~40GB VRAM을 갖춘 GPU | LoRA(FP16) | QLoRA보다 품질이 좋고, 훈련 속도가 더 빠릅니다. |
| 최고 품질이 요구됨 | 도라 | Full FT에 가까워 LoRA의 오버헤드 최소화 |
| 동일한 모델의 여러 적용 | 로라 | 소형 어댑터(~50MB), 작업 간 빠른 전환 |
| 소형 모델(< 1B 매개변수) | 전체 미세 조정 | 작은 모델의 경우 전체 FT가 실현 가능하고 더 나은 경우가 많습니다. |
| 단순작업(분류) | LoRA (r=4-8) | 낮고 충분한 순위; 과적합 방지 |
| 복잡한 작업(코드 생성) | LoRA/DoRA (r=32-64) | 작업의 복잡성을 포착하는 높은 순위 |
| 스킬의 구성 | 어댑터 퓨전 | 구조화된 방식으로 여러 적응을 결합 |
효율적이고 빠르게 진화하는 미세 조정 분야. 다음과 같은 새로운 기술 많음 (그라디언트 하위 투영) e ReLoRA (계층이 증가하는 반복 LoRA 훈련) 추가 감소 약속 완전한 미세 조정과의 격차. 그러나 LoRA와 QLoRA는 오늘날에도 여전히 표준으로 남아 있습니다. 성숙한 도서관 생태계를 통해 LLM 미세 조정을 위한 사실상 (HuggingFace PEFT, Unsloth, Axolotl) 및 활발한 커뮤니티.
시리즈의 다음 기사에서는 모델의 양자화: GPTQ, AWQ, INT8 및 품질을 유지하면서 모델 크기를 75% 줄이는 방법 프로덕션 배포용.
리소스 및 참고 자료
- LoRA 논문: “LoRA: 대규모 언어 모델의 낮은 순위 적응”(Hu et al., 2021)
- QLoRA 논문: "QLoRA: 양자화된 LLM의 효율적인 미세 조정"(Dettmers et al., 2023)
- 종이 DoRA: "DoRA: 체중 분해 낮은 순위 적응"(Liu et al., 2024)
- 종이 어댑터: “매개변수 효율적인 전이 학습”(Houlsby et al., 2019)
- 허깅페이스 PEFT: https://github.com/huggingface/peft
- 느림보: https://github.com/unslothai/unsloth (LoRA 2~5배 빠름)
- TRL(변압기 강화 학습): https://github.com/huggingface/trl







