Post

๐Ÿ–ฅ๏ธ LORA Practice!! : LORA ์‹ค์Šต!! with python

๐Ÿ–ฅ๏ธ LORA Practice!! : LORA ์‹ค์Šต!! with python

๐Ÿฆ–(ํ•œ๊ตญ์–ด) LORA ์‹ค์Šต!!

LORA : Low-Rank Adaptation of Large Language Models

์˜ค๋Š˜์€ ์ง€๋‚œํฌ์ŠคํŒ…์—์„œ ์ด๋ก ์— ๋Œ€ํ•˜์—ฌ ๊ณต๋ถ€ํ•ด๋ณด์•˜๋˜!
Fine-Tuning์˜ ์ •์ˆ˜! LORA ์˜ ์‹ค์Šต์„ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!!


๐Ÿงฑ 1. LORA ํŒจํ‚ค์ง€ ์„ค์น˜ ๋ฐ ๋ชจ๋ธ ๋กœ๋“œ!

LORA์˜ ๊ฒฝ์šฐ๋Š” ์›Œ๋‚™ ์œ ๋ช…ํ•œ ๋ฐฉ๋ฒ•์ด์–ด์„œ,
git repo ๋ณต์ œ๊ฐ€ ์•„๋‹ˆ๋ผ! Hugging Face์˜ ํŒจํ‚ค์ง€๋กœ์„œ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค!

์ด์—, ์•„๋ž˜์™€ ๊ฐ™์ด pip ๋กœ ํ•„์š” ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ ํ›„ ๋กœ๋“œ ํ•ด์ฃผ์„ธ์š”~!

1
pip install transformers peft datasets accelerate

PEFT๋ž€?
Parameter-Efficient Fine-Tuning ์˜ ์•ฝ์–ด๋กœ์„œ,
๋ชจ๋ธ์˜ ๋ชจ๋“  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋Œ€์‹  ์ผ๋ถ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ ํšจ์œจ์ ์œผ๋กœ ์กฐ์ •ํ•˜๋Š” ๊ธฐ์ˆ ๋“ค์˜ ์ด์นญ์ž…๋‹ˆ๋‹ค.

from peft import PrefixTuningConfig, PromptTuningConfig, AdaLoraConfig, IA3Config ๋ฅผ ํ†ตํ•ด LORA์™ธ์˜ ๋ฐฉ๋ฒ•๋„ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!!

1
2
3
4
5
6
7
8
9
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling
from peft import get_peft_model, LoraConfig, TaskType # peft!!!
from datasets import load_dataset # ๊ธฐ๋ณธ ์ œ๊ณต๋œ ํ•™์Šต๋ฐ์ดํ„ฐ๋กœ ํ•ด๋ณด๊ธฐ์œ„ํ•ด์„œ! 
from datasets import Dataset  # ์ดํ›„ ํ•™์Šต ์ง์ ‘ ์ž…๋ ฅ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด๊ฒŒ ํ•„์š”!

import torch
import os
os.environ["WANDB_DISABLED"] = "true" # ์ด๋ถ€๋ถ„์ด ์ถ”๊ฐ€ ์•ˆ๋˜๋ฉด wandb์˜ ์—๋Ÿฌ๊ฐ€ ๋‚˜์š”!

๊ทธ๋ฆฌ๊ณ  ์˜ค๋Š˜์˜ ํŒŒ์ธ ํŠœ๋‹์€ ํ˜„์‹œ์ ์—์„œ ์ตœ์‹ ์ด๋ฉด์„œ ๊ฐ€๋ฒผ์šด!
Qwen2.5์˜ 0.5B ๋ชจ๋ธ Qwen/Qwen2.5-0.5B ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Fine Tuning์„ ์ง„ํ–‰ํ•˜๊ณ ์žํ•ฉ๋‹ˆ๋‹ค!

์ด์—, ์•„๋ž˜์™€ ๊ฐ™์ด ๋ชจ๋ธ์„ ๋กœ๋“œํ•ด์ค๋‹ˆ๋‹ค!
Hugging Face์—์„œ ๋‹ค์šด๋ฐ›๊ธฐ์—, ์ฒ˜์Œ์—๋Š” ์‹œ๊ฐ„์ด ์ข€ ๊ฑธ๋ฆด๊ฑฐ์—์š”~!

1
2
3
4
5
6
7
8
9
10
11
12
# ๋ชจ๋ธ ๋ฐ ํ† ํฌ๋‚˜์ด์ € ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
model_name = "Qwen/Qwen2.5-0.5B"  
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token  # padding ํ† ํฐ ์„ค์ •

# ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ 
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    load_in_4bit=True,  # bitsandbytes๋ฅผ ํ†ตํ•œ 4bit quantization (์„ ํƒ์‚ฌํ•ญ)
    device_map="auto",
    trust_remote_code=True
)

