- ChatGPT原理與應用開發
- 郝少春 黃玉琳 易華揮
- 10905字
- 2024-04-22 11:47:53
1.3 ChatGPT基礎
1.3.1 最強表示架構Transformer設計與演變
接下來出場的是Transformer,它是一個基于注意力機制的編碼器-解碼器(encoder-decoder)架構,剛開始主要應用在NLP領域,后來橫跨到語音和圖像領域,并最終統一幾乎所有模態(文本、圖像、語音)的架構。Transformer來自谷歌公司在2017年發表的一篇論文“Attention Is All You Need”,其最重要的核心就是提出來的自注意力(self-attention)機制。簡單來說,就是在語言模型構建過程中,把注意力放在那些重要的Token上。
Transformer簡單來說,就是先把輸入映射到編碼器(encoder),這里大家可以把編碼器想象成前面介紹的RNN,解碼器(decoder)也可以想象成RNN。這樣,左邊負責編碼,右邊則負責解碼。這里不同的是,左邊因為我們是知道數據的,所以在建模時可以同時利用當前Token的歷史(后面的)Token和未來(前面的)Token;但在解碼時,因為是一個個Token輸出來的,所以只能根據歷史Token以及編碼器的Token表示進行建模,而不能利用未來Token。
Transformer的這種架構從更普遍的角度來看,其實是Seq2Seq(sequence to sequence)架構,簡單來說就是序列到序列的架構:輸入是一個文本序列,輸出是另一個文本序列。翻譯就是一個很好的例子,如圖1-6所示。

圖1-6 Seq2Seq架構示意圖(摘自GitHub的“google/seq2seq”項目)
剛剛已經講了,編碼器和解碼器可以采用RNN,編碼器這一側的每個Token都可以輸出一個向量表示,而這些所有Token的輸出向量都可以在處理后作為整句話的表示。說到這里,整句話又怎么表示呢?前面曾提到,對于RNN這種結構,可以把最后一個Token的輸出作為整個句子的表示。當然,很符合直覺的,你也可以取每個詞向量的平均值。除了平均值,也可以求和、取最大值等,我們就不更深入討論了。現在重點來了,看解碼的過程,仔細看,其實解碼器在生成每一個Token時都用到了編碼器中每一個Token的信息,以及已經生成的那些Token的信息。前面這種關注編碼器中每個Token的信息的機制就是注意力(attention)機制。直觀的解釋,就是當生成單詞“power”時,“力量”兩個字會被賦予更多權重(注意力),其他情況也類似。
好了,現在讓我們帶著之前的記憶,看一下Transformer的整體結構,如圖1-7所示。

