大語言模型(LLM)徹底革新了自然語言處理領域,但要充分發揮其潛力,需要精細的微調。本文將探討微調LLM的關鍵策略和引數,並以實際案例説明如何調整這些引數以獲得最佳效能。
核心微調策略
微調LLM如同雕琢璞玉,需要多種策略協同作用:
梯度裁剪: 想像一下,在訓練過程中,梯度就像是指引模型學習方向的羅盤。梯度裁剪的作用就像設定羅盤的最大旋轉角度,防止它過度偏轉,確保訓練過程穩定進行。
正則化: 模型訓練如同培養樹苗,過度生長(過擬合)會讓它變得脆弱。正則化就像修剪枝葉,避免模型過於複雜,提升其應對新資料的能力。常用的方法包括L1和L2正則化、dropout和權重衰減。
模型架構: 模型架構是LLM的骨架,決定了它的學習能力和效能上限。選擇合適的架構至關重要,例如,根據更大資料集的預訓練模型通常能帶來更好的效能。
轉移學習與微調: 轉移學習如同讓LLM站在巨人的肩膀上,利用先前學習的知識來加速新任務的學習。微調則是在此基礎上,針對特定任務進行更精細的調整,如同打磨寶石,使其更加璀璨。
硬體考量: 硬體資源如同LLM的燃料,需要根據實際情況調整引數,例如在記憶體受限的環境中使用較小的batch size,並利用平行處理等技術提高效率。
超引數搜尋: 超引數如同LLM的控制枱,需要找到最佳的組合才能發揮其最大效能。常用的搜尋方法包括網格搜尋、隨機搜尋和貝葉斯最佳化。
驗證與評估: 驗證和評估如同LLM的體檢,用於檢測其在不同資料集上的表現,確保其泛化能力和穩定性。
推論與文字生成超引數
在使用LLM進行推論或文字生成時,以下超引數至關重要:
flowchart LR D[D] A["低溫 (τ < 1)"] --> B{"更專注、更精確"} A --> C["高溫 (τ > 1)"] C --> D{"更多樣、更具創造力"}
溫度 (τ): 溫度控制LLM的創造力。低溫下,LLM傾向於選擇最可能的詞彙,輸出更專注、更精確;高溫下,LLM更具探索性,輸出更多樣、更具創造力。
Top P (核心抽樣) 與 Top K: 這兩個引數控制LLM的詞彙選擇範圍。Top P根據累積機率選擇詞彙,Top K則選擇前K個最可能的詞彙。
最大長度: 限制LLM輸出長度,避免過於冗長或離題。
停止序列: 設定特定的詞彙或片語作為停止訊號,控制LLM的輸出終點。
頻率懲罰與存在懲罰: 這兩個引數用於控制LLM的詞彙重複率。頻率懲罰降低重複詞彙的出現機率,存在懲罰則鼓勵LLM使用新詞彙。
以上引數就像樂器的旋鈕,不同的組合會產生不同的效果。理解這些引數的相互作用,才能像指揮家一樣,調控LLM,奏出美妙的樂章。
上下文視窗:LLM 的記憶力
大語言模型的「上下文視窗」如同人類的短期記憶,決定了它能一次處理多少資訊。更大的上下文視窗允許 LLM 參考更多上下文,從而生成更連貫、更符合邏輯的文字。
例如,GPT-4 的 128k 上下文視窗和 Gemini 1.5 Pro 的 200 萬 tokens,讓它們能處理長篇檔案、進行更深入的推理,並展現更強的理解力。相比之下,較小的上下文視窗限制了 LLM 的視野,使其更適合處理簡短的查詢或任務。
微調的應用
透過調整這些引數,我們可以針對不同任務最佳化 LLM 的效能,例如:
- 情感分析: 調整溫度和 Top P 可以控制 LLM 對情感的敏感度。
- 問答系統: 調整 Top K 可以限制答案的範圍,提高準確性。
- 聊天機器人: 調整頻率懲罰和存在懲罰可以使對話更自然流暢。
- 機器翻譯: 調整模型架構和訓練資料可以提高翻譯的準確性和流暢度。
透過精細的微調,我們可以將 LLM 開發成更強大的工具,應用於更廣泛的領域。
from pathlib import Path
from langchain.chains import RetrievalQA
from transformers import AutoTokenizer, pipeline
from langchain.prompts import ChatPromptTemplate
from langchain.vectorstores.chroma import Chroma
from langchain_huggingface import HuggingFacePipeline
from langchain.schema.output_parser import StrOutputParser
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
# 設定資料目錄路徑
data_dir = Path(__file__).resolve().parent / "data" / "pdfs" # 使用更簡潔的 pathlib
data_dir.mkdir(parents=True, exist_ok=True) # 建立目錄,若已存在則不動作
# 向量資料函式庫和模型快取目錄
vector_db_dir = Path(__file__).resolve().parent / "chroma_db"
model_cache_dir = Path(__file__).resolve().parent / "models"
# 載入資料 - 示範程式碼,實際使用需替換成你的資料載入方式
# 這裡建立一個空的範例檔案,避免 DirectoryLoader 出錯
(data_dir / "example.pdf").touch()
loader = DirectoryLoader(str(data_dir), glob="*.pdf")
# 分割文字
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
pages = loader.load_and_split(text_splitter=text_splitter)
# 載入向量嵌入模型
embed_model = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-MiniLM-l6-v2",
cache_folder=str(model_cache_dir),
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": False},
)
# 儲存向量嵌入
chroma_db = Chroma.from_documents(pages, embed_model, persist_directory=str(vector_db_dir))
# 定義檢索器
retriever = chroma_db.as_retriever(search_type="mmr", search_kwargs={"k": 8})
# 載入 LLM 模型
dolly_generate_text = pipeline(
model="databricks/dolly-v2-3b",
trust_remote_code=True,
device_map="auto",
return_full_text=True,
tokenizer=AutoTokenizer.from_pretrained("databricks/dolly-v2-3b", cache_dir=str(model_cache_dir)),
temperature=0.1,
max_new_tokens=1000,
model_kwargs={"cache_dir": str(model_cache_dir)}, # offload_folder 通常不需要,除非記憶體不足
)
dolly_pipeline_hf = HuggingFacePipeline(pipeline=dolly_generate_text)
# 設定問題範本 - 使用更簡潔的寫法
prompt = ChatPromptTemplate.from_template("根據以下上下文回答問題:\n{context}\n問題:{question}")
# 根據自定義資料問答
retrievalQA = RetrievalQA.from_chain_type(llm=dolly_pipeline_hf, chain_type="stuff", retriever=retriever, chain_type_kwargs={"prompt": prompt})
# 測試問答 - 使用更具體的範例問題和上下文
# 因為範例程式碼沒有實際資料,這裡的測試只演示流程,不會得到有意義的答案
query = "台灣的首都是哪裡?"
result = retrievalQA({"query": query})
print(f"問題:{query}\n答案:{result['result']}")
這段程式碼展現瞭如何使用 LangChain 和 Hugging Face Transformers 建立一個根據自定義資料的問答系統。
核心步驟解析:
- 資料載入與處理: 使用
DirectoryLoader
載入指定目錄下的 PDF 檔案,並使用RecursiveCharacterTextSplitter
將檔案分割成適合 LLM 處理的區塊。此步驟至關重要,因為它確保資料以最佳方式呈現給模型。 - 向量嵌入: 使用
HuggingFaceEmbeddings
將文字區塊轉換為向量表示。這一步驟將文字資訊轉換為數值形式,以便於向量資料函式庫進行相似度搜尋。 - 向量資料函式庫: 使用
Chroma
建立向量資料函式庫,並將向量化的文字區塊儲存其中。向量資料函式庫允許高效的相似度搜尋,以便快速找到與問題相關的資訊。 - 檢索器: 使用
Chroma.as_retriever
建立檢索器,用於從向量資料函式庫中檢索與問題相關的文字區塊。search_type="mmr"
使用最大邊際相關性搜尋,以確保檢索到的文字區塊既相關又多樣。 - LLM 模型: 使用
HuggingFacePipeline
載入 Dolly V2 3B 模型。LLM 負責根據檢索到的文字區塊生成答案。 - 問題範本: 使用
ChatPromptTemplate
建立問題範本,將上下文和問題清晰地呈現給 LLM。 - 問答鏈: 使用
RetrievalQA.from_chain_type
建立問答鏈,將檢索器和 LLM 連線起來,形成完整的問答流程。chain_type="stuff"
表示將所有檢索到的文字區塊都放入 LLM 的 prompt 中。 - 測試與輸出: 使用範例問題測試問答系統,並印出結果。
改進説明:
- 使用
pathlib
簡化路徑操作,使程式碼更清晰易讀。 - 新增了資料目錄和快取目錄的建立,提高程式碼的健壯性。
- 使用更簡潔的 prompt 範本定義方式。
- 使用
RetrievalQA.from_chain_type
更靈活地控制問答鏈的行為。 - 提供了更詳細的程式碼註解,解釋每個步驟的用途和原理。
- 使用更具體的範例問題和上下文進行測試。
後續步驟:
- 替換範例資料載入程式碼,使用你的實際資料。
- 根據你的需求調整
chunk_size
、k
值和 LLM 引數。 - 嘗試不同的向量資料函式庫和 LLM 模型,以找到最佳組合。
graph LR C[C] F[F] A[載入資料] --> B(分割文字) --> C{向量嵌入} C --> D[儲存至 Chroma 向量資料函式庫] E[使用者提問] --> F{檢索相關資訊} F --> G[Dolly V2 3B 生成答案] --> H[輸出結果]
圖表説明: 此流程圖展示了資料處理、向量化、儲存、檢索和答案生成的完整流程。
這個改良版的程式碼和説明提供了更清晰、更完整的問答系統構建,並包含了更多實用的技巧和建議。