๐Ÿ“ฆ 2. LORA ์„ธํŒ…!!

์ด์ œ ์‚ฌ์šฉํ•  LORA ๋ชจ๋ธ์˜ parameter๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ !,
๊ธฐ์กด qwen2.5 ๋ชจ๋ธ์— ํ•ฉ์ณํ•ด ์ค„ ๊ฒƒ ์ž…๋‹ˆ๋‹ค!!

1
2
3
4
5
6
7
8
9
10
11
12
# LoRA ์„ค์ •
peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,                 # ๋žญํฌ
    lora_alpha=16,       # scaling factor
    lora_dropout=0.05,   # dropout
    bias="none",
    target_modules=["c_proj", "c_attn", "q_proj", "v_proj", "o_proj", "k_proj"],  # Qwen ๊ตฌ์กฐ์— ๋งž๊ฒŒ ์กฐ์ •
)

# LoRA ์™€ ๊ธฐ์กด Qwen ๋ชจ๋ธ์™€ ํ•ฉ์น˜๊ธฐ!! ์ ์šฉ
model = get_peft_model(model, peft_config)

์œ„์—์„œ ์‚ฌ์šฉ๋˜๋Š” LORA Parameter์— ๋Œ€ํ•˜์—ฌ ์•Œ์•„๋ณด์ž๋ฉด~~

๐Ÿ”น task_type=TaskType.CAUSAL_LM
์„ค๋ช…: LoRA๋ฅผ ์ ์šฉํ•  ํƒœ์Šคํฌ ์œ ํ˜• ์„ค์ •
CAUSAL_LM: ๋‹ค์Œ ํ† ํฐ์„ ์˜ˆ์ธกํ•˜๋Š” ์–ธ์–ด ์ƒ์„ฑ ๋ชจ๋ธ

  • Qwen๋„ GPT์™€ ๋™์ผํ•œ ๊ตฌ์กฐ์˜ Causal Language Model์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ํƒœ์Šคํฌ ํƒ€์ž…์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ฐธ๊ณ ๋กœ, TaskType.CLASSIFICATION์€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ์—,
    TaskType.SEQ_2_SEQ_LM์€ ๋ฒˆ์—ญ, ์š”์•ฝ ๋“ฑ ์ž…๋ ฅ-์ถœ๋ ฅ ์Œ์„ ๊ฐ€์ง€๋Š” ๋ชจ๋ธ์—,
    TaskType.VISION์€ ๋น„์ „ ๋ชจ๋ธ (์˜ˆ: CLIP, ViT) ๋“ฑ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”น r=8
์„ค๋ช…: LoRA์—์„œ low-rank ๋ถ„ํ•ด ์‹œ์˜ ๋žญํฌ(rank)
์˜ํ–ฅ: ์ž‘์„์ˆ˜๋ก ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜๊ฐ€ ์ ๊ณ  ๊ณ„์‚ฐ์ด ํšจ์œจ์ ์ด๋‚˜,
๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ํ‘œํ˜„๋ ฅ์ด ๋–จ์–ด์ ธ ํ•™์Šต ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜์ ์œผ๋กœ 4~16 ์‚ฌ์ด ๊ฐ’์ด ์‹คํ—˜์ ์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”น lora_alpha=16
์„ค๋ช…: LoRA ๊ฐ€์ค‘์น˜์— ์ ์šฉํ•  scaling factor
๊ณ„์‚ฐ: ์‹ค์ œ LoRA ๊ฐ€์ค‘์น˜๋Š” alpha / r์„ ํ†ตํ•ด ์กฐ์ •๋จ
์˜ํ–ฅ:

  • ๊ฐ’์ด ํด์ˆ˜๋ก LoRA์˜ ์˜ํ–ฅ๋ ฅ์ด ์ปค์ง€๊ณ ,
  • ๊ฐ’์ด ์ž‘์„์ˆ˜๋ก ์›๋ž˜ ๋ชจ๋ธ์˜ ํ‘œํ˜„์— ๊ฐ€๊นŒ์šด ๋ณด์ˆ˜์  ํŠœ๋‹์ด ๋ฉ๋‹ˆ๋‹ค.
  • ์ ์ ˆํ•œ ๊ฐ’์€ ๋ฐ์ดํ„ฐ์™€ ํƒœ์Šคํฌ์— ๋”ฐ๋ผ ์กฐ์ •ํ•ด์•ผ ํ•˜๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ alpha = 2 * r ์ˆ˜์ค€์ด ์ถ”์ฒœ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”น lora_dropout=0.05