圖1-7 Transformer的整體結構(摘自論文“Attention Is All You Need”)
在圖1-7中,左邊是編碼器,一共有N個;右邊是解碼器,也有N個。為簡單起見,我們可以假設N=1,如此一來,圖1-7的左邊就是一個編碼器,右邊則是一個解碼器。也可以把它們想象成一個RNN,這樣有助于從宏觀上把握。現在,我們回到現實,Transformer用到的東西其實和RNN并沒有關系,這一點通過圖1-7也可以很明顯地看出來。Transformer主要用了兩個模塊:多頭注意力(multi-head attention)和前饋(feedforward)網絡。
對于多頭注意力,我們不妨回顧一下Seq2Seq架構的注意力機制,它是解碼器中的Token和編碼器中每一個Token的重要性權重。多頭注意力中用到了自注意力(self-attention),自注意力和剛剛講的注意力非常類似,只不過自注意力是自己的每一個Token之間的重要性權重。簡單來說,就是“一句話到底哪里重要”。自注意力機制可以說是Transformer的精髓,無論是ChatGPT還是其他非文本的大語言模型,都用到了它,它可以說是真正地“一統江湖”。多頭(multi-head)簡單來說,就是把剛剛的這種自己注意自己重復多次,每個頭注意到的信息不一樣,這樣就可以捕獲到更多信息。比如我們前面提到過的一句話——“人工智能讓世界變得更美好”,有的頭“人工智能”注意到“世界”,有的頭“人工智能”注意到“美好”……這樣看起來更加符合直覺。
前饋網絡主要引入非線性變換,幫助模型學習更復雜的語言特征和模式。另外,有個地方要特別注意,解碼器的淡黃色模塊內有一個遮蓋多頭注意力(masked multi-head attention),它和多頭注意力的區別就是遮蓋(mask)了未來Token。以本小節開頭提到的翻譯為例,當給定“Knowledge”生成下一個Token時,模型當然不知道下一個Token就是“is”。還記得前面講過的學習(訓練)過程嗎?下一個Token是“is”,這是訓練數據里的,模型輸出什么要看Token最大概率是不是在“is”這個Token上,如果不在,參數就得更新。
實際上,大多數NLP任務并不是Seq2Seq架構的,最常見的任務主要包括如下幾種:句子分類、Token分類(也叫序列標注)、相似匹配和文本生成,前三種應用得最為廣泛。這時候,編碼器和解碼器就可以拆開用了。左邊的編碼器在把句子表示成一個向量時,可以利用上下文信息,也就是說,可以把它看作雙向的;右邊的解碼器不能看到未來Token,一般只利用上文信息,是單向的。雖然它們都可以用來完成剛才提到的幾種任務,但從效果上來說,編碼器更適合非生成類任務,解碼器則更適合生成類任務。在NLP領域,一般也會把它們分別叫作自然語言理解(natural language understanding,NLU)任務和自然語言生成(natural language generation,NLG)任務。上面提到的這些任務,后面都會進一步介紹,這里大致了解一下即可。
我們首先介紹NLU任務。句子分類是指給定一個句子,輸出一個類別。因為句子可以表示為一個向量,所以經過張量運算后,自然可以映射到每個類別的概率分布。這和前面提到過的語言模型的做法沒有本質上的區別,只不過語言模型的類別是整個詞表大小,而分類的類別則要看具體的任務,有二分類、多分類、多標簽分類等。Token分類是指給定一個句子,給其中的每個Token輸出一個類別。這和語言模型就更像了,只不過把下一個Token換成了對應的類別,比如命名實體抽取就是把句子中的實體(人名、地名、作品等你所關注的詞,一般是名詞)提取出來。如果以地名(location,LOC)舉例的話,對應的類別是這樣的:B-LOC(begin of LOC)表示實體開始、I-LOC(inside of LOC)表示實體中間。舉個例子:“中國的首都是北京”。注意此時的Token是字,每個Token對應的類別為“B-LOC、I-LOC、O、O、O、O、B-LOC、I-LOC”,O表示Other。對于分類任務,類別一般也叫作標簽。相似匹配一般指給定兩個句子,輸出它們是否相似,其實可以將其看作特殊的分類任務。
接下來介紹NLG任務。除文本續寫外,其他常見的NLG任務還有文本摘要、機器翻譯、文本改寫、文本糾錯等。這里Seq2Seq架構就比較常見了,體現了一種先理解再輸出的思路。而純生成類任務,比如寫詩、寫歌詞、寫小說,則幾乎是純解碼器架構。此類任務稍微麻煩的是如何做自動評測,文本摘要、機器翻譯、文本改寫、文本糾錯等任務一般都會提供參考答案(reference),可以評估模型輸出和參考答案之間的重疊程度或相似程度,但純生成類任務就有點麻煩,這個好不好有時候其實很難衡量。不過,針對有具體目標的任務(如任務型聊天機器人的回復生成),還可以設計一些諸如“是否完成任務”“是否達到目標”的評測方法。但對于沒有具體目標的任務(比如閑聊),評測起來就見仁見智了,很多時候還得靠人工進行評測。
Transformer基于Seq2Seq架構,可以同時處理NLU和NLG任務,而且這種自注意力機制的特征提取能力(表示能力)很強。其結果就是NLP取得了階段性的突破,深度學習開始進入微調模型時代,大概的做法就是,拿著一個開源的預訓練模型,在自己的數據上微調一下,讓它能夠完成特定的任務。這個開源的預訓練模型往往就是一個語言模型,在大量語料中,使用我們前面所講的語言模型的訓練方法訓練而來。偏NLU領域的第一個成果是谷歌公司的BERT,相信不少人即便不是這個行業的也大概聽過。BERT就是使用了Transformer的編碼器(沒有使用解碼器),有12個Block(圖1-7左側的淡黃色模塊,每一個Block也可以叫作一層)和1億多個參數。BERT不預測下一個Token,而是隨機地把15%的Token蓋住(其中80%用[MASK]
替換,10%保持不變,10%隨機替換為其他Token),然后利用其他沒蓋住的Token來預測蓋住位置的Token。這其實和根據上文信息預測下一個Token是類似的,所不同的是它可以利用下文信息。偏NLG領域的第一個成果是OpenAI的GPT,GPT就是使用了Transformer的解碼器(沒有使用編碼器),參數和BERT差不多。BERT和GPT都發布于2018年,然后分別走上了不同的道路。
1.3.2 生成語言模型GPT進化與逆襲
GPT,就是ChatGPT中的那個GPT,中文叫作生成式預訓練Transformer。生成式的意思就是類似于語言模型那樣,一個Token一個Token地生成文本,也就是上面提到的解碼器的原理。預訓練剛剛也提過了,就是在大量語料中訓練語言模型。GPT模型從GPT-1到GPT-4,一共經歷了5個版本,中間的ChatGPT是3.5版。GPT-1、GPT-2和GPT-3都是有論文發表的,接下來分別介紹它們的基本思想。ChatGPT沒有論文發表,不過它的姐妹版本InstructGPT有論文發表,我們放在1.3.3節介紹。GPT-4也沒有論文發表,只有技術報告,不過里面并沒有技術細節。因此,我們對GPT-4不做介紹,讀者可以將其看作能力更強的ChatGPT升級版。
GPT-1和BERT一樣,用的是下游任務微調范式,也就是在不同下游任務數據上微調預訓練模型,如圖1-8所示。

