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目录下,多出了

|
文件/文件夹名称
|
类型
|
核心作用
|
白话解释(类比)
|
|---|---|---|---|
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.safetensors和adapter_config.json。 -
第三步:加载
tokenizer.json和chat_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))
程序 会打印现:

好像有点啰嗦。。。。
活到老,学到老。

浙公网安备 33010602011771号