統計系研究生 NLP 學習講義 · 2025

從菜鳥到出師
NLP 四層學習地圖

你已經能用工具分析文本。
這份講義告訴你,接下來還需要補齊哪四個層次,
才能真正駕馭 NLP 研究。

學習層次 四個核心層次
預估時程 4 – 6 個月
適合對象 統計系研究生

📍 你現在的位置(已掌握的能力)

TF-IDF理解稀疏向量表示
BERT Embedding理解稠密語義向量
UMAP / PCA高維資料降維視覺化
情感分析 Pipeline預訓練模型推論
零樣本分類(NLI)遷移學習泛化能力
統計檢定整合t-test、卡方、相關性
💡 這個基礎比多數「會跑 Colab 範例」的人紮實得多。以下四個層次是真正出師的關鍵缺口,請按順序學習。

01
🧱
Layer 1 · 最高優先

理論地基

最容易被跳過,最影響研究上限

很多人能操作工具,卻說不清楚為什麼這樣做。 在研究場景中,「知其然」卻「不知其所以然」,會在 seminar 或論文審查時直接被質疑。 理論地基的目標不是背公式,而是能用自己的話說清楚三件事。

必須能解釋的核心概念
Self-Attention 機制 Transformer 架構 MLM 預訓練目標 BERT vs GPT 差異 Word2Vec vs BERT Cross-entropy Loss Fine-tuning 原理
🎯 測試自己:能否用白話回答這些問題?
  • 為什麼 BERT 比 Word2Vec 對「一詞多義」更好?
  • Self-attention 的 Q、K、V 各代表什麼?計算步驟是什麼?
  • BERT 有 512 token 的限制,這個數字從哪來?
  • MLM(遮罩語言模型)和 CLM(因果語言模型)的差別,對下游任務有何影響?
  • 為什麼 Fine-tuning 比從頭訓練更有效率?
python · 核心概念示意 Attention 計算原理
# Attention 機制的直覺:對每個詞,計算它和其他詞的「相關度」
# 數學上就是:Attention(Q,K,V) = softmax(QK^T / √d_k) × V

import torch
import torch.nn.functional as F

d_k = 64   # 向量維度

# 假設 4 個詞,每個詞是 64 維向量
Q = torch.randn(4, d_k)   # Query:「我想找什麼?」
K = torch.randn(4, d_k)   # Key:「我有什麼?」
V = torch.randn(4, d_k)   # Value:「實際的內容」

# 計算注意力分數(相關度矩陣)
scores  = Q @ K.T / d_k**0.5   # shape: (4, 4)
weights = F.softmax(scores, dim=-1)  # 每行加總為 1
output  = weights @ V              # 加權平均所有詞的 Value

# → 「我」這個詞,透過 attention 知道它和「書」最相關
# → 所以「我」的新向量大量融合了「書」的資訊
# → 這就是「上下文感知」的來源!

print(f"注意力權重矩陣(4×4):\n{weights.detach().numpy().round(3)}")
📖 教科書
Speech and Language Processing
Jurafsky & Martin,免費線上版。第 6、10、11 章是核心,從詞向量到 Transformer 完整覆蓋。
🌐 圖解文章
The Illustrated Transformer
Jay Alammar 撰,業界公認最好的 Attention 圖解入門,中文翻譯版也很流通。
🌐 圖解文章
The Illustrated BERT
同作者,延伸到 BERT 的預訓練與 Fine-tuning 機制,搭配上面一起看。
✅ 層次一學習產出
能在 seminar 上用 30 分鐘,用投影片清楚說明「為什麼 BERT 理解語義,而 TF-IDF 不行」。 包含 Attention 機制示意圖、MLM 預訓練目標、以及和你工具中 Embedding 視覺化的連結。

02
🏋️
Layer 2 · 實作核心

Fine-tuning

從「用模型」到「訓練模型」的關鍵跨越

你現在能做的是零樣本推論(不需要標注資料)。 Fine-tuning 是用你自己的標注資料,讓通用模型「專門化」到你的任務上。 在有 100 筆以上標注資料時,Fine-tuning 的準確率通常比零樣本高 15–30%, 而且這往往是論文中「我們的方法 vs baseline」的核心差距所在。

