debain12.9使用unsloth微调Qwen2.5模型
debain12.9使用unsloth微调Qwen2.5模型
- 基础环境准备
- 下载模型
- 微调脚本
基础环境准备
基础环境安装
以Qwen2.5-0.5B为例
下载模型
source ai/bin/activate
modelscope download --model 'unsloth/Qwen2.5-0.5B' --local_dir 'unsloth/Qwen2.5-0.5B'
微调脚本
from unsloth import FastLanguageModel
import torch
max_seq_length = 2048 # Choose any! We auto support RoPE Scaling internally!
dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+
load_in_4bit = True # Use 4bit quantization to reduce memory usage. Can be False.
# 加载模型
print('加载模型...')
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "./unsloth/Qwen2.5-0.5B", # 加载本地模型,也可以自动下载huggingface模型(写huggingface模型id即可,不过需要科学上网或使用hf-mirror下载)
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit
)
# 添加LoRA适配器,因此我们只需要更新所有参数的1%到10%!
print('添加LoRA适配器...')
model = FastLanguageModel.get_peft_model(
model,
# LoRA 的秩(Rank),即低秩矩阵的维度大小。
# 常用 8、16、32、64、128,越大表示适配能力越强,但参数量和显存占用也会增加。
# 建议从较小的值(如 8)开始测试,逐步增加直到性能满意。
r = 16,
# 指定要对模型中哪些模块应用 LoRA 适配。
# `q_proj`, `k_proj`, `v_proj`, `o_proj`:Transformer 自注意力机制中的查询(Query)、键(Key)、值(Value)和输出(Output)投影层。
# `gate_proj`, `up_proj`, `down_proj`:Feed-Forward 网络(FFN)中的门控、上行、下行投影层。
# 默认选择所有注意力层和 FFN 层,可以缩小范围(如仅 `q_proj`, `v_proj`)以进一步减少参数量。
target_modules = [
"q_proj",
"k_proj",
"v_proj",
"o_proj",
"gate_proj",
"up_proj",
"down_proj",
],
# LoRA 的缩放因子,控制适配层对原始权重的调整幅度。
# 最终更新量 = LoRA 输出结果 × (`lora_alpha / r`)。
# 通常设置 `lora_alpha = r` 或为其倍数。例如 `r=8, alpha=16` 或 `r=16, alpha=32`。
lora_alpha = 16,
# 在 LoRA 适配层中应用 Dropout 的比例。
# 设为 `0` 可最大化内存利用率,仅在过拟合风险较高时设为非零值(如 `0.1`)。
lora_dropout = 0,
# 是否对模型的偏置项(Bias)进行训练。
# **可选值**:
# - `"none"`:不训练任何偏置(推荐,节省显存)。
# - `"all"`:训练所有偏置。
# - `"lora_only"`:仅训练 LoRA 层的偏置。
bias = "none",
# [NEW] "unsloth" uses 30% less VRAM, fits 2x larger batch sizes!
use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context
random_state = 3407,
# 是否使用 **Rank-Stabilized LoRA(RS-LoRA)**,一种改进的 LoRA 变体,通过调整初始化方式提升稳定性。
# 默认关闭,除非显存充足且追求更稳定训练。
use_rslora = False,
# 配置 **LoftQ(LoRA with Fine-Tuned Quantization)**,用于在量化(如 4-bit)模型上应用 LoRA。
# 默认无需设置,仅在使用量化微调时需要配置。
loftq_config = None, # And LoftQ
)
# 定义变量
alpaca_prompt = """下面是描述任务的说明,并配有提供更多上下文的输入。编写适当完成请求的响应。
### 指令:
{}
### 输入:
{}
### 回答:
{}"""
# 微调前推理
print('微调前推理...')
question = "业务对象功能简介?"
FastLanguageModel.for_inference(model)
inputs = tokenizer([alpaca_prompt.format(question, question, "")], return_tensors="pt").to("cuda")
from transformers import TextStreamer
text_streamer = TextStreamer(tokenizer)
_ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 256)
# 数据加载
print('加载数据...')
EOS_TOKEN = tokenizer.eos_token # Must add EOS_TOKEN
def formatting_prompts_func(examples):
instructions = examples["instruction"]
inputs = examples["input"]
outputs = examples["output"]
texts = []
for instruction, input, output in zip(instructions, inputs, outputs):
# Must add EOS_TOKEN, otherwise your generation will go on forever!
text = alpaca_prompt.format(instruction, input, output) + EOS_TOKEN
texts.append(text)
return { "text" : texts, }
pass
# huggingface
from datasets import load_dataset
# 加载本地数据集,也可以自动下载huggingface数据集(写huggingface数据集id即可,不过需要科学上网或使用hf-mirror下载)
# split可以控制加载指定数据区域,0:200,即前两百条数据
dataset = load_dataset("json", data_files="./qwen_ibps_qa.json", split = "train[0:200]")
dataset = dataset.map(formatting_prompts_func, batched = True,)
# 设置微调参数
print('设置微调参数...')
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
# 要微调的预训练模型(如 LLaMA、GPT-2)
model = model,
# 与模型匹配的分词器
tokenizer = tokenizer,
# 训练数据集(需是 HuggingFace Dataset 格式)
train_dataset = dataset,
# 数据集中包含训练文本的字段名(例如每行数据的 "text" 列)
dataset_text_field = "text",
# 输入序列的最大长度
max_seq_length = max_seq_length,
# 预处理数据集时使用的进程数(加速数据处理)
dataset_num_proc = 2,
# 是否将多个短序列打包成一个序列(True 可加速训练)
packing = False,
args = TrainingArguments(
# 每个GPU的批次大小(根据显存调整)
per_device_train_batch_size = 2,
# 梯度累积步数(等效批次大小 = batch_size * steps)
gradient_accumulation_steps = 4,
# 学习率预热步数(避免初始不稳定)
warmup_steps = 5,
# num_train_epochs = 1, # Set this for 1 full training run.
# 最大训练步数(覆盖 `num_train_epochs`)
max_steps = 100,
# 初始学习率(常用 1e-5 到 2e-4)
learning_rate = 2e-4,
# 使用 FP16 混合精度(NVIDIA GPU)
fp16 = not is_bfloat16_supported(),
# 使用 BF16 混合精度(AMD/TPU 或更新 NVIDIA GPU)
bf16 = is_bfloat16_supported(),
# 每隔多少步记录日志(损失、学习率等)
logging_steps = 10,
# 使用 8-bit AdamW 优化器(节省显存)
optim = "adamw_8bit",
# 权重衰减系数(防止过拟合)
weight_decay = 0.01,
# 学习率调度策略(如线性衰减)
# - **`linear`**:线性衰减到 0,经典策略。
# - 其他选项:`cosine`(余弦衰减)、`constant`(恒定学习率)等。
lr_scheduler_type = "linear",
# 随机种子(确保实验可复现)
seed = 3407,
# 模型和日志保存路径
output_dir = "outputs",
# 禁用第三方日志服务(如 WandB)
report_to = "none", # Use this for WandB etc
),
)
# 模型微调训练
print('开始微调训练...')
trainer.train()
# 微调后推理
print('微调后推理...')
question = "业务对象功能简介"
FastLanguageModel.for_inference(model) # Unsloth has 2x faster inference!
inputs = tokenizer([alpaca_prompt.format(question, question, "")], return_tensors="pt").to("cuda")
from transformers import TextStreamer
text_streamer = TextStreamer(tokenizer)
_ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 256)
# 保存到本地
print('保存到本地...')
new_model_local = "./unsloth/Qwen2.5-0.5B-001"
print('保存tokenizer...')
tokenizer.save_pretrained(new_model_local)
print('合并并保存merged_16bit...')
model.save_pretrained_merged(new_model_local, tokenizer, save_method = "merged_16bit")
print('合并并保存lora...')
model.save_pretrained_merged(new_model_local, tokenizer, save_method = "lora")
# 注意llama.cpp的安装喔,GGUF量化模型必须有这个工具!
# Save to 16bit GGUF
print('保存16bit GGUF...')
model.save_pretrained_gguf(new_model_local, tokenizer, quantization_method = "f16")
# Save to 8bit Q8_0
print('保存Q8_0 GGUF...')
model.save_pretrained_gguf(new_model_local, tokenizer)
# Save to q4_k_m GGUF
print('保存Q4_K_M GGUF...')
model.save_pretrained_gguf(new_model_local, tokenizer, quantization_method = "q4_k_m")
享受微调吧