PEFT를 활용한 PLM 파인튜닝 가이드

반응형

안녕하세요! 오랜만에 블로그 글쓰기를 재개하니 정말 설렙니다. 최근 개인 프로젝트를 진행하느라 블로그 글쓰기에 힘쓰지 못해서 반성합니다😂. 최근에 재밌게 읽고 있는 글들이 많아서 블로그 글을 작성하는데 자극이 많이 되는 것 같아요. 

 

출처:https://wandb.ai/iamleonie/Articles/reports/Understanding-LLMOps-Large-Language-Model-Operations--Vmlldzo0MDgyMDc2

 

저는 요즘 핫한 주제인 Large Language Models(LLM)에 대해 관심 있게 읽고 있는데요, 이전에 Transformer 기반의 모델을 활용한 연구에 많은 시간을 보냈는데, 최근에 LLM이 주목받으면서 이에 대한 다양한 강의와 튜토리얼을 살펴보고 있습니다. ChatGPT의 등장 이후로 LLM 관련 정보가 폭발적으로 증가하고 있는 것 같아, 한편으로는 벅차지만 그만큼 더 흥분되는 마음입니다.

 

본격적인 오늘의 포스팅을 시작하기 전에 그 중에서도 특히 마음에 든 강의를 한 번 소개하고자 합니다.

 

https://www.coursera.org/learn/generative-ai-with-llms

 

Generative AI with Large Language Models

In Generative AI with Large Language Models (LLMs), you’ll learn the fundamentals of how generative AI works, and how to deploy it in real-world ... 무료로 등록하십시오.

www.coursera.org

 

이 강의는 DeepLearning.AI와 AWS가 공동 제작'Generative AI with Large Language Models (LLMs)'라는 강좌입니다. 이 강좌를 통해 Generative AI에 대한 이해를 넓힐 수 있을 뿐만 아니라, 대규모 언어 모델인 LLM에 대한 깊은 이해를 쌓을 수 있습니다. 언어 모델의 핵심 요소인 Transformer부터 시작해, LLMs가 실제로 어떻게 활용되고 있는지까지 다룹니다. 하지만, 이 강좌는 깊이 있는 내용을 다루고 있어 Python 코딩에 익숙하고, 머신러닝에 대한 기본적인 이해가 필요합니다. 그래도 DeepLearning.AI의 다른 강의를 이미 들어봤다면, 이 강좌도 충분히 소화할 수 있을 거라 생각합니다. 또한, 이 강의 자체는 무료지만, 실습을 위해 AWS labs를 이용하면 일부 비용이 발생할 수 있습니다.

 

아직 Coursera 강의의 내용을 블로그에 공유하는 것에 대한 저작권 문제를 완전히 파악하지 못했기 때문에, 자세한 내용은 여기서는 다루지 않겠습니다. 하지만 기회가 된다면, 이 강의에 대해 더 상세히 다루는 글을 써볼 계획입니다. 마지막으로, DeepLearning.AI는 다양한 주제에 대한 수많은 강의를 무료로 제공하고 있습니다. 관심 있는 분들은 꼭 한 번 확인해보시길 바랍니다.

 


 

오늘은 Huggingface documentation을 참조하여, Pre-trained Language Model (PLM)을 효과적으로 Fine-tuning하기 위해 사용되는 라이브러리인 Parameter-Efficient Fine-Tuning (PEFT)에 대해 소개하고자 합니다.

 

최근에는 대규모 말뭉치를 대상으로 트랜스포머 모델을 사전 학습시킨 PLM이 다양한 자연어 처리 분야에서 뛰어난 성능을 보이고 있습니다. 연구자들이 모델의 크기를 점차 늘려가면서 언어 모델의 성능이 매개변수의 규모가 일정 수준을 초과하면 크게 향상된다는 사실을 발견했습니다. 이로 인해 Large Language Models(LLMs) 이라는 용어가 생겨나게 되었으며, 이것을 대규모 Pre-trained Language Model(PLM)라고도 부릅니다. 이렇게 대규모의 PLMs는 큰 성능을 내는 반면, Fine-tuning 과정에서 상당한 비용이 들게 되는 문제가 있습니다.

 

