Paper Reading #paper-reading#gpt-3#AI#LLM#python

論文共讀:《Language Models are Few-Shot Learners》(語言模型是少樣本學習者)

2026-02-11 · 4326 字 · 21 分鐘

更大的模型,更善於從上下文中誘發能力,附真實 Python 程式碼

2020 年 5 月 28 日,OpenAI 在 arXiv(一個學術論文預印本網站,論文不用等期刊審稿就能直接發布)上傳了一篇 75 頁的論文:《Language Models are Few-Shot Learners》(語言模型是少樣本學習者)。

作者有 31 人,全部來自 OpenAI。第一作者 Tom B. Brown,其餘包括 Jared Kaplan(縮放定律的核心研究者)、Alec Radford(GPT-1 和 GPT-2 的主要設計者)、Ilya Sutskever(OpenAI 聯合創始人兼首席科學家)、Dario Amodei(OpenAI 研究副總裁)等。

這份作者名單後來分化出了幾家最重要的 AI 公司:Dario Amodei 和 Jared Kaplan 離開 OpenAI 創立了 Anthropic,Ilya Sutskever 後來也聯合創立了 Safe Superintelligence Inc.(SSI)。

論文的核心主張很直接:把語言模型做大,大到 1750 億參數,它就能在不更新任何權重的情況下,僅靠幾個示例就完成各種任務:有時甚至逼近經過專門微調的模型。

這不是任務級微調,而是在固定參數下,透過上下文適配任務的能力:論文稱之為上下文學習(in-context learning)

0. 先認幾個詞

如果你對 GPT-3 這類模型的工作方式還沒有概念,先記住下面幾個詞就夠了:

  • 語言模型:給它一段前文,它的基本工作就是預測下一個詞。
  • 參數量:模型裡可學習的數字總數。你可以粗略把它理解成模型的「腦容量」。
  • prompt / 提示詞:你餵給模型看的任務說明、示例和輸入。
  • 上下文視窗:模型一次能看到多少文本的容量。例子太多,塞不進去,就沒辦法一起看。
  • few-shot / one-shot / zero-shot:分別指給多個例子、給一個例子、完全不給例子。
  • in-context learning / 上下文學習:不改模型參數,只靠 prompt 裡的說明和例子,就讓模型臨時學會怎麼做任務。

1. 要解決什麼問題

BERT 確立的「預訓練 + 微調」範式在 2020 年已經是主流做法。效果很好,但論文指出了三個根本問題。

第一,每個新任務仍然需要一個標註資料集。標註資料的獲取成本高,且很多實際任務根本沒有對應的標註集。

第二,微調後的模型在測試基準上的表現,不一定反映真實泛化能力。模型可能只是學到了訓練資料中的虛假相關性(spurious correlations):在基準集裡得分很高,但換個分布就崩了。

第三,人類不是這樣學習的。人類看一兩個例子,聽一句自然語言指令,就能完成新任務。而當時的 NLP 系統,每個新任務都需要成千上萬條標註資料來微調。

論文的出發點是:如果模型足夠大,它在預訓練階段累積的知識是否足以讓它直接「讀懂」任務描述和少量示例,然後給出答案?

2. 核心想法:不更新參數,只給提示

GPT-3 的評估方式和之前所有大模型都不一樣。它定義了三種設置,全部不涉及梯度更新:

少樣本(Few-Shot):給模型一段任務描述,加上 10 到 100 個示例(具體數量取決於上下文窗口能裝多少),然後讓它完成新的輸入。不更新權重,不做反向傳播。

單樣本(One-Shot):只給一個示例。這最接近人類學習新任務的方式:有人給你演示一次,你就上手。

零樣本(Zero-Shot):連示例都不給,只有一句自然語言指令。這是最難的設置,但也是最實用的:如果模型真的「理解」了任務本身,它不應該需要任何例子。

