健康一贴灵,专注医药行业管理信息化

Qwen3-0.6b模型微调

今天按AI的指示,一步一步微调了一个Qwen3-0.6b;

主要工作:

1、下载模型;

2、复制数据集文件:train_data.json

{"instruction": "你是一个礼貌的中文客服助手", "input": "我的快递三天没动了", "output": "非常抱歉给您带来不便,我帮您查询一下物流状态,请稍等。"}
{"instruction": "请总结以下文本", "input": "人工智能正在改变医疗、教育和交通行业。", "output": "AI正在影响医疗、教育和交通。"}
{"instruction": "将下面句子翻译成英文", "input": "今天天气很好。", "output": "The weather is nice today."}

 

3、复制代码到train_qlora_cpu.py,因为使用了某个插件的不同版本,代码改了几次;

"""
Qwen3-0.6B + QLoRA(CPU / 低显存优化版)
适用:无独显、8~16GB 内存、Windows
"""

import torch
from datasets import load_dataset
from transformers import (
    AutoTokenizer,
    AutoModelForCausalLM,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model, TaskType
#from trl import SFTTrainer
from trl import SFTTrainer, SFTConfig

# ============================================================
# 【必改】模型和数据路径
# ============================================================
MODEL_PATH = r"E:\ai\Qwen3-0.6B"   # ← 改成你的真实路径
DATA_PATH  = r"e:\ai\qwen_lora\train_data.json"

OUTPUT_DIR = r"e:\ai\qwen_lora\qwen3_lora_output"


# ===== Tokenizer =====
tokenizer = AutoTokenizer.from_pretrained(
    MODEL_PATH, trust_remote_code=True
)
if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token

# ===== Model =====
model = AutoModelForCausalLM.from_pretrained(
    MODEL_PATH,
    torch_dtype=torch.float32,
    trust_remote_code=True,
    device_map=None,
)

# ===== LoRA =====
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,
    lora_alpha=16,
    lora_dropout=0.05,
    target_modules="all-linear",
    bias="none",
)

model = get_peft_model(model, lora_config)

# ===== Dataset =====
dataset = load_dataset("json", data_files=DATA_PATH, split="train")

def formatting_func(example):
    messages = []
    if example.get("instruction"):
        content = example["instruction"]
        if example.get("input"):
            content += "\n" + example["input"]
        messages.append({"role": "user", "content": content})
    if example.get("output"):
        messages.append({"role": "assistant", "content": example["output"]})
    return {
        "text": tokenizer.apply_chat_template(
            messages, tokenize=False, add_generation_prompt=False
        )
    }

dataset = dataset.map(formatting_func, remove_columns=dataset.column_names)

# ===== TrainingArguments =====
training_args = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=4,
    learning_rate=1e-4,
    logging_steps=5,
    save_strategy="epoch",
    fp16=False,
    bf16=False,
    gradient_checkpointing=True,
    use_cpu=True,
    report_to="none",
    max_length=512,               # ✅ 新 API 叫 max_length
    dataset_text_field="text",   # 因为你数据集有 "text" 列
)

trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    processing_class=tokenizer,   # ✅ 新 API 用 processing_class
)

trainer.train()
model.save_pretrained(OUTPUT_DIR)
tokenizer.save_pretrained(OUTPUT_DIR)

print("✅ 训练完成")

4、程序执行完成后, 在指定的OUTPUT目录下,多出了

image

 