圖1-8 GPT-1基本結構和下游任務微調范式(摘自GPT-1論文“Improving Language Understanding by Generative Pre-Training”)
關于圖1-8左邊的GPT-1基本結構,我們在前面已經介紹過了,用的是Transformer的解碼器,不過這里因為沒有編碼器,所以不需要有和編碼器交互的多頭注意力模塊。現在重點看看圖1-8的右邊,這是GPT-1在各種下游任務上的處理流程。簡單來說,就是針對不同的任務構造不同的輸入序列,然后丟給GPT-1獲取Token或句子的Embedding表示,再通過Linear+Softmax輸出結果。Linear是一種最基礎的網絡結構,也就是線性映射,這里用于維度轉換,轉為輸出需要的大小。Softmax主要用來把輸出映射到概率分布(概率和為1)。這種拼接輸入的方法在當時非常流行,緊跟其后的BERT也使用類似的方式,并引領了一個時代,直至ChatGPT的出現讓我們進入大語言模型時代(不過,針對很多傳統NLP任務BERT依然具備優勢)。統一的處理方法能夠減小不同任務對模型的適配難度。因此不管什么任務,都想方設法將其變成一個序列就行,比如在圖1-8中,相似匹配就是把兩句話直接拼接起來,預測它們是否相似(輸出標簽為1或0)。
GPT-1的這篇論文還有幾個點在當時看起來可能沒什么感覺,現在回看卻有點意思。第一,預訓練模型中的每一層(圖1-8中的淡黃色模塊)都包含用于解決目標任務的有用功能,多層(意味著模型更深)有更多能力;第二,隨著參數的增加,零樣本獲得更好的性能。簡單總結就是,模型大了不僅能學到更多知識,有助于解決下游任務,還表現出了零樣本能力。這里的零樣本(zero-shot)是指直接給模型輸入任務,讓它輸出任務結果。與此類似的還有少樣本(few-shot)和單樣本(one-shot),即給模型提供一些(或一個)示例,然后給出任務,讓它輸出任務結果。
有了上面的結論,你是不是想看看更多層(更多參數)的表現如何?于是半年后,GPT-2來了,參數量從GPT-1的1.1億增加到了15億,增長了十幾倍。更有意思的是,GPT-1的博客文章“Improving language understanding with unsupervised learning”中有一個“未來工作列表”,排在第一位的就是擴大規模,還有兩個分別是提升微調,以及更好地理解為什么生成式預訓練能提升NLU能力。
GPT-1發布于2018年6月,GPT-2發布于2019年2月,GPT-2是GPT-1的升級版,主要在兩個方面進行進一步研究:首先是擴大規模,然后是零樣本。如果說GPT-1是觀察到了“規模大、能力強的零樣本”這個現象,那么GPT-2就是進一步研究這個現象。其結果自然是,模型越來越大,參數越來越多,能力越來越強。GPT-2進一步驗證了GPT-1的想法,下一步要做的就是繼續擴大規模。
不過且慢,在此之前,我們不妨看一下GPT-2中的Token生成策略,也就是生成下一個Token的方法。前面介紹過比較優秀的集束搜索,不過它有兩個比較明顯的問題:第一是生成的內容容易重復,第二是高質量的文本和高概率并不一定相關(有時甚至完全沒有關系)。簡單來看,這兩個問題其實可以歸結為一個問題:生成的內容依然確定性太大。人們更希望有“不一樣”的內容,而不是完全可預測的內容,比如張愛玲說過,“孤獨的人有他們自己的泥沼”,這種獨一無二的文字用高概率的詞大概率是得不到的。
現在,我們介紹一種基于采樣的方法,簡單來說,就是根據當前上下文得到的概率分布采樣下一個Token。這里可以用一個溫度(temperature)參數調整輸出的概率分布,參數值越大,分布看起來就越平滑,也就是說,高概率和低概率的差距變小了(對輸出不那么確定);當然,這個參數值越小的話,高概率和低概率的差距就會更明顯(對輸出比較確定);如果這個參數值趨近于0,那就和貪心搜索一樣了。請看下面的代碼示例。
import numpy as np
np.random.seed(42)
logits = np.random.random((2, 4))
logits /= temperature
scores = np.exp(logits)
probs = scores / np.sum(scores, axis=1, keepdims=True)
我們讓溫度參數分別取0.1和0.9,結果如下。
# temperature=0.1
array([[0.003, 0.873, 0.098, 0.026],
[0.001, 0.001, 0. , 0.998]])
# temperature=0.9
array([[0.176, 0.335, 0.262, 0.226],
[0.196, 0.196, 0.176, 0.432]])
以第一行為例,當溫度為0.1時,概率最大值為0.873;當溫度為0.9時,概率最大值依然在同樣位置(這是必然的),但值變為0.335。而且,你也可以很明顯地看出來,當溫度為0.9時,4個數字看起來更加接近。
還有一個重復懲罰參數(repetition_penalty),它可以在一定程度上避免生成重復的Token。它和溫度參數類似,只不過是將溫度放到了“已生成的Token”上。也就是說,如果有Token之前已經生成過了,我們就會在生成下一個Token時對那些已生成的Token的分數進行平滑,讓它們的概率不那么大。所以,這個參數值越大,越有可能生成和之前不重復的Token。
除了這些技巧,2018年的一篇論文“Hierarchical Neural Story Generation”另外介紹了一種新的采樣方案,它很簡單也很有效果,它就是GPT-2里使用到的Top-K采樣。簡單來說,就是在選擇下一個Token時,從Top-K(根據概率從大到小的前K個)個Token里面選。這種采樣方案不錯,不過還有個小問題,就是Top-K采樣其實是一種硬截斷,根本不管第K個概率是高還是低。在極端情況下,如果某個詞的概率是0.99(剩下的所有詞加起來才0.01),K稍微大一點就必然會囊括進來一些概率很低的詞。這會導致生成的內容不連貫。
于是,2019年的一篇論文“The Curious Case of Neural Text Degeneration”提出了另一種采樣方案——Top-P采樣,GPT-2里也有用到這種采樣方案。這種采樣方案是從累積概率超過P的詞里進行選擇。這樣,對于概率分布比較均勻的情況,可選的詞就會多一些(可能幾十個詞的概率和才會超過P);對于概率分布不均勻的情況,可選的詞就會少一些(可能兩三個詞的概率和就超過了P)。
Top-P采樣看起來更優雅一些,兩者也可以結合使用。不過在大部分情況下,當我們需要調參數的時候,調一個參數就好,包括前面的溫度參數。如果要調多個參數,請確保理解每個參數的作用。最后需要說明的是,任何一種采樣方案都不能100%保證每一次生成的效果都很好,也沒辦法完全避免生成重復的句子,也沒有任何一種采樣方案在任何場景下都適用。讀者在使用時需要根據實際情況多嘗試,選出效果最好的配置。不過,建議讀者從官方給的默認參數開始嘗試。
GPT-3發布于2020年7月,這在當時也是個大新聞,因為它的參數已經達到其他任何模型在當時都望塵莫及的量級——1750億,是GPT-2的100多倍,沒有開源。GPT-3既然有零樣本能力,那能不能不微調呢?碰到一個任務就微調,這多麻煩。對于人來說,只要幾個例子(少樣本)和一些簡單的說明,就可以處理任務了。怎么辦?GPT-2不是進一步確認了零樣本能力嗎?繼續加大參數量,于是就有了GPT-3。也就是說,各種任務來吧,不調參數,頂多就要幾個例子(預計下一步連例子也不要了),GPT-3就能幫你完成它們。其實現在回頭看,這篇論文是具有里程碑意義的,因為它從根本上觸動了原有的范式,而且是革命性的觸動。關于這一點,感興趣的讀者可以進一步閱讀筆者的一篇文章《GPT-3 和它的 In-Context Learning》。現在回憶,1750億的參數量在當時看太大了,而且也太貴了(幾百萬美元),一般的單位和個人根本負擔不起。關于這一點,不光小部分人沒意識到,可能是除了OpenAI團隊之外的整個世界都沒意識到。
請看圖1-9,橫坐標是樣本數量,縱坐標是精準度。圖1-9提供了如下信息。
● x-shot(x表示zero、one、few)在不同參數規模下差別巨大,大語言模型有超能力。
● 在大語言模型下,單樣本效果明顯大幅提升,增加提示詞會進一步大幅提升效果。
● 少樣本的邊際收益在遞減。大概在8樣本以下時,提示詞作用明顯,但從單樣本到8樣本,提示詞的效果提升幅度也在遞減。當超過10樣本時,提示詞基本就沒有作用了。

