지난번에는 unsloth에서 가이드로 제시한 yahma/alpaca-cleaned 데이터셋으로 학습을 시켜봤는데,
이번에는 직접 다른 데이터셋을 가져와서 간단하게 챗봇?을 만들어보았다.
alpaca-cleaned 데이터셋과 비슷한 한글 데이터셋이 없을까.. 하고 찾아봤는데,
오래 찾아보질 않아서 제대로 못찾은 것 같긴 하지만 일단 가장 비슷해 보이는 데이터셋을 찾았다.
허깅페이스에서 찾은 KorQuAD/squad_kor_v1 데이터셋이다.
KorQuAD/squad_kor_v1 · Datasets at Hugging Face
The viewer is disabled because this dataset repo requires arbitrary Python code execution. Please consider removing the loading script and relying on automated data support (you can use convert_to_parquet from the datasets library). If this is not possible
huggingface.co
사실 v1과 v2가 있는데, v1은 주어진 본문의 내용 선에서 질문에 답변을 할 수 있는 챗봇을 만들기에 적합하고,
v2는 위키백과 주소를 주면 거기서 질문에 대한 답변을 찾아 하는 챗봇을 만들기에 적합해보였다.
위키백과 주소는 링크 형식이 아니라 html 태그 형식으로 줘야하는게 귀찮아서 ㅋㅋ..
그래서 일단 v1 데이터셋을 사용하여 fine tuning을 시도해보았다.
- 개발환경 : Google Colab
- GPU : T4
코드는 사실 크게 다르지가 않다. (잘 정리된 최신 모델의 빅 장점..)
%%capture
# Installs Unsloth, Xformers (Flash Attention) and all other packages!
!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
!pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes
먼저 환경세팅부터 해주시고..
# Base Model 세팅
from unsloth import FastLanguageModel
import torch
max_seq_length = 2048
dtype = None
load_in_4bit = True
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Meta-Llama-3.1-8B",
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit,
)
기본 모델은 저번이랑 동일하게 Llama-3.1-8B로 선택했다.
# lora adapter 사용 (fine tuning 가속이 가능하다고 함.)
model = FastLanguageModel.get_peft_model(
model,
r = 16,
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",],
lora_alpha = 16,
lora_dropout = 0, # Supports any, but = 0 is optimized
bias = "none", # Supports any, but = "none" is optimized
use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context
random_state = 3407,
use_rslora = False, # We support rank stabilized LoRA
loftq_config = None, # And LoftQ
)
LoRA adapter까지 지난번이랑 동일하게 세팅해주면 준비 끝이다.
# KorQuAD 데이터셋으로 파인튜닝
KorQuAD_prompt = """
### 질문:
{}
### 보기:
{}
### 답변:
{}"""
EOS_TOKEN = tokenizer.eos_token # Must add EOS_TOKEN
def formatting_prompts_func(examples):
instructions = examples["question"]
inputs = examples["context"]
outputs = [item['text'][0] for item in examples["answers"]]
texts = []
for instruction, input, output in zip(instructions, inputs, outputs):
# Must add EOS_TOKEN, otherwise your generation will go on forever!
text = KorQuAD_prompt.format(instruction, input, output) + EOS_TOKEN
texts.append(text)
return { "text" : texts, }
pass
from datasets import load_dataset
dataset = load_dataset("KorQuAD/squad_kor_v1", split = "train")
dataset = dataset.map(formatting_prompts_func, batched = True,)
이제 여기서부터 조금 다르다.
한글 버전으로 만들거기 때문에, 친절하게 한글을 사용해서..ㅎㅎ;
formatting_prompts_func 함수 내부를 조금 바꿔줘야하는데,
alpaca-cleaned 데이터셋이랑 squad_kor_v1 데이터셋의 차이점을 잘 비교해서 바꿔야한다.
- instructions : 질문에 해당하는 부분
- inputs : 답변을 찾을 본문에 해당하는 부분
- outputs : 정답에 해당하는 부분
squad_kor_v1 데이터셋에는 답변이 리스트로 감싸져 있어서 따로 빼줘야했다.
* 추가적으로 커스텀 코드 사용할거냐고 물어보는데, 그냥 y 입력했다.
# 모델 훈련 세팅
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 2,
packing = False, # Can make training 5x faster for short sequences.
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
# num_train_epochs = 1, # Set this for 1 full training run.
max_steps = 60,
learning_rate = 2e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
output_dir = "outputs",
),
)
모델 훈련을 세팅해주고..
# 훈련합시다..
trainer_stats = trainer.train()
훈련까지 진행했다.
과연 잘 되었을지..
# 입력받은 질문 사용해서 KorQuAD로 파인튜닝한 모델 사용해보기
FastLanguageModel.for_inference(model)
from transformers import TextStreamer
text_streamer = TextStreamer(tokenizer)
while True:
print("질문을 입력하세요.")
question = input()
if question == "":
print("QnA를 종료합니다.")
break
print("보기를 입력하세요.")
context = input()
inputs = tokenizer(
[
KorQuAD_prompt.format(
question, #instruction
context, # input
"", # output
)
], return_tensors = "pt").to("cuda")
text_streamer = TextStreamer(tokenizer)
_ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 128)
print()
테스트 코드도 지난번이랑 똑같은 코드를 사용했다.
테스트에서 본문만 KorQuAD/squad_kor_v1의 validation 데이터셋에서 가져와서 사용해봤다.
질문은 혹시 모르니 내가 본문을 보고 만들어서 해봤다.
질문 : 빅뱅이 첫 싱글을 발매하고 오른 무대는?
보기 : 빅뱅은 2006년 8월 19일 첫 싱글 〈Bigbang〉을 발표하였고, 같은 날 YG 패밀리 10주년 콘서트에서 첫 무대에 섰다. 2006년 9월 23일 음악 프로그램 《쇼! 음악중심》에서 공식 데뷔하였다. 승리는 그해 12월에 발매 된 빅뱅의 첫 번째 정규 음반 《BIGBANG Vol.1》에 수록 된 "다음 날"로 첫 솔로 곡을 불렀다. 빅뱅은 2007년 그들의 첫 번째 EP 《Always》의 발매와 동시에 타이틀 곡 "거짓말"은 엄청난 메가히트를 기록했고, 이후 두 번째 EP 《Hot Issue》의 "마지막 인사"와 세 번째 EP 《Stand Up》의 "하루하루"가 연이어 차트 정상을 차지하며 최정상의 대세 그룹으로 우뚝 섰다.
답을 잘 찾아내는 것을 확인했다.
질문을 조금 애매하게 하면 다른 답을 하긴 해도, 제시해준 본문의 범주 밖을 벗어나진 않는 것 같다.
갑자기 또 테스트 욕구가 솟구쳐서, 지난번에 뉴진스에 관해서 질문한 것을 이용해보았다.
질문 : 뉴진스의 멤버 중 세글자 이름을 사용하는 멤버는?
보기 : 뉴진스(NewJeans)는 대한민국의 5인조 걸그룹으로, 2022년 7월 22일에 데뷔했습니다. ADOR(어도어) 소속으로, 하이브(HYBE)의 하위 레이블 중 하나입니다. 그룹의 구성원은 민지, 하니, 다니엘, 해린, 혜인으로 이루어져 있습니다.
아주 훌륭하게 답을 찾아내는 모습을 확인할 수 있었다.
이런 느낌으로 학습시킨 모델을 사용해서 본격적으로 챗봇을 만들어볼까 한다.