Views
No views yet
unsloth/Qwen3-8B,訓練資料為
DRCD(改編版,見下方 SFT dataset)。{"answer": "文中連續原文片段", "answerable": true|false}。已知限制:這個 checkpoint 在 DRCD 抽取式 QA 上表現接近滿分,代價是通用能力小幅退步。 TMMLU+(通用知識選擇題)test split 全量 20,118 題上,macro accuracy 從原廠的 0.5936 掉到 0.5604(Δ = −3.32 個百分點,95% CI [−3.96, −2.69],配對分層 bootstrap)。退步的型態是選項偏誤而不是知識遺忘:微調後模型選 B 的次數比原廠少 1,946 次、選 D 多 1,889 次,於是 gold 為 B 的題目掉 16.9 個百分點,而 gold 為 D 的題目反而進步 7.7 個 百分點。忘掉知識的模型不會在某個子集上變強。這個偏誤有 45% 校正得回來(160,880 次推論實測):把四個選項的內容做循環位移、 讓正確答案輪流落在 A/B/C/D 再投票,Δ 從 −3.46 pp 縮到 −1.92 pp,回收 +1.54 pp (95% CI [+0.90, +2.19])。偏誤撐過了位移(位移後 FT 仍只有 14.7% 選 B、32.2% 選 D), 確認是位置偏誤而非集成效應。剩下的約 1.9 pp 不能反推為「知識遺忘」——這個實驗只隔離位置偏誤,沒有檢定跟選項 內容綁在一起的偏誤。另外多數決是評分協定、不是模型本身的性質:你直接使用時拿到的 仍是單一順序的行為,投票要付 4 倍推論成本。如果需要保留通用能力,建議:(a) 只在需要精確抽取式 QA 的場景使用這個 adapter, (b) 選擇題場景加上選項順序隨機化的多數投票(實測可回收約四成退步), (c) 或參考本專案方法論自行用較低 epoch / 加入通用資料混合訓練。
| # | 組別 | overall EM | overall F1 | JSON 合法率 |
|---|---|---|---|---|
| 1 | base zero-shot(原廠) | 0.4756 | 0.6858 | 95.62% |
| 2 | base few-shot(3-shot) | 0.8253 | 0.9191 | 99.98% |
| 3 | 本 adapter(未量化 bf16) | 0.9325 | 0.9704 | 100% |
| 4 | 本 GGUF(Q8_0) | 0.9328 | 0.9706 | 100% |
| 5 | 本 GGUF(Q4_K_M,部署建議) | 0.9330 | 0.9700 | 100% |
unsloth/Qwen3-8B(LoRA 實際合併/推論用的起點權重;跟官方
Qwen/Qwen3-8B 同源,
unsloth 版本額外做了 tokenizer 修正)enable_thinking=False
(非思考模式)1from transformers import AutoModelForCausalLM, AutoTokenizer
2from peft import PeftModel
3import torch
4
5base = AutoModelForCausalLM.from_pretrained(
6 "unsloth/Qwen3-8B", dtype=torch.bfloat16, device_map="cuda"
7)
8model = PeftModel.from_pretrained(base, "steven0226/Qwen3-8B-DRCD-zhTW-QA-LoRA")
9tokenizer = AutoTokenizer.from_pretrained("steven0226/Qwen3-8B-DRCD-zhTW-QA-LoRA")
10
11messages = [
12 {"role": "system", "content": '你是精確的閱讀理解助手。根據「文章」回答「問題」:\n- 答案必須是文章中的連續原文片段,一字不改\n- 若文章中找不到答案,answer 填空字串、answerable 填 false\n- 只輸出 JSON:{"answer": "...", "answerable": true|false}'},
13 {"role": "user", "content": "文章:...\n\n問題:..."},
14]
15prompt = tokenizer.apply_chat_template(
16 messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
17)
18inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
19out = model.generate(**inputs, max_new_tokens=128, do_sample=False)
20print(tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))unsloth/Qwen3-8B 授權 Apache-2.0,歸屬 Qwen team / unsloth