圖1-9 x-shot在不同參數規模下的表現(摘自GPT-3論文“Language Models are Few-Shot Learners”)
總而言之,大語言模型具有In-Context(上下文)學習能力,這種能力使得它不需要針對不同任務再進行適應性訓練(微調),大語言模型用的就是它自己本身的理解力。這本來應該很讓人震驚(甚至有一點驚恐),不過大家可能都先被它的價格和規模震驚到了。接下來,我們再直觀地感受一下利用這種In-Context學習能力完成任務的方式,如圖1-10所示。

圖1-10 使用In-Context學習能力和微調完成任務(摘自GPT-3論文“Language Models are Few-Shot Learners”)
圖1-10右邊的微調方式需要先根據訓練樣本更新模型參數,之后再進行預測。圖1-10左邊的三種方式都利用了大語言模型(large language model,LLM)的In-Context學習能力,不需要更新模型,而且看起來也都不復雜,只需要按照格式把輸入構建好,然后傳給模型進行預測就可以了。這也是本書寫作的初衷之一——人工智能已經平民化,只要有手(可能以后不用手也行),通過使用LLM就可以做出人工智能應用了。不過這里有一點需要說明,為了簡便,圖1-10中的樣本都比較簡單,但實際中的樣本一般是完整的句子。
最后值得一提的是GPT-3論文中的展望,在GPT-3論文的“局限”小節中,作者提出了GPT-3目前的一些問題,其中有兩點需要特別指出,因為它們是下一代InstructGPT(也是ChatGPT的姐妹版)以及更高級版本的方向。
● 自監督訓練(也就是語言模型一般的訓練方法)范式已到極限,新的訓練方法迫在眉睫。未來的方向包括:從人類那里學習目標函數、強化學習微調或多模態。
● 不確定少樣本是在推理時學習到新的任務,還是識別出來了在訓練時學到的任務。最終,甚至不清楚人類從零開始學習與從之前的樣本中學習分別學到了什么。準確理解少樣本的工作原理是未來的一個方向。
上面的第一點在1.3.3節就會提到,這里主要說說第二點。當我們給出一些示例(少樣本)時,我們還無法精準確定是在推理時“學習”到新任務的處理方法(在這種情況下,沒有示例就沒有能力;這里的“學習”要打引號,因為它不調整參數),還是在訓練時就已經具備了這個能力,示例只是讓它“回想”起之前學的東西。這里有點繞,拿人來舉例,可能不太恰當,但能大致說明問題。假設當你讀到一首詩時,自己也詩興大發寫了一句詩。你說這句詩是因為你讀到這首詩時“領悟”到的,還是你本來就有這個積累(記憶),現在只是因為讀這首詩而被激發出來?這可能涉及大腦、思維、意識等領域知識,而人類至今也沒有弄清楚它們的原理,所以我們現在還不知道答案。
1.3.3 利器強化學習RLHF流程與思想
RLHF(reinforcement learning from human feedback,從人類反饋中強化學習)聽起來有點平淡無奇。確實,RLHF的思想非常樸素、簡單,但它有著不可忽視的效果。剛剛我們已經提到了,GPT-3論文指出未來要找到新的訓練方法,其中就包括從人類那里學習目標函數、強化學習微調、多模態等。時至今日,從InstructGPT到ChatGPT,再到GPT-4,人類正一步一步地實現這些新的訓練方法。這里有一點需要提醒,這些方向并不是一開始就清晰地擺在那里的,中間還有非常多的探索和階段性成果(既有OpenAI自己的研究,也有其他從業人員的研究)。千萬不要看到結果覺得平淡無奇,這中間的艱難探索永遠值得尊敬。另外,有時候即便知道了方法,要做出來,還要做出效果來,也是非常有難度的。而且本書只能介紹少部分內容,雖然整體結構比較完整,但總體還是比較簡單。總的來說,要做出來很有難度,不過我們如果只是用的話,如前所述,有手就行。
好了,言歸正傳,RLHF被人熟知應該主要源自OpenAI的InstructGPT論文“Training language models to follow instructions with human feedback”,更大范圍的熟知就是ChatGPT的發布。因為后者沒有論文發表,也沒有開源,所以我們也只能“拿InstructGPT的管窺一窺ChatGPT的豹”。當然,如果按照ChatGPT官方頁面上的說法,ChatGPT是InstructGPT的姐妹版,那么這個“管”可能還比較粗。如果用簡單的語言來描述InstructGPT,其實就是用強化學習的算法微調一個根據人類反饋來加以改進的語言模型,重要的是還調出了效果——規模為130億的InstructGPT堪比規模為1750億的GPT-3。
現在我們來看看具體是如何做的,RLHF在其中又起了什么作用,以及如何起作用。InstructGPT的整個流程分為三個步驟,如圖1-11所示。

