다양한 도메인/여러 크기의 오픈소스 고품질 모델이 개발되면서 파인튜닝이 이전 대비 더 실현 가능하고 매력적인 선택지가 됨
하지 말아야 하는 이유
잘 작성된 프롬프트와 컨텍스트로도 비슷한 효과를 낼 수 있음
프롬프트 캐싱 이전에는 반복적 프롬프트를 짧게 써도 되도록 파인튜닝하는 것이 토큰 사용 최적화 이점이 있었는데 프롬프트 캐싱이 도입되면서 이런 장점도 의미가 사라짐
특정 작업이 아닌 다른 작업에서는 오히려 성능이 떨어질 수 있으므로 다양한 프롬프트를 사용해야 하는 애플리케이션에서는 문제 (모든 작업 유형에 대해 다 파인튜닝 하기는 어렵다)
잘 주석이 달린 데이터를 얻는 비용, 모델 학습/디버깅/평가에 대한 지식이 필요, 최적화된 서빙(직접 호스팅 또는 API서비스)의 어려움, 모델을 모니터링하고 유지보수하기 위한 정책과 예산
파인튜닝 vs. RAG
모델이 잘 못하는 게 정보의 부족(사실)인지 행동 방식의 문제(형식)인지가 중요
시사 문제에 대한 질의, 최신 정보가 필요한 작업에서는 RAG가 더 낫다는 연구 결과가 존재
모델이 원하는 출력 형식을 따르지 못하거나(sementic parsing) 요청한 작업과 무관한 대응을 하는 경우 파인튜닝이 적합
물론 두 가지가 상호배타적인 것은 아님. 프롬프트만으로 해보고 예시 추가해보고 단순한 검색 수준의 RAG 추가해보고 파인튜닝 또는 임베딩 기반 검색 같은 고급 RAG 또는 둘다 해보기.. ←이런 식으로 개발 과정을 밟게 됨
src
모델의 메모리 사용에 대한 이해와 양자화
파인튜닝은 기본적으로 메모리를 많이 사용하므로 메모리 사용량과 병목 현상에 대한 이해가 필요
모델은 어디에 메모리를 쓰는가
핵심 요소는 학습 가능한 파라미터의 수
추론 시에는 forward pass만, 학습 시에는 forward/backward pass
forward pass의 경우, 파라미터 수(N) ∗ 각 파라미터에 필요한 메모리(M) + activation 및 Transformer key-value vector (시퀀스/배치 크기에 비례하여 증가)
activation, key-value의 경우 모델 가중치 메모리의 약 20%로 가정하여 N×M×1.2 로 생각해볼 수 있음. 모델이 커질수록 이는 급격히 증가할 것
학습시에는 여기에 backward pass를 더하여
모델 가중치 + activation + gradient + optimizer state 만큼을 사용
그래디언트와 옵티마이저 스테이트(옵티마이저 종류에 따라 각 파라미터별 0~2개)는 파라미터에 비례함
그래디언트 계산을 위해 activation을 계속 저장한다면 그 메모리가 모델 가중치 메모리를 훨씬 넘어설 수 있으므로, 메모리 대신 속도를 희생하여 이를 저장하지 않고 필요할 때마다 재계산(gradient checkpointing)할 수 있음
양자화(quantization)
파라미터 수만큼이나 각 파라미터에 필요한 메모리의 양도 직접적인 영향
FP16, FP32, FP64, BF16, TF32,… → 부동소수점을 표현하기 위해 몇바이트를 사용하느냐, 부호 1비트 외의 범위/정밀도에 얼만큼씩 쓰느냐
FP64는 신경망에서는 거의 사용되지 않음. 저정밀도 표현으로 변경하면 메모리 사용량을 낮추되 값이 부정확해질 수 있음
정밀도를 낮추는 메모리 최적화 방식 = 양자화
일반적으로는 가중치 양자화, 학습 후 양자화(PTQ; post-training)가 널리 사용됨
높은 정밀도로 모델 학습 후 정밀도를 낮춰 서빙하는 것이 표준이 됨
필요 시 혼합 정밀도로 서빙될 수도 있음
정밀도를 낮추면 메모리 사용량뿐 아니라 계산 속도도 향상되는 경우가 많음(배치 크기를 늘릴 수 있어 학습 및 추론 지연 시간 짧게)
학습 양자화는 학습 시 비용을 줄이기 위해+추론 시 양자화하면서 발생하는 성능 갭을 줄이기 위해 연구되고 있음
QAT(Quantization-aware training)은 학습은 고정밀도로 하되 낮은 정밀도에서의 동작을 시뮬레이션
아예 저정밀도로 학습하는 경우 대체로 혼합 정밀도 방식으로 가중치 사본을 고정밀도로, 그래디언트/활성화 값은 저정밀도로 유지 + 다수의 ML 프레임워크가 AMP(automatic mixed precision) 기능을 제공
파인튜닝 기법
PEFT (parameter-efficient FT)
훨씬 적은 파라미터를 사용하면서 전체 파인튜닝에 가까운 성능을 내기 위해
adapter-based : 모델 가중치에 추가 모듈을 붙이는 방식(파라미터를 추가)
soft prompt-based: 특별한 학습 가능한 토큰을 도입해 모델이 입력을 처리하는 방식을 바꿈 (하드 프롬프트와 달리 사람이 읽을 수 없는 수치 벡터로 튜닝 과정에서 학습을 통해 조정됨)
LoRA (low-rank adaptation)
가중치 행렬을 두 개의 더 작은 행렬 A,B의 곱으로 분해하고 이 작은 행렬을 업데이트한 후 원래 행렬로 병합 (즉 파인튜닝에서는 이 2개의 작은 행렬의 파라미터를 업데이트함으로써 파라미터 수를 줄임. 두 행렬의 곱은 원래의 full-rank행렬의 low-rank 근사치가 됨)
왜 이런 방식이 효과적인가?
LLM은 수많은 파라미터를 가지고 있지만 실제로는 매우 낮은 내재적 차원을 가짐(대규모 사전 학습 과정이 자연스럽게 모델 내재적 차원을 줄이는 압축 과정임 = 더 잘 학습될수록, 소규모의 파라미터와 소량의 데이터만으로도 모델을 효과적으로 파인튜닝할 수 있음)
그러면 처음부터(사전학습부터) low-rank학습을 하면 안되나? → 저랭크 분해가 효과적으로 작동할 수 있는 지점까지 모델의 내재적 차원을 줄이기 위해서는 여전히 풀랭크 사전 학습이 필요 (src)
어떤 행렬에 LoRA를 적용할까?
주로 트랜스포머 모델에서 어텐션 모듈의 4가지 가중치 행렬에 적용(쿼리, 키, 값, 출력 투영)
일반적으로 모델 내 같은 종류의 모든 행렬에 일괄적으로 적용
모든 행렬에 적용할 수도 있지만 학습 가능한 파라미터 수가 제한되어 있다면 피드포워드 레이어보다는 어텐션 기반 LoRA가 더 효과적이고, 그 내에서도 일부만이라면 쿼리/값 행렬을 선택하는 것이 일반적
하이퍼파라미터
4~64 정도의 작은 r값만으로도 대부분의 활용 사례에서 충분한 것으로 알려져 있고 r값을 많이 늘려도 성능이 크게 개선되지는 않음
alpha(행렬 병합 시 저랭크 행렬 곱이 새 행렬에 미치는 영향)의 경우 alpha:r 비율을 보통 1:8에서 8:1 사이로 설정
서빙
A,B를 미리 병합해서 W’ 상태로(지연시간 늘지 않음) vs. W,A,B를 따로 유지
모델이 하나뿐이라면 보통 전자가 좋고 멀티 LoRA 서빙시에는 후자 (지연시간이 늘긴 하지만 풀랭크 행렬을 저장하지 않고 어댑터만 꺼내 쓰기 때문에 저장 공간 및 로딩 시간을 대폭 절약)
QLoRA
LoRA 어댑터 메모리 사용량은 전체 모델 가중치에 비해 매우 적으므로 여기서 학습 가능한 파라미터 수를 더 줄이는 것은 메모리 사용량에는 큰 영향력이 없고 가중치/활성화/그래디언트를 양자화하는 편이 더 효과적
QLoRA는 NF4 (4비트) 양자화 과정에 비용이 많이 들고, 다시 되돌리는 과정에서 시간이 걸려 학습 시간이 늘어날 수 있다는 단점
모델 병합과 multi-task 파인튜닝
여러 모델을 결합하여 맞춤형 모델 만들기
여러 작업에 대한 각각의 파인튜닝을 진행 후 서로 다른 모델을 병합할 수 있음
특히 온디바이스 배포처럼 메모리가 제한된 환경에서 효과적
병합 방식
합산: linear combination, spherical linear interpolation(SLERP)
레이어 쌓기(passthrought, frankenmerging) = 여러 모델에서 서로 다른 레이어를 가져다가 쌓아올림. 보통 추가 파인튜닝이 필요. 모델 업스케일링에도 이 방식을 활용할 수 있음
파인튜닝 전술
기본 모델
progression path: 가장 저렴하고 빠른 모델로 파인튜닝 코드를 테스트해서 작동 확인 → 중간급 모델 파인튜닝 → 좋은 모델을 써서 성능이 어디까지 올라가는지 확인 → 비용 대비 성능 비교해서 선택
distillation path : 작은 데이터셋+가장 강력한 모델에서 시작 → 이 파인튜닝된 모델로 더 많은 학습 데이터를 생성 → 더 저렴한 모델을 학습
파인튜닝 방법
우선 LoRA 같은 방법으로 시작하고 나중에 전체 파인튜닝 시도
전체 파인튜닝은 최소 수천개, 대개는 더 많은 예시가 필요하지만 PEFT 방법은 더 적은 데이터로도 괜찮은 성능을 낼 수 있음
모델이 몇 개나 필요하고 어떻게 서빙할지도 고려(전체 파인튜닝은 LoRA 같은 어댑터 계열 모델과 달리 전체 모델을 여러개 서빙해야 함)