跳到主要內容

LV.15

歸鄉之門:匯出與部署

把練好的模型帶回你的 Mac,關掉 Wi-Fi 跑一次

BOSS
格式轉換九頭蛇
時間
約 60 分鐘
建議先過
LV.13

先看 Boss:格式轉換九頭蛇

你在 LV13 得到的是一個 adapter(LoRA 的小矩陣),它自己不是完整的模型。要在 Ollama 或 LM Studio 這類工具裡使用,需要先把 adapter 融回底座,再轉成它們讀得懂的格式。格式有 safetensors、GGUF、MLX 等,砍掉一個問題,又冒出兩個。

這是 Boss 的樣子。好消息是:對初學者最穩的原則是「先把 LoRA merge 回基底,產生完整模型,再匯入 runtime」。

🍎 Mac 主線:fuse → GGUF → Ollama

以下是作者在 M5 32GB(mlx-lm 0.32.0、Ollama 0.35.1、llama.cpp 2026-10-06 main)實測 E3 成功的路線。截至 2026-10,工具版本更新很快,請以你使用的版本文件為準。

先說失敗的捷徑(E2)

最直觀的想法是:mlx_lm fuse --dequantize 得到 fp16 的 safetensors,直接 ollama create。作者實測:

  • mlx_lm fuse --dequantize 成功,得到約 8.7GB 的 fp16 模型。
  • ollama create 顯示成功,但載入時出錯:layer 15: missing attention k projection。
  • 推論原因(作者的推測,非官方說明):Gemma 4 E2B 後段層共用 KV(key-value,注意力快取),mlx 版權重省略了那些層的 k_proj,但 Ollama 的 MLX runner 預期它存在。

所以 Gemma 4 E2B 走這條路目前行不通(截至 2026-10、上述版本)。換其他模型家族可能結果不同,要自行測試。

另外一個坑:ollama create 是用戶端匯入,會寫入 ~/.ollama/models。如果你的 Ollama server 設了自訂的 OLLAMA_MODELS 路徑,server 會看不到剛匯入的模型。

補充:—quantize 的行為

很多舊教學會寫 ollama create --quantize q4_K_M。作者在 Ollama 0.35.1 測試,--quantize 只接受 int4、int8、nvfp4、mxfp4、mxfp8,不再是 q4_K_M 這類寫法。遇到錯誤時先 ollama create --help 看你版本支援什麼。

實際可行的 E3 流程

步驟 1:融合並還原成 fp16

mlx_lm fuse \
  --model ./models/gemma-4-E2B-it-MLX-4bit \
  --adapter-path ./adapters/chartkeeper \
  --save-path ./fused/chartkeeper_fp16 \
  --dequantize
  • fuse:把 adapter 融進底座,產生完整模型。
  • --adapter-path:LV13 訓練出來的 adapter。
  • --save-path:輸出資料夾。
  • --dequantize:把 4-bit 還原成 16-bit,因為下一步的轉檔工具需要。(量化再還原不會找回已損失的精度,這只是格式轉換。)

步驟 2:在獨立的 venv 裡用 llama.cpp 轉成 GGUF

作者實測發現 llama.cpp 的 requirements 會把 transformers 釘在 4.57.6,與 mlx-lm 衝突,而且需要升級到 transformers 5.x 才能讀 mlx 存出來的 tokenizer_config。所以要開一個獨立的虛擬環境:

python3 -m venv ~/venvs/llamacpp
source ~/venvs/llamacpp/bin/activate
pip install -r requirements.txt   # 在 llama.cpp 資料夾內
pip install -U "transformers>=5"
python convert_hf_to_gguf.py ../fused/chartkeeper_fp16 \
  --outtype q8_0 \
  --outfile ../fused/chartkeeper.q8_0.gguf
  • python3 -m venv:建立一個隔離的 Python 環境,裡面裝的套件不影響其他工具,類比隔離病房。
  • pip install -r requirements.txt:安裝 llama.cpp 要求的套件。
  • pip install -U "transformers>=5":升級到能讀這份 tokenizer 的版本。
  • --outtype q8_0:輸出 8-bit 量化的 GGUF。作者實測約 4.9GB,約 4 分鐘完成。

步驟 3:建立 Modelfile,匯入 Ollama

