隨著 RAG 資料量的增長,儲存和檢索成本日益提升。為瞭解決這個問題,可以透過微調 OpenAI 模型來減少對大量靜態 RAG 資料的依賴。本文以 SciQ 硬科學資料集為例,示範如何將其轉換為 OpenAI 微調所需的 JSONL 格式,並用於訓練 GPT-4o-mini 模型。這個過程包含資料準備、模型微調、任務監控和結果驗證等步驟,旨在提升模型在特定領域的問答能力,並有效降低對龐大資料集的依賴。
微調OpenAI模型的RAG資料縮減架構
在本章中,我們將探討透過微調來實作RAG資料縮減的架構,並重點關注包含現成檔案和強調人為反饋因素的資料集。我們將展示如何將非引數資料轉換為引數化的微調資料,並在OpenAI模型中實作。
微調的架構
靜態RAG資料的挑戰
在本文中,我們將探討當非引數RAG資料超過可管理的閾值時的使用問題。如同在第一章《為什麼選擇檢索增強生成?》中所述,靜態資料的處理(D2)和儲存(D3)閾值已經達到。閾值的大小取決於每個專案和諸如以下引數:
- 要處理的RAG資料量:嵌入資料需要人力和機器資源。即使我們不嵌入資料,堆積積靜態資料(長時間保持穩定的資料)也毫無意義。
- 要儲存和檢索的RAG資料量:在某些時候,如果我們繼續堆積積資料,其中很多可能會重疊。
- 檢索需要資源:即使系統是開源的,仍然需要管理越來越多的資源。
RAG生態系統
在本文中,我們將回到第一章中描述的RAG生態系統,並重點關注本章所需的特定元件。下圖展示了微調元件的彩色表示和我們不需要的元件的灰色表示:
此圖示呈現了我們將要構建的微調生態系統的關鍵特徵,主要包括:
- 收集(D1)和準備(D2)資料集:我們將下載並處理在前一章中實作的人工製作的眾包SciQ硬科學資料集。
- 人為反饋(E2):我們可以假設人為反饋在SciQ硬科學資料集中發揮了重要作用。該資料集由人類控制和更新,因此可以認為它是可靠的人為反饋模擬,可以透過微調來減輕RAG資料集的數量。
- 微調(T2):我們將微調一個具有成本效益的OpenAI模型——GPT-4o-mini。
- 提示工程(G3)和生成與輸出(G4):我們將按照OpenAI的建議設計提示並顯示輸出。
- 指標(E1):我們將檢視OpenAI指標介面的主要功能。
安裝環境
安裝環境由於AI和跨平台依賴衝突的快速演變而變得複雜。因此,我們將盡可能凍結包版本。
程式碼實作
# 從檔案中檢索API金鑰或手動輸入
from google.colab import drive
drive.mount('/content/drive')
f = open("drive/MyDrive/files/api_key.txt", "r")
API_KEY = f.readline()
f.close()
try:
import openai
except:
!pip install openai==1.42.0
import openai
import os
os.environ['OPENAI_API_KEY'] = API_KEY
openai.api_key = os.getenv("OPENAI_API_KEY")
!pip install jsonlines==4.0.0
!pip install datasets==2.20.0
內容解密:
這段程式碼主要用於設定OpenAI API金鑰和安裝必要的Python包。首先,它從Google Drive掛載的檔案中讀取API金鑰,或者可以手動輸入。然後,它嘗試匯入openai
函式庫,如果未安裝,則安裝指定版本(1.42.0)。接著,它設定環境變數OPENAI_API_KEY
並將其指定給openai.api_key
。最後,它安裝jsonlines
和datasets
函式庫,分別用於處理JSONL資料和資料集操作。
準備微調資料集
微調OpenAI模型需要仔細準備,否則微調作業將失敗。在本文中,我們將執行以下步驟:
- 從Hugging Face下載資料集並透過處理其列來準備。
- 將資料集流式傳輸到JSONL格式的檔案中。
下載和視覺化資料集
# 下載SciQ資料集
from datasets import load_dataset
dataset = load_dataset("sciq")
內容解密:
這段程式碼使用datasets
函式庫從Hugging Face下載SciQ資料集。下載後的資料集儲存在dataset
變數中,可以用於後續的處理和微調。
圖表翻譯:
此圖示呈現了RAG生態系統中的微調元件及其相互關係。主要包括資料收集、準備、微調、提示工程和指標評估等關鍵步驟。
後續步驟
在下一節中,我們將繼續探討如何準備JSONL格式的資料集以進行微調,並使用OpenAI的處理工具生成JSONL資料集。然後,我們將微調GPT-4o-mini模型,並測試其在我們的資料集上的表現。最後,我們將探索OpenAI的指標介面,以評估我們的技術指標,如準確性和使用指標,以評估我們的成本效益方法。
微調GPT-4o-mini模型以增強科學問答能力
在人工智慧領域,模型的微調(fine-tuning)是提升特定任務表現的重要步驟。本章節將介紹如何下載並視覺化Hugging Face資料集,接著將資料集轉換為適合OpenAI微調的格式,最後進行模型的微調和監控。
1.1. 下載和視覺化資料集
首先,我們下載Hugging Face上的SciQ資料集,並過濾出包含支援文字的訓練資料:
# 匯入必要的函式庫
from datasets import load_dataset
import pandas as pd
# 從HuggingFace載入SciQ資料集
dataset_view = load_dataset("sciq", split="train")
# 過濾資料集,只保留包含支援文字的題目
filtered_dataset = dataset_view.filter(lambda x: x["support"] != "")
# 列印過濾後題目的數量
print("包含支援文字的題目數量:", len(filtered_dataset))
內容解密:
load_dataset("sciq", split="train")
:從Hugging Face載入SciQ資料集的訓練部分。dataset_view.filter(lambda x: x["support"] != "")
:使用lambda函式過濾資料,只保留support
欄位不為空的記錄。len(filtered_dataset)
:計算過濾後的資料集大小。
輸出結果顯示,我們得到了10,481筆包含支援文字的題目。
接著,將過濾後的資料轉換為pandas DataFrame,並移除包含錯誤答案的欄位:
# 將過濾後的資料集轉換為pandas DataFrame
df_view = pd.DataFrame(filtered_dataset)
# 需要移除的欄位列表
columns_to_drop = ['distractor3', 'distractor1', 'distractor2']
# 從DataFrame中移除指定的欄位
df_view = df_view.drop(columns=columns_to_drop)
# 顯示DataFrame的前幾行
df_view.head()
內容解密:
pd.DataFrame(filtered_dataset)
:將Hugging Face的Dataset物件轉換為pandas DataFrame。df_view.drop(columns=columns_to_drop)
:移除DataFrame中指定的欄位,這些欄位包含錯誤的答案選項。
1.2. 為微調準備資料集
為了微調GPT-4o-mini模型,我們需要將資料集轉換為JSONL格式。以下程式碼展示瞭如何準備資料:
# 準備JSONL檔案的資料專案
items = []
for idx, row in df.iterrows():
detailed_answer = row['correct_answer'] + " 解釋: " + row['support']
items.append({
"messages": [
{"role": "system", "content": "針對科學問題提供詳細答案"},
{"role": "user", "content": row['question']},
{"role": "assistant", "content": detailed_answer}
]
})
# 將資料寫入JSONL檔案
import jsonlines
with jsonlines.open('/content/QA_prompts_and_completions.json', mode='w') as writer:
writer.write_all(items)
內容解密:
detailed_answer = row['correct_answer'] + " 解釋: " + row['support']
:結合正確答案和支援文字,形成詳細的答案。items.append({...})
:將每個問題和對應的詳細答案組織成符合OpenAI格式的字典。jsonlines.open(...).write_all(items)
:將準備好的資料寫入JSONL檔案。
2. 微調模型
2.1. 建立微調任務
首先,建立OpenAI客戶端並上傳訓練檔案:
from openai import OpenAI
import jsonlines
# 建立OpenAI客戶端
client = OpenAI()
# 上傳訓練檔案
result_file = client.files.create(
file=open("QA_prompts_and_completions.json", "rb"),
purpose="fine-tune"
)
# 列印檔案資訊
print(result_file)
param_training_file_name = result_file.id
print(param_training_file_name)
內容解密:
client.files.create(file=open(...), purpose="fine-tune")
:上傳JSONL檔案作為微調任務的訓練資料。result_file.id
:取得上傳檔案的ID,用於後續的微調任務。
接著,建立並顯示微調任務:
# 建立微調任務
ft_job = client.fine_tuning.jobs.create(
training_file=param_training_file_name,
model="gpt-4o-mini-2024-07-18"
)
# 列印微調任務資訊
print(ft_job)
內容解密:
client.fine_tuning.jobs.create(training_file=..., model=...)
:使用指定的訓練檔案和模型建立微調任務。print(ft_job)
:輸出微調任務的詳細資訊,包括任務ID、狀態、模型名稱等。
2.2. 監控微調任務
為了監控微調任務的進度,可以查詢最近的三個微調任務:
# 取得最近的三個微調任務
response = client.fine_tuning.jobs.list(limit=3)
# 列印任務資訊
for job in response.data:
print(job.id, job.status, job.created_at)
內容解密:
client.fine_tuning.jobs.list(limit=3)
:取得最近建立的三個微調任務。for job in response.data:
:遍歷並列印每個任務的ID、狀態和建立時間。
此圖表呈現了微調任務的主要流程:
graph LR; A[下載並視覺化資料集] --> B[準備JSONL格式資料]; B --> C[上傳訓練檔案]; C --> D[建立微調任務]; D --> E[監控微調任務進度];
圖表翻譯: 此圖示展示了從下載資料集到監控微調任務的完整流程。首先,下載並視覺化SciQ資料集。接著,將資料轉換為JSONL格式並上傳至OpenAI。然後,使用上傳的檔案建立微調任務,並持續監控任務的進度和狀態。整個流程確保模型的微調順利進行並達到預期的效果。
微調OpenAI模型與應用實踐
在人工智慧與機器學習的領域中,模型的微調(Fine-Tuning)是提升模型效能的重要步驟。本文將介紹如何使用OpenAI的API進行模型的微調,並展示相關的程式碼實作與結果分析。
取得微調任務資訊
首先,我們需要取得OpenAI中已建立的微調任務資訊。透過client.fine_tuning.jobs.list
方法,可以列出最近的微調任務。
import pandas as pd
from openai import OpenAI
client = OpenAI()
response = client.fine_tuning.jobs.list(limit=3)
# 初始化列表以儲存提取的資料
job_ids = []
created_ats = []
statuses = []
models = []
training_files = []
error_messages = []
fine_tuned_models = []
# 遍歷任務以檢索所需資訊
for job in response.data:
job_ids.append(job.id)
created_ats.append(job.created_at)
statuses.append(job.status)
models.append(job.model)
training_files.append(job.training_file)
error_message = job.error.message if job.error else None
error_messages.append(error_message)
fine_tuned_model = job.fine_tuned_model if hasattr(job, 'fine_tuned_model') else None
fine_tuned_models.append(fine_tuned_model)
# 建立DataFrame
df = pd.DataFrame({
'Job ID': job_ids,
'Created At': created_ats,
'Status': statuses,
'Model': models,
'Training File': training_files,
'Error Message': error_messages,
'Fine-Tuned Model': fine_tuned_models
})
# 將時間戳轉換為可讀格式並排序
df['Created At'] = pd.to_datetime(df['Created At'], unit='s')
df = df.sort_values(by='Created At', ascending=False)
# 顯示DataFrame
print(df)
內容解密:
client.fine_tuning.jobs.list(limit=3)
:列出最近的三個微調任務。for job in response.data
:遍歷任務列表,提取每個任務的詳細資訊,包括任務ID、建立時間、狀態、模型、訓練檔案、錯誤訊息和微調後的模型名稱。pd.DataFrame
:將提取的資訊儲存到DataFrame中,便於後續分析和處理。pd.to_datetime(df['Created At'], unit='s')
:將Unix時間戳轉換為可讀的日期時間格式。df.sort_values(by='Created At', ascending=False)
:按建立時間對DataFrame進行降序排序。
檢查最新的微調模型
接下來,我們需要檢查最新的微調模型是否已經完成訓練。
generation = False # 初始狀態為False,表示未完成訓練
# 尋找第一個非空的Fine-Tuned Model
non_empty_models = df[df['Fine-Tuned Model'].notna()]
if not non_empty_models.empty:
first_non_empty_model = non_empty_models.iloc[0]['Fine-Tuned Model']
print("The latest fine-tuned model is:", first_non_empty_model)
generation = True
else:
print("No fine-tuned models found.")
內容解密:
non_empty_models = df[df['Fine-Tuned Model'].notna()]
:篩選出Fine-Tuned Model
欄位非空的行。generation = True
:如果找到非空的微調模型,將generation
設為True
,表示可以進行後續的操作。
使用微調後的OpenAI模型
當微調模型訓練完成後,我們可以使用它來進行推論。
if generation:
prompt = "What phenomenon makes global winds blow northeast to southwest?"
response = client.chat.completions.create(
model=first_non_empty_model,
temperature=0.0,
messages=[
{"role": "system", "content": "Given a question, respond with the appropriate answer."},
{"role": "user", "content": prompt}
]
)
print(response.choices[0].message.content)
else:
print("Error: Model is None, cannot proceed with the API request.")
內容解密:
client.chat.completions.create
:使用微調後的模型進行推論。temperature=0.0
:設定溫度為0,表示不引入隨機性,輸出結果更具確定性。messages
:定義對話內容,包括系統提示和使用者輸入的問題。
結果格式化
最後,我們可以對模型的輸出結果進行格式化,使其更易閱讀。
import textwrap
if generation:
response_text = response.choices[0].message.content
wrapped_text = textwrap.fill(response_text.strip(), 60)
print(wrapped_text)
內容解密:
textwrap.fill
:將長字串按照指定的寬度進行換行處理,使輸出結果更整潔。