오늘 리뷰할 논문은 현재 많이 쓰이고 있는 LLM Fine Tunning 기법인 LoRA 에 대해서 리뷰를 하려고 합니다. 저는 LoRA 에 전반적인 메커니즘은 알고는 있지만 조금 더 깊게 알아보고 싶어서 리뷰를 해보겠습니다.
마이크로소프트에서 발표한 내용이고, 예제 또한 GPT-2 에 관련된 내용들이 많습니다. LLM 시대에 맞아서 RAG도 그렇고 LoRA 또한 예전에 나온 방법론을 되돌아보게 되는 좋은 기회 같습니다. LoRA 는 LLM 자연어처리에만 국한되지 않게 뉴럴 네트워크 환경이라면 이미지모델이나 다른 모델들도 LoRA를 활용해서 학습이 가능합니다.
Abstract
자연어 처리의 중요한 패러다임은 일반 도메인 데이터에 대한 대규모 사전 학습과 특정 작업이나 도메인에 대한 적응으로 구성됩니다. 우리가 더 큰 모델을 사전 학습할수록, 모든 모델 매개변수를 재학습하는 전체 미세 조정은 실행하기 어려워집니다. 예를 들어, GPT-3 175B와 같은 경우 – 175B 매개변수를 갖는 미세 조정된 모델의 독립적인 인스턴스를 배포하는 것은 비용이 많이 듭니다. 우리는 저랭크 적응(Low-Rank Adaptation, LoRA)을 제안합니다. 이는 사전 학습된 모델 가중치를 고정하고 트랜스포머 아키텍처의 각 레이어에 학습 가능한 랭크 분해 행렬을 주입하여, 하류 작업에 대한 학습 가능한 매개변수의 수를 크게 줄입니다. Adam으로 미세 조정된 GPT-3 175B와 비교할 때, LoRA는 학습 가능한 매개변수의 수를 10,000배, GPU 메모리 요구 사항을 3배 줄일 수 있습니다. LoRA는 학습 가능한 매개변수가 더 적음에도 불구하고, RoBERTa, DeBERTa, GPT-2, GPT-3에서 모델 품질 면에서 미세 조정과 동등하거나 더 나은 성능을 보이며, 어댑터와 달리 추가적인 추론 지연 시간이 없고, 더 높은 학습 처리량을 가집니다. 우리는 또한 언어 모델 적응에서의 랭크-결핍에 대한 경험적 조사를 제공하여 LoRA의 효율성에 대한 통찰을 제공합니다. 우리는 PyTorch 모델과 LoRA의 통합을 용이하게 하는 패키지를 출시하고 RoBERTa, DeBERTa, GPT-2에 대한 우리의 구현과 모델 체크포인트를 https://github.com/microsoft/LoRA 에서 제공합니다.
Introduction
이 연구는 대규모 사전 훈련된 언어 모델을 다양한 다운스트림 응용 프로그램에 적용하는 과정에서 발생하는 문제를 해결하기 위한 새로운 접근 방식인 저순위 적응(Low-Rank Adaptation, LoRA)을 제안합니다. 기존의 미세 조정 방식은 모델의 모든 매개변수를 업데이트하는데, 이는 특히 GPT-3와 같이 매개변수의 수가 매우 많은 모델에서는 큰 저장 공간과 계산 비용을 요구합니다. LoRA는 사전 훈련된 모델의 밀집 계층에 대한 변경을 저순위 행렬로 최적화함으로써, 사전 훈련된 가중치를 고정한 채로 훨씬 적은 수의 매개변수만을 훈련시킵니다. 이 방법은 저장 공간과 계산 비용을 크게 절약하며, 다양한 작업에 대해 빠르게 전환할 수 있는 유연성을 제공합니다. 또한, LoRA는 훈련 효율성을 향상시키고 하드웨어 진입 장벽을 낮추며, 배포 시 추론 지연을 추가하지 않습니다. 이 연구는 Transformer 아키텍처와 관련된 용어와 관례를 사용하며, 모델 최적화에는 Adam 최적화기를 사용합니다. LoRA는 기존 방법들과 결합될 수 있으며, 특히 접두사 조정과 같은 방법과 함께 사용할 때 유용할 수 있습니다.
원리는 간단하다 기존의 Pretrained Weights 를 얼린다.🥶 그 후 저 순위 행렬 A,B 를 학습하고 기존의 Weight에 더하는 방식이다. 그렇게 한다면 Transformer의 FFN 구조를 따로 바꾸지 않고도 추론이 가능하기 떄문에 A,B 만 튜닝하고도 좋은 성능이 나온다.
논문에서 소개하는 LoRA의 장점은 다음과 같다:
- 사전 훈련된 모델은 공유되어 다양한 작업을 위한 많은 작은 LoRA 모듈을 구축하는 데 사용될 수 있습니다. 우리는 공유된 모델을 고정시키고 그림 1에서 A와 B 행렬을 교체함으로써 효율적으로 작업을 전환할 수 있으며, 이는 저장 요구 사항과 작업 전환 오버헤드를 크게 줄입니다.
- LoRA는 적응형 최적화기를 사용할 때 하드웨어 진입 장벽을 최대 3배까지 낮추는 등 훈련을 더 효율적으로 만듭니다. 이는 대부분의 매개변수에 대해 기울기를 계산하거나 최적화기 상태를 유지할 필요가 없기 때문입니다. 대신, 우리는 주입된 훨씬 더 작은 저순위 행렬만을 최적화합니다.
- 우리의 단순한 선형 설계는 배포 시 훈련 가능한 행렬을 고정된 가중치와 병합할 수 있게 해줍니다. 이는 구조적으로 완전히 미세 조정된 모델에 비해 추론 지연을 도입하지 않습니다.
- LoRA는 많은 이전 방법들과 직교하며, 그 중 많은 것들과 결합될 수 있습니다. 예를 들어, 접두사 조정과 같은 것입니다. 우리는 부록 E에서 예를 제공합니다
코드를 보면 알게 되겠지만, 응? 어떻게 더한다는거야? Pytorch 로 단 2줄로 쉽게 구현을 해놓았다.
PROBLEM STATEMENT
BERT 를 필두로 해서, 이때 부터 Transfer learning 라벨링 되지 않은 즉 대규모 말뭉치 코퍼스를 사람들이 배우듯이 사전학습을 해서, 모델이 Initialization point 를 찾아서 학습 후 Fine-tunning 을 거치는 과정의 튜닝방법을 거쳤었다. 결국 Pretrained 를 시켜서 fine-tunning 을 시켰더니 Downstream 문제를 잘 해결했고 크기가 커질수록 더 좋아짐에 따라 GPT-3 까지 크기가 커졌다.
현재 오픈소스로만 공개된 모델만하더라도 70B 라고 명시가 되어있고, 약 700억개이상의 파라미터를 통해 추론을 하는 LLM 모델들이 많아졌다. 이 당시 앞으로 모델들은 계속나오고 파라미터가 커지면 커질수록 성능이 좋아짐에 따라 이걸 효율적으로 계산하기 위해 만든 방법인데 현재 대세 방법론으로 QLoRA, 스테이블 디퓨전에서의 LoRA 튜닝 등 다양하게 쓰이고 있다.
논문으로 와서 Pre-trained 모델을 다양한 DownStream task adaptation 을 해야하는데, 이 사전 훈련된 모델을 요약, 기계 독해(MRC), 자연어에서 SQL로(NL2SQL)와 같은 다운스트림 조건부 텍스트 생성 작업에 적응하는 것을 고려해 봅시다
이렇게 보면 너무 어려워보일 수 있기 떄문에 간단하게 설명을 한다면 아래의 빨간색 식 만 잘 보면 된다.
Φ 이 기존 Weight의 가중치라면(175b 가중치를 업데이트), Θ(세타)는 원래의 파라미터양 보다 훨씬 작은 양의 set of params(0.01%만 학습하겠다) 로도 90%이상의 정보를 얻을 수 있다면 효과적일것이기에 objective 가 바뀐 것이다. 밑에 수식에서 오른쪽을 잘 본다면 set of params 세타에서 델타, 세타를 더한다(변화량) 라는 뜻을 하고 있다. 결국 변화량을 더한다 이걸 잘 초점 기억해 두면 된다.
class Linear(nn.Linear, LoRALayer):
# LoRA implemented in a dense layer
def __init__(
self,
in_features: int,
out_features: int,
r: int = 0,
lora_alpha: int = 1,
lora_dropout: float = 0.,
fan_in_fan_out: bool = False, # Set this to True if the layer to replace stores weight like (fan_in, fan_out)
merge_weights: bool = True,
**kwargs
):
nn.Linear.__init__(self, in_features, out_features, **kwargs)
LoRALayer.__init__(self, r=r, lora_alpha=lora_alpha, lora_dropout=lora_dropout,
merge_weights=merge_weights)
self.fan_in_fan_out = fan_in_fan_out
# Actual trainable parameters
if r > 0:
self.lora_A = nn.Parameter(self.weight.new_zeros((r, in_features)))
self.lora_B = nn.Parameter(self.weight.new_zeros((out_features, r)))
self.scaling = self.lora_alpha / self.r
# Freezing the pre-trained weight matrix
self.weight.requires_grad = False
self.reset_parameters()
if fan_in_fan_out:
self.weight.data = self.weight.data.transpose(0, 1)
A 행렬은 랜덤하게 초기화해주고 B는 zero init을 해주는데, 저 low rank matrices가 원론적으로는 delta_W를 의미하기 때문이라서 곱하면 0이 되게끔 input이 x면 Wx + BAx가 forward 되는거라고 생각하면 쉽다.
r은 파라미터를 얼마나 추가할것인지를 사용한다 해서 통상적으로 openllm 에서는 16을 많이들 쓰곤한다. 정답은 없다. 결국 r은 차원을 맞춰주기 위해 A,B 를 곱해서 W의 차원을 맞춰주고 계산된 델타 W를 기존의 웨이트W에 더해주는것이다. (r이 커지면 그만큼 파라미터를 추가하게 되므로, 모델복잡성이 올라갈것이고, 작으면 비용 계산은 감소하지만 학슴범위가 준다라고 생각하면 된다).
파라미터를 설정할때 고려를 해야하는 값들이다. alpha 같은 경우는 Scaling 값이다. 위의코드에도 나와있지만 알파값을 통해서 r과 스케일링을 해주는 값이다. dropout 은 우리가 배웠던 웨이트를 생략하는 방법이다. target_modules는 유연하게 Freezen 을 해서 사용을 할 수가 있다.
여기서 이제 우리가 또 더 추가 된 방법론인 QLoRA는 8bit 의 계산방법을 4bit 로 더욱 양자화를 통해서 훈련을해서 메모리를 그대화하겠다는 연장선의 파인튜닝 방법이라 할 수 있다. 이해가 되지 않는다면 그냥 얼리고 다른가중치의 a,b를 곱해서 더해! 라고 쉽게 생각하면 좋을것 같다.
'Paper summary' 카테고리의 다른 글
HyperCLOVA X Technical Report 한글 요약 리뷰 (0) | 2024.04.06 |
---|---|
RAFT: Adapting Language Model to Domain Specific RAG 리뷰 (0) | 2024.03.21 |
InstructGPT : Training language models to follow instructions with human feedback (0) | 2024.03.06 |