Fine-tuning 流程的四個階段
階段做什麼對應程式碼
① 資料準備 標注資料、切分 train/val/test(8:1:1)、轉為 Dataset 格式 datasets.Dataset.from_pandas()
② Tokenize 文本轉 token ID,加 padding/truncation,產生 attention_mask tokenizer(texts, padding=True, truncation=True)
③ 載入模型 用 AutoModelForSequenceClassification,指定 num_labels AutoModelForSequenceClassification.from_pretrained()
④ 訓練 設定 TrainingArguments,用 Trainer.train() 執行 trainer.train() / trainer.evaluate()
python · Fine-tuning 完整流程 文本分類任務
from transformers import (
    AutoTokenizer, AutoModelForSequenceClassification,
    TrainingArguments, Trainer, DataCollatorWithPadding
)
from datasets import Dataset
import numpy as np
from sklearn.metrics import classification_report

# ── Step 1:準備資料 ──
# 假設 df 有 'text' 和 'label'(整數)兩欄
train_df, val_df, test_df = ...  # 切分資料

# ── Step 2:Tokenize ──
MODEL_NAME = "bert-base-chinese"
tokenizer  = AutoTokenizer.from_pretrained(MODEL_NAME)

def tokenize(batch):
    return tokenizer(batch["text"], truncation=True, max_length=128)

train_ds = Dataset.from_pandas(train_df).map(tokenize, batched=True)
val_ds   = Dataset.from_pandas(val_df  ).map(tokenize, batched=True)
test_ds  = Dataset.from_pandas(test_df ).map(tokenize, batched=True)

# ── Step 3:載入模型(自動加分類頭)──
num_labels = train_df["label"].nunique()
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME, num_labels=num_labels
)

# ── Step 4:訓練設定 ──
args = TrainingArguments(
    output_dir         = "./results",
    num_train_epochs   = 3,
    per_device_train_batch_size = 16,
    per_device_eval_batch_size  = 32,
    evaluation_strategy = "epoch",
    save_strategy       = "epoch",
    load_best_model_at_end = True,
    metric_for_best_model  = "f1",   # ← 用 F1,不用 Accuracy!
    learning_rate   = 2e-5,        # ← Fine-tuning 標準學習率
    warmup_ratio    = 0.1,
    weight_decay    = 0.01,
    fp16            = True,         # GPU 加速(Colab 適用)
)

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    preds = np.argmax(logits, axis=-1)
    report = classification_report(
        labels, preds, output_dict=True, zero_division=0)
    return {"f1": report["weighted avg"]["f1-score"]}

trainer = Trainer(
    model           = model,
    args            = args,
    train_dataset   = train_ds,
    eval_dataset    = val_ds,
    data_collator   = DataCollatorWithPadding(tokenizer),
    compute_metrics = compute_metrics,
)

# 開始訓練!(T4 GPU 約 3 分鐘/epoch × 3 = 9 分鐘)
trainer.train()

# 測試集評估
preds_output = trainer.predict(test_ds)
preds = np.argmax(preds_output.predictions, axis=-1)
print(classification_report(test_ds["label"], preds, zero_division=0))
⚠️ 最常見的陷阱:用 Accuracy 當最佳模型指標。當類別不平衡時(如 80% 正面、20% 負面),模型全猜正面也有 80% 準確率,但 F1 只有 0.44。務必用 metric_for_best_model = "f1"
📚 官方課程
HuggingFace NLP Course
huggingface.co/learn/nlp-course,完全免費。第 3 章「Fine-tuning a pretrained model」是核心,含 Colab 範例。
🎯 第一個練習
文本分類 Fine-tuning
用你範例資料的 50 筆,標注後做 Fine-tuning,與零樣本的準確率對比。這個對比就是你第一個 NLP 實驗。
✅ 層次二學習產出
完成一份完整的實驗報告:
以你研究領域的資料,從標注(至少 200 筆)→ Fine-tuning → 測試集評估, 產出包含 Precision / Recall / F1 的 Classification Report, 並與零樣本 baseline 做顯著性比較。

