[TOOLS] 6 分鐘閱讀OraCore 編輯部

情緒辨識 SLM 微調實作指南

用 ISMOTE、LoRA 和 focal loss,把開放權重小語言模型微調成多標籤情緒辨識器。

分享 LinkedIn
情緒辨識 SLM 微調實作指南

用 ISMOTE、LoRA 和 focal loss,把開放權重小語言模型微調成多標籤情緒辨識器。

這篇給要把客服單、社群貼文、電子郵件,轉成可查詢情緒標籤的開發者看。你照著做完,會拿到一條可重現的訓練流程,能處理類別不平衡,並輸出可評估的情緒分類器。

完成後,你會有一個可直接跑的資料準備腳本、平衡後的訓練集、加入 LoRA 的 Mistral Small 模型,以及可在測試集上輸出每個情緒 F1 的評估結果。

開始之前

訂閱 AI 趨勢週報

每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。

不會寄垃圾信,隨時可取消。

  • Python 3.10+
  • Node 不需要;訓練環境請準備 CUDA 相容 GPU,至少 24 GB VRAM
  • PyTorch 2.4+,且已安裝 CUDA 版
  • Hugging Face 帳號與可用的 access token
  • 可存取 GoEmotions datasetUnsloth repository
  • 已安裝 transformers、datasets、scikit-learn、numpy、pandas、unsloth

Step 1: 建立情緒標籤表

這一步的產出是固定順序的 15 類情緒標籤表,後續資料切分、訓練與評估都會共用它。先從 GoEmotions 挑出你要的類別,再把輸出順序鎖死,避免多標籤向量在不同 split 之間對不上。

情緒辨識 SLM 微調實作指南
EMOTION_LABELS = [
  "fear", "sadness", "disgust", "disapproval", "annoyance",
  "anger", "disappointment", "optimism", "amusement", "surprise",
  "admiration", "excitement", "confusion", "joy", "love"
]

接著檢查每筆資料的 label vector 長度是否一致。你應該看到所有 split 都是固定 15 維的 multi-hot 格式。

Step 2: 平衡訓練資料分布

這一步的產出是去偏態的訓練集,讓 neutral 不會壓過其他情緒。先對多數類做隨機下採樣,再用 ISMOTE 擴增稀有情緒,讓少數類達到可訓練的樣本量。

情緒辨識 SLM 微調實作指南

驗證集與測試集要保持原樣,這樣最後的分數才反映真實不平衡分布。這個做法把下採樣、合成擴增與 loss weighting 放在一起,目標是改善少數類表現,不是美化指標。

你可以先畫出各標籤在前後的頻率圖。你應該看到 neutral 明顯下降,而目標情緒的數量彼此更接近。

Step 3: 載入 Mistral 基座模型

這一步的產出是可在本機運行的基座模型,準備接收參數高效率微調。使用 Unsloth 以 4-bit 方式載入 Mistral Small 3.1 24B Instruct,讓模型能放進可用 GPU 記憶體。

from unsloth import FastLanguageModel
import torch

MODEL_NAME = "unsloth/Mistral-Small-3.1-24B-Instruct-2503"
base_model, _ = FastLanguageModel.from_pretrained(
    model_name=MODEL_NAME,
    max_seq_length=2,
    load_in_4bit=True,
    dtype=torch.bfloat16,
)

驗收方式是模型成功初始化,沒有 OOM,並且確實以 4-bit 權重載入。你應該看到 backbone 已在 GPU 上可用,能直接進入 adapter 注入。

Step 4: 掛上 LoRA 與 focal loss

這一步的產出是輕量訓練配置,讓模型不用全參數微調也能學到多標籤情緒模式。把 LoRA 掛到 attention 與 MLP 投影層,再加上自訂多標籤 head 與 focal loss,讓較難、較稀有的標籤得到更高權重。

base_model = FastLanguageModel.get_peft_model(
    base_model,
    r=16,
    lora_alpha=32,
    lora_dropout=0,
    bias="none",
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    use_gradient_checkpointing="unsloth",
    random_state=3407,
    use_rslora=False,
)

驗收方式是可訓練參數數量明顯下降,但模型仍能輸出 15 個情緒的 logits。你應該看到 adapter 佔比遠小於完整模型,且輸入多標籤目標時不會報格式錯誤。

Step 5: 訓練並輸出測試分數

這一步的產出是已訓練完成的情緒分類器,以及一份可讀的測試集報告。設定按 epoch 驗證、計算 exact accuracy 與 macro、micro F1,並在驗證集表現最佳時保存 checkpoint。原始做法顯示,多數目標情緒的 F1 可高於 0.7。

from sklearn.metrics import f1_score, precision_score, recall_score, accuracy_score

# train with epoch evaluation, then score on the test set
# compute_metrics should threshold sigmoid outputs at 0.5

驗收方式是你能在 log 看到每個 epoch 的評估結果,並在測試集報告中讀到各情緒的 per-class metrics。你應該看到最佳 checkpoint 由驗證集分數選出,而不是手動挑模型。

指標基準/優化前結果/優化後
少數類平衡資料明顯偏向 neutralneutral 被下採樣,稀有情緒用 ISMOTE 擴增
訓練方式全參數微調需要更高記憶體4-bit 基座模型加 LoRA adapters
情緒 F1原始 baseline 未提供穩定結果多數目標情緒可達 F1 > 0.7

常見錯誤

  • 直接拿不平衡資料開訓練。修法:先下採樣 neutral,再對少數情緒做 ISMOTE。
  • 把多標籤問題當成單標籤分類。修法:輸出用 sigmoid,閾值用 0.5,不要用 softmax。
  • GPU 記憶體不足。修法:保留 4-bit 載入、LoRA 與 gradient checkpointing。

接下來可以看什麼

下一步可以把模型推到 Hugging Face Hub,為每個情緒單獨調整閾值,並比較 ISMOTE 與簡單 oversampling 在你自己的資料上的差異。