Unsloth 빠른 튜토리얼
Unsloth는 대규모 언어 모델을 빠르고 효율적으로 미세 조정하기 위한 라이브러리입니다. Hugging Face Transformers 라이브러리를 기반으로 구축되었으며, 다양한 작업에 대해 모델을 파인튜닝하는 데 사용할 수 있습니다. 여기서는 Llama 3.1 모델이 텍스트를 SQL로 변환하는 생성 작업을 수행하도록 학습시키겠습니다.
Unsloth를 사용하면 단일 GPU 환경에서 표준 미세 조정보다 2배 빠르게 학습하고 메모리를 60% 적게 사용할 수 있습니다. Unsloth는 QLoRA(Quantized Low Rank Adaptation)라는 기법을 사용하여 모델을 양자화하고, 모델 전체 대신 소수의 추가 학습 가능 매개변수만 학습합니다. 덕분에 단일 NVIDIA H100 GPU에서 모델을 학습시킬 수 있습니다.
flash-attn과 xformers는 pip를 직접 사용하여 소스에서 설치해야 합니다.
# Install flash-attn
poetry run pip install flash-attn --no-build-isolation
# Install xformers
poetry run pip install -v -U git+https://github.com/facebookresearch/xformers.git@main#egg=xformers
# Install unsloth
poetry run pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
나머지는 poetry를 통해 PyPI에서 설치할 수 있습니다.
[tool.poetry.dependencies]
trl = "^0.9.6"
nvitop = "^1.3.2"
xformers = "0.0.27"
peft = "^0.12.0"
accelerate = "^0.33.0"
bitsandbytes = "^0.43.3"
이제 train.py 스크립트를 초기화할 수 있습니다. 다음 Hugging Face 라이브러리들을 불러오십시오:
import torch
from datasets import load_dataset
from transformers import EarlyStoppingCallback, TextStreamer, TrainingArguments
from trl import SFTTrainer
from unsloth import FastLanguageModel, is_bfloat16_supported
from unsloth.chat_templates import get_chat_template
4비트로 양자화된 80억 매개변수 Llama 3.1 모델을 다운로드하겠습니다. 이는 모델의 가중치가 16비트 대신 4비트를 사용하도록 압축되었다는 뜻입니다. 이로 인해 모델을 훨씬 빠르게 불러오고 사용할 수 있지만, 여전히 상당히 큰 모델입니다.
max_seq_length = 2048
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Meta-Llama-3.1-8B-bnb-4bit",
max_seq_length=max_seq_length,
load_in_4bit=True,
dtype=None,
)
model = FastLanguageModel.get_peft_model(
model,
r=16,
lora_alpha=16,
lora_dropout=0,
target_modules=[
"q_proj",
"k_proj",
"v_proj",
"up_proj",
"down_proj",
"o_proj",
"gate_proj",
],
use_rslora=True,
use_gradient_checkpointing="unsloth",
)
tokenizer = get_chat_template(
tokenizer,
chat_template="chatml",
)
텍스트를 SQL로 변환하는 프롬프트로 구성된 합성 데이터셋을 사용하겠습니다.
def convert(question):
return {"user": question["sql_prompt"], "assistant": question["sql"]}
def apply_template(examples):
messages = examples["conversations"]
text = [
tokenizer.apply_chat_template(
convert(message), tokenize=False, add_generation_prompt=False
)
for message in messages
]
return {"text": text}
dataset = load_dataset("gretelai/synthetic_text_to_sql", split="train")
dataset = dataset.map(apply_template, batched=True)
코사인 어닐링 웜 리스타트(cosine annealing warm restarts) 스케줄러와 함께 8비트 AdamW 옵티마이저를 사용하겠습니다. 또한 과적합을 방지하기 위해 조기 종료(early stopping)를 추가하겠습니다.
callbacks = [
EarlyStoppingCallback(early_stopping_patience=3),
]
training_args = TrainingArguments(
learning_rate=3e-4,
lr_scheduler_type="linear",
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
num_train_epochs=6,
fp16=not is_bfloat16_supported(),
bf16=is_bfloat16_supported(),
logging_steps=1,
optim = "adamw_8bit",
lr_scheduler_type = "cosine_with_restarts",
weight_decay=0.05,
warmup_steps=10,
output_dir="output",
seed=0,
)
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
dataset_text_field="text",
max_seq_length=max_seq_length,
dataset_num_proc=2,
packing=True,
args=training_args,
load_best_model_at_end=True,
metric_for_best_model="eval_loss",
callbacks=callbacks,
)
trainer.train()
print("Done.")
이를 실행하면 다음과 같은 출력을 볼 수 있습니다. 이 작업은 6 에포크 동안 실행되며, Nvidia H100 GPU에서 완료까지 약 2~3시간이 소요됩니다.
# ==((====))== Unsloth - 2x faster free finetuning | Num GPUs = 1
# \\ /| Num examples = 2,254 | Num Epochs = 3
# O^O/ \_/ \ Batch size per device = 2 | Gradient Accumulation steps = 4
# \ / Total batch size = 8 | Total steps = 843
# "-____-" Number of trainable parameters = 29,884,416
이제 모델을 사용하여 텍스트를 생성할 수 있습니다.
model = FastLanguageModel.for_inference(model)
messages = [
{
"user": "What is the average salary of employees in the IT department?",
"assistant": "",
},
]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_tensors="pt",
).to("cuda")
text_streamer = TextStreamer(tokenizer)
_ = model.generate(
input_ids=inputs, streamer=text_streamer, max_new_tokens=128, use_cache=True
)
모델은 다양한 형식으로 내보낼 수도 있습니다.
model.save_pretrained_merged("model", tokenizer, save_method="merged_16bit")
trainer_stats = trainer.train()
print("Done.")
model.save_pretrained("lora_model")
tokenizer.save_pretrained("lora_model")
print("Merging model")
model.save_pretrained_merged("fused_model", tokenizer, save_method="merged_16bit")
print("Saving gguf")
model.save_pretrained_gguf("ggufs", tokenizer, quantization_method="f16")
model.save_pretrained_gguf("ggufs", tokenizer, quantization_method="q4_k_m")
다음과 같은 출력을 볼 수 있습니다:
==((====))== Unsloth: Conversion from QLoRA to GGUF information
\\ /| [0] Installing llama.cpp will take 3 minutes.
O^O/ \_/ \ [1] Converting HF to GGUF 16bits will take 3 minutes.
\ / [2] Converting GGUF 16bits to ['f16'] will take 10 minutes each.
"-____-" In total, you will have to wait at least 16 minutes.
Unsloth: [0] Installing llama.cpp. This will take 3 minutes...
Unsloth: [1] Converting model at lora-fused into f16 GGUF format.
The output location will be ./lora-fused/unsloth.F16.gguf
...
Writing: 100%|██████████| 7.64G/7.64G [01:18<00:00, 97.1Mbyte/s]
INFO:hf-to-gguf:Model successfully exported to lora-fused/unsloth.F16.gguf
Unsloth: Conversion completed! Output location: ./lora-fused/unsloth.F16.gguf
이것으로 끝입니다! 이제 파인튜닝된 텍스트-SQL 생성기를 갖게 되었습니다. 데이터 처리 스크립트를 최소한으로 변경하여 다른 작업에도 쉽게 적용할 수 있습니다.
여기서 더 나아가 다양한 강화 학습 기법을 사용하여 모델을 학습시켜 모델의 성능을 더욱 향상시킬 수도 있습니다.
- Kahneman-Tversky 최적화(KTO)는 이진 피드백 데이터로 언어 모델을 정렬하는 데 사용할 수 있습니다.
- 직접 선호 최적화(DPO)는 쌍별 피드백 데이터로 언어 모델을 정렬하는 데 사용할 수 있습니다.