03
📐
Layer 3 · 研究品質

評估框架

統計系背景最有優勢的地方,也最常被輕忽

這是你作為統計系研究生的護城河。CS 背景的人往往會訓練模型, 卻說不清楚「模型 A 比模型 B 好 2%,這個差距顯著嗎?」 嚴謹的評估框架是 NLP 研究品質的分水嶺。

三大評估主題
主題 1|正確的分類指標選擇
  • Precision / Recall / F1 的取捨邏輯:醫療診斷重 Recall(寧可誤報),垃圾郵件重 Precision(寧可漏報)
  • Macro vs Micro vs Weighted 平均:各適用什麼情境?
  • 混淆矩陣的解讀:模型在哪兩個類別之間最常混淆?為什麼?
主題 2|統計顯著性:模型間比較
  • 兩個模型的 Accuracy 差距,需要幾筆測試資料才能確認顯著?
  • McNemar's Test:比較兩個分類器,考慮配對結構
  • Bootstrap Confidence Interval:當測試集很小時的正確做法
主題 3|避免常見的評估陷阱
  • 資料洩漏(Data Leakage):預處理在切分前還是後做?
  • 測試集只能用一次,validation set 是選模型用的,不是評估最終模型
  • 類別不平衡時 Accuracy 的欺騙性(最常被忽略!)
  • 多次實驗後挑最好結果報告 = 統計上的「p-hacking」
python · 完整評估流程 分類器比較 + 統計顯著性
from sklearn.metrics import (
    classification_report, confusion_matrix,
    ConfusionMatrixDisplay
)
from statsmodels.stats.contingency_tables import mcnemar
import matplotlib.pyplot as plt
import numpy as np

# ── 完整的 Classification Report ──
print(classification_report(
    y_true, y_pred,
    target_names=["客訴", "詢價", "閒聊", "商品評價"],
    digits=4   # ← 論文報告通常要 4 位小數
))
# precision  recall  f1-score   support
# 客訴         0.8912  0.9104  0.9007    67
# 詢價         0.7634  0.8021  0.7823    53
# 閒聊         0.9321  0.8876  0.9093    45
# 商品評價      0.9102  0.9231  0.9166   135

# ── 混淆矩陣視覺化 ──
cm = confusion_matrix(y_true, y_pred)
disp = ConfusionMatrixDisplay(cm, display_labels=["客訴","詢價","閒聊","商品評價"])
disp.plot(cmap="Blues")
plt.title("混淆矩陣 — 觀察哪些類別最常混淆")

# ── McNemar's Test:比較兩個模型 ──
# 零樣本 vs Fine-tuned 模型,哪個真的更好?
correct_a = (y_true == y_pred_zeroshot)   # 零樣本答對的
correct_b = (y_true == y_pred_finetuned)  # Fine-tuned 答對的

# 建立 2×2 contingency table
n_both_right   = (correct_a & correct_b).sum()
n_only_a_right = (correct_a & ~correct_b).sum()
n_only_b_right = (~correct_a & correct_b).sum()
n_both_wrong   = (~correct_a & ~correct_b).sum()

table = [[n_both_right, n_only_a_right],
         [n_only_b_right, n_both_wrong]]

result = mcnemar(table, exact=True)
print(f"McNemar p-value = {result.pvalue:.4f}")
# p < 0.05 → 兩模型有顯著差異,可以宣稱 Fine-tuned 更好
# p ≥ 0.05 → 差距可能只是隨機波動,不能宣稱誰更好

# ── Bootstrap Confidence Interval(測試集小時使用)──
def bootstrap_f1(y_true, y_pred, n_bootstrap=1000, ci=0.95):
    from sklearn.utils import resample
    from sklearn.metrics import f1_score
    scores = []
    for _ in range(n_bootstrap):
        yt, yp = resample(y_true, y_pred)
        scores.append(f1_score(yt, yp, average="weighted"))
    alpha = (1 - ci) / 2
    return np.quantile(scores, [alpha, 1-alpha])