์„ค๋ช…: ํ•™์Šต ์‹œ LoRA layer์— ์ ์šฉ๋˜๋Š” dropout ๋น„์œจ
๋ชฉ์ : ๊ณผ์ ํ•ฉ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ์ผ๋ฐ˜ํ™” ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•œ regularization ๊ธฐ๋ฒ•

  • ํŠนํžˆ ๋ฐ์ดํ„ฐ์…‹์ด ์ž‘๊ฑฐ๋‚˜ noisyํ•  ๋•Œ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”น bias="none"
์„ค๋ช…: ๊ธฐ์กด ๋ชจ๋ธ์˜ bias ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹

  • "none": ๊ธฐ์กด bias ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์œ ์ง€ํ•˜๋ฉฐ ํ•™์Šต์ด๋‚˜ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Œ
  • "all": ๋ชจ๋“  bias ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•™์Šต ๋Œ€์ƒ์œผ๋กœ ํฌํ•จ
  • "lora_only": LoRA๊ฐ€ ์ ์šฉ๋œ ๋ชจ๋“ˆ์˜ bias๋งŒ ํ•™์Šต ๋Œ€์ƒ์œผ๋กœ ํฌํ•จ
    โ†’ ์ผ๋ฐ˜์ ์œผ๋กœ none์„ ์„ ํƒํ•ด ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜๋ฅผ ์ตœ๋Œ€ํ•œ ์ค„์ด๋Š” ๊ฒƒ์ด LoRA์˜ ๋ชฉ์ ๊ณผ ๋งž์Šต๋‹ˆ๋‹ค.

๐Ÿ”น target_modules=[...]
์„ค๋ช…: LoRA๋ฅผ ์ ์šฉํ•  ๋Œ€์ƒ ๋ชจ๋“ˆ ๋ชฉ๋ก
Qwen ๋ชจ๋ธ ๊ธฐ์ค€ ์ฃผ์š” ๋ชจ๋“ˆ:

  • q_proj, k_proj, v_proj: ์ฟผ๋ฆฌ(Query), ํ‚ค(Key), ๊ฐ’(Value) ๋ฒกํ„ฐ ์ƒ์„ฑ
  • o_proj: attention ์ถœ๋ ฅ ๋ฒกํ„ฐ ์ƒ์„ฑ
  • c_proj, c_attn: attention ์—ฐ์‚ฐ๊ณผ ์ „์ฒด ์ถœ๋ ฅ projection ๋‹ด๋‹น

๏ผ‹ ์ฐธ๊ณ  ์‚ฌํ•ญ:

  • LORA paper์— ๋”ฐ๋ฅด๋ฉด, Wq์™€ Wv์—๋งŒ LoRA๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ํšจ์œจ์ ์ด๋ผ๊ณ  ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค
  • ์ด์—, [โ€œq_projโ€, โ€œv_projโ€]๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๐ŸงŠ 3. Fine Tuning ํ•˜๊ธฐ!!

๋ฏธ์„ธ ์กฐ์ •(Fine tuning) ์€ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋กœ ํ•œ๋ฒˆ,
๊ทธ๋ฆฌ๊ณ  ์ง์ ‘ ๋งŒ๋“ ๋ฐ์ดํ„ฐ๋กœ ํ•œ๋ฒˆ ์ง„ํ–‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!!!

์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋กœ FT ํ•˜๊ธฐ!!

  • "tatsu-lab/alpaca", split="train[:100]" ์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ˜ํ”Œ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ์…‹ (Alpaca-style)
dataset = load_dataset("tatsu-lab/alpaca", split="train[:100]")  # ์ผ๋ถ€๋งŒ ์‚ฌ์šฉ
def preprocess(example):
    prompt = f"### Instruction:\n{example['instruction']}\n### Input:\n{example['input']}\n### Response:\n{example['output']}"
    tokenized = tokenizer(prompt, truncation=True, padding="max_length", max_length=512)
    tokenized["labels"] = tokenized["input_ids"].copy()
    return tokenized

tokenized_dataset = dataset.map(preprocess)

# ํ•™์Šต ์„ค์ •
training_args = TrainingArguments(
    output_dir="./qwen_lora_output",
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    num_train_epochs=1,
    learning_rate=2e-4,
    fp16=True,
    logging_steps=10,
    save_steps=100,
    save_total_limit=2,
)

# ํŠธ๋ ˆ์ด๋„ˆ ๊ตฌ์„ฑ
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    tokenizer=tokenizer,
    data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False)
)

# ํ•™์Šต ์‹œ์ž‘
trainer.train()
model.save_pretrained("qwen_lora_output")

์œ„์˜ ๋ฐฉ๋ฒ•์œผ๋กœ ํ•™์Šต์ด ๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋กœ๊ทธ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ณ ,

StepTraining Loss
102.292300

ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ qwen_lora_output ์— ๋ชจ๋ธ ์›จ์ดํŠธ ๊ฐ’์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค!