https://www.anyscale.com/blog/training-175b-parameter-language-models-at-1000-gpu-scale-with-alpa-and-ray

 

이전에는 모델의 모든 파라미터를 Fine-tuning하는 방식이 주를 이루었지만, LLMs의 파라미터 수가 기하급수적으로 증가함에 따라 이로 인한 비용이 높아져, 일반 사용자들이 사용하기 어려운 상황이 되었습니다. 이러한 문제를 해결하고자, PEFT와 같은 라이브러리는 모델 파라미터 중 일부만 미세 조정하거나, Low-rank adaptation (LoRA)와 같은 재매개변수화 방법을 사용하여, 계산 및 저장 비용을 크게 절감합니다.

 

따라서 PEFT는 다양한 방법을 통해 대규모 언어 모델의 Fine-tuning 비용을 혁신적으로 줄이는 라이브러리라고 할 수 있습니다.

 

오늘은 PEFT의 설치 방법, PeftConfig와 PeftModel, 그리고 PEFT로 훈련된 모델의 저장 및 로드 방법에 대해 간략히 살펴보겠습니다. 다음 글에서는 PEFT의 다양한 Tuners/methods를 상세히 소개하고, 실제 모델을 Fine-tuning 실습해보겠습니다.

 


 

1. Installation

Peft는 python3.8+ 환경에서 사용할 수 있습니다.

 

1) PyPI

pip install peft

 

2) Github

pip install git+https://github.com/huggingface/peft

 

2. Methods

출처: https://huggingface.co/docs/peft/main/en/index

PEFT는 다양한 방법을 지원하여 대규모 언어 모델의 미세조정을 최적화하는 데 도움이 됩니다. PEFT에서 지원하는 주요 메소드들은 PEFT의 documents에서 확인할 수 있습니다. 각 메소드 별로 지원하는 모델이 다르기 때문에 'Supported Models'와 'Task guides'를 확인해야 합니다.

 

 

3. PeftConfig

각 PEFT method는 Peftconfig class에 의해 정의되는데, 여기서 PeftModel을 build하기 위한 중요한 parameter들을 저장합니다.

출처: https://huggingface.co/docs/peft/main/en/package_reference/config#peft.PeftConfig

 

만약 LoRA를 사용한다면, LoraConfig class를 만들어야 합니다. LoraConfig에는 다음과 같은 파라미터들이 존재합니다.

파라미터에 대한 상세한 설명은 이후 LoRA를 사용하는 실습 때 기술하도록 하겠습니다. 

 

아래의 코드 처럼 PeftConfig를 정의할 수 있습니다.

from peft import LoraConfig, TaskType

peft_config = LoraConfig(task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1)

 

 

4. PeftModel

출처: https://huggingface.co/docs/peft/main/en/package_reference/peft_model#peft.PeftModel

PeftModel은 ‘get_peft_model()’ 함수를 통해 생성됩니다. 이 함수는 기본 모델과 PeftConfig를 argument로 받습니다. 이때 기본 모델은 Transformers 라이브러리에서 로드할 수 있고, PeftConfig는 위에서 정의한 대로, 특정 방법에 맞게 모델을 설정합니다.

 

예시를 위해 모델 ‘bigscience/mt0-large’ 을 Transformers 라이브러리에서 불러옵니다.

from transformers import AutoModelForSeq2SeqLM

model_name_or_path = "bigscience/mt0-large"
tokenizer_name_or_path = "bigscience/mt0-large"
model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)

 

