unsloth微调Qwen3模型实战

一、前言

Unsloth 是一个专注于优化大型语言模型(LLMs)微调效率的开源框架,旨在显著提升训练速度并降低显存占用,使得在资源有限的硬件(如单张消费级GPU)上高效微调大模型成为可能。

下面我将使用阿里最新的Qwen3模型进行微调训练

二、准备

1、环境准备

利用conda创建虚拟环境(如果你没有开启jupyter,则需要做这一步)

conda create -n unsloth_env python=3.10
conda activate  unsloth_env2

安装Unsloth

pip install unsloth

2、下载模型

此次微调我用的是Qwen3-0.6B的版本,相对来说参数量不大,我这里主要是方便演示,你们可以使用更大的模型。
先用pip安装modelscope模块

pip install modelscope

然后创建目录,并下载模型:

mkdir -p ./models/
modelscope download --model Qwen/Qwen3-0.6B --local_dir ./models/Qwen3-4B

3、下载数据集

这里我是用modelscope上的一个脑筋急转弯的数据集作为演示

mkdir -p ./datasets/
modelscope download --dataset helloworld0/Brain_teasers --local_dir ./datasets

三、微调前测试

微调之前可以先加载初始模型做推理测试,编写测试脚本befor_train.py,内容如下:


from unsloth import FastLanguageModel

model_name = "./models/Qwen3-0.6B"  # 替换为实际模型路径
max_seq_length = 2048  # 最大上下文长度
dtype = None  # 自动选择 float16 或 bfloat16
load_in_4bit = True  # 启用 4-bit 量化

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name=model_name,
    max_seq_length=max_seq_length,
    dtype=dtype,
    load_in_4bit=load_in_4bit,
)

FastLanguageModel.for_inference(model)
inputs = tokenizer(
    ["Instruction: 失败是成功之母,那成功为失败的什么?"], return_tensors="pt"
).to("cuda")
outputs = model.generate(**inputs, max_new_tokens=1024)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

运行脚本

python befor_train.py

unsloth微调Qwen3模型实战_第1张图片

四、微调模型

编写微调的脚本train.py,内容如下:


from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset
import torch
# 加载模型
model_name = "./models/Qwen3-0.6B"
max_seq_length = 2048
dtype = None
load_in_4bit = True
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name=model_name,
    max_seq_length=max_seq_length,
    dtype=dtype,
    load_in_4bit=load_in_4bit,
)
# 配置 LoRA
model = FastLanguageModel.get_peft_model(
    model,
    r=32,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    lora_alpha=64,
    lora_dropout=0.2,
    bias="none",
    use_gradient_checkpointing=True,
    random_state=3407,
)
# 加载和预处理数据集
dataset = load_dataset("json", data_files="./datasets/data.json", split="train")
train_prompt_style = """下面是一个脑筋急转弯问题,请提供合适的答案,不需要提供思考过程。
### 指令:
你是一个脑筋急转弯专家,请回答以下问题,不需要提供思考过程。
### 问题:
{}
### 回复:
{}"""
def formatting_prompts_func(examples, eos_token):
    inputs = examples["instruction"]
    outputs = examples["output"]
    texts = []
    for inputs, outputs in zip(inputs, outputs):
        text = train_prompt_style.format(inputs, outputs) + eos_token # eos token在training的时候必须要加
        texts.append(text)
    return {
        "text": texts,
    }
dataset = dataset.map(
    formatting_prompts_func,
    batched=True,
    fn_kwargs={'eos_token': tokenizer.eos_token}, # tokenizer为前面加载model是加载的tokenizer
)
# 配置训练
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    args=TrainingArguments(
        per_device_train_batch_size=8,
        gradient_accumulation_steps=4,
        warmup_steps=10,
        max_steps=80,
        learning_rate=5e-5,
        fp16=not torch.cuda.is_bf16_supported(),
        bf16=torch.cuda.is_bf16_supported(),
        logging_steps=5,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
        output_dir="outputs",
    ),
)
# 开始训练
trainer.train()
## 保存LoRA适配器
model.save_pretrained("qwen3_lora_finetuned")
tokenizer.save_pretrained("qwen3_lora_finetuned")
## 保存新模型
model.save_pretrained_merged("/models/Qwen3-0.6B-sft", tokenizer, save_method="merged_16bit")

微调会比较耗时,主要取决你的硬件配置以及脚本中你设定的max_steps参数,这个数值越大,它训练的时间就越久。微调后的模型路径为:/models/Qwen3-0.6B-sft

unsloth微调Qwen3模型实战_第2张图片

五、微调后测试

from unsloth import FastLanguageModel
max_seq_length = 2048
dtype = None
load_in_4bit = False  ##如果显存足够,这里设置为False

model, tokenizer = FastLanguageModel.from_pretrained(     
		model_name="/models/Qwen3-0.6B-sft",
    	max_seq_length=max_seq_length,
        dtype=dtype,    
        load_in_4bit=load_in_4bit,)
        
FastLanguageModel.for_inference(model)

inputs = tokenizer(    
	["Instruction: 你是脑筋急转弯专家,请回答我的问题:什么动物的屁股不能碰?"],
 	return_tensors="pt").to("cuda")
 	
outputs = model.generate(
		**inputs,
		 max_new_tokens=256)
 
 print(tokenizer.decode(outputs[0], skip_special_tokens=True))

你可能感兴趣的:(大模型,语言模型,LLM,unsloth,微调大模型,人工智能)