以下參考課程 LLM Twin: Building Your Production-Ready AI Replica 撰寫
LLM Fine-tuning 是將已經預訓練的大型語言模型(如 GPT-3.5 或 Mistral-7B),透過針對性的小型數據集進行進一步訓練,從而優化其在特定任務上的表現。這就像是一個通才模型學會了廣泛的知識,但在需要提供專業領域的精確回答時,我們會進一步微調模型,使其能夠專注於特定的知識範疇。
簡單來說,Fine-tuning 就像是將一個「萬能模型」轉變為針對特定領域的「專家模型」。這樣的過程不僅能讓模型具備應對日常任務的能力,還能在特定場景中提供更加準確的回應。
為什麼微調很重要?
預訓練模型雖然已經學到了大量的通用知識,但在處理專業任務時,通常無法達到最好的效果。例如,預訓練的模型可能能回答你有關常見知識的問題,但當你問到更細緻的領域問題,如法律條款或醫學知識,模型可能無法提供足夠精確的答案。這就是為什麼我們需要進行 Fine-tuning:它可以讓模型專注於特定的任務或領域,提升其在該領域的準確度和效率。
在開始微調之前,我們需要準備一個專門的資料集。這些資料集包含模型需要學習的「指令-內容」資料對,這樣模型才能理解如何針對特定指令生成合適的回應。
資料準備的重要性
資料集是模型微調的基礎。好的資料集能夠幫助模型學習如何應對不同的任務。假設你想讓模型能夠撰寫 LinkedIn 貼文,我們可以收集來自 LinkedIn 的貼文資料,並為每個貼文生成一個指令。模型在學習這些指令的同時,也會學會如何處理這類型的任務。
以下是一個準備資料集的範例,我們將使用 Qdrant 平台上儲存的資料,結合 OpenAI 的 GPT-3.5-turbo 模型來自動生成「指令-內容」資料對。
為什麼使用「指令-內容」資料集?
「指令-內容」資料集的目的在於幫助模型理解具體指令。例如,如果我們告訴模型「撰寫一篇介紹某個免費課程的 LinkedIn 貼文」,模型就需要學會如何生成這樣的內容。透過大量相似的「指令-內容」資料對,模型將能夠更精確地應對未來類似的請求。
以下是兩個來自 Qdrant 平台的資料範例,這些「已清理的內容」(cleaned_content)將作為生成指令的基礎資料:
{
"author_id": "2",
"cleaned_content": "Do you want to learn to build hands-on LLM systems using good LLMOps practices? A new Medium series is coming up...",
"platform": "linkedin",
"type": "posts"
},
{
"author_id": "2",
"cleaned_content": "RAG systems are far from perfect. This free course teaches you how to improve your RAG system...",
"platform": "linkedin",
"type": "posts"
}
這些資料代表了來自不同社交媒體平台的貼文內容,接下來我們將利用 LLM 生成相應的指令,幫助模型針對這些貼文進行優化。
為了自動生成訓練資料,課程使用 DataFormatter 類將資料式化成 LLM 可以理解的格式,並產生對應的指令。
DataFormatter
:將資料格式化成模型能接受的提示內容DataFormatter 是一個用來將資料點轉換為模型可以理解的文本格式的類。它可以自動將資料組織好,以便 LLM(大型語言模型)能夠根據我們提供的指令進行微調。這樣做的好處是,我們可以減少手動操作,並確保資料的結構正確,讓模型能正確地學習。
以下是如何使用 DataFormatter 類來格式化內容的範例:
data_type = "posts"
USER_PROMPT = (
f"I will give you batches of contents of {data_type}. Please generate me exactly 1 instruction for each of them. The {data_type} text "
f"for which you have to generate the instructions is under Content number x lines. Please structure the answer in json format,"
f"ready to be loaded by json.loads(), a list of objects only with fields called instruction and content. For the content field, copy the number of the content only!."
f"Please do not add any extra characters and make sure it is a list with objects in valid json format!\n"
)
class DataFormatter:
@classmethod
def format_data(cls, data_points: list, is_example: bool, start_index: int) -> str:
text = ""
for index, data_point in enumerate(data_points):
if not is_example:
text += f"Content number {start_index + index }\n"
text += str(data_point) + "\n"
return text
@classmethod
def format_batch(cls, context_msg: str, data_points: list, start_index: int) -> str:
delimiter_msg = context_msg
delimiter_msg += cls.format_data(data_points, False, start_index)
return delimiter_msg
@classmethod
def format_prompt(cls, inference_posts: list, start_index: int):
initial_prompt = USER_PROMPT
initial_prompt += f"You must generate exactly a list of {len(inference_posts)} json objects, using the contents provided under CONTENTS FOR GENERATION\n"
initial_prompt += cls.format_batch(
"\nCONTENTS FOR GENERATION: \n", inference_posts, start_index
)
return initial_prompt
這樣的提示會告訴模型如何根據給定的資料生成合適的指令。我們讓模型理解每個貼文的內容,並讓它為每個貼文生成相應的指令。
為了簡化資料集的生成過程,課程中計了 DatasetGenerator 類。這個類負責自動從資料庫中提取資料、將資料格式化,並最終將結果推送至訓練平台(如 Comet ML)進行微調。
DatasetGenerator
:自動化訓練資料生成過程這個類會自動執行資料提取和處理過程,幫助我們大大減少手動操作。它由三個部分組成:
以下是 DatasetGenerator 類的初始化方法:
class DatasetGenerator:
def __init__(self, file_handler, api_communicator, data_formatter):
self.file_handler = file_handler
self.api_communicator = api_communicator
self.data_formatter = data_formatter
自動生成微調數據generate_training_data
方法負責自動生成微調資料,以下是它的運作方式:
def generate_training_data(self, collection_name: str, batch_size: int = 1):
all_contents = self.fetch_all_cleaned_content(collection_name)
response = []
for i in range(0, len(all_contents), batch_size):
batch = all_contents[i : i + batch_size]
initial_prompt = self.data_formatter.format_prompt(batch, i)
response += self.api_communicator.send_prompt(initial_prompt)
for j in range(i, i + batch_size):
response[j]["content"] = all_contents[j]
self.push_to_comet(response, collection_name)
這個方法會從指定的資料集合中提取內容,並利用 LLM 生成相應的「指令-內容」資料對,最後將結果上傳到 Comet ML 進行微調。
提取資料內容fetch_all_cleaned_content
方法負責從 Qdrant 中提取所有已清理的內容,準備進行後續處理:
def fetch_all_cleaned_content(self, collection_name: str) -> list:
all_cleaned_contents = []
scroll_response = client.scroll(collection_name=collection_name, limit=10000)
points = scroll_response[0]
for point in points:
cleaned_content = point.payload["cleaned_content"]
if cleaned_content:
all_cleaned_contents.append(cleaned_content)
return all_cleaned_contents
這個方法使用了 Qdrant 的 scroll
功能,一次提取大量資料,並將其整理成為已清理的內容列表,這些內容將被用來生成「指令-內容」資料對。
透過上述流程,我們最終得到了由 LLM 生成的訓練資料。這些資料可以作為模型微調的訓練集,以下是一個簡單的生成結果範例:
[
{
"instruction": "撰寫一篇 LinkedIn 貼文,宣傳即將推出的關於 LLM 系統實作課程,重點介紹 LLMOps 的最佳實踐,並鼓勵讀者關注更多課程內容。",
"content": "Do you want to learn to build hands-on LLM systems using good LLMOps practices?..."
},
{
"instruction": "撰寫一篇 LinkedIn 貼文,宣傳一個免費的 RAG 系統改進課程,強調學習最新的技術如查詢擴展和嵌入自適應技術。",
"content": "RAG systems are far from perfect. This free course teaches you how to improve your RAG system..."
}
]
透過這種方式,我們成功生成了一個針對 LinkedIn 貼文的訓練資料集,為微調 Mistral-7B 模型做好了準備。這樣的資料集可以讓模型在這類型任務上表現更好,並提供更精準的結果。
ref.