1.概述
ChatGPT是當前自然語言處理領域的重要進展之一,透過預訓練和微調的方式,ChatGPT可以生成高質量的文字,可應用於多種場景,如智慧客服、聊天機器人、語音助手等。本文將詳細介紹ChatGPT的原理、實戰演練和流程圖,幫助讀者更好地理解ChatGPT技術的應用和優勢。
2.內容
在當今快速發展的人工智慧領域,自然語言處理(Natural Language Processing, NLP)技術是研究的重要方向之一。NLP技術的目標是幫助計算機更好地理解和處理人類語言,從而實現人機互動、自然語言搜尋、文字摘要、語音識別等應用場景。
ChatGPT是當前自然語言處理領域的重要進展之一,可以生成高質量的文字,可應用於多種場景,如智慧客服、聊天機器人、語音助手等。本文將詳細介紹ChatGPT的原理、實戰演練和流程圖,幫助讀者更好地理解ChatGPT技術的應用和優勢。
2.1 原理分析
ChatGPT是由OpenAI推出的一種基於Transformer的預訓練語言模型。在自然語言處理中,預訓練語言模型通常是指使用無標籤文字資料訓練的模型,目的是為了提高下游任務(如文字分類、命名實體識別、情感分析)的效能。ChatGPT是預訓練語言模型的一種,它採用了單向的Transformer模型,透過大規模的文字資料預訓練模型,再在具體任務上進行微調,從而實現高質量的文字生成和自然對話。
下面我們來詳細介紹一下ChatGPT的原理。
2.1.1 Transformer模型
ChatGPT模型採用了單向的Transformer模型,Transformer模型是一種基於注意力機制的編碼-解碼框架,由Google在2017年提出。它是目前自然語言處理中應用最廣泛的模型之一,已經被證明在多種任務上取得了比較好的效能。
Transformer模型的核心是多頭注意力機制,它允許模型在不同位置上對輸入的資訊進行不同的關注,從而提高模型的表達能力。同時,Transformer模型採用了殘差連線和Layer Normalization等技術,使得模型訓練更加穩定,減少了梯度消失和梯度爆炸等問題。
在Transformer模型中,輸入的序列首先經過Embedding層,將每個詞對映為一個向量表示。然後輸入到多層Transformer Encoder中,每一層包括多頭注意力機制和前向傳播網路。在多頭注意力機制中,模型會計算出每個位置與其他位置的關聯程度,從而得到一個權重向量,將這個權重向量應用到輸入上,就得到了每個位置的加權表示。接下來,模型會將每個位置的加權表示與原始輸入進行殘差連線和Layer Normalization,從而得到更好的表達。
在ChatGPT模型中,Encoder和Decoder是相同的,因為它是單向的模型,只能使用歷史資訊生成當前的文字。每次生成一個新的詞時,模型會將歷史文字作為輸入,透過Decoder生成下一個詞。
2.1.2 預訓練
ChatGPT模型的預訓練使用的是大規模的無標籤文字資料,例如維基百科、網頁文字等,這些資料可以包含數十億甚至數百億的單詞。預訓練的目的是讓模型學習到文字的語言規律和語義資訊,從而提高模型的泛化能力。預訓練使用的是語言建模任務,即在給定部分文字的情況下,模型預測下一個詞是什麼。預測的損失函式採用交叉熵損失函式,透過反向傳播和隨機梯度下降演算法更新模型引數。
2.1.3 微調
ChatGPT模型的微調是指在特定的任務上,針對不同的資料集,對預訓練模型進行微調。微調的目的是將模型應用到具體的場景中,例如聊天機器人、智慧客服等。微調過程中,我們會為模型新增一些特定的輸出層,根據具體的任務來調整模型的引數。
2.2 ChatGPT
ChatGPT是一款通用的自然語言生成模型,即GPT翻譯成中文就是生成型預訓練變換模型。這個模型被網際網路巨大的語料庫訓練之後,它就可以根據你輸入的文字內容,來生成對應的文字回答。也就是常見的聊天問答模式,比如:
語言模型的工作方式,是對語言文字進行機率建模。
用來預測下一段輸出內容的機率,形式上非常類似於我們小時候玩的文字接龍游戲。比如輸入的內容是你好,模型就會在可能的結果中,選出機率最高的那一個,用來生成下一部分的內容
從體驗的反饋來看,ChatGPT對比其他的聊天機器人,主要在這樣幾個方面上進步明顯:
- 首先,它對使用者實際意圖的理解有了明顯的提升,以前用過類似的聊天機器人,或者自動客服的朋友,應該會經常遇到機器人兜圈子,甚至答非所問的情況,而ChatGPT在這方面有了顯著的提升,大家在實際體驗了之後感覺都非常的明顯;
- 其次,是非常強的上下文銜接能力,你不僅能夠問他一個問題,而且還可以透過不斷追加提問的方式,讓它不斷的改進回答內容,最終達到使用者想要的理想效果。
- 然後,是對知識和邏輯的理解能力,當你遇到某個問題,它不僅只是給一個完整的回答,同時,你對這個問題的各種細節追問,它都能回答出來。
ChatGPT目前暫時還沒有看到與之相關的論文,但是,官網有一篇Instruct GPT和ChatGPT是非常接近的。在官網上也指出了ChatGPT是InstructGPT的兄弟模型,它經過訓練可以按照指示中的說明進行操作並提供詳細的響應。
這裡我們可以看到2個模型的訓練過程非常的相似,文章地址:
-
https://openai.com/research/instruction-following
- https://openai.com/blog/chatgpt
ChatGPT訓練流程如下所示:
InstructGPT訓練流程如下所示:
在OpenAI關於InstructiGPT中的論文中,有可以找到這些直觀優勢的量化分析。
InstructGPT對比上一代GPT3:
- 首先在71%的情況下,InstructGPT生成的回答要比GPT3模型的回答要更加符合訓練人員的喜好。這裡提到GPT3是OpenAI的上一代自然語言生成模型。
- 其次,InstructGPT在回答問題的真實程度上,也會更加可靠,當兩個模型同時被問到他們完全不知道的內容時,InstructGPT只有21%的情況會編造結果,而GPT3就高了,多達到了41%。這裡,我們可以發現,即便是最厲害的模型它也有五分之一的機率會胡說八道;
- 除此之外,InstructGPT在產生有毒回答的機率上也減小了25%。
所以,彙總下來,InstructGPT比上一代模型能夠提供更加真實可靠的回答,並且回答的內容也會遠比上一代更加符合使用者的意願。
3.如何做到這些提升的呢?
我們要看清楚ChatGPT,為什麼可以做到如此出色的效果。就需要我們把視角稍微拉遠一點,看一看這款模型,近幾年的發展歷史。
ChapGPT是OpenAI的另一款模型,它是InstructGPT的兄弟模型,也就是基於InstructGPT做了一些調整,而InstructGPT的上一代是GPT3,再往上一個版本是GPT2,再往上是GPT,那再往前就是Google的那一篇關於transformer的著名論文(https://arxiv.org/pdf/1706.03762.pdf),這裡需要提一下的是,同樣是基於transformer結構的,還有Google自家的BERT架構,以及對應的分支。
所以,我們能夠得到這樣一個分支圖。
這裡,本人能力有限,沒法對每一篇論文分析總結。但是,想提到一些自己在學習的過程中感覺比較有趣的決定和突破。
首先,同樣是transformer架構上分支出來的,BERT和GPT的一大不同,來自於他們transformer具體結構的區別,BERT使用的是transformer的encoder元件,而encoder的元件在計算某個位置時,會關注他左右兩側的資訊,也就是文章的上下文。而GPT使用的是transformer decoder元件,decoder元件在計算某個位置時,只關注它左側的資訊,也就是文章的上文。
我們如果用一個通俗的比喻就是,BERT在結構上對上下文的理解會更強,更適合嵌入式的表達,也就是完型填空式的任務。而GPT在結構上更適合只有上文,完全不知道下文的任務,而聊天恰好就是這樣的場景。
另一個有趣的突破,來自模型量級上的提升。
從GPT到GPT2,再到GPT3,OpenAI大力出奇跡,將模型引數從1.17億,提升到15億,然後進一步暴力提升到了1750億個。以至於GPT3比以前同型別的語言模型,引數量增加了10倍以上。
同時,訓練資料量也從GPT的5GB,增加到GPT2的40GB,再到GPT3的45TB,與此相關的是在方向上(https://arxiv.org/pdf/2005.14165.pdf)
OpenAI沒有追求模型在特定型別任務上的表現,而是不斷的增加模型的泛化能力。同時,GPT3的訓練費用,也到達了驚人的1200萬美元。
那下一個有趣的節點,就達到了今天的主角ChatGPT的兄弟,InstructGPT。從GPT3到InstructGPT的一個有趣改進。來自於引入了人類的反饋。用OpenAI論文的說法是,在InstructGPT之前,大部分大規模語言模型的目標,都是基於上一個輸入片段token,來推測下一個輸入片段。
然而這個目標和使用者的意圖是不一致的,使用者的意圖是讓語言模型,能夠有用並且安全的遵循使用者的指令,那這裡的指令instruction,也就是InstructGPT名字的來源,當然,也就呼應的今天ChatGPT的最大優勢,對使用者意圖的理解。為了達到這個目的,他們引入了人類老師,也就是標記人員,透過標記人員的人工標記,來訓練出一個反饋模型,那這個反饋模型,實際上就是一個模仿喜好,用來給GPT3的結果來打分的模型,然後這個反饋模型再去訓練GPT3,之所以沒有讓標記人員,直接訓練GPT3,可能是因為資料量太大的原因吧。
所以,這個反饋模型,就像是被抽象出來的人類意志。可以用來激勵GPT3的訓練,那整個訓練方法,就被叫做基於人類反饋的強化學習。至此簡易版的InstructGPT的前世今生就介紹完了。我們來回顧一下OpenAI一直在追求的幾個特點:
- 首先,是隻有上文的decoder結構,這種結構下訓練出來的模型,天然適合問答這種互動方式;
- 然後,是通用模型,OpenAI一直避免在早期架構和訓練階段,就針對某個特定的行業做調優,這也讓GPT3有著很強的通用能力
- 最後,是巨量資料和巨量引數,從資訊理論的角度來看,這就像深層的語言模型,涵蓋的人類生活中,會涉及的幾乎所有的自然語言和程式語言,當然,這也就極大的提高了個人或者小公司參與的門檻。
既然說到了原理,還有一個方面是前面沒有提及到的,就是連續對話的能力。所以,ChatGPT是如何做到能夠記住對話的上下文的呢?
這一能力,其實在GPT3時代就已經具備了,具體做法是這樣的,語言模型生成回答的方式,其實是基於一個個的token,這裡的token,可以粗略的理解為一個個單詞。所以ChatGPT給你生成一句話的回答,其實是從第一個詞開始,重複把你的問題以及當前生成的所有內容,再作為下一次的輸入,再生成下一個token,直到生成完整的回答。
4.實戰演練
為了更好地理解ChatGPT模型的實際應用,我們可以嘗試使用Hugging Face提供的Transformers庫來構建一個聊天機器人模型。
1.準備資料集
我們可以使用Cornell電影對話資料集來作為ChatGPT模型的訓練資料集。Cornell電影對話資料集包含了超過220,579條對話記錄,每條記錄都有一個問題和一個回答。我們可以將問題和回答組合在一起,形成聊天機器人的訓練樣本。
2.資料預處理
在訓練ChatGPT模型之前,我們需要對資料進行預處理,將文字轉換為數字表示。我們可以使用tokenizer將文字轉換為tokens,並將tokens轉換為模型輸入的數字表示。在使用Hugging Face的Transformers庫中,我們可以使用AutoTokenizer自動選擇適合的tokenizer,根據模型的型別和配置來進行初始化。
以下是對電影對話資料集進行預處理的程式碼:
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, truncation=True, padding=True, max_length=max_length) return inputs, pad_token_id inputs, pad_token_id = preprocess_data('movie_conversations.txt')
在上述程式碼中,我們使用了AutoTokenizer來初始化tokenizer,並指定了最大的序列長度為512。同時,我們也定義了padding token的id,並使用preprocess_data函式來對Cornell電影對話資料集進行預處理。在預處理過程中,我們將每個問題和回答組合在一起,使用tokenizer將文字轉換為tokens,並將tokens轉換為數字表示。我們還設定了padding和truncation等引數,以使得所有輸入序列長度相同。
3.訓練模型
在對資料集進行預處理後,我們可以使用Hugging Face的Transformers庫中提供的GPT2LMHeadModel類來構建ChatGPT模型。GPT2LMHeadModel是一個帶有語言模型頭的GPT-2模型,用於生成與前面輸入的文字相關的下一個詞。
以下是使用GPT2LMHeadModel訓練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模型,並調整Embedding層的大小以適應我們的tokenizer。接下來,我們定義了TrainingArguments來配置訓練引數。其中包括了訓練的輪數、每批次的大小、模型儲存路徑等資訊。最後,我們使用Trainer類來訓練模型。在這裡,我們將輸入資料傳遞給train_dataset引數,並使用一個data_collator函式將輸入資料打包成一個批次。
4.生成文字
在訓練完成後,我們可以使用ChatGPT模型來生成文字。在Hugging Face的Transformers庫中,我們可以使用pipeline來實現文字生成。
以下是使用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函式來初始化一個文字生成器,其中指定了ChatGPT模型和tokenizer。接下來,我們定義了generate_text函式來使用生成器生成文字。在這裡,我們傳入一個prompt字串作為生成的起始點,並使用max_length引數來指定生成文字的最大長度,使用do_sample和temperature引數來控制文字的隨機性和流暢度。
5.總結
ChatGPT是一個強大的自然語言生成模型,可以用於生成對話、推薦、文字摘要等多種任務。在本文中,我們介紹了ChatGPT的原理、實現流程和應用場景,並提供了Cornell電影對話資料集的預處理和ChatGPT模型的訓練程式碼。透過使用Hugging Face的Transformers庫,我們可以輕鬆地構建和訓練ChatGPT模型,並使用pipeline來生成文字。希望本文能夠幫助讀者更好地理解ChatGPT,以及如何應用自然語言生成技術來解決實際問題。
因為,GPT3 API裡面單次互動最多支援4000多個token(https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them)
因此,我猜測ChatGPT的上下文大概也是4000個token左右。