์ด์ œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ชจ๋ธ์„ ๋ถˆ๋Ÿฌ์˜จ ๋’ค, ์งˆ์˜๋ฅผ ํ•ด๋ณด๋ฉด?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from peft import PeftModel
from transformers import AutoTokenizer, AutoModelForCausalLM

base_model_name =  "Qwen/Qwen2.5-0.5B"  # ์‚ฌ์šฉํ•œ ๋ฒ ์ด์Šค ๋ชจ๋ธ
peft_path = "qwen_lora_output"  # trainer์—์„œ ์ง€์ •ํ•œ ๊ฒฐ๊ณผ ๋””๋ ‰ํ† ๋ฆฌ

model = AutoModelForCausalLM.from_pretrained(base_model_name, device_map="auto")
model = PeftModel.from_pretrained(model, peft_path)
model.eval()

tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)

prompt = "### Instruction:\n๋Œ€ํ•œ๋ฏผ๊ตญ ์ˆ˜๋„๋Š”?\n### Input:\n\n### Response:\n"

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
    outputs = model.generate(**inputs, max_new_tokens=64, do_sample=False)

print(tokenizer.decode(outputs[0], skip_special_tokens=True))

์•„๋ž˜์™€ ๊ฐ™์ด ์ž˜ ๋‹ต๋ณ€ํ•˜๋Š”๊ฒƒ์„ ๋ณผ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค~~

1
2
3
4
5
6
### Instruction:
๋Œ€ํ•œ๋ฏผ๊ตญ ์ˆ˜๋„๋Š”?
### Input:

### Response:
๋Œ€ํ•œ๋ฏผ๊ตญ ์ˆ˜๋„๋Š” ์„œ์šธ์ด๋‹ค.

ํ•œํŽธ, ์ž‘์€ ๋ชจ๋ธ์ผ ๋ชจ๋ฅผ๊ฒƒ ๊ฐ™์€ ์•„๋ž˜์˜ ์งˆ๋ฌธ์„ ํ•ด๋ณด๋ฉด!?

prompt = "### Instruction:\n๋ถ„๋‹จ๋œ ํ•œ๊ตญ ๊ตฐ ์ด๋ฆ„์€??\n### Input:\n\n### Response:\n"

1
2
3
4
5
6
### Instruction:
๋ถ„๋‹จ๋œ ํ•œ๊ตญ ๊ตฐ ์ด๋ฆ„์€??
### Input:

### Response:
ํ•œ๊ตญ๊ตฐ์€ ํ•œ๊ตญ์˜ ๊ตฐ์‚ฌ ์กฐ์ง์œผ๋กœ, 1945๋…„ 11์›” 25์ผ๋ถ€ํ„ฐ 1949๋…„ 12์›” 25์ผ๊นŒ์ง€ 1๋…„ 10์›” 25์ผ๊นŒ์ง€ 1๋…„ 10์›” 25

์œ„์™€ ๊ฐ™์ด ์˜๋ฏธ์—†๋Š” ๋‹ต์„ ํ•˜๊ฒŒ๋˜์ง€์š”!

์ง์ ‘ ๋งŒ๋“  ๋ฐ์ดํ„ฐ๋กœ FT ํ•˜๊ธฐ!!

