深度長文,手把手教你微調Qwen-3大模型,基于Python和Unsloth(下)
維持對話與推理的比例平衡
在準備好數據集后,通常即可開始模型訓練,但我們仍需考慮模型的對話與推理比例(Chat-to-Reason Ratio)。較高的對話比例側重對話流暢性和通用知識,而較高的推理比例則強調邏輯推理和問題解決能力。二者的平衡對構建既能進行自然對話又能處理復雜任務的多功能模型起著重要作用。
本文假設需要構建一個對話模型,因此設定對話部分占比70%,推理部分占比30%。實現方式如下:
import pandas as pd
# 設定對話比例
chat_percentage = 0.7
# 按比例采樣通用對話數據集
non_reasoning_subset = pd.Series(non_reasoning_conversations)
non_reasoning_subset = non_reasoning_subset.sample(
int(len(reasoning_conversations) * (1.0 - chat_percentage)),
random_state=2407,
)
數據預處理的最后一步是合并數據集,代碼如下:
data = pd.concat([
pd.Series(reasoning_conversations),
pd.Series(non_reasoning_subset)
])
data.name = "text"
from datasets import Dataset
combined_dataset = Dataset.from_pandas(pd.DataFrame(data))
combined_dataset = combined_dataset.shuffle(seed=3407)
四、模型訓練
在準備好結構化數據和帶有LoRA適配器的模型后,即可開始訓練。訓練前需初始化超參數,這些參數會影響訓練過程和模型精度。
我們使用??SFTTrainer?
?和預設超參數初始化訓練器:
from trl import SFTTrainer, SFTConfig
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=combined_dataset, # 結構化數據集
eval_dataset=None,
args=SFTConfig(
dataset_text_field="text", # 用于訓練的數據集字段
per_device_train_batch_size=2, # 單設備訓練批次大小
gradient_accumulation_steps=4, # 梯度累積步數
warmup_steps=5, # 學習率預熱步數
max_steps=30, # 總訓練步數
learning_rate=2e-4, # 學習率
logging_steps=1, # 日志記錄頻率
optim="adamw_8bit", # 優化器
weight_decay=0.01, # 權重衰減
lr_scheduler_type="linear", # 學習率衰減策略
seed=3407,
report_to="none", # 日志平臺(可選wandb)
),
)
代碼說明:
- ?
?SFTTrainer?
?用于基于自定義數據集微調大語言模型,支持梯度累積、混合精度優化等技術,適用于指令調優、對話生成等任務。 - 本例中未設置驗證數據集(?
?eval_dataset=None?
?),可根據需求添加。
完成所有設置后,啟動訓練:
trainer_stats = trainer.train()
訓練過程中,內核將輸出每一步的訓練損失:
訓練LoRA適配的Qwen3模型
五、微調模型推理
訓練完成后,需對微調模型進行推理以評估響應效果。推理方式分為禁用思考和啟用思考兩種模式。
禁用思考模式
此模式下模型直接生成回答,適用于簡單任務,計算效率更高:
messages = [
{"role": "user", "content": "Solve (x + 2)^2 = 0."}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True, # 生成響應必需
enable_thinking=False, # 禁用思考
)
from transformers import TextStreamer
_ = model.generate(
**tokenizer(text, return_tensors="pt").to("cuda"),
max_new_tokens=256, # 最大生成token數
temperature=0.7, top_p=0.8, top_k=20,
streamer=TextStreamer(tokenizer, skip_prompt=True),
)
輸出結果:
<|im_start|> 要解這個方程(x + 2)2=0,我們可以對兩邊取平方根,得到x+2=0,然后兩邊減去2,解得x=-2。<|im_end|>
啟用思考模式
此模式下模型會生成詳細推理過程,適用于復雜任務:
messages = [
{"role": "user", "content": "Solve (x + 2)^2 = 0."}
]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=True, # 啟用思考
)
_ = model.generate(
**tokenizer(text, return_tensors="pt").to("cuda"),
max_new_tokens=1024, # 延長生成長度以容納推理過程
temperature=0.6, top_p=0.95, top_k=20,
streamer=TextStreamer(tokenizer, skip_prompt=True),
)
輸出結果:
用戶讓我解這個方程(x + 2)2=0。首先,我需要回憶一下如何解二次方程。可能的方法有幾種,比如直接開平方、展開后用求根公式,或者因式分解。不過這個方程看起來已經是平方的形式了,所以直接開平方可能是最快捷的方法。
首先,方程兩邊都是非負數,因為左邊是一個平方,右邊是0。所以開平方后,左邊變成|x+2|,右邊是0。絕對值等于0的情況只有一種,就是里面的表達式等于0,所以x+2=0,解得x=-2。
不過,為了確保正確,我可以再檢查一下。把x=-2代入原方程,左邊就是(-2+2)2=02=0,右邊也是0,所以解是正確的。
另外,從二次方程的性質來看,這個方程的判別式b2-4ac=0,說明有一個實根(重根),所以確實只有x=-2一個解。這樣看來,結果是正確的。
保存微調模型
訓練完成后,需保存微調模型及分詞器。以下是將模型保存至本地的方法:
model.save_pretrained_merged(
"Qwen3-16bit-OpenMathReasoning-Finetuned-Merged",
tokenizer,
save_method="merged_16bit"
)
若需將模型推送到Hugging Face Hub,可使用以下代碼(需替換為個人訪問令牌):
model.push_to_hub_merged(
"Qwen3-16bit-OpenMathReasoning-Finetuned-Merged",
tokenizer,
save_method="merged_16bit",
token="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"
)
六、總結
本文分上、下篇,請完整閱讀。主要內容包括:
- Qwen-3的競爭力:在多項基準測試中超越DeepSeek-R1、Gemini-2.5-Pro等主流模型。
- 微調核心目標:通過任務特定數據優化模型響應,使其更貼合垂直領域需求。
- 主要工具鏈:使用unsloth、torch、transformers、trl等庫實現高效微調。
- 數據與訓練流程:結構化數據集構建、LoRA適配器應用、SFTTrainer訓練及推理驗證。
- 模型部署:合并LoRA參數后保存至本地或Hugging Face Hub,便于后續應用。
通過合理平衡對話與推理比例、選擇高效工具鏈及優化訓練流程,開發者可基于Qwen-3構建定制化AI助手,極大提升垂直領域任務的處理能力。
本文轉載自????AI科技論談???????,作者:AI科技論談
贊
1
收藏
回復
分享
微博
QQ
微信
舉報

回復
相關推薦