빅데이터의 등장 이후 막대한 크기의 지식을 이미 pre-trained 한 언어 모델이 등장하였고, 이러한 등장은 굳이 Open-domain QA를 해야할까란 의문을 들게함.
왜냐하면 이미 사전학습된 거대언어모델이 하나의 knowledge storage이기 때문에, 추가적으로 다른 곳에서 지식을 가져와야할 필요가 없어졌기 때문.
2019년 fill-mask와 같은 Task에 관해 BERT가 보여준 퍼포먼스와 GPT-2가 한번도 본적이 없는 Natural Questions 데이터셋에 어느정도 응답하면서, 위와 같은 Closed-book QA에 대한 주장은 근거가 있는 것으로 판단되었음.
| Open-book QA | Closed-book QA | |
|---|---|---|
| 지식을 찾는 방식 | 대량의 지식 소스를 특정 문서 단위로 나누어 Dense/Sparse 형태로 표현한 후, query가 들어오면 그와 관련된 문서를 search | 대량의 지식 소스(위키피디아 등)를 기반으로 사전학습된 언어 모델이 그 지식을 기억하고 있을 것이라 가정함. Search 과정 없이 바로 정답을 생성함 |
| 문제점 | 지식 소스를 저장하기 어려움, 검색하는 시간 소요 | 사전학습된 언어 모델이 얼마나 지식을 잘 기억하고 있는지가 매우 중요함 |
계산 비용 높음
시간 많이 걸림
리소스 많이 필요
유연성 떨어짐
과적합 위험 있음
위와 같은 문제를 해결하려고 PEFT 기법들이 등장했고, LoRA와 같은 기법을 쓰면 일부 매개변수만 업데이트해서 효율적으로 fine-tuning 할 수 있음.
위와 같이 매번 새로운 Specific Task에 대해 Fine-tuing된 모델을 만들 바에 T5와 같이 모든 문제를 text-to-text로 해결하는 모델이 등장함.
그리고 실제 연구를 하였을 시에 MRC 데이터셋의 QA쌍에 대하여 T5가 잘 응답하였음
Instruction Tuning:
모델에게 특정한 지시사항을 제공하여 학습시키는 방법. 모델이 이전에 접하지 못한 작업에도 지시사항을 따라 답을 추론할 수 있게 함
In-Context Learning (ICL):
대형 언어 모델이 사전 훈련된 맥락을 이용하여 새로운 작업을 배우는 능력. 모델의 매개변수를 수정하지 않고 입력 예시를 통해 특정 작업을 수행하도록 조정함
Instruction Tuning은 모델에게 다양한 지시사항과 그에 대한 적절한 응답을 학습시키는 방법임. 이를 통해 모델은 새로운 지시사항에 대해서도 적절히 대응할 수 있게 됨.
예시:
Instruction: "김치찌개 끓이는 법을 알려줘"
Output: "물 몇cc, 돼지고기 몇그람, 두부 반모.. 끓이는 순서는.."이런 형식의 데이터셋을 대량으로 학습시켜 모델이 다양한 지시에 대응할 수 있게 함
ICL은 모델이 주어진 맥락(context)을 이해하고 그에 맞는 답변을 생성하는 능력을 말함. 모델 파라미터의 변경 없이 입력 예시만으로 새로운 작업을 수행할 수 있음.
예시:
입력:
2010년 월드컵 우승국: 스페인
2006년 월드컵 우승국: 이탈리아
2014년 월드컵 우승국: ?
출력: 독일이 예시에서 모델은 주어진 패턴을 파악하고 2014년 월드컵 우승국을 추론함
학습 방식:
데이터 요구사항:
유연성:
Instruction Tuning과 In-Context Learning은 모두 LLM의 성능을 향상시키는 중요한 방법이다.
Instruction Tuning은 모델의 일반적인 지시 따르기 능력을 향상시키는 반면, In-context Learning은 즉각적인 맥락 이해와 적용 능력을 강화하기 때문이다.
두 방법을 적절히 조합하여 사용하면 더욱 강력하고 유연한 AI 시스템을 구축할 수 있다.
In-context Learning과 Prompt Engineering
In-Context Learning은 Prompt Engineering의 한 기법으로, 예시를 통해 모델이 새로운 작업을 수행하도록 하는 특정 방법이다.
반면 Prompt Engineering은 ICL을 포함한 더 광범위한 기법들을 활용하여 AI 모델의 출력을 최적화하는 전반적인 프로세스를 의미하기에, 두 접근 방식은 상호 보완적이며 효과적으로 조합하여 사용할 때 AI 시스템의 성능을 크게 향상시킬 수 있다.
LoRA는 모델의 가중치 행렬을 두 개의 저차원 행렬로 분해하여 학습한다.
원래의 가중치 행렬 W는 다음과 같이 근사된다:
W ≈ W₀ + BA
일반적으로 Transformer 모델의 attention 레이어에 LoRA를 적용하는데, 구체적으로는
위 두개에 적용된다.
주요 하이퍼파라미터:
r: 저차원 행렬의 랭크 (일반적으로 8, 16, 32 등)alpha: 스케일링 팩터dropout: LoRA 레이어에 적용할 드롭아웃 비율# 필요 라이브러리 다운로드
!pip install transformers peft bitsandbytes trl pandas numpy datasets wandb
!pip install accelerate -U
# 라이브러리 import
import os
import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, pipeline
from peft import LoraConfig, get_peft_model
from trl import SFTTrainer
import huggingface_hub
import wandb
# 데이터셋 다운로드
train_dataset_name = "something/something"
train_dataset = load_dataset(train_dataset_name, split="train")
# base model 정하기
base_model_name = "meta-llama/Meta-Llama-3.1-8B-Instruct"
# 허깅페이스 login , read
import huggingface_hub
huggingface_hub.login(token='토큰아이디')
# 모델 불러오기
llama_3_8b_lora = AutoModelForCausalLM.from_pretrained(
base_model_name,
device_map = 'auto')
# tokenizer 불러오기
tokenizer = AutoTokenizer.from_pretrained(
base_model_name,
trust_remote_code=True
)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# peft config 설정
peft_config = LoraConfig(
lora_alpha = 32,
lora_dropout=0.1,
r=128,
bias="none",
task_type="CAUSAL_LM",
)
# TextStreamer로 토큰 생성할 때 마다 뱉어내게 하기
from transformers import TextStreamer
streamer = TextStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
# Training_arguments 설정
training_arguments = TrainingArguments(
output_dir="./tuning_results",
num_train_epochs=1,
per_device_train_batch_size=16,
gradient_accumulation_steps=2,
optim="paged_adamw_32bit",
save_steps=2000,
logging_steps=100,
learning_rate=2e-4,
weight_decay=0.001,
fp16=False,
bf16=True,
max_grad_norm=0.3,
max_steps=-1,
warmup_ratio=0.03,
group_by_length=True,
lr_scheduler_type="constant"
)
# SFTTrainer 설정
trainer = SFTTrainer(
model=llama_3_8b_lora,
train_dataset=train_dataset,
peft_config=peft_config,
dataset_text_field="text",
max_seq_length=None,
tokenizer=tokenizer,
args=training_arguments,
packing=False,
)
# W&B API 키 설정
wandb.login(key="wandb 키")
# 로깅 될 config들 기록되도록 처리
combined_config = {**vars(training_arguments), **vars(peft_config)}
# wandb 실행 초기화
run = wandb.init(name = "llama3_8b_lora", project="mentos", config= combined_config)
# finetuning
trainer.train()
wandb.finish()
# 모델 저장
new_model = "tuned-llama-3-8b-lora"
trainer.model.save_pretrained(new_model)
trainer.tokenizer.save_pretrained(new_model)
# 모델 불러오기
model = get_peft_model(temp_model)
# 원래 get_peft_model은 peft_config 까지 두개의 인자를 받으나, temp_model이 peft로 학습되었고, 이를 저장했으므로 그냥 temp_model만 불러온다)