為什麼需要序列模型?
「世界上很多資料,不是看一眼就懂的,而是要照順序讀下去才有意義。」
上一堂的 CNN 在做什麼?
上一堂我們講的 CNN,本質上是在處理「空間」的問題 — 一張圖片每個 pixel 的位置是固定的,CNN 透過 kernel 在空間上滑來滑去,找出 local pattern,再一層一層組合成更大的概念。
但「順序」很重要
世界上很多資料不是「空間性」的,而是「時間性 / 順序性」的:
CNN/MLP 處理不來的兩個問題
MLP 要求輸入是固定維度,但句子有長有短 — 一句 5 個字、另一句 50 個字,要怎麼塞進同一個模型?
每個輸入都被獨立處理,模型不知道「之前發生了什麼」。但語言、音訊、影片,缺了上下文就毫無意義。
所以我們需要一種新架構:它要能記住過去,然後用這個記憶幫助理解現在。
這就是 RNN 出場的時刻。
本堂課的演進地圖
• 頂部 tabs 直接跳到任何章節 ;底部箭頭 順序往下走,左右鍵盤 也能切換
• 所有 虛線標記的詞 跟圖中元素都可以 hover,會出現詳細解釋
• 互動 demo 在 RNN/LSTM/Self-Attention 三頁都有,可以親自玩
RNN — 加一條「自己連到自己」的線
「讓網路擁有記憶 — 這個想法簡單到令人感動。」
核心想法
普通的神經網路是「輸入 → 隱藏層 → 輸出」,資訊只往前流。RNN 做了一件很簡單的事:把上一個時間點的隱藏層輸出,當作這一個時間點的額外輸入。 這條多出來的線,就是所謂的 recurrent connection。
把 RNN 攤開來看
數學長這樣
① 更新 hidden state:
② 產生輸出:
兩個重要觀念
RNN 處理一句 10 個字的句子,不是用 10 組不同的權重,而是同一組 W_xh, W_hh, W_hy 用 10 次。
這跟 CNN 的 kernel 共享是同樣的精神 — 不管字出現在哪個位置,處理它的方式都應該一樣。
→ 結論:RNN 可以處理任意長度的輸入,因為參數量跟序列長度無關。
訓練 RNN 的方法叫做 「時間上的反向傳播」。 把 RNN 在時間軸攤開(如上圖右),就會變成一個很深的前饋網路 — 然後用一般的反向傳播算梯度就好。
RNN 的致命傷 — 梯度消失/爆炸
當序列很長,反向傳播要經過很多層 W_hh 的乘法。
想像一下:如果 W_hh 的某個 eigenvalue 是 0.9:
結論:RNN 在實務上很難記住超過 10~20 步以前的資訊。下面這個小 demo 給你直接看數字。
梯度消失/爆炸 互動模擬器
拉動 slider 改變權重大小(W_hh 的 eigenvalue)和序列長度,看看梯度在 BPTT 過程中會變成什麼樣子。
RNN 即時句子處理器
輸入一段文字,看 RNN 如何逐字更新 hidden state。h_t 是累積到第 t 步為止的「記憶摘要」。越後面的字,前面的記憶就越淡(梯度消失)。
假設 hidden size = 2,embedding size = 2:
字的 embedding:好=[1, 0]、開=[0, 1]、心=[1, 1]
W_xh = [[0.5, 0.3], [0.2, 0.7]]
W_hh = [[0.1, 0.4], [0.6, 0.2]]
初始 h₀ = [0, 0]
注意 h₂ 裡面同時包含了「好」和「開」的資訊 — 這就是 RNN 的「記憶」。到 h₃ 時,三個字的語意全部被壓縮在一個 2 維向量裡。
這個梯度問題就是 LSTM 要解決的事情。
LSTM — 給模型一條「高速公路」
「與其反覆改寫記憶,不如另外開一條路讓它幾乎原封不動傳下去。」
核心 insight
LSTM 的關鍵想法是:與其讓記憶被反覆 matrix multiply 搞到消失,不如另外開一條通道,讓記憶可以幾乎原封不動地一路傳下去,只在必要的時候才修改它。 這條額外的通道就是 cell state。
LSTM Cell — 完整解剖圖
三個 Gate 在做什麼?
① Forget Gate
Sigmoid 把每個維度壓到 0~1。0 代表完全忘掉,1 代表完全保留。
② Input Gate
C̃_t = tanh(W_C·[h_{t-1}, x_t]+b_C)
分兩部分:i_t 是「寫入閥門」,C̃_t 是「準備要寫的內容」。
③ Output Gate
h_t = o_t ⊙ tanh(C_t)
cell state 可能存了一堆東西,但這個時間點不見得每個都要輸出。
關鍵公式 — Cell State 更新
這個式子有多漂亮 — 注意它是加法不是乘法:因為是相加 → 梯度可以沿 cell state 高速公路幾乎無損傳回去 → 不會梯度消失。
LSTM 時間步動畫 — 一步一步看記憶怎麼更新
用「The cat sat on the mat」逐步展示 4 維 cell state 的演化。色塊深淺 = gate 開啟強度,所有過渡都是 GPU 加速的 CSS transition。
RNN 是「強迫每個時間點都重寫記憶」,
LSTM 是「讓模型自己決定什麼時候要改記憶、改哪裡、改成什麼」。
Gradient Flow 動畫 — RNN vs LSTM
觀察梯度如何在 RNN 和 LSTM 中反向傳播。RNN 的梯度經過每層會被乘一個小於 1 的數(衰減),LSTM 的 cell state 高速公路讓梯度幾乎不變。
假設模型在處理:「那隻黑色的貓,在經過了很多條街道和巷弄之後,最後終於回到了家」
即使中間隔了十幾個字,因為 forget gate 一直輸出接近 1,cell state 上的「貓」資訊就被原封不動地保留下來。這就是「高速公路」的威力。
順帶一提:GRU
GRU 是 LSTM 的簡化版 — 把三個 gate 合成兩個(update + reset),cell state 和 hidden state 也合併。參數比較少,效果通常跟 LSTM 差不多。
ELMo — biLSTM 的最後光輝
「字的向量,應該根據它在句子裡的上下文來決定。」
在 ELMo 之前 — Word2Vec / GloVe 的限制
在 ELMo 之前,大家用的是 Word2Vec 或 GloVe — 每個字對應一個固定向量。問題是:
I deposit money in the bank
→ "bank" 是金融機構
I sit by the river bank
→ "bank" 是河岸
這兩個 "bank" 在 Word2Vec 裡是完全一樣的向量,但意思完全不同。
ELMo 的核心想法:字的向量應該根據它在句子裡的上下文動態產生。
ELMo 的三層架構
數學表達
對每個 token t_k,L 層 biLM 會產生 2L+1 = 5 個 representation(L=2):
不同層學到不同東西
| 層 | 傾向學到什麼 | 適合的下游任務 |
|---|---|---|
| Char CNN(第 0 層) | 字形、拼寫、字根 | 對未知詞的處理 |
| biLSTM 第 1 層 | 語法(POS、依存關係) | 詞性標註(POS tagging) |
| biLSTM 第 2 層 | 語意(word sense) | 語意消歧(WSD) |
Word Embedding 向量算術遊樂場
Word2Vec 最知名的特性:向量之間可以做算術!選不同的詞組合看結果。這展示了 embedding 空間有「語意結構」。
Word2Vec / GloVe(靜態 embedding):
ELMo(動態 embedding):
OOV(Out-Of-Vocabulary)問題:Word2Vec 遇到沒見過的字(如 "ChatGPT")就完全崩潰。但 ELMo 用字元 CNN 從字母 C-h-a-t-G-P-T 中抽特徵,即使沒見過也能猜出大致含義(如 "-GPT" 可能暗示技術相關)。
ELMo 還是有 LSTM 的限制:sequential 計算,沒辦法平行化。在 GPU 時代這是非常奢侈的浪費 — 於是 Transformer 來了。
Transformer — Attention Is All You Need
「把 sequential 計算徹底丟掉。只用 attention 就好。」
動機 — 為什麼要丟掉 RNN?
LSTM 解決了長序列記憶問題,但它還是要一個時間步一個時間步算。在 GPU 時代很不友善。Transformer 的野心:完全不要 RNN,只用 attention 機制就好。
核心 — Self-Attention
讀「The animal didn't cross the street because it was too tired」。讀到 "it" 的時候,你的腦袋會自動回去看:「it 指的是什麼?」然後發現它指 "animal"。
Self-attention 就是讓每個字都去看句子裡所有其他字,然後決定要從哪些字「拿資訊」過來組合成自己的新表示。
Q, K, V — 圖書館比喻
Query (Q)
當前 token 想要找的資訊類型 — 像是你在 Google 打的搜尋字。
Key (K)
每個 token 對外的「索引標籤」 — 像是書的標題、tag。
Value (V)
實際的資訊內容 — 像是書的真正內容。
Attention 公式拆解
假設 d_k = 2(極簡化)。每個 token 有自己的 Q, K, V 向量:
| Token | Q | K | V |
|---|---|---|---|
| I | [1, 0] | [0, 1] | [1, 0] |
| love | [0, 1] | [1, 1] | [0, 1] |
| cats | [1, 1] | [1, 0] | [1, 1] |
「I」的新表示 [0.60, 0.80] 融合了三個 token 的資訊,其中「love」和「cats」的貢獻更大。這就是 attention 的本質:每個 token 的新表示 = 所有 token 的加權組合。
Multi-Head Attention — 多重視角
只用一個 attention 不夠 — 一個字可能同時要關注「語法上的主詞」、「意義上的相關物」、「位置上的鄰居」。所以 Transformer 用多個 attention 平行跑,每個叫一個 "head"。
head_i = Attention(Q·W_i^Q, K·W_i^K, V·W_i^V)
研究發現:訓練後,不同 head 會自發分工 — 有些學語法依賴、有些學位置鄰近、有些學共指。沒人預先指派誰做什麼,這種「emergent specialization」是 Transformer 強大的關鍵之一。下一頁的 demo 你可以親自玩玩看。
Positional Encoding
Self-attention 是 permutation-invariant!「The cat sat on the mat」跟「mat the on sat cat The」對 self-attention 是一樣的。
解法:把位置資訊「加」到 input embedding 上。原始 Transformer 用 sin/cos:
PE(pos, 2i+1) = cos(pos / 10000^{2i/d_model})
後來的 BERT、GPT 改成 learnable positional embedding,再後來有 RoPE、ALiBi 等更新方法。
Positional Encoding 互動熱力圖
觀察 sin/cos 如何隨「位置」和「維度」變化。低維度像秒針(變化快),高維度像時針(變化慢)。每個位置的 pattern 都是唯一的「位置指紋」。
X 軸 = 維度(偶數 sin / 奇數 cos),Y 軸 = 位置。紅色 = 正值,藍色 = 負值。注意左邊變化快(高頻),右邊變化慢(低頻)。
Softmax Temperature 探索器
Temperature τ 控制 softmax 的「尖銳程度」。τ→0 時分布極度集中(只看最高分),τ→∞ 時均勻分布(全部平等)。Transformer 用 √d_k 當 τ。
為什麼 Transformer 這麼成功?
① 完全平行化
所有位置可以同時計算 — GPU 吃滿。不像 RNN 要等前一步算完。
② 長距離依賴一步到位
任何兩個位置都直接連接(attention),不用像 RNN 一樣靠記憶慢慢傳。
③ Scalable
層數加深、寬度加寬都能持續變強 — 這是 GPT-3、GPT-4 的基礎。
原始 Transformer 論文("Attention Is All You Need")是做機器翻譯的,所以它有 encoder 跟 decoder 兩部分:
Encoder(6 層)
每層:Self-Attention → Add & Norm → FFN → Add & Norm。
看完整個輸入序列,產生「理解後的表示」。
Decoder(6 層)
每層:Masked Self-Attention → Cross-Attention → FFN。
Cross-Attention 的 K, V 來自 encoder 輸出,Q 來自 decoder 自己。
Cross-Attention 是什麼?Decoder 在生成每個字時,用自己當前的狀態當 Query,去 attend encoder 的輸出(Key, Value)。這讓 decoder 可以「回頭看」源語言的哪些部分跟要生成的字最相關。
後來 BERT 只用 encoder,GPT 只用 decoder(且去掉 cross-attention),就分出兩條路線了。
Self-Attention 互動可視化
「Q、K、V 算出來的注意力權重長什麼樣?玩玩看就知道。」
Self-Attention 注意力熱力圖
輸入句子(用空格分字),點擊任一個 token 看它對其他 token 的注意力分布。 切換不同 head 風格看不同 pattern。所有顏色都用 CSS transition,順暢過渡。
注意力熱力圖(i 列 → j 行)
每一列總和為 1。深色 = 注意力高。點任一格切換焦點。
所選 token 的注意力分布
三個常見的注意力 pattern
對角線 pattern
每個 token 主要注意自己附近的 token。常見於早期層。
共指 pattern
「it」「he」「she」會強烈 attend 到它們指的名詞。
句法依賴 pattern
動詞 attend 主詞、形容詞 attend 修飾的名詞。
上面的 demo 用規則化的模擬,真正訓練出來的 Transformer 注意力 pattern 更複雜。但你可以從這個 demo 體會核心概念:Q-K 內積 = token 之間的相關性。
BERT vs GPT — 兩條技術路線
「Transformer 原本是 encoder-decoder 一起用的,但有時候只需要其中一邊。」
對照表
| BERT | GPT | |
|---|---|---|
| 架構 | Encoder-only | Decoder-only |
| 注意力 | 雙向 | 單向(causal mask) |
| 訓練目標 | MLM + NSP | 預測下一個 token |
| 強項 | 理解(分類、QA、NER) | 生成(對話、寫作、寫程式) |
| 代表後繼 | RoBERTa, DeBERTa, ELECTRA | GPT-2/3/4, LLaMA, Claude |
為什麼最後 GPT 路線贏了?
雖然 BERT 在理解任務上很強,但有一個關鍵差異:GPT 的訓練目標跟「人類使用語言」更接近。我們講話、寫文章都是一個字一個字往下產生的,所以 GPT 的能力可以很自然地用在所有任務上。
所有 NLP 任務都可以重新表達成「文字接龍」:
• 翻譯 → "Translate to French: I love you →" 接龍出 "Je t'aime"
• 分類 → "Sentiment of '太爛了': →" 接龍出 "negative"
• 摘要 → "Summarize: <長文章> →" 接龍出摘要
• 問答 → "Q: 太陽從哪裡升起? A:" 接龍出答案
這就是為什麼現在大家都做 decoder-only 的大模型。
任務:判斷「這部電影太爛了」是正面還是負面。
BERT 做法
GPT 做法
GPT 路線的關鍵優勢:Prompt as Task Definition。你不用為每個新任務設計新的模型頭、收集標註資料、重新 fine-tune。只要改 prompt 就能做新任務。當模型夠大時(GPT-3 175B 以上),這種 zero-shot / few-shot 能力就會「湧現」。
Attention Mask 視覺化 — BERT vs GPT 看到什麼?
點擊切換 BERT(雙向)和 GPT(causal mask)模式,看每個 token 能「看到」哪些其他 token。綠色 = 可以 attend,紅色 = 被遮住。
多模態 — CLIP, BLIP, LLaVA
「多模態的核心其實很簡單:把圖、文、音、影片都壓到同一個向量空間,剩下的就是常見的 ML 任務了。」
三個經典模型
① CLIP — Contrastive Language-Image Pre-training (OpenAI 2021)
訓練方式叫 contrastive learning — 給 N 對 (圖, 文),組成 N×N 矩陣,對角線是 positive pair(推近),其他是 negative(推遠)。
假設一個 batch 有 4 對 (圖, 文):
| # | 圖片 | 文字描述 |
|---|---|---|
| 1 | 🐱 一隻貓 | "a photo of a cat" |
| 2 | 🐶 一隻狗 | "a dog playing fetch" |
| 3 | 🚗 一台車 | "a red car on the road" |
| 4 | 🌅 日落 | "sunset over the ocean" |
計算 4×4 的 cosine similarity 矩陣:
Loss 使用 InfoNCE(其實就是兩個方向的 cross-entropy):從圖找文、從文找圖。Batch 越大,negative pair 越多,學到的 embedding 品質越好 — CLIP 論文用 batch size = 32,768!
CLIP 訓練完可以做 zero-shot classification:把 "a photo of a cat"、"a photo of a dog" 編成文字向量,跟圖片向量算 cosine similarity,誰高分到哪類 — 完全不用為了分類任務再訓練!
Cosine Similarity 互動計算器
拖動 slider 改變兩個向量的方向,即時看 cosine similarity 如何變化。這就是 CLIP 判斷「圖文是否匹配」的核心計算。
② BLIP — Bootstrapping Language-Image Pre-training (Salesforce 2022)
CLIP 主要做理解/檢索,BLIP 想要連生成(caption)也一起做。BLIP 同時訓練三個任務:
| 任務 | 做什麼 |
|---|---|
| ITC(Image-Text Contrastive) | 跟 CLIP 一樣的對比學習 |
| ITM(Image-Text Matching) | 給一對圖文,二分類判斷是否匹配 |
| LM(Language Modeling) | 看圖片產生 caption(CLIP 沒有這個) |
BLIP-2 引入 Q-Former — 用 learnable query 從 vision encoder 抽視覺資訊,再餵給凍結的 LLM,省錢又有效。
③ LLaVA — Large Language and Vision Assistant (2023)
LLaVA 的訓練非常聰明 — 不是一次全部訓練,而是分兩個階段:
為什麼分兩階段?如果一開始就解凍 LLM,projection 還沒學好(輸出的向量是垃圾),LLM 會被帶壞。先讓 projection 學會「翻譯」,再讓 LLM 學會「理解翻譯後的視覺語言」。
LLaVA-1.5 的改進:把 linear projection 換成 2-layer MLP,讓翻譯能力更強。這個小改動帶來顯著效果提升。
三個模型對照
| CLIP | BLIP | LLaVA | |
|---|---|---|---|
| 主要能力 | 檢索、零樣本分類 | 檢索 + 生成 caption | 對話式視覺問答 |
| Vision Encoder | ViT | ViT | CLIP ViT(凍結) |
| 連接方式 | 共享 embedding | Q-Former (BLIP-2) | Projection layer |
| 哲學 | 對齊兩個空間 | 多任務聯合訓練 | 把視覺翻譯成 LLM 看得懂的「語言」 |
融合策略(作業會用到)
| 策略 | 說明 | 例子 |
|---|---|---|
| Early Fusion | 很早就把不同模態串起來 | 直接 concat 兩種向量丟同一個模型 |
| Late Fusion | 各自處理到最後才合併 | CLIP(兩個 encoder 各跑完才算 similarity) |
| Cross-Attention | 一邊的 Q 去 attend 另一邊的 K/V | Flamingo, BLIP-2 的 Q-Former |
| Unified Token | 所有模態變成 token 給同一個 Transformer | LLaVA, GPT-4V |
作業 2 — 設計你自己的多模態模型
「資料集規模不用大,重點是流程跑得通、設計有思考。」
作業要求
① 自己建資料集
不能用 COCO、Flickr 等現成資料集。
規模 30~100 對就夠:自己拍的照 + 描述、影片片段 + 字幕、音樂 + 歌詞、心情日記 + emoji…
② 設計自己的架構
兩個模態自選(圖+文、音+文、影片+字幕…)。選一個融合策略並說明為什麼。可以用 pretrained encoder(CLIP, BERT 都 OK)。
③ 簡短報告
PDF 或 Markdown 都可以。重點不在 accuracy,在思考過程。
報告必須回答的四個問題
為什麼選這兩個模態? 這個組合可以解什麼問題、有什麼有趣的應用?
兩個模態怎麼融合? Early / Late / Cross-attention / Unified Token — 你選哪個?為什麼?這個選擇有什麼 trade-off?
訓練上遇到什麼問題?怎麼解決的?(沒遇到問題反而可疑)
有 demo 結果就放上來(不管成功失敗)。失敗的 demo 配上分析,比成功但沒思考的 demo 分數還高。
起手式建議
| 步驟 | 建議 |
|---|---|
| ① 想題目 | 選一個你「真的覺得有趣」的應用 — 動力是最重要的 |
| ② 收資料 | 30~100 對就夠。寧可少而精,不要多而髒 |
| ③ 切 train/test | 20% 留 test,千萬別偷看 |
| ④ 用 pretrained 起步 | CLIP、BERT、ResNet — 不要從零訓練 |
| ⑤ 先用最簡單的融合 | Late fusion + cosine similarity 是最容易跑通的 baseline |
| ⑥ 出問題 → 分析 → 改進 | 這個 loop 走幾遍才是學習發生的地方 |
重要程度排序:
① 思考清晰度 > ② 流程完整性 > ③ 創意 > ④ 結果效能
做不出 SOTA 沒關係,不知道自己為什麼這樣做才是大問題。
交件方式
GitHub repo 包含:(1) 程式碼、(2) 資料集(或下載連結)、(3) 報告 PDF/Markdown、(4) README 寫怎麼跑。給未來會回來看自己 code 的你,留一份體面的 repo。
期待看到你們的設計 — 玩得開心。