lo, hi = bootstrap_f1(y_true, y_pred_finetuned)
print(f"Weighted F1: {f1:.4f} (95% CI: [{lo:.4f}, {hi:.4f}])")
📊 統計系優勢的最佳體現:在論文方法比較的章節,同時報告 McNemar's p-value 和 Bootstrap CI,顯示你理解「統計顯著性」和「實用顯著性」的差異——這正是純 CS 背景研究者最容易缺漏的部分。
✅ 層次三學習產出
完成一份模型比較報告:零樣本分類 vs Fine-tuning, 包含完整 Classification Report、混淆矩陣、McNemar's Test p-value、 以及 Bootstrap 95% CI。說明「為什麼某個類別 F1 特別低」,提出可能原因與改善方向。

04
🚀
Layer 4 · 前沿視野

大型語言模型時代的新技能

BERT 是地基,LLM 是現在的前沿

BERT 系列是基礎,研究前沿已移向 LLM(GPT-4、Claude、LLaMA)。 你需要理解這個轉變,並知道你現有的 Embedding 技術如何和 LLM 接軌。 這層不需要「精通」,但需要「看懂」,才能閱讀最新論文。

三個必須了解的前沿概念
概念 A|Prompt Engineering
  • Few-shot Prompting:給模型幾個範例,比零樣本準確率更高,比 Fine-tuning 更省資源
  • Chain-of-Thought(CoT):讓模型先「思考推理過程」再給答案,準確率大幅提升
  • 這和你的零樣本工具的關係:零樣本是 NLI 模型;Prompt Engineering 是直接對話 LLM
概念 B|RAG(檢索增強生成)
  • LLM 的知識有截止日期,也不認識你的領域文件——RAG 解決這個問題
  • 你的 BERT Embedding 就是 RAG 的向量資料庫基礎!技術直接相通
  • 流程:文件 → Embedding → 向量資料庫 → 使用者問題 → 找最相關文件 → 餵給 LLM 回答
概念 C|PEFT / LoRA(參數高效微調)
  • Full Fine-tuning 需要更新數億個參數,Colab 免費版 GPU 跑不動大模型
  • LoRA:只訓練少量「低秩分解矩陣」,效果接近全量訓練,參數量少 100 倍
  • 在 Colab 免費 GPU 上,可以 LoRA 微調 7B 的 LLaMA 模型
python · 三個概念示意 Prompt / RAG / LoRA
# ═══════════════════════════════════════
# 概念 A:Few-shot Prompting
# ═══════════════════════════════════════
few_shot_prompt = """
請判斷以下評論的類別(客訴/詢價/閒聊/商品評價)。

範例:
評論:這個商品品質很差,要求退款! → 客訴
評論:請問有黑色款嗎?            → 詢價
評論:今天天氣很好。              → 閒聊
評論:超好用,強力推薦!          → 商品評價

請判斷:
評論:{text}                    →"""

# 對比零樣本:few-shot 給了模型「格式範例」,通常準確率更高


# ═══════════════════════════════════════
# 概念 B:RAG — 你的 Embedding 技術直接用得上
# ═══════════════════════════════════════
from sklearn.metrics.pairwise import cosine_similarity

# 假設你有一批領域文件的 BERT Embedding(就是 Module 2 的成果)
doc_embeddings = state.embeddings["bert"]  # shape: (n_docs, 768)
doc_texts      = df["review"].tolist()

def rag_retrieve(query, top_k=3):
    # 問題也轉成 Embedding
    query_emb = get_bert_embeddings([query], "bert-base-chinese")
    # 找最相似的文件
    sims = cosine_similarity(query_emb, doc_embeddings)[0]
    top_idx = sims.argsort()[::-1][:top_k]
    return [(doc_texts[i], sims[i]) for i in top_idx]

# 這就是 RAG 的核心:用相似度檢索 → 餵給 LLM → 讓 LLM 基於真實資料回答
results = rag_retrieve("客服態度的問題")


# ═══════════════════════════════════════
# 概念 C:LoRA 微調(需安裝 peft)
# ═══════════════════════════════════════
# !pip install peft
from peft import get_peft_model, LoraConfig, TaskType