로드한 모델과 PeftConfig를 ‘get_peft_model’ 함수로 감싸서 PeftModel 정의합니다. 모델의 훈련 가능한 파라미터 수를 확인하고 싶다면, ‘print_trainable_parameters’ 메소드를 사용하면 됩니다. all_params는 모델의 전체 파라미터이고, trainable_parameters는 훈련 가능한 파라미터, trainable는 모델 파라미터의 몇 퍼센트를 훈련하는지를 보여줍니다. 이 경우에는 모델 파라미터의 단지 0.19%만 훈련하게 됩니다.

from peft import get_peft_model

model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
"output: trainable params: 2359296 || all params: 1231940608 || trainable%: 0.19151053100118282"

 

이렇게 PEFT를 활용하면, 기존 방법보다 훨씬 적은 파라미터를 훈련함으로써 훨씬 효율적으로 대규모 모델을 Fine-tuning 할 수 있습니다.

 

 

5. Save and load a model

훈련이 완료된 모델은 ‘save_pretrained’함수를 통해 저장할 수 있습니다. ‘push_to_hub’함수를 통해 Hugging Face 계정에 모델을 저장할 수도 있습니다.

model.save_pretrained("output_dir")

# if pushing to Hub
from huggingface_hub import notebook_login

notebook_login()
model.push_to_hub("my_awesome_peft_model")

 

이렇게 저장하는 방식은 훈련된 PEFT의 가중치만 저장되기 때문에, 저장, 전송, 로드에 매우 효율적입니다. 예를 들어 LoRA로 RAFT dataset의 twitter_complanits에 대해 훈련된 ‘bigscience/T0_3B’ 모델은 adapter_config.json과 adapter_model.bin 이라는 두 파일만 존재하고, bin 파일의 용량은 19MB로 매우 작습니다.

from transformers import AutoModelForSeq2SeqLM
from peft import PeftModel, PeftConfig

peft_model_id = "smangrul/twitter_complaints_bigscience_T0_3B_LORA_SEQ_2_SEQ_LM"
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)

 

Inference를 위해 모델을 로드하기 위해서는 ‘from_pretrained’ 함수를 사용합니다.

from transformers import AutoModelForSeq2SeqLM
+ from peft import PeftModel, PeftConfig

+ peft_model_id = "smangrul/twitter_complaints_bigscience_T0_3B_LORA_SEQ_2_SEQ_LM"
+ config = PeftConfig.from_pretrained(peft_model_id)
  model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
+ model = PeftModel.from_pretrained(model, peft_model_id)
  tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)

  model = model.to(device)
  model.eval()
  inputs = tokenizer("Tweet text : @HondaCustSvc Your customer service has been horrible during the recall process. I will never purchase a Honda again. Label :", return_tensors="pt")

  with torch.no_grad():
      outputs = model.generate(input_ids=inputs["input_ids"].to("cuda"), max_new_tokens=10)
      print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0])
  'complaint'

 

 

6. Easy Loading with Auto Classes

Model adapter를 로컬이나 Hub에 저장했다면, AutoPeftModelForXXX 클래스를 사용해 코드 한줄로 PEFT모델을 로드할 수 있습니다. 

 

기존 코드는 peft와 transformers에서 필요한 라이브러리를 불러와서, 모델을 불러와야 한다면,

from peft import PeftConfig, PeftModel
from transformers import AutoModelForCausalLM

peft_config = PeftConfig.from_pretrained("ybelkada/opt-350m-lora") 
base_model_path = peft_config.base_model_name_or_path
transformers_model = AutoModelForCausalLM.from_pretrained(base_model_path)
peft_model = PeftModel.from_pretrained(transformers_model, peft_config)

 

peft 라이브러리를 불러오고 모델을 로드하는 것이 매우 간편합니다.

from peft import AutoPeftModelForCausalLM
peft_model = AutoPeftModelForCausalLM.from_pretrained("ybelkada/opt-350m-lora")

 


참고:

 

https://huggingface.co/docs/peft

 

PEFT

🤗 Accelerate integrations

huggingface.co

 

반응형