探索ChatGPT的Fine-tuning和Embeddings

2023-08-29 06:01:41

1.概述

今天我們將深入探索ChatGPT的兩項核心技術:Fine-tuning(微調)和Embeddings(嵌入)。這些技術在現代自然語言處理領域扮演著至關重要的角色,為模型的效能提升和適應特定任務需求提供了關鍵支援。ChatGPT作為GPT家族的一員,已經在多個領域展現了出色的表現,而其背後的Fine-tuning和Embeddings技術則是其成功的關鍵因素之一。

2.內容

2.1 什麼是Fine-tuning

Fine-tuning,又稱微調,是指在預訓練模型(如GPT-3)的基礎上,通過在特定任務上繼續訓練模型,使其適應特定任務的需求。GPT-3在大規模文字語料上進行了預訓練,學會了豐富的語言知識和模式。然而,要使模型在特定任務上表現出色,就需要對其進行進一步的微調。

ChatGPT的Fine-tuning涉及到將模型暴露在各種對話和語境中,以便它能夠更好地理解並生成自然對話。舉個例子,如果我們想要讓ChatGPT用於醫療諮詢,Fine-tuning的過程將包括讓模型學習醫學知識、專業術語和與患者交流的最佳實踐。這種Fine-tuning使得ChatGPT能夠根據任務的特定上下文作出更準確的迴應。

微調可讓你通過 API 提供以下功能,從而更充分地利用可用模型:

  • 比提示更高質量的結果
  • 能夠訓練超出提示範圍的範例
  • 由於提示較短而節省了代幣
  • 更低的延遲請求

GPT 模型已經過大量文字的預訓練。為了有效地使用模型,在提示中包含說明,有時還包含幾個範例。使用演示來展示如何執行任務通常稱為「小樣本學習」。

微調通過訓練超出提示範圍的更多範例來改進小樣本學習,讓你在大量任務上取得更好的結果。一旦模型經過微調,你就不需要在提示中提供那麼多範例。這可以節省成本並實現更低延遲的請求。

在較高層面上,微調涉及以下步驟:

  • 準備並上傳訓練資料
  • 訓練新的微調模型
  • 使用你的微調模型

2.2 哪些模型可以進行微調

目前可對以下型號進行微調:

  • gpt-3.5-turbo-0613(推薦)
  • babbage-002
  • davinci-002

目前gpt-3.5-turbo在結果和易用性方面成為大多數使用者的正確模型。

2.3 何時使用微調

微調 GPT 模型可以使其更好地適應特定應用,但這需要仔細投入時間和精力。建議首先嚐試通過 Prompt 工程、Prompt Chaining(將複雜的任務分解為多個Prompt)和函數呼叫來獲得良好的結果,主要原因是:

  • 對於許多工,模型最初可能表現不佳,但通過更好的 Prompt,我們可以取得更好的結果,並且可能不需要進行微調
  • 迭代 Prompt 和其他策略比微調迭代具有更快的反饋迴圈,後者需要建立資料集並執行訓練作業
  • 在仍然需要微調的情況下,最初的 Prompt 工程工作不會浪費 - 在微調資料中使用良好的 Prompt(或將 Prompt Chaining /工具使用與微調相結合)時,我們通常會看到最佳結果

GPT 最佳實踐指南提供了一些最有效的策略和策略的背景知識,無需微調即可獲得更好的效能。

2.4 常見用例

微調可以改善結果的一些常見用例:

  • 設定風格、基調、格式或其他定性方面
  • 提高產生所需輸出的可靠性
  • 糾正未能遵循複雜提示的問題
  • 以特定方式處理許多邊緣情況
  • 執行難以在提示中闡明的新技能或任務

思考這些案例的一種高階方法是「展示而不是講述」更容易。在接下來的部分中,我們將探討如何設定用於微調的資料以及微調可以提高基準模型效能的各種範例。

微調有效的另一種情況是通過替換 GPT-4 或使用較短的 Prompt 來降低成本和/或延遲,而不犧牲質量。gpt-3.5-turbo如果您可以使用 GPT-4 獲得良好的結果,那麼您通常可以通過對 GPT-4 補全進行微調(可能還需要縮短指令提示)來使用微調模型達到類似的質量。

2.5 準備資料集

一旦你確定微調是正確的解決方案(即已經儘可能優化了 Prompt 並確定了模型仍然存在的問題),你將需要準備資料來訓練模型。你應該建立一組多樣化的演示對話,這些對話類似於您要求模型在生產中的推理時響應的對話。

資料集中的每個範例都應該是與我們的聊天完成 API 格式相同的對話,特別是訊息列表,其中每條訊息都有角色、內容和可選名稱。至少一些訓練範例應該直接針對提示模型未按預期執行的情況,並且資料中提供的輔助訊息應該是您希望模型提供的理想響應。

