基于ChatGPT用AI實(shí)現(xiàn)自然對(duì)話
1.概述
ChatGPT是當(dāng)前自然語(yǔ)言處理領(lǐng)域的重要進(jìn)展之一,通過預(yù)訓(xùn)練和微調(diào)的方式,ChatGPT可以生成高質(zhì)量的文本,可應(yīng)用于多種場(chǎng)景,如智能客服、聊天機(jī)器人、語(yǔ)音助手等。本文將詳細(xì)介紹ChatGPT的原理、實(shí)戰(zhàn)演練和流程圖,幫助讀者更好地理解ChatGPT技術(shù)的應(yīng)用和優(yōu)勢(shì)。
2.內(nèi)容
在當(dāng)今快速發(fā)展的人工智能領(lǐng)域,自然語(yǔ)言處理(Natural Language Processing, NLP)技術(shù)是研究的重要方向之一。NLP技術(shù)的目標(biāo)是幫助計(jì)算機(jī)更好地理解和處理人類語(yǔ)言,從而實(shí)現(xiàn)人機(jī)交互、自然語(yǔ)言搜索、文本摘要、語(yǔ)音識(shí)別等應(yīng)用場(chǎng)景。
ChatGPT是當(dāng)前自然語(yǔ)言處理領(lǐng)域的重要進(jìn)展之一,可以生成高質(zhì)量的文本,可應(yīng)用于多種場(chǎng)景,如智能客服、聊天機(jī)器人、語(yǔ)音助手等。本文將詳細(xì)介紹ChatGPT的原理、實(shí)戰(zhàn)演練和流程圖,幫助讀者更好地理解ChatGPT技術(shù)的應(yīng)用和優(yōu)勢(shì)。
2.1 原理分析
ChatGPT是由OpenAI推出的一種基于Transformer的預(yù)訓(xùn)練語(yǔ)言模型。在自然語(yǔ)言處理中,預(yù)訓(xùn)練語(yǔ)言模型通常是指使用無(wú)標(biāo)簽文本數(shù)據(jù)訓(xùn)練的模型,目的是為了提高下游任務(wù)(如文本分類、命名實(shí)體識(shí)別、情感分析)的性能。ChatGPT是預(yù)訓(xùn)練語(yǔ)言模型的一種,它采用了單向的Transformer模型,通過大規(guī)模的文本數(shù)據(jù)預(yù)訓(xùn)練模型,再在具體任務(wù)上進(jìn)行微調(diào),從而實(shí)現(xiàn)高質(zhì)量的文本生成和自然對(duì)話。
下面我們來詳細(xì)介紹一下ChatGPT的原理。
2.1.1 Transformer模型
ChatGPT模型采用了單向的Transformer模型,Transformer模型是一種基于注意力機(jī)制的編碼-解碼框架,由Google在2017年提出。它是目前自然語(yǔ)言處理中應(yīng)用最廣泛的模型之一,已經(jīng)被證明在多種任務(wù)上取得了比較好的性能。
Transformer模型的核心是多頭注意力機(jī)制,它允許模型在不同位置上對(duì)輸入的信息進(jìn)行不同的關(guān)注,從而提高模型的表達(dá)能力。同時(shí),Transformer模型采用了殘差連接和Layer Normalization等技術(shù),使得模型訓(xùn)練更加穩(wěn)定,減少了梯度消失和梯度爆炸等問題。
在Transformer模型中,輸入的序列首先經(jīng)過Embedding層,將每個(gè)詞映射為一個(gè)向量表示。然后輸入到多層Transformer Encoder中,每一層包括多頭注意力機(jī)制和前向傳播網(wǎng)絡(luò)。在多頭注意力機(jī)制中,模型會(huì)計(jì)算出每個(gè)位置與其他位置的關(guān)聯(lián)程度,從而得到一個(gè)權(quán)重向量,將這個(gè)權(quán)重向量應(yīng)用到輸入上,就得到了每個(gè)位置的加權(quán)表示。接下來,模型會(huì)將每個(gè)位置的加權(quán)表示與原始輸入進(jìn)行殘差連接和Layer Normalization,從而得到更好的表達(dá)。
在ChatGPT模型中,Encoder和Decoder是相同的,因?yàn)樗菃蜗虻哪P?,只能使用歷史信息生成當(dāng)前的文本。每次生成一個(gè)新的詞時(shí),模型會(huì)將歷史文本作為輸入,通過Decoder生成下一個(gè)詞。
2.1.2 預(yù)訓(xùn)練
ChatGPT模型的預(yù)訓(xùn)練使用的是大規(guī)模的無(wú)標(biāo)簽文本數(shù)據(jù),例如維基百科、網(wǎng)頁(yè)文本等,這些數(shù)據(jù)可以包含數(shù)十億甚至數(shù)百億的單詞。預(yù)訓(xùn)練的目的是讓模型學(xué)習(xí)到文本的語(yǔ)言規(guī)律和語(yǔ)義信息,從而提高模型的泛化能力。預(yù)訓(xùn)練使用的是語(yǔ)言建模任務(wù),即在給定部分文本的情況下,模型預(yù)測(cè)下一個(gè)詞是什么。預(yù)測(cè)的損失函數(shù)采用交叉熵?fù)p失函數(shù),通過反向傳播和隨機(jī)梯度下降算法更新模型參數(shù)。
2.1.3 微調(diào)
ChatGPT模型的微調(diào)是指在特定的任務(wù)上,針對(duì)不同的數(shù)據(jù)集,對(duì)預(yù)訓(xùn)練模型進(jìn)行微調(diào)。微調(diào)的目的是將模型應(yīng)用到具體的場(chǎng)景中,例如聊天機(jī)器人、智能客服等。微調(diào)過程中,我們會(huì)為模型添加一些特定的輸出層,根據(jù)具體的任務(wù)來調(diào)整模型的參數(shù)。
2.2 ChatGPT
ChatGPT是一款通用的自然語(yǔ)言生成模型,即GPT翻譯成中文就是生成型預(yù)訓(xùn)練變換模型。這個(gè)模型被互聯(lián)網(wǎng)巨大的語(yǔ)料庫(kù)訓(xùn)練之后,它就可以根據(jù)你輸入的文字內(nèi)容,來生成對(duì)應(yīng)的文字回答。也就是常見的聊天問答模式,比如:
圖片
語(yǔ)言模型的工作方式,是對(duì)語(yǔ)言文本進(jìn)行概率建模。
圖片
用來預(yù)測(cè)下一段輸出內(nèi)容的概率,形式上非常類似于我們小時(shí)候玩的文字接龍游戲。比如輸入的內(nèi)容是你好,模型就會(huì)在可能的結(jié)果中,選出概率最高的那一個(gè),用來生成下一部分的內(nèi)容
圖片
從體驗(yàn)的反饋來看,ChatGPT對(duì)比其他的聊天機(jī)器人,主要在這樣幾個(gè)方面上進(jìn)步明顯:
- 首先,它對(duì)用戶實(shí)際意圖的理解有了明顯的提升,以前用過類似的聊天機(jī)器人,或者自動(dòng)客服的朋友,應(yīng)該會(huì)經(jīng)常遇到機(jī)器人兜圈子,甚至答非所問的情況,而ChatGPT在這方面有了顯著的提升,大家在實(shí)際體驗(yàn)了之后感覺都非常的明顯;
- 其次,是非常強(qiáng)的上下文銜接能力,你不僅能夠問他一個(gè)問題,而且還可以通過不斷追加提問的方式,讓它不斷的改進(jìn)回答內(nèi)容,最終達(dá)到用戶想要的理想效果。
- 然后,是對(duì)知識(shí)和邏輯的理解能力,當(dāng)你遇到某個(gè)問題,它不僅只是給一個(gè)完整的回答,同時(shí),你對(duì)這個(gè)問題的各種細(xì)節(jié)追問,它都能回答出來。
ChatGPT目前暫時(shí)還沒有看到與之相關(guān)的論文,但是,官網(wǎng)有一篇Instruct GPT和ChatGPT是非常接近的。在官網(wǎng)上也指出了ChatGPT是InstructGPT的兄弟模型,它經(jīng)過訓(xùn)練可以按照指示中的說明進(jìn)行操作并提供詳細(xì)的響應(yīng)。
圖片
這里我們可以看到2個(gè)模型的訓(xùn)練過程非常的相似,文章地址:
ChatGPT訓(xùn)練流程如下所示:
圖片
InstructGPT訓(xùn)練流程如下所示:
圖片
在OpenAI關(guān)于InstructiGPT中的論文中,有可以找到這些直觀優(yōu)勢(shì)的量化分析。
圖片
InstructGPT對(duì)比上一代GPT3:
- 首先在71%的情況下,InstructGPT生成的回答要比GPT3模型的回答要更加符合訓(xùn)練人員的喜好。這里提到GPT3是OpenAI的上一代自然語(yǔ)言生成模型。
- 其次,InstructGPT在回答問題的真實(shí)程度上,也會(huì)更加可靠,當(dāng)兩個(gè)模型同時(shí)被問到他們完全不知道的內(nèi)容時(shí),InstructGPT只有21%的情況會(huì)編造結(jié)果,而GPT3就高了,多達(dá)到了41%。這里,我們可以發(fā)現(xiàn),即便是最厲害的模型它也有五分之一的概率會(huì)胡說八道;
- 除此之外,InstructGPT在產(chǎn)生有毒回答的概率上也減小了25%。
所以,匯總下來,InstructGPT比上一代模型能夠提供更加真實(shí)可靠的回答,并且回答的內(nèi)容也會(huì)遠(yuǎn)比上一代更加符合用戶的意愿。
3.如何做到這些提升的呢?
我們要看清楚ChatGPT,為什么可以做到如此出色的效果。就需要我們把視角稍微拉遠(yuǎn)一點(diǎn),看一看這款模型,近幾年的發(fā)展歷史。
ChapGPT是OpenAI的另一款模型,它是InstructGPT的兄弟模型,也就是基于InstructGPT做了一些調(diào)整,而InstructGPT的上一代是GPT3,再往上一個(gè)版本是GPT2,再往上是GPT,那再往前就是Google的那一篇關(guān)于transformer的著名論文(https://arxiv.org/pdf/1706.03762.pdf),這里需要提一下的是,同樣是基于transformer結(jié)構(gòu)的,還有Google自家的BERT架構(gòu),以及對(duì)應(yīng)的分支。
所以,我們能夠得到這樣一個(gè)分支圖。
圖片
這里,本人能力有限,沒法對(duì)每一篇論文分析總結(jié)。但是,想提到一些自己在學(xué)習(xí)的過程中感覺比較有趣的決定和突破。
首先,同樣是transformer架構(gòu)上分支出來的,BERT和GPT的一大不同,來自于他們transformer具體結(jié)構(gòu)的區(qū)別,BERT使用的是transformer的encoder組件,而encoder的組件在計(jì)算某個(gè)位置時(shí),會(huì)關(guān)注他左右兩側(cè)的信息,也就是文章的上下文。而GPT使用的是transformer decoder組件,decoder組件在計(jì)算某個(gè)位置時(shí),只關(guān)注它左側(cè)的信息,也就是文章的上文。
圖片
我們?nèi)绻靡粋€(gè)通俗的比喻就是,BERT在結(jié)構(gòu)上對(duì)上下文的理解會(huì)更強(qiáng),更適合嵌入式的表達(dá),也就是完型填空式的任務(wù)。而GPT在結(jié)構(gòu)上更適合只有上文,完全不知道下文的任務(wù),而聊天恰好就是這樣的場(chǎng)景。
另一個(gè)有趣的突破,來自模型量級(jí)上的提升。
圖片
從GPT到GPT2,再到GPT3,OpenAI大力出奇跡,將模型參數(shù)從1.17億,提升到15億,然后進(jìn)一步暴力提升到了1750億個(gè)。以至于GPT3比以前同類型的語(yǔ)言模型,參數(shù)量增加了10倍以上。
圖片
同時(shí),訓(xùn)練數(shù)據(jù)量也從GPT的5GB,增加到GPT2的40GB,再到GPT3的45TB,與此相關(guān)的是在方向上(https://arxiv.org/pdf/2005.14165.pdf)。
OpenAI沒有追求模型在特定類型任務(wù)上的表現(xiàn),而是不斷的增加模型的泛化能力。同時(shí),GPT3的訓(xùn)練費(fèi)用,也到達(dá)了驚人的1200萬(wàn)美元。
圖片
那下一個(gè)有趣的節(jié)點(diǎn),就達(dá)到了今天的主角ChatGPT的兄弟,InstructGPT。從GPT3到InstructGPT的一個(gè)有趣改進(jìn)。來自于引入了人類的反饋。用OpenAI論文的說法是,在InstructGPT之前,大部分大規(guī)模語(yǔ)言模型的目標(biāo),都是基于上一個(gè)輸入片段token,來推測(cè)下一個(gè)輸入片段。
圖片
然而這個(gè)目標(biāo)和用戶的意圖是不一致的,用戶的意圖是讓語(yǔ)言模型,能夠有用并且安全的遵循用戶的指令,那這里的指令instruction,也就是InstructGPT名字的來源,當(dāng)然,也就呼應(yīng)的今天ChatGPT的最大優(yōu)勢(shì),對(duì)用戶意圖的理解。為了達(dá)到這個(gè)目的,他們引入了人類老師,也就是標(biāo)記人員,通過標(biāo)記人員的人工標(biāo)記,來訓(xùn)練出一個(gè)反饋模型,那這個(gè)反饋模型,實(shí)際上就是一個(gè)模仿喜好,用來給GPT3的結(jié)果來打分的模型,然后這個(gè)反饋模型再去訓(xùn)練GPT3,之所以沒有讓標(biāo)記人員,直接訓(xùn)練GPT3,可能是因?yàn)閿?shù)據(jù)量太大的原因吧。
圖片
所以,這個(gè)反饋模型,就像是被抽象出來的人類意志??梢杂脕砑?lì)GPT3的訓(xùn)練,那整個(gè)訓(xùn)練方法,就被叫做基于人類反饋的強(qiáng)化學(xué)習(xí)。至此簡(jiǎn)易版的InstructGPT的前世今生就介紹完了。我們來回顧一下OpenAI一直在追求的幾個(gè)特點(diǎn):
- 首先,是只有上文的decoder結(jié)構(gòu),這種結(jié)構(gòu)下訓(xùn)練出來的模型,天然適合問答這種交互方式;
- 然后,是通用模型,OpenAI一直避免在早期架構(gòu)和訓(xùn)練階段,就針對(duì)某個(gè)特定的行業(yè)做調(diào)優(yōu),這也讓GPT3有著很強(qiáng)的通用能力
- 最后,是巨量數(shù)據(jù)和巨量參數(shù),從信息論的角度來看,這就像深層的語(yǔ)言模型,涵蓋的人類生活中,會(huì)涉及的幾乎所有的自然語(yǔ)言和編程語(yǔ)言,當(dāng)然,這也就極大的提高了個(gè)人或者小公司參與的門檻。
既然說到了原理,還有一個(gè)方面是前面沒有提及到的,就是連續(xù)對(duì)話的能力。所以,ChatGPT是如何做到能夠記住對(duì)話的上下文的呢?
這一能力,其實(shí)在GPT3時(shí)代就已經(jīng)具備了,具體做法是這樣的,語(yǔ)言模型生成回答的方式,其實(shí)是基于一個(gè)個(gè)的token,這里的token,可以粗略的理解為一個(gè)個(gè)單詞。所以ChatGPT給你生成一句話的回答,其實(shí)是從第一個(gè)詞開始,重復(fù)把你的問題以及當(dāng)前生成的所有內(nèi)容,再作為下一次的輸入,再生成下一個(gè)token,直到生成完整的回答。
4.實(shí)戰(zhàn)演練
為了更好地理解ChatGPT模型的實(shí)際應(yīng)用,我們可以嘗試使用Hugging Face提供的Transformers庫(kù)來構(gòu)建一個(gè)聊天機(jī)器人模型。
(1)準(zhǔn)備數(shù)據(jù)集
我們可以使用Cornell電影對(duì)話數(shù)據(jù)集來作為ChatGPT模型的訓(xùn)練數(shù)據(jù)集。Cornell電影對(duì)話數(shù)據(jù)集包含了超過220,579條對(duì)話記錄,每條記錄都有一個(gè)問題和一個(gè)回答。我們可以將問題和回答組合在一起,形成聊天機(jī)器人的訓(xùn)練樣本。
(2)數(shù)據(jù)預(yù)處理
在訓(xùn)練ChatGPT模型之前,我們需要對(duì)數(shù)據(jù)進(jìn)行預(yù)處理,將文本轉(zhuǎn)換為數(shù)字表示。我們可以使用tokenizer將文本轉(zhuǎn)換為tokens,并將tokens轉(zhuǎn)換為模型輸入的數(shù)字表示。在使用Hugging Face的Transformers庫(kù)中,我們可以使用AutoTokenizer自動(dòng)選擇適合的tokenizer,根據(jù)模型的類型和配置來進(jìn)行初始化。
以下是對(duì)電影對(duì)話數(shù)據(jù)集進(jìn)行預(yù)處理的代碼:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained('distilgpt2')
pad_token_id = tokenizer.pad_token_id
max_length = 512
def preprocess_data(filename):
with open(filename, 'r', encoding='iso-8859-1') as f:
lines = f.readlines()
conversations = []
conversation = []
for line in lines:
line = line.strip()
if line.startswith('M '):
conversation.append(line[2:])
elif line.startswith('E '):
conversation.append(line[2:])
if len(conversation) > 1:
conversations.append(conversation)
conversation = []
questions = []
answers = []
for conversation in conversations:
for i in range(len(conversation) - 1):
questions.append(conversation[i])
answers.append(conversation[i+1])
inputs = tokenizer(questions, answers, truncatinotallow=True, padding=True, max_length=max_length)
return inputs, pad_token_id
inputs, pad_token_id = preprocess_data('movie_conversations.txt')
在上述代碼中,我們使用了AutoTokenizer來初始化tokenizer,并指定了最大的序列長(zhǎng)度為512。同時(shí),我們也定義了padding token的id,并使用preprocess_data函數(shù)來對(duì)Cornell電影對(duì)話數(shù)據(jù)集進(jìn)行預(yù)處理。在預(yù)處理過程中,我們將每個(gè)問題和回答組合在一起,使用tokenizer將文本轉(zhuǎn)換為tokens,并將tokens轉(zhuǎn)換為數(shù)字表示。我們還設(shè)置了padding和truncation等參數(shù),以使得所有輸入序列長(zhǎng)度相同。
(3)訓(xùn)練模型
在對(duì)數(shù)據(jù)集進(jìn)行預(yù)處理后,我們可以使用Hugging Face的Transformers庫(kù)中提供的GPT2LMHeadModel類來構(gòu)建ChatGPT模型。GPT2LMHeadModel是一個(gè)帶有語(yǔ)言模型頭的GPT-2模型,用于生成與前面輸入的文本相關(guān)的下一個(gè)詞。
以下是使用GPT2LMHeadModel訓(xùn)練ChatGPT模型的代碼:
from transformers import GPT2LMHeadModel, Trainer, TrainingArguments
model = GPT2LMHeadModel.from_pretrained('distilgpt2')
model.resize_token_embeddings(len(tokenizer))
training_args = TrainingArguments(
output_dir='./results',
num_train_epochs=3,
per_device_train_batch_size=4,
save_total_limit=2,
save_steps=1000,
logging_steps=500,
evaluation_strategy='steps',
eval_steps=1000,
load_best_model_at_end=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=inputs['input_ids'],
data_collator=lambda data: {'input_ids': torch.stack(data)},
)
trainer.train()
在上述代碼中,我們首先使用GPT2LMHeadModel來初始化ChatGPT模型,并調(diào)整Embedding層的大小以適應(yīng)我們的tokenizer。接下來,我們定義了TrainingArguments來配置訓(xùn)練參數(shù)。其中包括了訓(xùn)練的輪數(shù)、每批次的大小、模型保存路徑等信息。最后,我們使用Trainer類來訓(xùn)練模型。在這里,我們將輸入數(shù)據(jù)傳遞給train_dataset參數(shù),并使用一個(gè)data_collator函數(shù)將輸入數(shù)據(jù)打包成一個(gè)批次。
(4)生成文本
在訓(xùn)練完成后,我們可以使用ChatGPT模型來生成文本。在Hugging Face的Transformers庫(kù)中,我們可以使用pipeline來實(shí)現(xiàn)文本生成。
以下是使用ChatGPT模型生成文本的代碼:
from transformers import pipeline
generator = pipeline('text-generation', model=model, tokenizer=tokenizer)
def generate_text(prompt):
outputs = generator(prompt, max_length=1024, do_sample=True, temperature=0.7)
generated_text = outputs[0]['generated_text']
return generated_text
generated_text = generate_text('Hello, how are you?')
print(generated_text)
在上述代碼中,我們首先使用pipeline函數(shù)來初始化一個(gè)文本生成器,其中指定了ChatGPT模型和tokenizer。接下來,我們定義了generate_text函數(shù)來使用生成器生成文本。在這里,我們傳入一個(gè)prompt字符串作為生成的起始點(diǎn),并使用max_length參數(shù)來指定生成文本的最大長(zhǎng)度,使用do_sample和temperature參數(shù)來控制文本的隨機(jī)性和流暢度。
5.總結(jié)
ChatGPT是一個(gè)強(qiáng)大的自然語(yǔ)言生成模型,可以用于生成對(duì)話、推薦、文本摘要等多種任務(wù)。在本文中,我們介紹了ChatGPT的原理、實(shí)現(xiàn)流程和應(yīng)用場(chǎng)景,并提供了Cornell電影對(duì)話數(shù)據(jù)集的預(yù)處理和ChatGPT模型的訓(xùn)練代碼。通過使用Hugging Face的Transformers庫(kù),我們可以輕松地構(gòu)建和訓(xùn)練ChatGPT模型,并使用pipeline來生成文本。希望本文能夠幫助讀者更好地理解ChatGPT,以及如何應(yīng)用自然語(yǔ)言生成技術(shù)來解決實(shí)際問題。
因?yàn)椋珿PT3 API里面單次交互最多支持4000多個(gè)token(https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them)
圖片
因此,我猜測(cè)ChatGPT的上下文大概也是4000個(gè)token左右。