์ด์  , ์ง์ ‘ ๋งŒ๋“  ๋ฐ์ดํ„ฐ๋กœ FTํ•˜์—ฌ ๋Œ€๋‹ต์„ ํ•˜๊ฒŒ ํ•ด๋ด…์‹œ๋‹ค!!
๋ฐ˜๋ณต์ด ์ข€ ๋˜์–ด์•ผํ•˜๋‹ˆ~ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
data = [
    {"instruction": "ํ•œ๊ตญ ๊ตฐ ์ค‘ ๋ถํ•œ๊ณผ ๋ถ„๋‹จ๋œ ๊ณณ์€ ์–ด๋””์ธ๊ฐ€์š”?", "input": "", "output": "๊ฒฝ๊ธฐ๋„ ์—ฐ์ฒœ๊ตฐ, ๊ฐ•์›๋„ ์ฒ ์›๊ตฐ, ๊ณ ์„ฑ๊ตฐ์€ ๋ถํ•œ๊ณผ ํ–‰์ •๊ตฌ์—ญ์ƒ ๋˜๋Š” ์—ญ์‚ฌ์ ์œผ๋กœ ๋ถ„๋‹จ๋œ ์ง€์—ญ์ž…๋‹ˆ๋‹ค."},
    {"instruction": "๋ถํ•œ๊ณผ ์ ‘๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋ถ„๋‹จ๋œ ํ•œ๊ตญ์˜ ๊ตฐ์„ ์•Œ๋ ค์ค˜.", "input": "", "output": "์—ฐ์ฒœ๊ตฐ, ์ฒ ์›๊ตฐ, ๊ณ ์„ฑ๊ตฐ์€ ๋ถํ•œ๊ณผ ์ง์ ‘ ์ ‘๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋™์ผ ์ด๋ฆ„์œผ๋กœ ๋‚จ๋ถ์— ๋ถ„๋‹จ๋œ ๊ตฐ์ž…๋‹ˆ๋‹ค."},
    {"instruction": "๋ถ„๋‹จ๋œ ํ•œ๊ตญ ๊ตฐ(้ƒก) ์ด๋ฆ„์„ ๋ชจ๋‘ ๋‚˜์—ดํ•ด์ค˜.", "input": "", "output": "์—ฐ์ฒœ๊ตฐ, ์ฒ ์›๊ตฐ, ๊ณ ์„ฑ๊ตฐ"},
    {"instruction": "๋ถ„๋‹จ๋œ ๊ตฐ ๋‹จ์œ„ ํ–‰์ •๊ตฌ์—ญ์ด ์žˆ๋‚˜์š”?", "input": "", "output": "๋„ค, ์—ฐ์ฒœ๊ตฐ, ์ฒ ์›๊ตฐ, ๊ณ ์„ฑ๊ตฐ ๋“ฑ์ด ๋‚จ๋ถํ•œ์— ๊ฑธ์ณ ๋ถ„๋‹จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค."},
    {"instruction": "๋ถํ•œ์—๋„ ๊ฐ™์€ ์ด๋ฆ„์˜ ๊ตฐ์ด ์žˆ๋Š” ํ•œ๊ตญ ๊ตฐ์€?", "input": "", "output": "์ฒ ์›๊ตฐ๊ณผ ๊ณ ์„ฑ๊ตฐ์€ ๋ถํ•œ์—๋„ ๊ฐ™์€ ์ด๋ฆ„์˜ ๊ตฐ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค."},
]

