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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
| import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
Trainer,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
from transformers import TrainerCallback
# 1. 加载模型(4-bit量化)
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-2-7b-hf",
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(
"meta-llama/Llama-2-7b-hf",
trust_remote_code=True,
)
tokenizer.pad_token = tokenizer.eos_token
# 2. 准备模型进行训练
model = prepare_model_for_kbit_training(model)
# 3. 配置LoRA
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM,
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 4. 准备数据
dataset = load_dataset("json", data_files="training_data.json")
def format_prompt(example):
return {
"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['output']}"
}
dataset = dataset.map(format_prompt)
def tokenize_function(examples):
return tokenizer(
examples["text"],
padding="max_length",
truncation=True,
max_length=512,
)
tokenized_dataset = dataset.map(tokenize_function, batched=True)
# 5. 训练参数
training_args = TrainingArguments(
output_dir="./qlora_checkpoints",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
warmup_steps=100,
learning_rate=2e-4,
fp16=True,
logging_steps=10,
optim="paged_adamw_8bit", # 分页优化器
save_strategy="steps",
save_steps=100,
evaluation_strategy="steps",
eval_steps=100,
load_best_model_at_end=True,
report_to=["wandb"], # 或 "tensorboard"
run_name="qlora-finetune",
)
# 6. 自定义回调
class LoggingCallback(TrainerCallback):
def on_log(self, args, state, control, logs=None, **kwargs):
if logs:
print(f"Step: {state.global_step}, Loss: {logs.get('loss', 'N/A')}")
# 7. 训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
eval_dataset=tokenized_dataset["validation"],
callbacks=[LoggingCallback()],
)
trainer.train()
# 8. 保存
model.save_pretrained("./final_qlora_model")
tokenizer.save_pretrained("./final_qlora_model")
# 9. 合并权重(可选)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged_model")
|