FROM ./fused/chartkeeper.q8_0.gguf
PARAMETER temperature 0
SYSTEM """(貼上 LV11 的 SYSTEM 全文)"""
ollama create my-deid -f Modelfile
ollama run my-deid
  • FROM:指向 GGUF 檔。
  • PARAMETER temperature 0:讓輸出盡量固定,不隨機。
  • SYSTEM:把訓練時用的任務說明放進去,宜和訓練時的一致。
  • ollama create:把模型登錄給 Ollama。

作者實測:載入正常,輸出了正確的 PHI JSON,速度約 17 tok/s。

☁️ Colab 路線:save_pretrained_gguf

Unsloth 提供 save_pretrained_gguf 一步輸出 GGUF。本站 notebook 的最後兩格是:

model.save_pretrained_gguf(
    "chartkeeper_gemma4_e2b",
    tokenizer,
    quantization_method = "Q8_0",
)
  • notebook 裡這段包在 if False: 底下,預設不執行;要匯出時把它改成 if True:。
  • 第一個參數是輸出資料夾名稱。
  • quantization_method:notebook 註解寫目前僅支援 Q8_0、BF16、F16。
  • 下一格會產生 Modelfile 並下載 GGUF。下載到 Mac 後可用 ollama create 或在 LM Studio 匯入。

實測結論(E5):Colab 免費版匯出完整 GGUF 失敗。 save_pretrained_gguf 合併 16-bit 權重成功(約 9.5GB),但轉 GGUF 時 host RAM(免費版約 12.7GB)不足而被系統終止(SIGKILL);Unsloth 自動改用 --use-temp-file 重試仍被終止,停在 per_layer_token_embd.weight。原因是 Gemma 4 E2B 的 per-layer embedding 約 23.5 億參數(8960 x 262144),轉檔時記憶體吃不下。所以上面這段程式在免費版 T4 上走不通,只有 RAM 更大的環境才可能成功。

替代路線(待實測):Colab 只存 LoRA adapter,帶回 Mac 轉換。

  1. Colab:model.save_pretrained("lora_adapter")、tokenizer.save_pretrained("lora_adapter"),打包成 zip 下載到 Mac(notebook 已附這一格)。
  2. Mac:用 llama.cpp 的 convert_lora_to_gguf.py 轉成 LoRA GGUF:python convert_lora_to_gguf.py --base-model-id google/gemma-4-E2B-it lora_adapter --outfile chartkeeper_lora.gguf(也可用 --base 指向本機 HF 模型資料夾)。
  3. Modelfile 寫 FROM gemma4:e2b 與 ADAPTER ./chartkeeper_lora.gguf,再 ollama create。

Unsloth 預裝的 llama.cpp 沒有 convert_lora_to_gguf.py,所以第 2 步宜在 Mac 上做。這條替代路線本站尚未實測;建議以 Mac 主線(E3)為準。

斷網測試

匯出成功不等於好用。最後一關:

  1. 準備一份新的合成病歷(不要用訓練或測試集中的)。
  2. 關掉 Wi-Fi(拔掉網路線)。
  3. ollama run my-deid,貼入病歷,檢查輸出是否為合法 JSON、PHI 是否被列出。
  4. 用 LV11 的方式(程式依清單取代)做遮蔽,看結果。

這證明推論在本機完成,不需要網路。但請記得:本站只用合成資料。 即使流程在本機跑,處理真實病歷仍需院方核准與 IRB,本地不等於合法。

本關重點

  • adapter 不是完整模型,要先融回底座。
  • Mac 主線(作者實測 E3):mlx_lm fuse --dequantize → llama.cpp convert_hf_to_gguf → ollama create;llama.cpp 要用獨立 venv。
  • 直接用 ollama create 匯入 Gemma 4 E2B 的 safetensors 失敗(E2,missing k projection);Ollama 0.35 的 --quantize 只接受 int4、int8 等,不是 q4_K_M。
  • Colab 免費版匯出完整 GGUF 實測失敗(E5,host RAM 約 12.7GB 不足);改存 LoRA adapter 再到 Mac 轉換的路線待實測。
  • 最後用斷網測試確認沒有依賴網路;斷網不等於合法。

BOSS 戰:格式轉換九頭蛇

HP0/5
  1. 作者實測中,把 mlx 融合後的 Gemma 4 E2B 用 `ollama create` 直接匯入 safetensors,結果如何?

  2. 本站 Mac 主線的匯出順序是?

  3. 為什麼 llama.cpp 要用獨立的 Python 虛擬環境(venv)?

  4. 「Ollama 0.35 的 --quantize 只接受 int4、int8 等」這個資訊最需要注意什麼?

  5. 斷網測試的目的是什麼?