文件/文件夹名称
类型
核心作用
白话解释(类比)
checkpoint-1,2,3
文件夹
训练检查点(中间态)
就像写论文时的“自动保存”草稿。记录了训练到第几分钟、损失值降到多少时的模型状态。如果中途电脑断电,可以从这里恢复训练,而不用从头开始。
adapter_model.safetensors
模型文件
核心训练产物(LoRA权重)
这是你这次微调真正学到的东西(仅约 19.7 MB)。它不包含原模型的庞大参数,只包含为了让模型学会客服回复而新增的“低秩矩阵”。
adapter_config.json
配置文件
LoRA 配置说明书
告诉加载器:“我是怎么训练的”(比如秩 r=8、目标层是哪些)。没有它,系统不知道如何把这组轻量级权重挂载到原模型上。
chat_template.jinja
模板文件
对话格式化规则
Qwen 模型的“语法规则”。它定义了如何将用户的提问(user)和助手的回答(assistant)拼接成模型能看懂的特定格式(如包含 `<
tokenizer.json
数据文件
分词器主文件
模型的“字典”(约 11 MB)。包含了将中文/英文文本切分成模型能理解的“词元(Token)”的规则和词表。
tokenizer_config.json
配置文件
分词器行为配置
分词器的“操作手册”,指定使用哪个分词器类、特殊标记(如 pad_token)的定义等,确保代码能正确初始化分词器。
README
说明文档
训练信息记录
通常由 Trainer 自动生成,记录了本次训练的超参数(如学习率、批次大小、训练时长等),方便日后复现。

为了避免不必要的麻烦,建议将版本锁定下

E:\ai\my_code\` 下建个requirements.txt`,下次重装环境直接对齐:

torch
transformers==4.51.0
trl==0.12.0
peft==0.12.0
datasets==2.21.0
accelerate==0.34.0
这是你使用 SFTTrainer 成功完成 Qwen3-0.6B LoRA 微调后,生成的最终输出目录(对应你之前代码里的 OUTPUT_DIR)。
在 LoRA 微调中,因为原大模型(Base Model)的参数被冻结,只训练了极少量的新增参数(即 LoRA 适配器),所以输出目录非常“轻量”。这些文件各司其职,共同构成了你微调后的模型资产:

📁 输出文件/文件夹详细解释

 
文件/文件夹名称
类型
核心作用
白话解释(类比)
checkpoint-1,2,3
文件夹
训练检查点(中间态)
就像写论文时的“自动保存”草稿。记录了训练到第几分钟、损失值降到多少时的模型状态。如果中途电脑断电,可以从这里恢复训练,而不用从头开始。
adapter_model.safetensors
模型文件
核心训练产物(LoRA权重)
这是你这次微调真正学到的东西(仅约 19.7 MB)。它不包含原模型的庞大参数,只包含为了让模型学会客服回复而新增的“低秩矩阵”。
adapter_config.json
配置文件
LoRA 配置说明书
告诉加载器:“我是怎么训练的”(比如秩 r=8、目标层是哪些)。没有它,系统不知道如何把这组轻量级权重挂载到原模型上。
chat_template.jinja
模板文件
对话格式化规则
Qwen 模型的“语法规则”。它定义了如何将用户的提问(user)和助手的回答(assistant)拼接成模型能看懂的特定格式(如包含 `<
tokenizer.json
数据文件
分词器主文件
模型的“字典”(约 11 MB)。包含了将中文/英文文本切分成模型能理解的“词元(Token)”的规则和词表。
tokenizer_config.json
配置文件
分词器行为配置
分词器的“操作手册”,指定使用哪个分词器类、特殊标记(如 pad_token)的定义等,确保代码能正确初始化分词器。
README
说明文档
训练信息记录
通常由 Trainer 自动生成,记录了本次训练的超参数(如学习率、批次大小、训练时长等),方便日后复现。

💡 进阶实用建议

1. 如何用它来做推理(回答问题)?

在实际部署时,不需要把这些文件全部塞给程序。标准的 LoRA 推理流程是:
  • 第一步:加载原版的基础模型(比如 Qwen3-0.6B-Instruct)。
  • 第二步:通过 PeftModel.from_pretrained(...) 加载 adapter_model.safetensorsadapter_config.json
  • 第三步:加载 tokenizer.jsonchat_template.jinja
这样,原模型就会“穿上”你微调好的 LoRA 外衣,摇身一变成为你的专属客服助手。
最后试一下应用;
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel

MODEL_PATH = r"E:\ai\Qwen3-0.6B"
LORA_PATH = r"E:\ai\qwen_lora\qwen3_lora_output"

# ===== Tokenizer =====
tok = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
if tok.pad_token is None:
    tok.pad_token = tok.eos_token

# ===== Base Model =====
base = AutoModelForCausalLM.from_pretrained(
    MODEL_PATH,
    torch_dtype=torch.float32,
    trust_remote_code=True,
    device_map=None,
)

# ===== Load LoRA =====
model = PeftModel.from_pretrained(base, LORA_PATH)
model.eval()

# ===== Input =====
messages = [
    {"role": "user", "content": "我的快递三天没动了"}
]

inputs = tok.apply_chat_template(
    messages,
    return_tensors="pt",      # ✅ 返回 PyTorch tensors
    padding=True,
    add_generation_prompt=False,
)

# ⚠️ 关键:取出 input_ids
input_ids = inputs["input_ids"]

with torch.no_grad():
    out = model.generate(
        input_ids=input_ids,
        max_new_tokens=128,
        do_sample=True,
        temperature=0.7,
    )

print(tok.decode(out[0], skip_special_tokens=True))

程序 会打印现:

image

 好像有点啰嗦。。。。

posted @ 2026-07-29 16:40  一贴灵  阅读(5)  评论(0)    收藏  举报
学以致用,效率第一