from dataclasses import dataclass
from typing import Union
@dataclass
class ZeroShot:
instruction: str
prompt: str
@dataclass
class OneShot:
instruction: str
example: tuple[str, str]
prompt: str
@dataclass
class FewShot:
instruction: str
examples: list[tuple[str, str]]
prompt: str
EvalSetting = Union[ZeroShot, OneShot, FewShot]
def build_prompt(setting: EvalSetting) -> str:
if isinstance(setting, ZeroShot):
return f"{setting.instruction}\n{setting.prompt}"
if isinstance(setting, OneShot):
example_input, example_output = setting.example
return f"{setting.instruction}\n{example_input} {example_output}\n{setting.prompt}"
lines = [setting.instruction]
lines.extend(f"{example_input} {example_output}" for example_input, example_output in setting.examples)
lines.append(setting.prompt)
return "\n".join(lines)

論文把這種能力叫做上下文學習:模型在預訓練時,從海量文本中隱式地學到了各種任務的模式;推理時,示例被拼接進上下文,模型在前向傳播的過程中「識別」出當前任務是什麼,然後完成它。論文用「元學習」來描述這個過程:預訓練是外循環,上下文學習是內循環。

這和微調的區別是根本性的。微調修改模型參數來適應任務,上下文學習不修改任何東西:同一個模型,同一組權重,只靠輸入文本的不同,就能切換任務。

3. 模型架構與規模

GPT-3 的架構本身沒有新發明。它和 GPT-2 一樣,就是 Transformer 的解碼器部分,一層層堆起來。改動只有一處:在 Transformer 層中交替使用稠密注意力和局部帶狀稀疏注意力(來自 Sparse Transformer)。

真正不同的是規模。論文訓練了 8 個不同大小的模型,參數量跨越三個數量級:

模型參數量層數隱藏維度注意力頭數
GPT-3 Small1.25 億1276812
GPT-3 Medium3.5 億24102416
GPT-3 Large7.6 億24153616
GPT-3 XL13 億24204824
GPT-3 2.7B27 億32256032
GPT-3 6.7B67 億32409632
GPT-3 13B130 億40514040
GPT-3 175B1750 億961228896

1750 億參數,96 層,96 個注意力頭,隱藏維度 12288。上下文窗口 2048 個詞元。這個規模在當時是前所未見的:比 GPT-2(15 億參數)大了 100 多倍。

from dataclasses import dataclass
@dataclass(frozen=True)
class GPT3Config:
n_params: int
n_layers: int
d_model: int
n_heads: int
d_head: int
d_ff: int
n_ctx: int
def gpt3_175b() -> GPT3Config:
return GPT3Config(
n_params=175_000_000_000,
n_layers=96,
d_model=12_288,
n_heads=96,
d_head=128,
d_ff=49_152,
n_ctx=2_048,
)

論文訓練這些模型的目的很明確:驗證縮放定律(scaling laws)。之前 Kaplan 等人的研究(就是這篇論文的共同作者之一)已經表明,語言模型的損失和參數量之間存在平滑的冪律關係。GPT-3 把這個假設推到了 1750 億參數的規模,看看上下文學習能力是否也遵循同樣的規律。

答案是肯定的:模型越大,少樣本學習的提升越陡。零樣本性能隨模型規模穩步上升,少樣本性能的上升速度更快。這意味著大模型不只是「更準」,它們在利用上下文資訊的效率上也更高。

4. 訓練資料

GPT-3 在大約 3000 億個詞元上訓練,資料來自五個來源:

資料集詞元數訓練佔比
Common Crawl(過濾後)4100 億約 60%
WebText2190 億約 22%
Books1120 億約 8%
Books2550 億約 8%
英文 Wikipedia30 億約 3%

注意一個關鍵細節:資料集的取樣比例和它們的大小不成正比。品質更高的資料集(WebText2、Books、Wikipedia)被過取樣了:WebText2 在訓練中被看了 2.9 遍,Wikipedia 被看了 3.4 遍,而 Common Crawl 連一遍都沒看完(0.44 遍)。論文有意用少量過擬合的代價,換取更高品質的訓練訊號。

Common Crawl 的原始資料有 45TB,經過三步處理:(1)基於與高品質參考語料的相似度做過濾;(2)文件級模糊去重;(3)混入已知的高品質資料集來增加多樣性。過濾後剩下 570GB,約 4100 億詞元。