# ๋‹ค์–‘ํ•œ ๋ฌธ์žฅ ํ‘œํ˜„๊ณผ ์งˆ๋ฌธ ํ˜•ํƒœ๋กœ ๋ณ€ํ˜•ํ•˜์—ฌ 50๊ฐœ ์ƒ์„ฑ
variants = [
    "๋ถํ•œ๊ณผ ๊ฒฝ๊ณ„๋ฅผ ์ด๋ฃจ๋Š” ํ•œ๊ตญ์˜ ๊ตฐ ์ง€์—ญ์€?",
    "๋ถ„๋‹จ ์ƒํƒœ์ธ ํ•œ๊ตญ์˜ ๊ตฐ์—๋Š” ์–ด๋–ค ๊ณณ์ด ์žˆ๋‚˜์š”?",
    "๋‚จ๋ถ์œผ๋กœ ๋‚˜๋‰˜์–ด ์žˆ๋Š” ๊ตฐ์„ ์•Œ๋ ค์ฃผ์„ธ์š”.",
    "๋‚จํ•œ๊ณผ ๋ถํ•œ์— ๋™์ผํ•œ ์ด๋ฆ„์˜ ๊ตฐ์ด ์žˆ๋‚˜์š”?",
    "๋ถํ•œ๊ณผ ์ง์ ‘์ ์œผ๋กœ ๋งž๋‹ฟ์•„ ์žˆ๋Š” ๊ตฐ์€ ์–ด๋””์ธ๊ฐ€์š”?",
    "DMZ์™€ ์ ‘ํ•ด ์žˆ๋Š” ํ•œ๊ตญ์˜ ๊ตฐ์„ ์•Œ๋ ค์ค˜.",
    "๋ถ„๋‹จ๋œ ์ฑ„๋กœ ์ด๋ฆ„์ด ๋™์ผํ•œ ๊ตฐ์ด ์žˆ๋‹ค๋ฉด?",
    "ํ–‰์ •๊ตฌ์—ญ์ƒ ๋ถ„๋‹จ๋œ ๊ตฐ์ด ์กด์žฌํ•˜๋‚˜์š”?",
    "ํ˜„์žฌ๋„ ๊ตฐ์‚ฌ๋ถ„๊ณ„์„ ์„ ์‚ฌ์ด์— ๋‘๊ณ  ๋‚˜๋‰œ ๊ตฐ์ด ์žˆ๋‚˜์š”?",
    "๋ถํ•œ์— ์ผ๋ถ€ ์ง€์—ญ์ด ์†ํ•ด ์žˆ๋Š” ํ•œ๊ตญ ๊ตฐ์€ ์–ด๋””์ธ๊ฐ€์š”?",
    "๊ณ ์„ฑ๊ตฐ๊ณผ ์ฒ ์›๊ตฐ์€ ์–ด๋–ค ํŠน์ด์ ์ด ์žˆ๋‚˜์š”?",
    "์—ฐ์ฒœ๊ตฐ์€ ๋ถ„๋‹จ๊ณผ ์–ด๋–ค ๊ด€๋ จ์ด ์žˆ๋‚˜์š”?",
    "๊ฐ•์›๋„ ๋‚ด ๋ถ„๋‹จ๋œ ๊ตฐ์„ ์•Œ๋ ค์ค˜.",
    "๋ถํ•œ๊ณผ ๊ฐ™์€ ๊ตฐ ์ด๋ฆ„์„ ๊ณต์œ ํ•˜๋Š” ๋‚จํ•œ ๊ตฐ์€?",
    "6.25 ์ „์Ÿ ์ดํ›„ ๋ถ„๋‹จ๋œ ๊ตฐ์€?",
    "๋ถํ•œ ์ ‘๊ฒฝ์ง€๋Œ€ ๊ตฐ์„ ์„ธ ๊ณณ ๋งํ•ด์ค˜.",
    "ํœด์ „์„ ๊ณผ ๋งž๋‹ฟ์€ ํ•œ๊ตญ์˜ ๊ตฐ์€ ์–ด๋””?",
    "์ฒ ์›๊ณผ ๊ณ ์„ฑ์€ ๋‚จ๋ถํ•œ์— ๋ชจ๋‘ ์žˆ๋‚˜์š”?",
    "๋‚จํ•œ ์ตœ๋ถ๋‹จ ๊ตฐ ์ค‘ ํ•˜๋‚˜๋Š”?",
    "๋ถ„๋‹จ์˜ ์ƒ์ง•์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฐ์€ ์–ด๋””์ธ๊ฐ€์š”?",
    "๊ฐ•์›๋„์—์„œ ๋‚จ๋ถ ๋ชจ๋‘์— ์กด์žฌํ•˜๋Š” ๊ตฐ์€?",
    "๊ตฐ ๋‹จ์œ„์—์„œ ๋‚จ๋ถํ•œ์ด ๋‚˜๋‰œ ์‚ฌ๋ก€๋Š”?",
    "๊ณ ์„ฑ๊ตฐ์€ ๋‚จ๋ถํ•œ์— ๋ชจ๋‘ ์กด์žฌํ•˜๋‚˜์š”?",
    "์—ฐ์ฒœ๊ตฐ์€ ํ˜„์žฌ ์™„์ „ํžˆ ๋‚จํ•œ์— ์†ํ•ด ์žˆ๋‚˜์š”?",
    "๋ถํ•œ์—๋„ ๊ณ ์„ฑ๊ตฐ์ด ์žˆ๋‚˜์š”?",
    "๋‚จ๋ถํ•œ์ด ๊ณต์œ ํ–ˆ๋˜ ๊ตฐ ๋‹จ์œ„ ํ–‰์ •๊ตฌ์—ญ?",
    "ํœด์ „์„  ์ธ๊ทผ ๊ตฐ์„ ์•Œ๋ ค์ค˜.",
    "๋‚จ๋ถํ•œ ๊ฒฝ๊ณ„์— ์žˆ๋Š” ๋Œ€ํ‘œ์ ์ธ ๊ตฐ์€?",
    "์—ฐ์ฒœ, ์ฒ ์›, ๊ณ ์„ฑ ์™ธ ๋‹ค๋ฅธ ๋ถ„๋‹จ ๊ตฐ์ด ์žˆ๋‚˜์š”?",
    "์ฒ ์›๊ตฐ์€ ๋‚จ๋ถ ์–ด๋””์— ์žˆ๋‚˜์š”?",
    "ํ•œ๊ตญ์—์„œ ๋‚จ๋ถ ๋ถ„๋‹จ์ด ๋ฐ˜์˜๋œ ๊ตฐ ๋ช…์นญ?",
    "๋ถ„๋‹จ๊ณผ ๊ด€๋ จ๋œ ๊ตฐ์„ ๊ต์œก์ž๋ฃŒ์— ํฌํ•จ์‹œํ‚ค๊ณ  ์‹ถ์€๋ฐ ์–ด๋–ค ๊ณณ์ด ์žˆ์ฃ ?",
    "๋‚จ๋ถ ๋ถ„๋‹จ์„ ๋Œ€ํ‘œํ•˜๋Š” ๊ตฐ ๋‹จ์œ„ ์ง€์—ญ ์„ธ ๊ณณ?",
    "๋ถํ•œ์—๋„ ์žˆ๋Š” ๋‚จํ•œ ๊ตฐ ์ด๋ฆ„์€?",
    "ํ•œ๊ตญ์—์„œ ๋ถ„๋‹จ์˜ ํ”์ ์ด ๋‚จ์•„์žˆ๋Š” ๊ตฐ ์ง€์—ญ์€?",
    "์—ฐ์ฒœ๊ตฐ์˜ ๋ถ์ชฝ ์ผ๋ถ€๋Š” ๋ถํ•œ์ธ๊ฐ€์š”?",
    "์ฒ ์›๊ตฐ์€ 6.25 ์ „์Ÿ ์ „ํ›„๋กœ ์–ด๋–ค ๋ณ€ํ™”๊ฐ€ ์žˆ์—ˆ๋‚˜์š”?",
    "๋ถ„๋‹จ ๋‹น์‹œ ๊ณ ์„ฑ๊ตฐ์€ ์–ด๋–ป๊ฒŒ ๋‚˜๋‰˜์—ˆ๋‚˜์š”?",
    "๋ถ„๋‹จ๊ณผ ๊ตฐ์‚ฌ๋ถ„๊ณ„์„ ์ด ๊ด€๋ จ ์žˆ๋Š” ๊ตฐ์€?",
    "๊ฐ•์›๋„์˜ ๋ถ„๋‹จ๋œ ๊ตฐ ์ง€๋ช…์€?",
    "์—ฐ์ฒœ์€ ์™œ ๋ถ„๋‹จ ๊ด€๋ จ ๊ตฐ์œผ๋กœ ์–ธ๊ธ‰๋˜๋‚˜์š”?",
    "๊ตฐ ๋‹จ์œ„ ๋ถ„๋‹จ ์ง€์—ญ์„ ์กฐ์‚ฌํ•˜๋ ค๋ฉด ์–ด๋””๋ถ€ํ„ฐ ์‚ดํŽด์•ผ ํ•˜๋‚˜์š”?",
    "ํ˜„์žฌ๋Š” ๋‚จํ•œ์ด์ง€๋งŒ ๊ณผ๊ฑฐ ๋ถํ•œ์ด์—ˆ๋˜ ๊ตฐ์€?",
    "๋ถ„๋‹จ๋œ ๊ตฐ์ด ์ง€์—ญ ๋ฐœ์ „์— ์–ด๋–ค ์˜ํ–ฅ์„ ์ฃผ์—ˆ๋‚˜์š”?",
    "๋ถํ•œ๊ณผ์˜ ๊ด€๊ณ„๊ฐ€ ํŠน์ดํ•œ ํ•œ๊ตญ ๊ตฐ์€?",
    "์—ฐ์ฒœ๊ตฐ์— ๋ฏผ๊ฐ„์ธํ†ต์ œ๊ตฌ์—ญ์ด ์žˆ๋Š” ์ด์œ ๋Š”?",
    "DMZ๋กœ ์ธํ•ด ์˜ํ–ฅ์„ ๋ฐ›์€ ๊ตฐ ์ง€์—ญ?",
    "๋‚จํ•œ๊ณผ ๋ถํ•œ์ด ๋‚˜๋ˆ ๊ฐ€์ง„ ๊ตฐ ๋ช…์นญ์€?",
    "๊ณ ์„ฑ๊ตฐ์ด ๋ถ„๋‹จ๋œ ์ด์œ ๋Š”?",
]

