본문 바로가기
ML

Parameter Efficient Fine-Tuning(PEFT)

by ML_MJSHIN 2024. 1. 18.

개요

LLM 을 새롭게 원하는 도메인의 데이터를 사용하여 학습하고자 할 때 가장 큰 문제는 GPU의 VRAM 용량입니다.

LLM은 성능을 위해서 이름 그대로 큰 모델을 사용하게 되는게 일반적이다보니 이 모델을 그대로 VRAM에 올려서 fine-tuning을 하려면 최소한 24G 이상의 VRAM이 필요하게 됩니다. 

문제는 이렇게 큰 모델 전체의 파라미터들을 재학습하기 위해서는 VRAM 도 VRAM 이지만 학습 시간도 오래 걸릴 뿐 아니라 생각보다 데이터의 량, 상태 등에 따라서 수렴도 어렵다는 문제가 있습니다.

 

이러한 문제들을 해결하기 위해서 최근에 많은 방법들이 발표되고 있지만 이런 연구들의 가장 기반이 되는 Parameter Efficient Fine-Tuning(PEFT)에 대해서 먼저 알아보려고 합니다.

 

이 연구의 시작은 LM 모델과 같은 많은 수의 파라미터를 가진 모델의 경우 전체 파라미터 중 일부의 파라미터를 튜닝해도 전체를 다시 학습해서 만들어진 모델과 비슷한 성능을 낼 수 있다는 선행연구들의 결과에서 시작되었습니다.

 

그러한 방법론중에서 가장 유명한 것중 하나가 LoRA가 있으며 최근에는 LoRA를 개선한 방법론들도 많이 나오고 있습니다.

PEFT의 초기 접근 방식 중 하나는 '어댑터(Adapter)'의 사용이었습니다.

어댑터(Adapter)

어댑터는 사전에 학습된 모델(pre-trained model) 사이에 삽입되는 학습 가능한 작은 feed-forward 네트워크들입니다. 이 구조의 핵심은 사전 학습된 모델의 가중치(weights)는 고정하고, 추가된 feed-forward 네트워크만 학습시킴으로써 효율적으로 모델을 튜닝합니다. 이 방식은 적은 수의 파라미터 조정으로도 높은 효율을 얻을 수 있다는 장점이 있습니다.

 

어댑터 기반 방법 외에도 다양한 PEFT 기법들이 제안되었습니다. 이 중 주목할 만한 것들은 LoRA, prompt tuning, 그리고 prefix tuning입니다.

더보기

LoRA (Low-Rank Adaptation)

Microsoft에 의해 공개된 LoRA는 현재 가장 유명한 방법론 중 하나입니다. 이 기법은 기존 모델의 가중치를 직접적으로 수정하지 않고 낮은 순위의 행렬을 사용하여 모델의 동작을 조정합니다. LoRA는 특히 Stable diffusion, LLaMA, Alpaca와 같은 최신 모델에 널리 적용되고 있습니다.

Prompt Tuning

Prompt tuning은 모델에 입력되는 프롬프트를 조정하여 모델의 반응을 특정 방향으로 유도하는 기법입니다. 이 방법은 특히 언어 모델에서 유용하게 사용됩니다.

Prefix Tuning

Prefix tuning은 입력 시퀀스의 시작 부분에 고정된 토큰들(prefix)을 추가하여 모델의 출력을 조정합니다. 이는 특히 시퀀스 생성 작업에 효과적입니다.

https://arxiv.org/pdf/1902.00751.pdf

Adapter 논문에서 제시하고 있는 Adapter Layer의 구조를 보여주는 그림입니다. 우리가 흔히 알고 있는 Transformer구조에서 Layer Normalization 을 수행하기 이전 단계에 Feed Forward Layer를 추가한 모습을 확인 할 수 있습니다.

 

사실 최근에는 이미 이러한 것들이 쉽게 적용될 수 있도록 하는 라이브러리들이 충분히 많아서 pytorch로 일일히 구현할 필요가 없이 학습을 할 수 있게 되어있습니다.

 

아래에 대표적인 코드 사용방법을 첨부합니다.

PyTorch에서 어댑터 사용하기

초기화 및 어댑터 로드

어댑터를 사용하기 위해서는 먼저 PyTorch와 AdapterHub 라이브러리를 사용하여 모델을 초기화해야 합니다. 예를 들어, BERT 모델을 사용할 경우 아래와 같이 코드를 작성할 수 있습니다:

import torch
from transformers import BertTokenizer
from adapters import BertAdapterModel

tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertAdapterModel.from_pretrained('bert-base-uncased')

어댑터 로드 및 활성화

다음으로, 특정 작업에 유용한 사전 훈련된 어댑터를 AdapterHub에서 로드합니다. 예를 들어, 감정 분석 작업의 경우 SST-2 데이터셋에서 훈련된 어댑터를 사용할 수 있습니다:

adapter_name = model.load_adapter("sentiment/sst-2@ukp", config='pfeiffer')
model.set_active_adapters(adapter_name)
 

예측 및 어댑터 저장

이제 모델을 사용하여 예측을 수행하고, 어댑터를 저장할 수 있습니다:

input_data = tokenizer("Your sentence here", return_tensors="pt")
outputs = model(**input_data)
predicted = torch.argmax(outputs[0]).item()

model.save_adapter("your_path", adapter_name)

어댑터 삭제

필요 없는 어댑터는 다음과 같이 삭제할 수 있습니다:

 
model.delete_adapter(adapter_name)

이 예시 코드를 통해, 사전 훈련된 LLM에 어댑터를 적용하고, 이를 통해 모델의 성능을 개선하는 방법을 이해하실 수 있을 거라고 생각합니다. 자세한 설명은 AdapterHub의 문서에서 보실 수 있습니다. 



다음에는 가장 흔하게 사용되고 있고 주목받고 있는 QLoRA에 대해서 자세히 알아보도록 하겠습니다.