圖1-11 InstructGPT流程圖(摘自InstructGPT論文“Training language models to follow instructions with human feedback”)
● 步驟一:SFT(supervised fine-tuning,有監督微調)。顧名思義,SFT是在有監督(有標注)數據上微調訓練得到的。這里的有監督數據其實就是輸入提示詞,輸出相應的回復,只不過這里的回復是人工編寫的。這個工作要求比一般標注要高,其實算是一種創作。
● 步驟二:RM(reward model,獎勵模型)。具體來說,將一個提示詞丟給前一步的SFT,輸出若干(4~9個)回復,由標注人員對這些回復進行排序。然后從4~9個回復中每次取兩個,因為是有序的,所以可以用來訓練RM,讓模型學習到好壞評價。這一步非常關鍵,它就是所謂的人類反饋(human feedback),用于引導下一步模型的更新方向。
● 步驟三:RL(reinforcement learning,強化學習),使用PPO進行訓練。PPO(proximal policy optimization,近端策略優化)是一種強化學習優化方法,它背后的主要思想是避免每次太大的更新,提高訓練的穩定性。具體過程如下:首先初始化一個語言模型,然后丟給它一個提示詞,生成一個回復,用上一步的RM給這個回復打分,將這個打分回傳給模型更新參數。這里的語言模型在強化學習視角下就是一個策略。這一步有個很重要的動作,就是在更新模型時考慮模型每一個Token的輸出和SFT輸出之間的差異性,要讓它們盡量相似。這是為了緩解強化學習可能的過度優化。
就這樣?對,就這樣,RLHF都表現在上面了,效果大家都知道了。雖然ChatGPT沒有相關論文發表,但我們基本相信它也是基于類似的思路實現的。當然,這里面細節非常多,即便知道了這個思路,也不一定能復現出來。這在深度學習時代很正常,里面的各種小設計、小細節實在太多了。當它們堆積到一定量時,造成的差別是很難一下子彌補的,如果別人不告訴你,那你就只能自己慢慢做實驗去逐步驗證了。
下面我們強行解釋一下RLHF是如何起作用的,以及為什么它現在能成為一個基本的范式。其實,對于將強化學習用在NLP領域一直以來都有研究,正好筆者也由于一些原因一直在關注文本生成,以及強化學習在文本生成方面的研究。這里可能有兩個難點:一是訓練的穩定性;二是獎勵函數的設計。前者有PPO與SFT的差異衡量,得到不小的改進;而對于后者,如果要從客觀角度考慮設計一個規則,就不那么容易了。筆者也曾設想過很多類似的方法,比如加入一些語法規則限制,甚至加入類似最省力法則這樣的規則。
最省力法則:是由齊夫在Human Behavior and the Principle of Least Effort: An Introduction to Human Ecology一書中提出的。簡單來說,就是語言具有惰性,它會朝著使用較少的詞語表達盡可能多的語義這個方向演化。
InstructGPT使用人類反饋直接作為“規則”,把這種“規則”給隱式化,當作黑盒。我們只管結果好壞,至于中間有什么規則,有多少種規則,怎么起作用,統統不關心。這是和深度學習類似的思路,相比而言,我們之前的想法可能有些過于想當然了,畢竟語言學本身也有不少爭議,認識并沒有得到統一,比如語言能力是不是人與生俱來的能力?InstructGPT的做法則更加簡單、直接,而且有效。
剩下要解決的就是怎么衡量“好壞”,畢竟最終是要有個結果的,既然要結果,就要有標準。讀者不妨思考一下,如果換作你,你會如何設計一些指標來衡量兩段輸出內容的好壞。這一步看似容易,其實特別難,因為指標的設計會影響到模型的學習方向,最終就會影響到效果。因為這個輸出的好壞衡量標準太多了,雖然看起來是對給出的幾個結果進行排序(上文的步驟二),但其實這個過程中間隱藏了大量人類的認知,模型訓練過程其實就是和步驟二這個衡量過程對齊的過程;所以,如果步驟二指標沒設計好,步驟三就會白費力氣。尤其是對于InstructGPT這樣要完成大量不同任務的設計,衡量就更加不容易。以一個文本摘要任務為例,我們可能最關注的是能否準確概括原文信息,而一個生成任務可能更關注流暢性和前后邏輯一致性。InstructGPT里面有10種任務,分別針對每種任務設計指標,不僅麻煩,而且效果還不一定好,因為這些指標并不一定都是一個方向。還有就是,萬一又有了一個新任務,難道要再去設計一套指標,全部重新訓練一遍模型嗎?
讓我們來看看InstructGPT是怎么設計衡量指標的,筆者覺得這是InstructGPT論文最寶貴的地方,也是最值得我們思考和實踐的地方。感興趣的讀者可以進一步閱讀筆者之前寫的一篇專門介紹ChatGPT標注的文章《ChatGPT 標注指南:任務、數據與規范》。首先,InstructGPT用了三大通用指標——有幫助、真實性和無害性,有點類似于阿西莫夫的機器人三定律。也就是說,不管是什么任務,都得朝著這三個方向靠攏。這個想法值得稱贊。現在我們看到這個結果了,自然感覺好像沒什么,但如果事先不知道要去設計出來,大部分人可能還是很容易陷入被任務影響的境地。其實,OpenAI團隊在“In-Context”學習能力上的堅持也是一樣的。當別人告訴你那個結果時,你可能覺得好像沒有什么,甚至很多研究機構、研究人員都有過這種想法。但在有效果之前,篤信一條罕有人走的路,且一直堅定不移地走下去,這是很不容易的。
有了剛剛的三大通用指標,接下來就是細化,使其具有可操作性。比如,對于通用指標“有幫助”,InstructGPT給了一些屬于“有幫助”行為的示例,如下所示。
● 用清晰的語言寫作。
● 回答他們想問的問題,即使問錯了,也要回答。
● 對國際性敏感(比如“football”不應該指美式足球,“總統”不一定指美國總統)。
● 如果指令(instruction)太讓人困惑,要求澄清并解釋指令為什么讓人困惑。
● 不給出過長或冗長的答案,或重復問題中的信息。
● 不在給定的內容之外假設無關的額外上下文,除非是關于世界的事實,或是任務的隱含部分。比如,如果要求“禮貌地回復這封電子郵件:{郵件內容}”,則輸出不應該假設“我這次不能來,但下周末有空”。但如果要求“給蘇格拉底寫一封電子郵件”,則可以放心地使用上面的假設。
筆者相信實際上這個列表可能很長,有很多例子會在實際標注過程中被依次添加進去,直到能覆蓋絕大多數情況為止,即對于大部分要標注的數據,根據提供的細則很容易就判斷出來是否“有幫助”。現在不妨停下來思考一下,如果一開始就奔著這些細則設計獎勵規則——只是想想就覺得不太現實。其他兩個通用指標也有一些示例,這里不贅述,感興趣的讀者可以閱讀上面提到的筆者之前寫的那篇文章,以及這篇文章最后所列的參考資料(因為有些文檔資料在這篇文章中并沒有提及)。
有了細則還沒完,接下來要解決的是指標之間的沖突權衡問題。因為這是一個比較任務(比較哪個輸出好),當涉及多個指標時,一定會出現A指標的一個結果好于另一個結果,但B指標可能相反的情況。指標越多,情況越復雜(好在只有三個指標)。對此,InstructGPT也給出了指導原則。
● 對于大部分任務,無害性和真實性比有幫助更加重要。
● 然而,如果一個輸出比另一個輸出更有幫助,或者該輸出只是稍微不那么真實或無害,又或者該任務似乎不屬于“高風險領域”(如貸款申請、醫療、法律咨詢等),則更有幫助的輸出得分更高。
● 當選擇同樣有幫助但以不同方式不真實或有害時,問自己哪個輸出更有可能對用戶(現實世界中受任務影響最大的人)造成傷害。這個輸出應該排名較低。如果在任務中不清楚這一點,則將這些輸出標記為并列。
對于邊界樣例的總體指導原則是,你更愿意從試圖幫助你完成此任務的客戶助理那里收到哪種輸出?這是一種設身處地的原則,把自己假想為任務提出者,然后問自己期望得到哪種輸出。
看看這些,你是不是也覺得這一步沒那么容易了,它們雖然看起來沒那么“技術性”,想要很好地完成卻需要優秀的設計能力、宏觀把控能力和細節感知能力。筆者更加相信這些細則是自底向上逐步構建起來的,而不是一開始就設想好的。它一定是在實踐中不斷產生疑惑,然后經過仔細分析權衡,逐步加入一條條規則,最終逐步構建起來的一整套系統方案。筆者覺得這套系統方案可能是比數據還要珍貴的資產,它所產生的壁壘是用時間不斷實踐堆積出來的。
InstructGPT或ChatGPT相比GPT-3有更強的零樣本能力,少樣本很多時候已經用不著,但提示詞還是需要的,由此催生了一個新的行當——提示工程。不過,據OpenAI的CEO在一次采訪中所言,再過幾年提示工程也不需要了(可能在生成圖片時還需要一些),用戶要做的就是直接通過自然語言和人工智能交互。我們無法判斷他說的會不會真的實現,但有一點可以肯定,人工智能的門檻必定會進一步降低,再過幾年,可能一名初中生都能通過已有的服務創造出不錯的人工智能應用。