2.6 格式範例

在此範例中,我們的目標是建立一個偶爾給出諷刺性響應的聊天機器人,這是我們可以為資料集建立的三個訓練範例(對話):

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

對話式聊天格式需要微調gpt-3.5-turbo。對於babbage-002和,你可以遵循用於傳統微調的davinci-002提示完成對格式,如下所示。

{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}

2.7 範例計數

要微調模型,你需要提供至少 10 個範例。我們通常會看到對 50 到 100 個訓練範例進行微調會帶來明顯的改進,gpt-3.5-turbo但正確的數量根據具體的用例而有很大差異。

建議從 50 個精心設計的演示開始,看看模型在微調後是否顯示出改進的跡象。在某些情況下,這可能就足夠了,但即使模型尚未達到生產質量,明顯的改進也是一個好兆頭,表明提供更多資料將繼續改進模型。沒有任何改進表明你可能需要重新考慮如何在超出有限範例集之前設定模型任務或重組資料。

2.8 檢查資料格式

編譯資料集後,在建立微調作業之前,檢查資料格式非常重要。為此,我們建立了一個簡單的 Python 指令碼,您可以使用它來查詢潛在錯誤、檢查令牌計數並估計微調作業的成本。

驗證資料後,需要上傳檔案才能用於微調作業:

 

openai.File.create(
  file=open("mydata.jsonl", "rb"),
  purpose='fine-tune'
)

2.9 建立微調模型

確保資料集的數量和結構正確並上傳檔案後,下一步是建立微調作業。

使用 OpenAI SDK 開始微調工作:

import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
openai.FineTuningJob.create(training_file="file-abc123", model="gpt-3.5-turbo")

model是您要從其開始的模型的名稱(gpt-3.5-turbo、babbage-002或davinci-002)。可以使用字尾引數自定義微調模型的名稱。

開始微調工作後,可能需要一些時間才能完成。你的作業可能排在我們系統中的其他作業後面,訓練模型可能需要幾分鐘或幾小時,具體取決於模型和資料集大小。

除了建立微調作業外,你還可以列出現有作業、檢索作業狀態或取消作業。

# List 10 fine-tuning jobs
openai.FineTuningJob.list(limit=10)

# Retrieve the state of a fine-tune
openai.FineTuningJob.retrieve("ft-abc123")

# Cancel a job
openai.FineTuningJob.cancel("ft-abc123")

# List up to 10 events from a fine-tuning job
openai.FineTuningJob.list_events(id="ft-abc123", limit=10)

# Delete a fine-tuned model (must be an owner of the org the model was created in)
import openai
openai.Model.delete("ft-abc123")

2.10 迭代資料質量

如果微調作業的結果不如預期,請考慮以下方式調整訓練資料集:

  • 收集範例以解決剩餘問題
    • 如果模型在某些方面仍然不擅長,請新增訓練範例,直接向模型展示如何正確地完成這些方面
  • 仔細檢查現有範例是否存在問題
    • 如果您的模型存在語法、邏輯或樣式問題,請檢查您的資料是否存在任何相同的問題。例如,如果模型現在說「我將為您安排這次會議」(實際上不應該如此),請檢視現有範例是否教導模型說它可以做它不能做的新事情
  • 考慮資料的平衡性和多樣性
    • 如果資料中 60% 的助理回答說「我無法回答這個問題」,但在推理時只有 5% 的回答應該這麼說,那麼您可能會得到過多的拒絕
  • 確保您的訓練範例包含響應所需的所有資訊
    • 如果我們希望模型根據使用者的個人特徵來讚美使用者,並且訓練範例包括對先前對話中未找到的特徵的輔助讚美,則模型可能會學習產生幻覺資訊
  • 檢視訓練範例中的一致性/一致性
    • 如果多個人建立了訓練資料,則模型效能可能會受到人們之間的一致性/一致性程度的限制。例如,在文字提取任務中,如果人們僅同意 70% 的提取片段,則模型可能無法做得更好
  • 確保所有訓練範例都採用相同的格式,正如推理所預期的那樣

3.Embeddings

3.1 什麼是Embeddings?

OpenAI 的文字嵌入衡量文字字串的相關性。嵌入通常用於:

  • 搜尋(結果按與查詢字串的相關性排名)
  • 聚類(文字字串按相似性分組)
  • 推薦(推薦具有相關文字字串的專案)
  • 異常檢測(識別出相關性很小的異常值)
  • 多樣性測量(分析相似性分佈)
  • 分類(文字字串按最相似的標籤進行分類)

嵌入是浮點數的向量(列表)。兩個向量之間的距離衡量它們的相關性。距離小表明相關性高,距離大表明相關性低。

3.2 如何獲得Embeddings

