LinguaForge — Qwen3.5-0.8B 繁中/英/日翻譯特化(v5e, LoRA)
LinguaForge 是以 Qwen/Qwen3.5-0.8B(約 873M 參數)為基底、經 LoRA 監督式微調(SFT)的翻譯特化模型,支援 繁體中文(臺灣)↔ 英文 ↔ 日文 六個方向。設計目標是輸出臺灣正體中文(非簡體),並在消費級單卡上可訓練、可推論。
One-line (EN): A 0.8B six-direction (zh-TW ↔ en ↔ ja) translation LoRA for
Qwen/Qwen3.5-0.8B, tuned for Taiwanese Traditional Chinese with near-zero simplified-character leakage.
| 資源 | 連結 |
|---|---|
| 本頁(模型權重) | Hugging Face 模型庫 |
| 訓練/評測程式與實驗紀錄 | GitHub · RX5950XT/LinguaForge-Qwen3.5-0.8B-zhTW-en-ja |
| 研究報告 | docs/REPORT.md |
| 應用接入指南 | docs/INTEGRATION.md |
本模型卡描述權重與使用方式;語料不 re-host,重建請使用 GitHub 倉庫中的資料腳本。
解決的問題
官方 0.8B 基底在語意上已有一定水準,但中文輸出常混入簡體字形與非臺灣用語:FLORES ja→zhtw 方向約 43.6% 的句子含簡體專用字。v5e 將 en→zhtw / ja→zhtw 的簡體洩漏分別降至約 1.09% / 0.69%,同時六方向語意指標整體上升。
評測
- 基準:FLORES-200 devtest 全量 n=1012
- 解碼:
num_beams=4,並依目標語言套用防重複參數(見下文) - 指標:chrF++ / BLEU(sacrebleu;日文
ja-mecab、中文zh)、COMET(Unbabel/wmt22-comet-da)、簡體洩漏率(簡體專用字集比對) - 對照:相同樣本與相同解碼設定下的官方
Qwen/Qwen3.5-0.8B
| 方向 | chrF++ (base → v5e) | BLEU (base → v5e) | COMET (base → v5e) | 簡體洩漏 (base → v5e) |
|---|---|---|---|---|
| en→zhtw | 19.38 → 20.26 | 25.57 → 28.90 | 86.32 → 86.23 | 10.18% → 1.09% |
| zhtw→en | 47.78 → 50.33 | 19.34 → 23.72 | 84.79 → 85.27 | — |
| en→ja | 20.26 → 24.15 | 19.81 → 22.65 | 86.17 → 88.44 | — |
| ja→en | 45.67 → 50.17 | 16.67 → 22.70 | 84.85 → 86.20 | — |
| ja→zhtw | 10.53 → 16.60 | 10.38 → 23.07 | 81.44 → 86.10 | 43.58% → 0.69% |
| zhtw→ja | 14.80 → 18.48 | 12.97 → 16.93 | 84.24 → 87.14 | — |
| 均值 | 26.40 → 30.00 | 17.46 → 22.60 | 84.64 → 86.56 |
COMET 均分約 +1.92;chrF++ 與 BLEU 六方向皆上升。
en→zhtw 語意與官方統計持平:paired bootstrap 95% CI 約 [−0.414, +0.225](跨 0)。其餘五個方向 COMET 提升約 +0.48 ~ +4.66。官方 en→zhtw 的 COMET 是在約 10% 簡體洩漏下取得的;COMET 對簡繁字形不敏感,兩邊產出的字形品質並不相同。
通用能力
| 基準 | 官方 0.8B | v5e |
|---|---|---|
| BELEBELE zh-TW / ja / en(閱讀理解,選項輪轉去偏,各 900 題) | 55.81 / 51.78 / 57.83 | 57.28 / 52.36 / 62.81 |
| 知識(TMMLU+ / MMMLU-JA / MMLU,各 900 題) | 30.67 / 36.08 / 43.67 | 30.53 / 36.64 / 43.81 |
| 自建通用問答(n=90,三語各 30) | 78.9 | 72.2 |
| 指令遵循 ifeval(n=90) | 53.3 | 48.9 |
BELEBELE 與知識軸六格皆不低於官方基底。自建問答與指令遵循略低——通用指令 replay 約 3.5 萬筆,且授權相容的繁中指令語料有限。本模型為翻譯特化,不建議作為通用助手。
選擇題基準採選項輪轉(×4)去除位置先驗:0.8B 級模型對答案字母常有強先驗。絕對分數僅供與官方基底相減比較,不宜單獨作為對外能力宣稱。
長文件翻譯(25 篇 × 6 方向)
| 指標 | 官方 0.8B | v5e |
|---|---|---|
| 行數對齊比(中位) | 1.375 ~ 1.500 | 1.000(六方向) |
| 尾段譯出比(中位) | 1.101 ~ 1.646 | 0.851 ~ 0.924 |
| 腰斬率(譯文 < 參考長度一半) | 0 ~ 4% | 0 ~ 4% |
官方模型常多生成 40–50% 的行並在尾段超譯;v5e 行數較精準對齊。早期微調版本曾有「長文只翻前兩段」的問題,v5e 已消除。
建議解碼參數
⚠ generation prompt 必須以空 think 區塊收尾
chat_template.jinja在未開 thinking 時,會固定在<|im_start|>assistant\n之後補上<think>\n\n</think>\n\n(token248068, 271, 248069, 271)。訓練與評測全程帶著這 4 個 token, 少了就會掉出分布。完整的 prompt 應長成:<|im_start|>system\nYou are a professional translator.<|im_end|>\n <|im_start|>user\n翻譯成繁體中文:\n{原文}<|im_end|>\n <|im_start|>assistant\n<think>\n\n</think>\n\n
- transformers:
apply_chat_template(..., add_generation_prompt=True)會自動補,不必額外處理。- llama.cpp 系:預設不補。
llama-cli需加--jinja;node-llama-cpp 內建的QwenChatWrapper是照 Qwen3 撰寫,其thoughts六個選項沒有任何一個會補上這段,需自行覆寫generateContextState:class Qwen35ChatWrapper extends QwenChatWrapper { generateContextState(options) { const state = super.generateContextState(options) const last = options.chatHistory[options.chatHistory.length - 1] if (last?.type === 'model' && (last.response == null || last.response.length === 0)) state.contextText = LlamaText([state.contextText, '<think>\n\n</think>\n\n']) return state } }缺這 4 個 token 的實測後果(同一組 30 句、f16 全精度、greedy):
指標 缺 think 補 think 憑空標籤前綴( 說明:/問:/1./選擇:)9 句 0 拉丁專名保留率(Q8_0) 73.3% 93.3% 原文無年份卻生出年份 2 句 0 客觀缺陷總數(Q4_K_M) 20 5 例:
The NVIDIA H200 has 141GB of HBM3e memory.缺 think 時譯為「141GB HBM3e 記憶體。」 (NVIDIA、H200 整個消失),補上後為「NVIDIA H200 擁有 141GB HBM3e 記憶體。」這與
--reasoning off是兩件事:後者關的是「解析/生成 thinking 輸出」,補不了這 4 個 token,兩者都要做。 若出現上述症狀,不要用後處理 regex 剝掉前綴——那只遮住最顯眼的症狀,同時發生的專名消失與年份幻覺 regex 抓不到。 復現與驗收腳本見 GitHubscripts/bench_defects.py,完整證據見docs/DEFECT-AUDIT-2026-08-03.md。
以下為與官方評測一致的 transformers 設定(GitHub scripts/evaluate.py):
| 參數 | 建議值 |
|---|---|
num_beams |
4 |
length_penalty |
1.2 |
do_sample |
false |
eos_token_id |
[248046, 248044](`< |
| 目標語 en / ja | repetition_penalty=1.1 + no_repeat_ngram_size=4 |
| 目標語 zhtw | 僅 no_repeat_ngram_size=4(勿對繁中使用 repetition_penalty) |
常見異常與處理
| 現象 | 常見原因 | 處理 |
|---|---|---|
| 譯文憑空多出「說明:」「問:」「1. 」等前綴/專名被吃掉/生出原文沒有的年份 | generation prompt 少了 <think>\n\n</think>\n\n(僅 llama.cpp 系會發生) |
見上方警示;勿以 regex 剝前綴 |
| 譯完後持續生成至上限 | 只設定單一 EOS | 使用雙 EOS |
| 長口語/社群文 → 英文句級重複 | 未開 no_repeat_ngram_size;或 GGUF 僅 greedy |
依上表;GGUF 可加 repeat-penalty 並分段 |
| 譯文前綴出現思考/選項雜訊 | 未關閉 thinking | llama.cpp:--reasoning off --reasoning-budget 0 |
| GGUF 繁中夾簡體 | 無 beam | 輸出後 OpenCC s2twp |
| 對繁中開 rep-penalty 後字形更亂 | 對 zhtw 使用了 repetition_penalty |
僅對 en / ja 開啟 |
更完整的接入清單與檢查表:GitHub docs/INTEGRATION.md。
倉庫檔案
| 路徑 | 說明 |
|---|---|
| 倉庫根目錄 | LoRA adapter(adapter_model.safetensors + adapter_config.json,r=64 / α=128 / dropout 0.05,約 173MB;base = Qwen/Qwen3.5-0.8B)。library_name: peft 要求 adapter 置於根目錄 |
merged-bf16-v5e/ |
合併後 bf16 全模型(約 1.7GB,可不依賴 peft) |
gguf-v5e/ |
GGUF:Q8_0 / Q4_K_M / f16 |
快速使用(PEFT + transformers)
import torch
from transformers import AutoTokenizer, AutoModelForImageTextToText
from peft import PeftModel
BASE = "Qwen/Qwen3.5-0.8B"
ADAPTER = "RX5950XT/LinguaForge-Qwen3.5-0.8B-zhTW-en-ja"
tok = AutoTokenizer.from_pretrained(BASE)
model = AutoModelForImageTextToText.from_pretrained(
BASE, dtype=torch.bfloat16, attn_implementation="sdpa").cuda()
model = PeftModel.from_pretrained(model, ADAPTER).eval()
# SFT 以 <|im_end|> 收尾,但 base config 預設 eos 為 <|endoftext|>;兩者皆須視為結束。
EOS = [tok.convert_tokens_to_ids(t) for t in ("<|im_end|>", "<|endoftext|>")] # [248046, 248044]
INSTR = {"zhtw": "翻譯成繁體中文:", "en": "翻譯成英文:", "ja": "翻譯成日文:"}
# 依目標語言分流防重複參數:
# beam=4 改善漏譯;no_repeat_ngram_size=4 抑制句級刷屏。
# length_penalty=1.2 略優於 1.0。
# 繁中目標不可用 repetition_penalty(會干擾繁簡選字,簡體洩漏可能上升)。
DECODE = {
"ja": {"repetition_penalty": 1.1, "no_repeat_ngram_size": 4},
"en": {"repetition_penalty": 1.1, "no_repeat_ngram_size": 4},
"zhtw": {"no_repeat_ngram_size": 4},
}
def translate(text, tgt="zhtw"):
convs = [
{"role": "system", "content": "You are a professional translator."},
{"role": "user", "content": f"{INSTR[tgt]}\n{text}"},
]
inputs = tok.apply_chat_template(
convs, add_generation_prompt=True, return_dict=True, return_tensors="pt"
).to("cuda")
with torch.no_grad():
gen = model.generate(
**inputs,
max_new_tokens=256,
num_beams=4,
length_penalty=1.2,
do_sample=False,
eos_token_id=EOS,
pad_token_id=tok.pad_token_id,
**DECODE[tgt],
)
return tok.decode(
gen[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True
).strip()
print(translate("The patient should take this medication twice a day.", "zhtw"))
量化推論(GGUF)
| 檔案 | 大小 |
|---|---|
gguf-v5e/linguaforge-v5e-0.8b-Q8_0.gguf |
約 812M |
gguf-v5e/linguaforge-v5e-0.8b-Q4_K_M.gguf |
約 529M |
gguf-v5e/linguaforge-v5e-0.8b-f16.gguf |
約 1.5G |
llama-cli -m linguaforge-v5e-0.8b-Q8_0.gguf --jinja -st -ngl 99 --temp 0 \
--reasoning off --reasoning-budget 0 \
-sys "You are a professional translator." \
-f prompt.txt
# prompt.txt 內容示例:
# 翻譯成繁體中文:
# The night market is crowded on weekends.
# → 週末的夜市人聲鼎沸。
實測(RTX 5060 Ti,-ngl 99):Q8_0 約 186 t/s,Q4_K_M 約 171–217 t/s。
GGUF 與上方評測路徑的差異
llama-cli 通常沒有 beam search,也常無法設定 no_repeat_ngram_size,預設為 greedy。上方 FLORES 表格則是以 beam=4 + 目標語防重複參數量測。因此:
- 追求與評測一致的穩定性與品質:請使用 PEFT 或合併 bf16 + 上表參數。
- GGUF 適合低記憶體與高吞吐;建議加
--repeat-penalty 1.1,長文分段翻譯,並對繁中輸出做 OpenCC 後處理。
FLORES en→zhtw 前 100 句對照(同 runtime):
| 系統 | chrF++ | BLEU | 簡體洩漏 |
|---|---|---|---|
| GGUF f16(greedy) | 20.50 | 27.83 | 2.00% |
| GGUF Q8_0 | 20.21 | 27.28 | 2.00% |
| GGUF Q4_K_M | 19.49 | 26.07 | 2.00% |
| bf16 + beam=4(評測路徑) | 20.00 | 28.48 | 0.00% |
- 量化會單調降低字面分數(相對 GGUF f16:Q8_0 約 −0.29 chrF++,Q4_K_M 約 −1.01)。
- greedy 本身未造成明顯漏譯;主要代價是簡體洩漏約 0% → 2%(同一行內混用字形)。
- GGUF 輸出建議經 OpenCC
s2twp:實測洩漏 2.00% → 0.00%,chrF++ 約只降 0.04。
from opencc import OpenCC
cc = OpenCC("s2twp")
print(cc.convert(llama_output))
其他注意:
--jinja不可省:省略時llama-cli不會補空 think 區塊(見上方警示),品質會明顯下降。 自行組 prompt 的 runtime(node-llama-cpp、Ollama 等)需自行確認這 4 個 token 有進去。- 精度建議 Q8_0:Q4_K_M 實測會把罕見專名音譯掉(
Kimi→金剛、Sol→索爾),f16 與 Q8_0 則保留; 這是量化本身的代價,與上述 think 區塊無關。 - 關閉 thinking:舊旗標
--chat-template-kwargs '{"enable_thinking":false}'在現行 llama.cpp 可能被靜默忽略;請使用--reasoning off --reasoning-budget 0。 - CJK 提示詞:Windows 上請用
-f prompt.txt(UTF-8),避免-p經 cp950 破壞輸入。 - 轉檔:Qwen3.5 含 MTP 層;部分 llama.cpp 版本若未加
--no-mtp,runtime 可能報missing tensor 'blk.24.attn_norm.weight'。基底含未訓練視覺塔,GGUF 為純文字轉檔。
重現 GGUF 對照表:GitHub 倉庫中 uv run python scripts/eval_gguf.py --direction en2zhtw --limit 100。
訓練摘要
- 資料:六方向各約 80,000 句,合計 502,993 筆(COCT、TED2020、WikiMatrix、JParaCrawl、KFTT、GlobalVoices、KDE4、OpenSubtitles 等)+ 通用指令 replay 35,177 筆。清洗包含評測集污染閘、LaBSE 雙語語意過濾(閾值 0.65)、OpenCC 統一臺灣正體等。
- LoRA:r=64、α=128、dropout 0.05;目標含標準注意力、MLP 與 Qwen3.5 線性注意力層(
in_proj_qkv/z/a/b、out_proj)。 - 其他:bf16、不使用 packing、token 預算組 batch、
max_length1408、lr 1e-4 cosine、單 epoch 5,677 步;final eval_loss 1.7708。 - 成本:單張 RTX 5060 Ti 16GB,峰值 VRAM 約 4.00GB,約 10.5 小時。
較大 rank(r=128)曾使 COMET 再升約 0.18,但 BELEBELE 中日文明顯退步,故發布版維持 r=64。設定檔見 GitHub configs/sft_lora_v5e.yaml。
限制
- 0.8B 容量有限;最高語意品質請考慮更大模型。
- en→zhtw 與官方基底語意統計持平(其餘五方向領先);該方向瓶頸尚未完全定位。
- 通用問答與指令遵循低於官方基底——翻譯特化,非通用助手。
- 多行且各行互不相關的輸入(規格表、清單、UI 字串)常只譯出第一行:訓練語料中的多行樣本皆為連貫段落,此為分布外情形。請逐行送入。
- 2023 年後的 AI 領域術語未學到(如
open weight、agentic coding),會被逐字直譯。 - 含未訓練視覺塔,僅供文字翻譯。
- 主要評測為 FLORES-200 單一測試集;COMET 差異在約 ±0.4 以內時宜視為雜訊。
授權
模型與程式碼 Apache-2.0(繼承自 Qwen3.5-0.8B)。訓練語料各依原始來源授權;本庫僅發布微調權重,不轉發語料。重建資料請使用 GitHub 專案之 scripts/download_data.py 與 prepare_data.py。