for v in variants:
    data.append({
        "instruction": v,
        "input": "",
        "output": "์—ฐ์ฒœ๊ตฐ, ์ฒ ์›๊ตฐ, ๊ณ ์„ฑ๊ตฐ์€ ๋ถํ•œ๊ณผ ๋ถ„๋‹จ๋œ ํ•œ๊ตญ์˜ ๋Œ€ํ‘œ์ ์ธ ๊ตฐ ์ง€์—ญ์ž…๋‹ˆ๋‹ค."
    })

# ๋ฐ์ดํ„ฐ ์ˆ˜ ํ™•์ธ
len(data) 

๊ทธ๋ฆฌ๊ณ ~ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ๋กœ ํ•™์Šต ๊ณ ๊ณ !!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# LoRA ์„ค์ •
peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,                 # ๋žญํฌ
    lora_alpha=16,       # scaling factor
    lora_dropout=0.05,   # dropout
    bias="none",
    target_modules=["c_proj", "c_attn", "q_proj", "v_proj", "o_proj", "k_proj"],  # Qwen ๊ตฌ์กฐ์— ๋งž๊ฒŒ ์กฐ์ •
)

# ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฐ LoRA ์ ์šฉ
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    load_in_4bit=True,  # bitsandbytes๋ฅผ ํ†ตํ•œ 4bit quantization (์„ ํƒ์‚ฌํ•ญ)
    device_map="auto",
    trust_remote_code=True
)
model = get_peft_model(model, peft_config)

dataset = Dataset.from_list(data) ## ์—ฌ๊ธฐ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค!!
def preprocess(example):
    prompt = f"### Instruction:\n{example['instruction']}\n### Input:\n{example['input']}\n### Response:\n{example['output']}"
    tokenized = tokenizer(prompt, truncation=True, padding="max_length", max_length=512)
    tokenized["labels"] = tokenized["input_ids"].copy()
    return tokenized

