使用GPT-4生成訓練數據微調GPT-3.5 RAG管道

OpenAI在2023年8月22日宣佈,現在可以對GPT-3.5 Turbo進行微調了。也就是說,我們可以自定義自己的模型了。然後LlamaIndex就發佈了0.8.7版本,集成了微調OpenAI gpt-3.5 turbo的功能

也就是說,我們現在可以使用GPT-4生成訓練數據,然後用更便宜的API(gpt-3.5 turbo)來進行微調,從而獲得更準確的模型,並且更便宜。所以在本文中,我們將使用NVIDIA的2022年SEC 10-K文件來仔細研究LlamaIndex中的這個新功能。並且將比較gpt-3.5 turbo和其他模型的性能。

RAG vs 微調

微調到底是什麼?它和RAG有什麼不同?什麼時候應該使用RAG和微調?以下兩張總結圖:

這兩個圖像總結了它們基本的差別,爲我們選擇正確的工具提供了很好的指導。

但是,RAG和微調並不相互排斥。將兩者以混合方式應用到同一個應用程序中是完全可行的。

RAG/微調混合方法

LlamaIndex提供了在RAG管道中微調OpenAI gpt-3.5 turbo的詳細指南。從較高的層次來看,微調可以實現下圖中描述的關鍵任務:

簡單的總結來說就是,這種集成使gpt-3.5 turbo能夠對gpt-4訓練的數據進行微調,並輸出更好的響應。

步驟2和7是可選的,因爲它們僅僅是評估基本模型與微調模型的性能。

我們下面將演示這個過程,在演示時,使用NVIDIA 2022年的SEC 10-K文件。

主要功能點

1、OpenAIFineTuningHandler

這是OpenAI微調的回調處理程序,用於收集發送到gpt-4的所有訓練數據,以及它們的響應。將這些消息保存爲.jsonl (jsonline)格式,OpenAI的API端點可以使用該格式進行微調。

2、OpenAIFinetuneEngine

微調集成的核心是OpenAIFinetuneEngine,它負責啓動微調作業並獲得一個微調模型,可以直接將其插件到LlamaIndex工作流程的其餘部分。

使用OpenAIFinetuneEngine, LlamaIndex抽象了OpenAI api進行微調的所有實現細節。包括:

我們可以使用OpenAIFinetuneEngine的gpt-4和OpenAIFineTuningHandler來收集我們想要訓練的數據,也就是說我們使用gpt-4的輸出來訓練我們的自定義的gpt-3.5 turbo模型

from llama_index import ServiceContextfrom llama_index.llms import OpenAIfrom llama_index.callbacks import OpenAIFineTuningHandlerfrom llama_index.callbacks import CallbackManager# use GPT-4 and the OpenAIFineTuningHandler to collect data that we want to train on.finetuning_handler = OpenAIFineTuningHandler()callback_manager = CallbackManager([finetuning_handler])gpt_4_context = ServiceContext.from_defaults(llm=OpenAI(model="gpt-4", temperature=0.3),context_window=2048, # limit the context window artifically to test refine processcallback_manager=callback_manager,)# load the training questions, auto generated by DatasetGeneratorquestions = []with open("train_questions.txt", "r") as f:for line in f:questions.append(line.strip())from llama_index import VectorStoreIndex# create index, query engine, and run query for all questionsindex = VectorStoreIndex.from_documents(documents, service_context=gpt_4_context)query_engine = index.as_query_engine(similarity_top_k=2)for question in questions:response = query_engine.query(question)# save fine-tuning events to jsonl filefinetuning_handler.save_finetuning_events("finetuning_events.jsonl")from llama_index.finetuning import OpenAIFinetuneEngine# construct OpenAIFinetuneEnginefinetune_engine = OpenAIFinetuneEngine("gpt-3.5-turbo","finetuning_events.jsonl")# call finetune, which calls OpenAI API to fine-tune gpt-3.5-turbo based on training data in jsonl file.finetune_engine.finetune()# check current job statusfinetune_engine.get_current_job()# get fine-tuned modelft_llm = finetune_engine.get_finetuned_model(temperature=0.3)

需要注意的是,微調函數需要時間,對於我測試的169頁PDF文檔,從在finetune_engine上啓動finetune到收到OpenAI的電子郵件通知我新的微調工作已經完成,這段時間大約花了10分鐘。下面的電子郵件如下。

在收到該電子郵件之前,如果在finetune_engine上運行get_finetuned_model,會得到一個錯誤,提示微調作業還沒有準備好。

3、ragas框架

ragas是RAG Assessment的縮寫,它提供了基於最新研究的工具,使我們能夠深入瞭解RAG管道。

ragas根據不同的維度來衡量管道的表現:忠實度、答案相關性、上下文相關性、上下文召回等。對於這個演示應用程序,我們將專注于衡量忠實度和答案相關性。