要獲得Embeddings,請將文字字串以及嵌入模型 ID 的選擇(例如)傳送到嵌入 API 端點text-embedding-ada-002。響應將包含一個嵌入,你可以提取、儲存和使用它。

請求範例:

curl https://api.openai.com/v1/embeddings \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "input": "Your text string goes here",
    "model": "text-embedding-ada-002"
  }'

響應範例:

{
  "data": [
    {
      "embedding": [
        -0.006929283495992422,
        -0.005336422007530928,
        ...
        -4.547132266452536e-05,
        -0.024047505110502243
      ],
      "index": 0,
      "object": "embedding"
    }
  ],
  "model": "text-embedding-ada-002",
  "object": "list",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5
  }
}

3.3 Embeddings模型

OpenAI 提供了一個第二代嵌入模型(-002在模型 ID 中用 表示)和 16 個第一代模型(-001在模型 ID 中用 表示)。

建議對幾乎所有用例使用 text-embedding-ada-002。它更好、使用更簡單。

在Github中獲取資料集,該資料集包含截至 2012 年 10 月亞馬遜使用者留下的總共 568,454 條食品評論。出於說明目的,我們將使用 1,000 條最新評論的子集。評論是英文的,往往是正面的或負面的。每條評論都有 ProductId、UserId、Score、評論標題(摘要)和評論正文(文字)。例如:

def get_embedding(text, model="text-embedding-ada-002"):
   text = text.replace("\n", " ")
   return openai.Embedding.create(input = [text], model=model)['data'][0]['embedding']

df['ada_embedding'] = df.combined.apply(lambda x: get_embedding(x, model='text-embedding-ada-002'))
df.to_csv('output/embedded_1k_reviews.csv', index=False)

要從儲存的檔案載入資料,你可以執行以下命令:

import pandas as pd

df = pd.read_csv('output/embedded_1k_reviews.csv')
df['ada_embedding'] = df.ada_embedding.apply(eval).apply(np.array)

3.4 Embeddings彙總常見問題

3.4.1 在嵌入字串之前如何知道它有多少個標記?

在 Python 中,您可以使用 OpenAI 的 tokenizer 將字串拆分為標記tiktoken。

範例程式碼:

import tiktoken

def num_tokens_from_string(string: str, encoding_name: str) -> int:
    """Returns the number of tokens in a text string."""
    encoding = tiktoken.get_encoding(encoding_name)
    num_tokens = len(encoding.encode(string))
    return num_tokens

num_tokens_from_string("tiktoken is great!", "cl100k_base")

對於像文字嵌入ada-002這樣的第二代嵌入模型,請使用cl100k_base編碼。

3.4.2 如何快速檢索 K 個最近的嵌入向量?

為了快速搜尋許多向量,我們建議使用向量資料庫。您可以在 GitHub 上的 Cookbook 中找到使用向量資料庫和 OpenAI API 的範例。

向量資料庫選項包括:

  • Chroma,一個開源嵌入商店
  • Milvus,一個為可延伸的相似性搜尋而構建的向量資料庫
  • Pinecone,一個完全託管的向量資料庫
  • Qdrant,向量搜尋引擎
  • Redis作為向量資料庫
  • Typesense,快速開源向量搜尋
  • Weaviate,一個開源向量搜尋引擎
  • Zilliz,資料基礎設施,由 Milvus 提供支援

3.4.3 應該使用哪個距離函數?

推薦餘弦相似度。距離函數的選擇通常並不重要。

OpenAI 嵌入標準化為長度 1,這意味著:

  • 僅使用點積即可稍微更快地計算餘弦相似度
  • 餘弦相似度和歐氏距離將導致相同的排名

4.Fine-tuning和Embeddings的挑戰

儘管Fine-tuning和嵌入技術在提高ChatGPT效能方面起到了關鍵作用,但也存在一些挑戰。其中之一是過擬合的問題。在Fine-tuning過程中,如果模型過於關注訓練資料中的噪聲或特定範例,可能導致模型在其他情況下表現不佳。因此,合適的正則化和資料淨化是確保模型泛化能力的重要因素。

另一個挑戰是平衡預訓練和Fine-tuning的關係。預訓練階段使模型具備了廣泛的語言知識,但Fine-tuning階段又需要在特定任務上進行調整。如何在這兩者之間取得平衡,以及如何在Fine-tuning過程中保留預訓練模型的有益特性,都需要深入研究和實驗。

5.總結

ChatGPT的成功背後離不開Fine-tuning和Embeddings技術的支援。Fine-tuning使得模型能夠適應特定任務,而嵌入技術則使模型能夠更好地理解語意和上下文。然而,這些技術也面臨著挑戰,需要持續的研究和改進。隨著人工智慧領域的不斷髮展,我們可以期待看到更多關於Fine-tuning、嵌入技術以及模型個性化的創新和突破。