tokenized_dataset = dataset.map(preprocess)

# ํ•™์Šต ์„ค์ •
training_args = TrainingArguments(
    output_dir="./qwen_lora_output_mytext",
    per_device_train_batch_size=2,
    gradient_accumulation_steps=4,
    num_train_epochs=10, ## ์—ฌ๊ธฐ๋ฅผ 1์—์„œ 10์œผ๋กœ ๋ฐ”๊ฟˆ
    learning_rate=2e-4,
    fp16=True,
    logging_steps=10,
    save_steps=100,
    save_total_limit=2,
)

# ํŠธ๋ ˆ์ด๋„ˆ ๊ตฌ์„ฑ
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    tokenizer=tokenizer,
    data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False)
)

# ํ•™์Šต ์‹œ์ž‘
trainer.train()
model.save_pretrained("qwen_lora_output_mytext")

ํ•™์Šต์„ ๋งŽ์ด ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ! num_train_epochs=10, ๋งŒ ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค!!

๊ทธ๋ฆฌ๊ณ  ์•„๊นŒ์™€ ๊ฐ™์ด ์งˆ๋ฌธ์„ ํ•ด๋ณด๋ฉด!?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from peft import PeftModel
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
base_model_name =  "Qwen/Qwen2.5-0.5B"  # ์‚ฌ์šฉํ•œ ๋ฒ ์ด์Šค ๋ชจ๋ธ
peft_path = "qwen_lora_output_mytext"  # trainer์—์„œ ์ง€์ •ํ•œ ๊ฒฐ๊ณผ ๋””๋ ‰ํ† ๋ฆฌ

model = AutoModelForCausalLM.from_pretrained(base_model_name, device_map="auto")
model = PeftModel.from_pretrained(model, peft_path)
model.eval()

tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)

prompt = "### Instruction:\n๋ถ„๋‹จ๋œ ํ•œ๊ตญ ๊ตฐ ์ด๋ฆ„์€??\n### Input:\n\n### Response:\n"

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
    outputs = model.generate(**inputs, max_new_tokens=64, do_sample=False)

print(tokenizer.decode(outputs[0], skip_special_tokens=True))
1
2
3
4
5
6
### Instruction:
๋ถ„๋‹จ๋œ ํ•œ๊ตญ ๊ตฐ ์ด๋ฆ„์€??
### Input:

### Response:
์—ฐ์ฒœ๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ, ์ฒ ์›๊ตฐ,

๊ทธ๋Ÿผ!! ์œ„์™€ ๊ฐ™์ด ์™„๋ฒฝํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์•„๊นŒ๋ณด๋‹ค๋Š” ๋ฐœ์ „๋œ ๋‹ต์„ํ•ฉ๋‹ˆ๋‹ค!
์™„์ „ ๋ฟŒ๋“ฏํ•˜์ฃ ~? ใ…Žใ…Ž
์ด๋Ÿฐ ๋ฐฉ์‹์„, ๋ณด๋‹ค ๋งŽ์€ ๋ฐ์ดํ„ฐ์…‹, epoch๋กœ ํ•˜๋ฉด ํ•™์Šต์ด ์ž˜ ๋˜๊ฒ ์ง€์š”??

์ถ”๊ฐ€๋กœ model.eval() ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด LORA๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ฒฐํ•ฉ๋ฌ๋Š”์ง€ ๋ณผ ์ˆ˜ ์žˆ๊ณ !

์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋กœ LORA์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜๋„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค~!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from peft import get_peft_model
from peft.tuners.lora import LoraLayer

def count_lora_parameters(model):
    total = 0
    for module in model.modules():
        if isinstance(module, LoraLayer):
            for name, param in module.named_parameters():
                if "lora_" in name:
                    total += param.numel()
    return total

print("LoRA ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜:", count_lora_parameters(model))

1
LoRA ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆ˜: 1081344

๐ŸŽ‰ ๋งˆ๋ฌด๋ฆฌ

์˜ค๋Š˜์€ ์ด๋ ‡๊ฒŒ LORA๋ฅผ ์‹ค์Šตํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค!!
์ฒด๊ณ„์ ์ธ ํŒจํ‚ค์ง€๋“ค ๋•๋ถ„์— ์ง€๊ธˆ ๋‹น์žฅ์ด๋ผ๋„ ์—ฌ๋Ÿฌ ๋ถ„์•ผ์— ์ ์šฉํ• ์ˆ˜ ์žˆ์„ ์ž์‹ ๊ฐ์ด ๋ฟœ๋ฟœํ•˜๋„ค์š”!!^^
LORA ์™ธ์˜ PEFT๋„ ๊ณต๋ถ€ํ•ด๋ณด์•„์•ผ๊ฒ ์–ด์š”~!

This post is licensed under CC BY 4.0 by the author.