語言模型
台南一中AI選修教材 / 顏永進
Table of Contents
1. 什麼是語言模型
你每天都在用語言模型,只是你不知道而已。
打開手機輸入「今天天氣」,鍵盤會自動建議「很好」、「不錯」、「真熱」——這背後就是語言模型在運作。Google 搜尋欄打幾個字就會跳出一整串建議,也是語言模型。甚至你在 LINE 上打字時出現的自動完成,統統都是。
語言模型的核心任務只有一件事:*根據前面的文字,預測下一個最可能出現的字*。
1.1. 用數學來說
假設有一句話「我 今天 吃了 一碗 _____」,語言模型的工作就是計算:
- P(拉麵 | 我今天吃了一碗) = 0.15
- P(牛肉麵 | 我今天吃了一碗) = 0.12
- P(飯 | 我今天吃了一碗) = 0.10
- P(水泥 | 我今天吃了一碗) = 0.0001
模型會選擇機率最高的字詞作為預測結果。那這些機率是怎麼來的?答案是:*從大量的文本中統計出來的*。如果模型讀過的文章中,「一碗」後面常常接「飯」、「麵」、「湯」,那這些字的機率就會比較高;「水泥」幾乎從來沒出現在「一碗」後面,所以機率趨近於零。
1.2. 用 Python 感受一下
我們來寫一個最簡單的「語言模型」——統計一段文字中,每個字後面最常接什麼字:
1: text = "我喜歡吃拉麵我喜歡吃牛肉麵我喜歡喝珍珠奶茶我不喜歡吃苦瓜" 2: 3: # 統計每個字後面接什麼字 4: next_char = {} 5: for i in range(len(text) - 1): 6: current = text[i] 7: follow = text[i + 1] 8: if current not in next_char: 9: next_char[current] = {} 10: if follow not in next_char[current]: 11: next_char[current][follow] = 0 12: next_char[current][follow] += 1 13: 14: # 看看「我」後面最常接什麼 15: print("「我」後面接的字及出現次數:") 16: for char, count in sorted(next_char["我"].items(), key=lambda x: -x[1]): 17: print(f" {char}: {count} 次") 18: 19: print() 20: print("「喜」後面接的字及出現次數:") 21: for char, count in sorted(next_char["喜"].items(), key=lambda x: -x[1]): 22: print(f" {char}: {count} 次")
預期輸出:
「我」後面接的字及出現次數: 喜: 3 次 不: 1 次 「喜」後面接的字及出現次數: 歡: 4 次
這個迷你模型雖然只統計了一句話,但已經掌握了語言模型的核心精神:*觀察規律,預測未來*。ChatGPT 做的事情本質上和這個一模一樣,只是它讀了幾乎整個網際網路的資料,模型有數千億個參數,預測的精準度自然不可同日而語。
2. 語言模型的進化史
語言模型的發展就像是「猜字遊戲」的進化——從死背到理解,從短視到遠望。
2.1. 第一代:N-gram 模型(數人頭法)
最原始的語言模型就是「數人頭」:統計大量文章中,某幾個字連在一起出現的次數。
例如 Bigram(2-gram)模型只看前一個字:
- 看到「我」→ 預測下一個字(統計「我」後面最常接什麼)
- 看到「今天」→ 預測下一個字(統計「天」後面最常接什麼)
1: import random 2: 3: # 用 bigram 來「生成」文字 4: def build_bigram(text): 5: """建立 bigram 模型:統計每個字後面各個字出現的次數""" 6: model = {} 7: for i in range(len(text) - 1): 8: c = text[i] 9: n = text[i + 1] 10: if c not in model: 11: model[c] = {} 12: model[c][n] = model[c].get(n, 0) + 1 13: return model 14: 15: def predict_next(model, current_char): 16: """根據 bigram 模型預測下一個字""" 17: if current_char not in model: 18: return "?" 19: candidates = model[current_char] 20: total = sum(candidates.values()) 21: # 顯示每個候選字的機率 22: for char, count in sorted(candidates.items(), key=lambda x: -x[1]): 23: prob = count / total * 100 24: print(f" {char}: {prob:.1f}%") 25: # 回傳機率最高的 26: return max(candidates, key=candidates.get) 27: 28: corpus = "我喜歡吃拉麵我喜歡吃牛肉麵我喜歡喝珍珠奶茶我不喜歡吃苦瓜我喜歡打籃球" 29: model = build_bigram(corpus) 30: 31: print("給定「吃」,模型預測下一個字的機率:") 32: best = predict_next(model, "吃") 33: print(f"→ 模型選擇:{best}") 34: print() 35: print("給定「歡」,模型預測下一個字的機率:") 36: best = predict_next(model, "歡") 37: print(f"→ 模型選擇:{best}")
N-gram 的致命弱點:*記憶力太差*。Bigram 只看前 1 個字,Trigram 看前 2 個字,頂多看到前 4-5 個字就是極限了。面對「小明上週去日本旅遊,他在那裡吃了很多 _____」這種需要理解整句話才能回答的問題,N-gram 完全無能為力——它只看到「多」這個字,根本不知道前面在講日本。
2.2. 第二代:神經網路語言模型
既然 N-gram 記憶力差,那就換一個記憶力好的模型吧!2003 年,Yoshua Bengio 提出了用神經網路來做語言模型的方法。
核心改進:
- *詞向量(Word Embedding)*:把每個字/詞轉換成一串數字(向量),讓意思相近的詞在數學空間中靠得更近。例如「貓」和「狗」的向量會很接近,但「貓」和「微積分」就離很遠
- *學會泛化*:因為相似的詞有相似的向量,模型即使沒看過「我喜歡吃拉麵」,但看過「我喜歡吃牛肉麵」,也能推測出「吃」後面可以接「拉麵」
不過,這個模型的記憶力還是有限——它一次只能看固定長度的前文。
2.3. 第三代:RNN 語言模型
RNN(循環神經網路)的出場解決了記憶力的問題。RNN 有一個「隱藏狀態」會不斷傳遞,理論上可以記住從句子開頭到目前為止的所有資訊。
如果 N-gram 是金魚腦(只記得前幾秒),RNN 就是一個認真做筆記的學生——雖然筆記越寫越潦草(記憶會隨距離衰減),但至少有在記。
後來 LSTM 和 GRU 改良了 RNN 的記憶機制,讓重要的資訊可以保留更久。想了解更多可以參考循環神經網路這篇教材。
2.4. 第四代:Transformer 與 GPT(注意力就是你需要的一切)
2017 年,Google 發表了一篇名為《Attention Is All You Need》的論文(光看標題就知道他們有多得意),提出了 Transformer 架構,徹底改變了遊戲規則。
Transformer 的核心武器是 *自注意力機制(Self-Attention)*:
想像你在讀一篇文章:「小明養了一隻貓,他每天都會餵牠吃飼料。」
當你讀到「牠」的時候,你的大腦會自動回去找「牠」指的是誰——是「貓」,不是「小明」。
Self-Attention 做的就是這件事:讓模型在處理每個字的時候,能夠「回頭看」整句話中所有的字,並判斷哪些字跟當前的字最相關。
Transformer 相比 RNN 的優勢:
| 比較項目 | RNN | Transformer |
|---|---|---|
| 處理方式 | 一個字一個字依序處理 | 整句話同時處理 |
| 訓練速度 | 慢(無法平行化) | 快(可以平行化) |
| 長距離記憶 | 容易遺忘 | 透過 Attention 直接連結 |
| 適合規模 | 中小型模型 | 超大型模型 |
OpenAI 用 Transformer 的解碼器(Decoder)打造了 GPT 系列:
| 模型 | 年份 | 參數量 | 里程碑 |
|---|---|---|---|
| GPT-1 | 2018 | 1.17 億 | 證明「預訓練 + 微調」路線可行 |
| GPT-2 | 2019 | 15 億 | 太強了,OpenAI 一度不敢公開 |
| GPT-3 | 2020 | 1750 億 | 少樣本學習,不用微調也能用 |
| GPT-4 | 2023 | 未公開 | 多模態,能看圖說故事 |
| GPT-4o | 2024 | 未公開 | 即時語音對話,像電影場景 |
想了解更多 GPT 的應用,可以參考 ChatGPT 這篇教材。
2.5. 小結:語言模型進化比較
| 世代 | 模型 | 記憶力 | 比喻 |
|---|---|---|---|
| 第一代 | N-gram | 只記前幾個字 | 金魚:「前面說了什麼?忘了。」 |
| 第二代 | 神經網路 LM | 固定長度 | 近視眼:看得到附近,看不到遠方 |
| 第三代 | RNN/LSTM | 理論上無限,但會衰減 | 認真但健忘的學生:筆記越寫越潦草 |
| 第四代 | Transformer | 整句話都能看到 | 全知視角:每個字都能直接關聯到任何其他字 |
3. 語言模型的應用
語言模型已經滲透到我們生活的各個角落,很多你每天都在用的功能,背後都有語言模型在運作:
- *手機鍵盤預測*:打字時自動建議下一個詞——最基礎的語言模型應用
- *語音助手*:Siri、Google Assistant 把你說的話轉成文字(語音辨識),再理解你的意思(語言理解)
- *機器翻譯*:Google 翻譯、DeepL 能把一種語言翻譯成另一種語言
- *文字生成*:ChatGPT、Claude 能寫文章、寫程式、回答問題
- *搜尋引擎*:理解你輸入的搜尋意圖,找出最相關的結果
- *垃圾信件過濾*:判斷一封信是正常信件還是垃圾信
- *自動摘要*:把長文章濃縮成重點
- *程式碼補完*:GitHub Copilot 能根據你寫的註解自動生成程式碼
4. 動手做:文字生成器
我們來用 bigram 模型做一個簡單的「文字生成器」,讓電腦自己寫句子:
1: import random 2: 3: def generate_text(model, start_char, length=20): 4: """用 bigram 模型生成文字""" 5: result = start_char 6: current = start_char 7: for _ in range(length): 8: if current not in model: 9: break 10: candidates = model[current] 11: # 根據機率隨機選擇下一個字(而不是每次都選最高的) 12: chars = list(candidates.keys()) 13: weights = list(candidates.values()) 14: current = random.choices(chars, weights=weights, k=1)[0] 15: result += current 16: return result 17: 18: # 用比較豐富的語料來訓練 19: corpus = ("我喜歡吃拉麵我喜歡吃牛肉麵我喜歡喝珍珠奶茶" 20: "我不喜歡吃苦瓜我喜歡打籃球我今天吃了一碗拉麵" 21: "今天天氣很好我想出去玩今天我要去打籃球" 22: "珍珠奶茶很好喝我每天都想喝珍珠奶茶") 23: 24: model = build_bigram(corpus) 25: 26: # 生成 5 句話 27: random.seed(42) 28: print("=== AI 小作家上線 ===") 29: for i in range(5): 30: sentence = generate_text(model, "我", length=15) 31: print(f"第{i+1}句:{sentence}")
你會發現,這個「AI 小作家」寫出來的句子有時候通順,有時候亂七八糟。這是因為 bigram 模型只看前一個字,完全沒有「理解」語意的能力。它純粹是在做機率性的文字接龍。
ChatGPT 之所以能寫出通順的長篇文章,是因為:
- 訓練資料量大到難以想像(幾乎整個網路)
- 模型架構(Transformer)能同時看到整段文字的上下文
- 參數量高達數千億,能記住極其複雜的語言規律
- 經過人類反饋強化學習(RLHF)的調校
5. 作業
5.1. 作業一:我的 Bigram 文學獎
你的 bigram 模型只用了幾十個字的語料就能「寫作」了。如果給它更多資料,它會寫得更好嗎?
- 任務說明
修改上面「文字生成器」的程式碼,把
corpus換成你自己準備的語料(至少 200 個字),然後觀察生成結果的變化。
步驟:
- 準備一段至少 200 字的中文語料(可以從維基百科、新聞、或你喜歡的小說中複製)
- 用這段語料訓練 bigram 模型
- 分別用 3 個不同的起始字生成句子,每個起始字生成 5 句
- 從 15 句中選出「最通順」和「最荒謬」的各一句
- 準備一段至少 200 字的中文語料(可以從維基百科、新聞、或你喜歡的小說中複製)
- 繳交內容
- 你使用的語料來源
- 程式碼(含修改後的 corpus)
- 生成的 15 句話
- 你選出的「最通順」和「最荒謬」各一句,並解釋為什麼
- 你使用的語料來源
- 預期輸出格式
=== 語料來源:維基百科「台灣」條目(前200字) === 起始字「台」: 第1句:台灣是一個⋯⋯ 第2句:台北市的⋯⋯ ... 最通順的句子:台灣是一個美麗的島嶼 → 因為語料中「台灣是」出現頻率高,後續接詞也合理 最荒謬的句子:台北市的氣候是一個美麗的 → 因為 bigram 只看前一個字,「的」後面接「氣」和接「美」的機率差不多
5.2. 作業二:Attention 偵探社
Transformer 的自注意力機制(Self-Attention)讓模型能判斷句子中哪些字跟哪些字最相關。現在請你當一回「人肉 Attention」。
- 任務說明
以下有三個句子,每個句子中有一個畫底線的詞。請你找出句子中與該詞 最相關 的其他詞(1-3個),並解釋為什麼。
句子 1:「小明養了一隻 貓 ,他每天都會餵牠吃飼料。」
句子 2:「台北 101 是台灣最高的 建築 ,它位於信義區。」
句子 3:「雖然今天下雨,但小華還是決定去 跑步 ,因為她正在準備馬拉松。」
- 繳交格式
句子 1:「貓」最相關的詞: - 「牠」(關聯度:高)→ 因為「牠」就是指「貓」 - 「餵」(關聯度:中)→ 因為餵的對象是貓 - 「小明」(關聯度:中)→ 因為小明是貓的主人 句子 2:⋯⋯ 句子 3:⋯⋯
- 延伸思考
如果用 bigram 模型來處理句子 1,它在讀到「牠」的時候能知道「牠」指的是「貓」嗎?為什麼?(提示:bigram 只看前一個字)
5.3. 作業三:語言模型時光機
語言模型從 N-gram 進化到 Transformer,花了將近 30 年。下面這張表格少了一些內容,請你補完它:
- 任務說明
| 世代 | 代表模型 | 優點 | 缺點 | 生活中的比喻 | |------+----------+------+------+--------------| | 1 | N-gram | ??? | ??? | ??? | | 2 | FFNN LM | ??? | ??? | ??? | | 3 | RNN/LSTM | ??? | ??? | ??? | | 4 | Transformer | ??? | ??? | ??? |
要求:
- 每個模型的優點和缺點至少寫一項(用自己的話,不要直接抄教材)
- 「生活中的比喻」要用一個你自己想的比喻來形容每個模型(教材中的不算,要自己想新的)
- 每個模型的優點和缺點至少寫一項(用自己的話,不要直接抄教材)
- 預期成果
一張完整的比較表,比喻要有創意。例如:
N-gram 就像是一個只會死背課文的學生, 你問他「台灣的首都是?」他背得出來, 但問他「為什麼台灣的首都是台北?」他就當機了。