所有模型在 V100 GPU 上訓練,使用微軟提供的高頻寬叢集。

5. 實驗結果

論文在二十多個資料集上做了評估,覆蓋 9 大類任務。以下是幾個關鍵結果。

語言建模:在 Penn Tree Bank 上,GPT-3 少樣本困惑度(perplexity,衡量模型對文本的「意外程度」,越低越好)達到 20.50,刷新了當時的紀錄。在 LAMBADA(需要根據長距離上下文預測最後一個詞)上,零樣本準確率 76.2%,少樣本 86.4%,大幅超過之前的最好結果。

翻譯:GPT-3 從未被專門訓練過翻譯,但在法語→英語翻譯上,少樣本 BLEU 分數達到 32.6,超過了無監督神經機器翻譯的最好結果。不過英語→法語方向(25.2 BLEU)和微調模型的差距仍然很大。一個有趣的發現:GPT-3 翻譯成英語的能力明顯強於從英語翻譯出去,這和訓練資料以英語為主有直接關係。

閉卷問答:在 TriviaQA 上,少樣本準確率(exact match)71.2%,超過了同一閉卷設置下經過微調的模型。模型不看任何參考文件,純靠參數裡儲存的知識回答問題。

SuperGLUE:在這個綜合基準上,GPT-3 的少樣本表現已經接近一些經過微調的強基線,但仍落後於當時最強的專門微調系統。

合成任務:論文還設計了一些專門測試上下文學習能力的新任務。比如給模型幾個「造新詞」的例子(定義一個不存在的詞,然後用它造句),GPT-3 能正確地學會並使用這個新詞。再比如三位數加法,少樣本準確率接近 100%(兩位數加法也幾乎完美),但四五位數時急劇下降。

from typing import Callable, Protocol
class AutoregressiveModel(Protocol):
def forward(self, tokens: list[int]) -> list[list[float]]:
...
def in_context_learning(
model: AutoregressiveModel,
examples: list[tuple[str, str]],
query: str,
tokenize: Callable[[str], list[int]],
decode: Callable[[list[int]], str],
sample_from: Callable[[list[float]], int],
eos_token: int,
) -> str:
prompt_lines = [f"{example_input} {example_output}" for example_input, example_output in examples]
prompt_lines.append(query)
prompt = "\n".join(prompt_lines)
context = tokenize(prompt)
output_tokens: list[int] = []
while True:
logits = model.forward(context)
next_token = sample_from(logits[-1])
if next_token == eos_token:
break
output_tokens.append(next_token)
context.append(next_token)
return decode(output_tokens)

6. 資料污染問題

論文在第四章花了大量篇幅討論一個棘手的問題:訓練資料和測試資料的重疊。

GPT-3 的訓練資料包含大量網路文本,而很多測試基準的內容也在網路上公開存在。這意味著模型可能在訓練時就「看過」了測試題。論文團隊嘗試在訓練前移除這些重疊,但由於一個處理流程中的 bug,部分重疊沒有被完全清除。而重新訓練一遍的成本太高,不現實。

他們的做法是:為每個基準建構一個「乾淨子集」(移除所有和訓練資料有 13-gram 重疊的樣本),然後對比模型在完整集和乾淨子集上的表現。結論是:大多數基準上,污染對結果的影響很小。但 PIQA 和 Winograd 兩個資料集存在可疑的表現下降,論文對這些結果加了星號標註。

這種誠實在當時相當罕見。多數論文對資料污染問題避而不談。GPT-3 不僅主動調查,還開發了系統化的檢測工具。這本身就是對後續研究的一個貢獻。

7. 局限性

論文在第五章對自身局限性的討論相當坦率。

文本連貫性:GPT-3 在文件級別仍然會出現語義重複、自相矛盾、甚至生成無意義句子的情況。生成品質雖然比 GPT-2 好了很多,但長文本的連貫性仍然不夠。

常識物理:GPT-3 對「把起司放進冰箱,它會融化嗎?」這類常識物理問題表現不佳。它能處理語言層面的推理,但對物理世界的理解仍然是膚淺的。

