用 LoRA 而不是全參數微調,理由:資料量不大(千筆級)、任務單一、要保留原版能力、GB10 訓練時間可控。
# train/lora_sft.py
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig
lora = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
task_type="CAUSAL_LM")
cfg = SFTConfig(
output_dir="ckpt/shieldgemma-2b-inj",
num_train_epochs=3,
per_device_train_batch_size=8,
gradient_accumulation_steps=2,
learning_rate=1e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.05,
bf16=True,
eval_strategy="steps", eval_steps=50,
save_strategy="steps", save_steps=50,
load_best_model_at_end=True,
completion_only_loss=True, # 只算 Yes/No token 的 loss(Day 19)
)
trainer = SFTTrainer(model=model, args=cfg, peft_config=lora,
train_dataset=train, eval_dataset=valid)
trainer.train()
超參數不是調出來的最佳值,是一組合理的起點。本系列不做大規模超參數搜尋——搜尋是用 validation 集做的,過度搜尋等於變相對 validation 過擬合。
LoRA adapter 合併回 base 權重後,用 Day 18 同一套 vLLM 容器部署,確保延遲量測條件相同。
merged = model.merge_and_unload()
merged.save_pretrained("/models/shieldgemma-2b-inj")
現在才碰 eval 集。三方對照:原版 ShieldGemma(自訂政策)、微調版、Model Armor(Day 9 的數字)。閾值統一用 Day 5 的方法——各自調到相同的 B-benign 誤判率目標(本系列 ≤ 5%)再比攔截率。
Day 17 提過:微調版是 Gemma 的衍生模型,散布時要遵守 Gemma 授權條款與使用政策。本系列的微調版權重不公開,只公開訓練腳本與資料建置流程——讀者用自己的語料重訓。
在 eval 集(六類、共 N 筆)上,將 B-benign 誤判率統一控制在 ≤ 5% 的條件下:ShieldGemma 2B 微調版對 D-zh 的攔截率由原版 _% 提升至 _%,D-en 由 _% 變為 _%;9B 微調版對應為 _% / _%。同條件下 Model Armor v3 對 D-zh 為 _%。
Day 21:LLM Guard 框架層——離線自架的組裝。L1 與微調後的 L2 都有了,明天把它們裝進閘道:用 LLM Guard 當骨架、LiteLLM hook 掛上去、健康檢查與降級(Day 4)、以及完全離線環境的模型與規則載入。Week 3 收尾。
Instagram @aid3fend。
更多 AI 資安筆記:aid3fend.com