忠實度:衡量給定上下文下生成的答案的信息一致性。如果答案中有任何不能從上下文推斷出來的主張,則會被扣分。

答案相關性:指回答直接針對給定問題或上下文的程度。這並不考慮答案的真實性,而是懲罰給出問題的冗餘信息或不完整答案。

在RAG管道中應用ragas的詳細步驟如下:

代碼如下:

contexts = []answers = []# loop through the questions, run query for each questionfor question in questions:response = query_engine.query(question)contexts.append([x.node.get_content() for x in response.source_nodes])answers.append(str(response))from datasets import Datasetfrom ragas import evaluatefrom ragas.metrics import answer_relevancy, faithfulnessds = Dataset.from_dict({"question": questions,"answer": answers,"contexts": contexts,})# call ragas evaluate by passing in dataset, and eval categoriesresult = evaluate(ds, [answer_relevancy, faithfulness])print(result)import pandas as pd# print result in pandas dataframe so we can examine the question, answer, context, and ragas metricspd.set_option('display.max_colwidth', 200)result.to_pandas()

評估結果

最後我們可以比較一下微調前後的eval結果。

基本gpt-3.5-turbo的評估請看下面的截圖。answer_relevance的評分不錯,但忠實度有點低。

經過微調,模型的性能在答案相關性中略有提高,從0.7475提高到0.7846,提高了4.96%。

使用gpt-4生成訓練數據對gpt-3.5 turbo進行微調確實看到了改善。

一些有趣的發現

1、對小文檔進行微調會導致性能下降

最初用一個小的10頁PDF文件進行了實驗,我發現eval結果與基本模型相比性能有所下降。然後又繼續測試了兩輪,結果如下:

第一輪基本模型:Ragas_score: 0.9122, answer_relevance: 0.9601, faithfulness: 0.8688

第一輪微調模型:Ragas_score: 0.8611, answer_relevance: 0.9380, faithfulness: 0.7958

第二輪基本模型:Ragas_score: 0.9170, answer_relevance: 0.9614, faithfulness: 0.8765

第二輪微調模型:Ragas_score: 0.8891, answer_relevance: 0.9557, faithfulness: 0.8313

所以換衣小文件可能是微調模型比基本模型表現更差的原因。所以使用了NVIDIA長達169頁的SEC 10-K文件。對上面的結果做了一個很好的實驗——經過微調的模型表現得更好,忠實度增加了4.96%。

2、微調模型的結果不一致

原因可能是數據的大小和評估問題的質量

儘管169頁文檔的微調模型獲得了預期的評估結果,但我對相同的評估問題和相同的文檔運行了第二輪測試,結果如下:

第二輪基本模型:Ragas_score: 0.8874, answer_relevance: 0.9623, faithfulness: 0.8233

第二輪微調模型:Ragas_score: 0.8218, answer_relevance: 0.9498, faithfulness: 0.7242

是什麼導致了eval結果的不一致?

數據大小很可能是導致不一致的微調計算結果的根本原因之一。“至少需要1000個微調數據集的樣本。”這個演示應用顯然沒有那麼多的微調數據集。

另一個根本原因很可能在於數據質量,也就是eval問題的質量。我將eval結果打印到一個df中,列出了每個問題的問題、答案、上下文、answer_relevance和忠實度。

通過目測,有四個問題在忠實度中得分爲0。而這些答案在文件中沒有提供上下文。這四個問題質量很差,所以我從eval_questions.txt中刪除了它們,重新運行了評估,得到了更好的結果:

基本模型eval:Ragas_score: 0.8947, answer_relevance: 0.9627, faithfulness: 0.8356

微調模型eval:Ragas_score: 0.9207, answer_relevance: 0.9596, faithfulness: 0.8847

可以看到在解決了這四個質量差的問題後,微調版的上升了5.9%。所以評估問題和訓練數據需要更多的調整,以確保良好的數據質量。這確實是一個非常有趣的探索領域。

3、微調的成本

經過微調的gpt-3.5-turbo的價格高於基本模型的。我們來看看基本模型、微調模型和gpt-4之間的成本差異:

比較gpt-3.5-turbo (4K環境)、微調gpt-3.5-turbo和gpt-4 (8K環境),可以看到:

總結

本文探索了LlamaIndex對OpenAI gpt-3.5 turbo微調的新集成。我們通過NVIDIA SEC 10-K歸檔分析的RAG管道,測試基本模型性能,然後使用gpt-4收集訓練數據,創建OpenAIFinetuneEngine,創建了一個新的微調模型,測試了它的性能,並將其與基本模型進行了比較。

可以看到,因爲GPT4和gpt-3.5 turbo的巨大成本差異(20倍),在使用微調後,我們可以得到近似的效果,並且還能節省不少成本(2.5倍)

如果你對這個方法感興趣,源代碼在這裡:

https://avoid.overfit.cn/post/0a4ae4d87e69457dbd899d7a9af07237

作者:Wenqi Glantz