單向性的代價:作為自回歸模型,GPT-3 只能從左往右看。論文承認,在需要雙向上下文的任務上(比如判斷兩個句子裡同一個詞的含義是否相同),GPT-3 的少樣本表現不如經過微調的雙向模型。這說明在 GPT-3 的自回歸設定下,這類任務並不是它的強項;單向建模目標本身會帶來結構性偏好。

取樣效率:GPT-3 在預訓練階段看了約 3000 億個詞元,遠超人類一生接觸的文本量。論文明確指出,即使少樣本學習在推理時很高效,預訓練的資料需求仍然巨大。

推理成本:1750 億參數的模型,推理成本高且不方便部署。論文提到蒸餾(distillation,用大模型的輸出來訓練小模型)是一個可能的方向,但在千億參數量級上還沒有嘗試過。

8. 社會影響

論文用了整整一個章節(第六章)討論社會影響,涵蓋三個方面。

濫用風險:GPT-3 生成的新聞文章,人類評估者的識別準確率接近隨機猜測(約 52%)。模型越強,生成的虛假文本越難辨別。論文團隊表示已經在監控論壇和聊天群,追蹤惡意使用的趨勢。

偏見:論文用大量實驗測試了 GPT-3 在性別、種族和宗教方面的偏見。例如,在職業-性別關聯測試中,GPT-3 更傾向於將「nurse」和女性關聯、將「banker」和男性關聯。在宗教-情感關聯中,「Islam」更多地與暴力相關詞共現。論文承認這些偏見來自訓練資料,但沒有給出解決方案。

能源消耗:訓練 GPT-3 需要大量算力,論文引用了估算資料但沒有公布具體的能耗數字。不過論文指出,一旦訓練完成,模型可以被多次使用到不同任務上,比為每個任務單獨訓練模型更節能。

9. 我的思考

讀完這篇論文,有幾個感受。

第一,GPT-3 展示了一件事:規模能把上下文學習推到可用閾值。1750 億參數的模型不只是「更大的 GPT-2」,它在上下文學習上的表現比小模型強出了一個量級。模型在沒有任何參數更新的情況下,僅靠上下文中的幾個示例就能完成新任務。這種能力不是顯式手工設計出來的,而是在規模擴大過程中逐步增強,到 GPT-3 這個量級才第一次變得足夠清晰、足夠實用。BERT 證明了預訓練的價值,GPT-3 證明了規模的價值。

第二,論文的寫作方式值得注意。31 個作者,75 頁篇幅,用了大量實驗來回答一個簡單的問題:更大的模型是否更善於利用少量示例?他們沒有迴避局限性:文本連貫性、常識推理、資料污染、偏見:全部正面討論。這種嚴謹程度,在後來的大模型論文中反而越來越少見了。

第三,這篇論文的作者列表就是一部 AI 行業分裂史。Dario Amodei 和 Jared Kaplan 後來創立了 Anthropic(Claude 的開發商),Ilya Sutskever 後來離開 OpenAI 創立了 SSI。這些人在 2020 年還在同一個團隊裡合作寫論文,兩年後就走向了不同的方向。論文裡關於社會影響和安全風險的討論,也許正是後來分歧的伏筆。

第四,從技術演進的角度看,GPT-3 是從「預訓練 + 微調」到「預訓練 + 提示」的轉折點。BERT 的思路是:先學通用知識,再在每個任務上微調參數。GPT-3 說:如果模型夠大,微調這一步可以省掉:直接用自然語言告訴模型你要做什麼。這個思路後來演化成了 ChatGPT、Claude 等產品的核心互動範式:使用者用自然語言提問,模型直接回答。

從 Seq2Seq 的編碼-解碼,到 Bahdanau 注意力的「該看哪裡」,到 Transformer 的「所有位置同時看」,到 BERT 的「先學再調」,再到 GPT-3 的「大到不用調」:每一步都在減少人工干預,增加模型自主完成任務的能力。

GPT-3 不是終點。但它第一次讓人們認真思考一個問題:如果繼續把模型做大,還會湧現出什麼?

這個問題的答案,就是後來發生的一切。


論文共讀系列

全文完 · 謝謝閱讀

評論