lora_config = LoraConfig(
    task_type = TaskType.SEQ_CLS,
    r         = 8,       # 低秩維度(越小越省,通常 4-16)
    lora_alpha = 32,     # 縮放係數
    target_modules = ["query", "value"],  # 只更新 Q、V 矩陣
    lora_dropout = 0.1,
)

# 把 LoRA 套在現有模型上:只有 ~0.5% 的參數需要訓練!
peft_model = get_peft_model(model, lora_config)
peft_model.print_trainable_parameters()
# trainable params: 294,912 || all params: 102,267,648 (0.29%)
# → 只需訓練 0.29% 的參數,效果接近 Full Fine-tuning!
🌐 論文入口
Papers With Code
paperswithcode.com,追蹤各任務 SOTA(State of the Art),每篇論文附有 GitHub 實作連結。
📖 必讀論文
LoRA 原始論文
Hu et al., 2021. "LoRA: Low-Rank Adaptation of Large Language Models." 是理解 PEFT 的基礎。
📖 必讀論文
RAG 原始論文
Lewis et al., 2020. "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks." 你的 Embedding 就是 RAG 的一部分。
✅ 層次四學習產出
用你的領域資料,實作一個簡單的 RAG 系統: BERT Embedding 作為向量資料庫 → 使用者輸入問題 → 檢索最相關的 3 筆資料 → 組成 Prompt 回答。 這直接連結了你的 Module 2 技術和 LLM 應用,形成一個完整的研究展示。

🗓️ 建議學習路徑(4–6 個月)

Month 1–2 · 層次一
補理論地基:每週讀 2 章 Jurafsky & Martin + 1 篇 Jay Alammar 圖解。 目標是能對同學解釋「Attention 為什麼讓 BERT 理解語義」。 不需要手推數學,重點是直覺。
Month 2–3 · 層次二
動手做 Fine-tuning:選一個你研究領域的任務, 手動標注 200–500 筆,完成從資料清洗到 Trainer.train() 的完整流程。 重點:記錄每個超參數選擇的理由。
Month 3–4 · 層次三
建立評估框架:把層次二的實驗結果,用嚴謹的統計方法重新評估。 加入 McNemar's Test、Bootstrap CI、混淆矩陣分析。 這個過程就是一篇 conference paper 的 Experiment 章節。
Month 5–6 · 層次四
接軌 LLM 時代:用你的 Embedding 技術實作 RAG, 或嘗試 LoRA 微調一個較大的模型, 並與層次二的 Fine-tuning 結果比較準確率與計算成本。

🧭 面對新任務的決策地圖

拿到新領域資料 │ ▼ 有沒有對應的領域預訓練模型?(medBERT, legalBERT...) 是 → 優先使用,再評估是否需要 Fine-tuning 否 → 從 bert-base-chinese 或 xlm-roberta 開始 │ ▼ 有標注資料嗎? < 50 筆 → 零樣本分類 + 精心設計標籤描述 50-500 筆 → Few-shot Prompting 或 LoRA 微調 > 500 筆 → Fine-tuning(層次二),預期 F1 提升 15-30% │ ▼ 評估結果(層次三) F1 < 0.7 → 檢查標注品質、類別定義、換模型 F1 ≥ 0.7 → 可用於研究,報告 McNemar's p-value │ ▼ 需要即時回答問題 / 整合外部知識? 是 → 實作 RAG(層次四) 否 → 完成,準備論文的 Experiment 章節

🎯 你的護城河:統計系的獨特優勢

統計系研究生在 NLP 上的優勢,不在於會不會寫 PyTorch, 而在於對「評估」與「推斷」的嚴謹度

很多 CS 背景的人能跑出模型,卻說不清楚: 「這個差距有多少是真實改進,有多少是隨機波動?」 「類別不平衡的情況下,我報告的 Accuracy 真的有意義嗎?」

當你能同時說:「Fine-tuned 模型的 Weighted F1 = 0.834, 95% Bootstrap CI 為 [0.812, 0.857],與零樣本基線的 McNemar's p = 0.003(顯著)」—— 這就是研究品質的分水嶺,也是你獨特的學術貢獻。