我看了一份很適合入門的微調開源教程:github.com/R6410418/Jackrong-llm-finetuning-guideackrong-llm-finetuning-guide,它的定位很明確,面向初學者和開發者,把大模型微調從“聽起來很貴的技術活”,拆成一條可以在 Kaggle / Colab 上復現的工程管線
![]()
Jackrong LLM 微調教程項目總覽
倉庫里已經給出了 Qwen3.5 9B 的 Kaggle SFT notebook,主線是:
Kaggle 環境
-> Unsloth 加載 Qwen3.5 9B
-> 4-bit 節省顯存
-> LoRA / PEFT 微調
-> 多源數據清洗
-> qwen3-thinking 模板
-> response-only SFT
-> 保存 LoRA / 合并 16-bit / 導出 GGUF
先說結論如果你第一次做開源模型微調,我建議從 Qwen3.5 9B 入手
原因有三個
第一,9B 這個尺寸剛剛好它比 4B 更有表達能力,又比 27B、35B 輕很多,Kaggle 這種免費或低成本云環境還有折騰空間
第二,Qwen3.5 本身很強官方模型卡顯示,Qwen3.5 9B 是 9B 參數、32 層、4096 hidden size,原生上下文長度 262,144 tokens,對長文本、代碼、推理、多語言場景都比較友好
第三,Unsloth 已經把訓練門檻壓低了Unsloth 文檔明確支持 Qwen3.5 家族微調,包括 0.8B、2B、4B、9B、27B、35B-A3B、122B-A10B 等型號對個人開發者來說,這類工具鏈的價值很直接:少踩環境坑,少爆顯存,快點看到 loss 往下走
這里也要提前說一個最新版文檔里的提醒:Unsloth 當前不推薦在 Qwen3.5 上做 QLoRA / 4-bit 訓練,原因是量化差異偏高;如果你有足夠顯存,優先考慮 bf16 LoRA本文拆的是 Jackrong Kaggle notebook 的可復現路線,它為了壓低 Kaggle 資源門檻使用了 4-bit 加載,適合學習鏈路;嚴肅實驗建議把 bf16 LoRA 也納入對照組
這個教程到底教什么?
Jackrong 這個倉庫的核心價值,是把微調流程變成了一套“可跑的教材”
它包含幾類東西:
多語言 README:中文、英文、韓文、日文都有
訓練 notebook:Qwen3.5 9B、Qwopus3.5 27B、Qwopus3.5 35B、Llama3.2-R1 GRPO
高保真蒸餾數據集:倉庫里列了 24 個數據集,覆蓋推理、數學、代碼、多輪對話、寫作反饋等方向
訓練后導出:LoRA 保存、16-bit 合并、GGUF 量化上傳
這套教程的目標很樸素:讓你從瀏覽器打開 notebook 開始,一路看到訓練、保存、發布
如果你是第一次做微調,最難的地方通常不在某一個 API,而在“每一步為什么這么做”這份教程最值得借鑒的地方,也在它的數據處理部分
第一步:準備 Kaggle 環境和密鑰
Qwen3.5 9B 的 notebook 先讓你在 Kaggle Secrets 里準備兩個密鑰:
WANDB_API_KEY
HF_TOKEN
WANDB_API_KEY 用來登錄 Weights & Biases,記錄訓練日志、loss 曲線、實驗參數
HF_TOKEN 用來登錄 Hugging Face,后面如果你要上傳 LoRA、合并模型或 GGUF 文件,就會用到
這里有個很重要的習慣:不要把 API Key 直接寫進 notebook
教程里用的是 Kaggle Secrets:
from kaggle_secrets import UserSecretsClient
user_secrets = UserSecretsClient()
secret_value_0 = user_secrets.get_secret("WANDB_API_KEY")import wandb
wandb.login(key=secret_value_0)
這一步看起來小,實戰里很關鍵很多初學者第一次上傳 notebook,就把 token 一起傳到了公開平臺這個坑很低級,也很疼
第二步:安裝 Unsloth、Transformers 和 TRL
教程里的安裝邏輯會區分 Colab 和普通環境Kaggle 里直接裝 Unsloth:
!pip install unsloth
!pip install transformers==5.3.0
!pip install --no-deps trl==0.22.2
這幾個包分別管不同層:
unsloth:負責高效加載模型、4-bit、LoRA、訓練優化transformers:負責模型、tokenizer、推理和底層兼容trl:負責 SFTTrainer 這類訓練封裝
版本最好跟 notebook 保持一致大模型訓練環境最怕“差一點能跑”,尤其是 transformers、trl、bitsandbytes、accelerate 這幾類包,一旦版本互相打架,報錯會非常玄學
第三步:加載 Qwen3.5 9B
教程使用 Unsloth 的 FastLanguageModel.from_pretrained 加載模型:
from unsloth import FastLanguageModel
import torchmodel, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Qwen3.5-9B",
max_seq_length=16384,
load_in_4bit=True,
load_in_8bit=False,
full_finetuning=False,
)
這里有幾個參數要看懂
model_name="unsloth/Qwen3.5-9B":使用 Unsloth 適配過的 Qwen3.5 9B 權重,方便后續訓練notebook 原文里 namespace 寫成了 Unsloth,Hugging Face 頁面上的規范寫法是小寫 unsloth,建議讀者按規范寫
max_seq_length=16384:訓練上下文設置成 16KQwen3.5 9B 的官方上下文更長,但訓練時上下文越長,顯存和時間開銷越大16K 是一個比較務實的起點
load_in_4bit=True:按 Jackrong notebook 的路線,用 4-bit 加載模型以降低顯存占用需要注意,Unsloth 當前文檔對 Qwen3.5 的 QLoRA / 4-bit 訓練給了謹慎提醒;如果顯存夠,優先試 bf16 LoRA
full_finetuning=False:采用 LoRA 這種參數高效微調路線全參微調對顯存、存儲、訓練穩定性都更挑剔,入門階段先用 LoRA 更穩
一句話概括:這一步是在告訴機器,“我想用省顯存的方式,把 Qwen3.5 9B 先請進來”
第四步:加 LoRA 適配器
LoRA 的本質,是凍結大部分原始權重,只訓練一小部分低秩矩陣這樣訓練更輕,保存也更輕
教程里給的核心參數是:
r = 64
lora_alpha = 64
lora_dropout = 0
bias = "none"
use_gradient_checkpointing = "unsloth"
random_state = 3407
目標模塊覆蓋注意力和 MLP:
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
"out_proj",
]
我在本地讀 notebook 時發現一個細節:LoRA 那個 cell 的括號和縮進疑似有誤,直接運行可能會報語法錯誤讀者照著跑的時候,可以改成下面這種結構:
model = FastLanguageModel.get_peft_model(
model,
r=64,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
"out_proj",
],
lora_alpha=64,
lora_dropout=0,
bias="none",
use_gradient_checkpointing="unsloth",
random_state=3407,
use_rslora=False,
loftq_config=None,
)
如果你對顯存沒把握,可以把 r 從 64 降到 32 或 16rank 越高,適配能力通常越強,顯存和訓練時間也會跟著漲
第五步:數據處理才是微調的命門
很多人做微調,第一反應是調參數實際上,微調里最影響結果的通常是數據
這個教程的數據處理值得仔細看
Qwen3.5 9B notebook 里用了兩類數據:
Jackrong/Competitive-Programming-python-blend:抽樣 700 條
stepfun-ai/Step-3.5-Flash-SFT:抽樣 100000 條
第一類數據偏代碼、算法、推理它本身是一個混合 SFT 數據集,主要圍繞 Python 競賽編程,也混入少量 C++、SWE、推理聊天數據
第二類數據規模更大,是主訓練數據來源notebook 里為了適配 Kaggle 臨時存儲,會隨機抽取 5 個 JSON 文件,再從中清洗樣本
數據處理流程大概是這樣:
加載原始數據
-> 隨機抽樣
-> 統一 conversations 格式
-> 移除 system message
-> 規范 user / assistant 角色
-> 合并連續同角色消息
-> 確保 user 和 assistant 交替
-> 強制 assistant 輸出含
...
-> 套用 qwen3-thinking chat template
-> 合并兩個數據集
-> shuffle
-> 按 text 去重
-> 過濾超過 16K tokens 的樣本
這里最有意思的是
...
教程會把 assistant 輸出統一成:
推理過程最終答案
如果原始輸出里已經有 think block,就抽取并規范;如果沒有,就補一個空的 think block
這一步的目的,是讓模型學會一種穩定的“先組織思路,再輸出答案”的格式Jackrong 的 Neo 模型卡也提到,訓練時用了 response-only masking,并把 assistant 的
作為響應起點
這對推理模型很重要你希望模型變強,訓練數據里就要有穩定的行為結構數據格式亂,模型學到的風格也會亂
第六步:套用 qwen3-thinking 模板
notebook 里使用的是:
from unsloth.chat_templates import get_chat_templatetokenizer = get_chat_template(
tokenizer,
chat_template="qwen3-thinking",
)
然后將 conversations 轉成最終訓練文本:
def formatting_prompts_func(examples):
convos = examples["conversations"]
texts = [
tokenizer.apply_chat_template(
convo,
tokenize=False,
add_generation_prompt=False,
)
for convo in convos
]
return {"text": texts}
這一步很容易被忽略
模型訓練看到的并非你腦子里的 JSON 結構,它看到的是 token 序列chat template 決定了 user、assistant、特殊標記、生成提示怎么拼在一起
微調 Qwen3.5 這種帶 thinking 風格的模型,模板最好保持一致模板亂了,模型輕則輸出格式漂移,重則訓練目標和推理格式對不上
第七步:用 SFTTrainer 開始訓練
教程使用 TRL 的 SFTTrainer:
from trl import SFTTrainer, SFTConfigtrainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
train_dataset=dataset,
eval_dataset=None,
args=SFTConfig(
dataset_text_field="text",
per_device_train_batch_size=6,
gradient_accumulation_steps=6,
warmup_ratio=0.04,
num_train_epochs=2,
learning_rate=2e-4,
logging_steps=1,
optim="adamw_8bit",
weight_decay=0.001,
lr_scheduler_type="linear",
seed=3407,
save_steps=100,
save_total_limit=1,
save_strategy="steps",
report_to="wandb",
output_dir="/kaggle/working/",
),
)
這里最值得關注的是有效 batch:
per_device_train_batch_size = 6
gradient_accumulation_steps = 6
有效 batch 約等于 36
在顯存有限的情況下,梯度累積非常好用它不會一次塞進 36 條樣本,會分 6 次前向和反向,累積梯度后再更新
學習率 2e-4 對 LoRA SFT 來說屬于常見起點教程里也備注了,長訓練可以降到 2e-5如果你訓練的是高質量小數據,學習率太大容易把模型風格帶偏
第八步:只訓練 assistant 的回答
教程里還有一個很關鍵的步驟:
from unsloth.chat_templates import train_on_responses_onlytrainer = train_on_responses_only(
trainer,
instruction_part="<|im_start|>user\n",
response_part="<|im_start|>assistant\n " ,
)
這一步叫 response-only training
簡單講,訓練時只讓模型為 assistant 部分承擔 loss,user prompt 部分會被 mask 掉
為什么這么做?
因為我們希望模型學會“如何回答”,而用戶輸入只是條件把用戶輸入也納入 loss,很多時候會浪費訓練信號,還可能讓模型學習復讀 prompt
尤其是對指令微調來說,response-only masking 是很實用的工程習慣
第九步:訓練、保存、上傳
開始訓練:
trainer.train()
如果中斷,可以從 checkpoint 恢復:
trainer.train(resume_from_checkpoint=True)
保存 LoRA:
model.save_pretrained("qwen_lora")
tokenizer.save_pretrained("qwen_lora")
合并 16-bit 并上傳 Hugging Face:
model.push_to_hub_merged(
repo_id,
tokenizer,
save_method="merged_16bit",
token=hf_token,
)
導出 GGUF:
model.push_to_hub_gguf(
repo_id,
tokenizer,
quantization_method=["q4_k_m"],
token=hf_token,
)
這里教程給了一個很現實的提醒:Kaggle 臨時存儲空間有限,實際可用大約 92GB導出全套 GGUF 量化文件時,空間可能不夠
更穩的方式是:先在 Kaggle 上傳合并后的 16-bit 模型,再去 Colab 或本地更大磁盤環境里做 GGUF 全量導出
實戰避坑清單
第一,Qwen3.5 的 4-bit 訓練要謹慎
Jackrong notebook 為了讓 Kaggle 環境更容易跑起來,采用了 load_in_4bit=True但 Unsloth 最新微調文檔提醒,Qwen3.5 模型不推薦 QLoRA / 4-bit 訓練,原因是量化差異偏高如果你只是學習完整鏈路,可以先復現 notebook;如果你要做嚴肅模型迭代,建議優先準備能跑 bf16 LoRA 的環境,并把 4-bit 結果當成低成本實驗組
第二,倉庫里的大數據文件可能受 Git LFS 配額影響
我本地 clone 時,普通 clone 在一個 LFS 數據文件上失敗,原因是倉庫 LFS budget 超限解決方式是跳過 LFS smudge:
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/R6410418/Jackrong-llm-finetuning-guide.git
這樣文檔、notebook、README 都能拿到真正訓練時,數據可以從 Hugging Face Hub 拉
第三,數據質量比數據量更重要
教程里的 Qwen3.5-reasoning-700x 數據卡也提醒,蒸餾數據可能含少量計算錯誤或邏輯問題訓練前建議抽樣檢查,尤其是數學、代碼、金融、醫學這類高敏場景
第四,16K 上下文是務實選擇
Qwen3.5 9B 官方上下文很長,但微調階段直接拉滿上下文,顯存和訓練時間都會急劇上升先用 16K 跑通流程,再根據業務調整,會舒服很多
第五,LoRA rank 別一上來就拉滿
r=64 可以作為教程復現參數你如果只是做風格、格式、輕量領域適配,r=16 或 r=32 往往也值得試
第六,推理能力和格式服從之間會有取舍
Jackrong 的 Qwen3.5-9B-Neo 模型卡里提到,這一版更強調結構化推理,IFEval 指令跟隨指標有回落這個提醒很真誠,也很適合寫進自己的實驗記錄里
這是 Neo 模型卡里給出的 LM Eval Harness 截圖之一,重點看它把微調前后結果擺在一起,便于讀者理解“提升”和“回落”都要記錄
![]()
Jackrong Qwen3.5-9B-Neo LM Eval Harness 截圖
第七,GGUF 量化參數里不要帶尾隨空格
notebook 里的 GGUF 導出 cell 寫的是 quantization_method=["q4_k_m "],字符串末尾多了一個空格建議改成 quantization_method=["q4_k_m"],和 Unsloth 文檔中的 q4_k_m 寫法保持一致
誰適合照著這套教程學?
我建議這幾類人重點看:
想第一次完整跑通 SFT 的開發者
想訓練一個數學、代碼、邏輯推理小模型的團隊
想理解
格式、response-only training、chat template 的同學想把模型發布成 Hugging Face / GGUF / Ollama 可用形態的玩家
如果你的目標是生產級模型,這份教程更像起點你還需要補上評測集、A/B 測試、安全過濾、數據授權審查、訓練日志復盤、推理參數調優
但作為入門教材,它已經把最難的那條鏈路鋪好了
最后
微調這件事,真正有意思的地方在于:你開始從“調用模型的人”,變成“改造模型的人”
Qwen3.5 9B 這種模型,對個人開發者很友好它足夠強,也足夠輕再加上 Unsloth、Kaggle、Hugging Face 這些工具,門檻已經低到可以動手試
我的建議很簡單:
先別想著訓練一個全能模型先選一個清晰任務,比如:
Python 算法題解
中文長文總結
企業內部 FAQ
專業術語問答
固定格式報告生成
準備一批高質量樣本,按教程里的思路清洗成統一 conversations 格式,套上 qwen3-thinking 模板,跑一次 LoRA SFT
訓練完成后,拿同一批測試題做對比:
base Qwen3.5 9B
vs
你的 LoRA / merged model
只要你能清楚看到“哪里變好了,哪里變差了”,這次微調就有價值
大模型時代,最好的學習方式依然很樸素:讀代碼,跑實驗,看結果,改數據,再來一輪
這條路,真的可以從一個 Kaggle notebook 開始
.5
制作不易,如果這篇文章覺得對你有用,可否點個關注,給我個三連擊:點贊、轉發和在看,若可以再給我加個,謝謝你看我的文章,我們下篇再見!
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.