
社群是國內外知名的機器學習與自然語言處理社群,受眾覆蓋國內外NLP碩博生、高校老師以及企業研究人員。
開門見山,直接給大家展示微調前後的效果。
微調前:

微調後:

在此處可以看到很明顯大模型進行微調後口吻已經發生了更改。據筆者使用下來的記錄表示,微調後的大模型思考時間更加短暫。
接下來,讓我們一起逐步完成微調實踐,共同最佳化模型效能!
一、什麼是大模型微調?
微調就像給一個“學霸”補課,讓它從“通才”變成某個領域的“專家”。
此處以本文進行微調的醫學資料進行舉例: 假設你有一個很聰明的朋友,他讀過全世界的書(相當於大模型的預訓練階段),能和你聊歷史、科學、文學等各種話題。 但如果你需要他幫你看醫學報告段),能和你聊歷史、科學、文學等各種話題。 但如果你需要他幫你看醫學報告,雖然他懂一些基礎知識,但可能不夠專業。這時候,你給他一堆醫學書籍和病例,讓他專門學習這方面的知識(這就是微調),他就會變得更擅長醫療領域的問題。
📖 故事解釋:
想象你有一個會畫小貓的機器人🤖(這就是預訓練模型)。現在你想讓它學會畫戴帽子的小貓🎩🐱。不需要從頭教它畫畫,只需要給它看很多"戴帽子小貓"的圖片,然後說:"保持原來的畫畫能力,但要學會加帽子哦!" 這就是微調!
📖 生活案例解釋:
案例1:智慧音箱調方言
-
基礎版音箱只會普通話(預訓練模型) -
給它聽 100 句四川話(微調資料) -
現在能聽懂"擺龍門陣"(方言理解能力↑)
案例2:相機濾鏡原理
-
原始相機拍所有場景(通用模型) -
載入“美食濾鏡”引數(微調後的模型) -
拍食物時自動增強飽和度(專業能力強化)
加強版解釋:樂高城堡改造成兒童醫院
第一步:原有結構 —— 通用樂高城堡
[通用城堡]
▸ 比喻:就像網購的"標準款城堡積木套裝",有城牆、塔樓、尖頂,能當普通房子用。
▸ 對應技術:預訓練模型(比如 ChatGPT),已經學會通用語言能力,但不夠專業。
第二步:區域性改造 —— 低成本改裝
① 拆尖頂 → 改圓頂
[尖頂改圓頂]
▸ 操作:把塔頂的尖積木換成圓積木,更溫和可愛。
▸ 技術含義:微調模型頂層引數(比如修改分類頭),讓輸出風格更適合兒童對話。
② 加裝旋轉門[旋轉門]
▸ 操作:在門口插入一個可旋轉的積木模組,不破壞原有門結構。
▸ 技術含義:插入介面卡模組(Adapter),讓模型新增兒科醫學術語理解能力,且不干擾原有知識。
③ 塗裝醫院標誌
[醫院標誌]
▸ 操作:在城堡外牆貼上"十字元號"和卡通動物貼紙。
▸ 技術含義:特徵空間偏移(Feature Shift),調整模型內部表示,讓它更關注醫療相關詞彙和童趣表達。
第三步:新功能 —— 變身兒童醫院
[兒童醫院]
▸ 成果:改裝後的城堡能接待小患者,有玩具區、溫和的醫生(圓頂),還有專用醫療裝置(旋轉門)。
▸ 技術含義:透過輕量改造,通用模型變成"兒科醫療問答機器人",專精兒童健康諮詢。
二、當前嘗試過的硬體配置
顯示卡:NVIDIA GeForce RTX 4060
CPU:Intel Core i7-13700H
記憶體:16 G(因為家庭電腦所以日常狀態是 8.8/15.7 GB)
三、微調工作
(1) 資料集準備
本文資料集來源,魔搭社群的 medical-o1-reasoning-SFT。
本文主要說明,資料集格式是:

在 DeepSeek 的蒸餾模型微調過程中,資料集中引入 Complex_CoT(複雜思維鏈)是關鍵設計差異。若僅使用基礎問答對進行訓練,模型將難以充分習得深度推理能力,導致最終效能顯著低於預期水平。這一特性與常規大模型微調的資料要求存在本質區別。

(2) 模型微調程式碼(此處是無框架純手搓)——直接上了,後面會有細節講解
需要引入的庫:
pipinstall torch transformers peft datasets matplotlib accelerate safetensors
import torch
import matplotlib.pyplot as plt
from transformers import (
AutoTokenizer,
AutoModelForCausalLM,
TrainingArguments,
Trainer,
TrainerCallback
)
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
import os
# 配置路徑(根據實際路徑修改)
model_path = r"你的模型路徑"# 模型路徑
data_path = r"你的資料集路徑"# 資料集路徑
output_path = r"你的儲存微調後的模型路徑"# 微調後模型儲存路徑
# 強制使用GPU
assert torch.cuda.is_available(), //"必須使用GPU進行訓練!"
device = torch.device("cuda")
# 自定義回撥記錄Loss
classLossCallback(TrainerCallback):
def__init__(self):
self.losses = []
defon_log(self, args, state, control, logs=None, **kwargs):
if"loss"in logs:
self.losses.append(logs["loss"])
# 資料預處理函式
defprocess_data(tokenizer):
dataset = load_dataset("json", data_files=data_path, split="train[:1500]")
defformat_example(example):
instruction = f"診斷問題:{example['Question']}\n詳細分析:{example['Complex_CoT']}"
inputs = tokenizer(
f"{instruction}\n### 答案:\n{example['Response']}<|endoftext|>",
padding="max_length",
truncation=True,
max_length=512,
return_tensors="pt"
)
return {"input_ids": inputs["input_ids"].squeeze(0), "attention_mask": inputs["attention_mask"].squeeze(0)}
return dataset.map(format_example, remove_columns=dataset.column_names)
# LoRA配置
peft_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# 訓練引數配置
training_args = TrainingArguments(
output_dir=output_path,
per_device_train_batch_size=2, # 視訊記憶體最佳化設定
gradient_accumulation_steps=4, # 累計梯度相當於batch_size=8
num_train_epochs=3,
learning_rate=3e-4,
fp16=True, # 開啟混合精度
logging_steps=20,
save_strategy="no",
report_to="none",
optim="adamw_torch",
no_cuda=False, # 強制使用CUDA
dataloader_pin_memory=False, # 加速資料載入
remove_unused_columns=False# 防止刪除未使用的列
)
defmain():
# 建立輸出目錄
os.makedirs(output_path, exist_ok=True)
# 載入tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_path)
tokenizer.pad_token = tokenizer.eos_token
# 載入模型到GPU
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float16,
device_map={"": device} # 強制使用指定GPU
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
# 準備資料
dataset = process_data(tokenizer)
# 訓練回撥
loss_callback = LossCallback()
# 資料載入器
defdata_collator(data):
batch = {
"input_ids": torch.stack([torch.tensor(d["input_ids"]) for d in data]).to(device),
"attention_mask": torch.stack([torch.tensor(d["attention_mask"]) for d in data]).to(device),
"labels": torch.stack([torch.tensor(d["input_ids"]) for d in data]).to(device) # 使用input_ids作為labels
}
return batch
# 建立Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=data_collator,
callbacks=[loss_callback]
)
# 開始訓練
print("開始訓練...")
trainer.train()
# 儲存最終模型
trainer.model.save_pretrained(output_path)
print(f"模型已儲存至:{output_path}")
# 繪製訓練集損失Loss曲線
plt.figure(figsize=(10, 6))
plt.plot(loss_callback.losses)
plt.title("Training Loss Curve")
plt.xlabel("Steps")
plt.ylabel("Loss")
plt.savefig(os.path.join(output_path, "loss_curve.png"))
print("Loss曲線已儲存")
if __name__ == "__main__":
main()
(3) 程式碼詳細講解
1. 匯入必要的庫和模組
功能總結:匯入專案依賴的第三方庫,包括 PyTorch 基礎庫、HuggingFace 工具庫、視覺化庫等。
import torch
import matplotlib.pyplot as plt
from transformers import ( # HuggingFace Transformer模型工具
AutoTokenizer,
AutoModelForCausalLM,
TrainingArguments,
Trainer,
TrainerCallback
)
from peft import LoraConfig, get_peft_model # 引數高效微調庫
from datasets import load_dataset # 資料集載入工具
import os # 系統路徑操作
有關類庫介紹:
1. torch (PyTorch 庫的核心模組)
-
功能:深度學習框架,提供張量計算和神經網路構建功能。 -
程式碼中的作用: -
管理GPU裝置 (torch.cuda.is_available() 檢查GPU可用性) -
定義模型訓練時的張量操作 -
控制混合精度訓練 (torch.float16)
2. matplotlib.pyplot (Matplotlib 繪相簿)
-
功能:資料視覺化工具庫。 -
程式碼中的作用: -
繪製訓練損失曲線 (plt.plot(losses)) -
生成並儲存訓練過程的Loss變化圖 (loss_curve.png)
3. transformers (HuggingFace Transformers 庫)
-
核心元件: -
AutoTokenizer:自動載入預訓練模型對應的分詞器 -
用於將文字轉換為模型可理解的 token ID 序列 -
AutoModelForCausalLM:自動載入因果語言模型(如GPT系列) -
提供基礎的大語言模型結構 -
TrainingArguments:定義訓練超引數 -
控制批次大小、學習率、日誌頻率等 -
Trainer:封裝訓練流程的類 -
自動處理訓練迴圈、梯度下降、日誌記錄等 -
TrainerCallback:訓練回撥基類 -
用於實現自定義訓練監控邏輯(如示例中的損失記錄)
4. peft (Parameter-Efficient Fine-Tuning)
-
功能:實現引數高效微調方法的庫。 -
核心元件: -
LoraConfig:LoRA(Low-Rank Adaptation)的配置類 -
定義秩(r)、目標模組(target_modules)等關鍵引數 -
get_peft_model:將基礎模型轉換為 PEFT 模型 -
僅需訓練原模型約 0.1% 的引數即可實現有效微調 -
程式碼中的作用: -
對 LLaMA 等大模型進行輕量化微調 -
視訊記憶體佔用量減少約 60-70%,適合消費級 GPU
5. datasets (HuggingFace Datasets 庫)
-
功能:高效資料集載入與處理工具。 -
核心方法: -
load_dataset:載入多種格式的資料 -
支援 JSON/CSV/Parquet 等格式(示例中使用 JSON) -
map:資料預處理流水線 -
應用自定義的格式化函式 (format_example) -
程式碼中的作用: -
從本地檔案載入醫療問答資料集 -
將原始資料轉換為模型需要的輸入格式
6. os (作業系統介面)
-
功能:提供作業系統相關功能。 -
程式碼中的作用: -
建立輸出目錄 (os.makedirs) -
處理檔案路徑相關操作 -
確保模型儲存路徑的有效性
2. 配置路徑和硬體檢查
功能總結:配置模型/資料路徑,強制檢查GPU可用性
# 配置路徑(根據實際路徑修改)
model_path = r"你的模型路徑"# 預訓練模型存放路徑
data_path = r"你的資料集路徑"# 訓練資料路徑(JSON格式)
output_path = r"你的儲存微調後的模型路徑"# 微調後模型儲存位置
# 強制使用GPU(確保CUDA可用)
assert torch.cuda.is_available(), "必須使用GPU進行訓練!"
device = torch.device("cuda") # 指定使用CUDA裝置
3.自定義訓練回撥類
功能總結:實現自定義回撥,在模型訓練過程中,即時記錄損失值(Loss)的變化。損失值是用來衡量模型預測結果與真實結果之間的差距的,損失值越小,說明模型的表現越好。
classLossCallback(TrainerCallback):
def__init__(self):
self.losses = [] # 儲存損失值的列表
# 當訓練過程中有日誌輸出時觸發
defon_log(self, args, state, control, logs=None, **kwargs):
if"loss"inlogs:# 過濾並記錄損失值
self.losses.append(logs["loss"])
4. 資料預處理函式
功能總結:載入並格式化訓練資料,將原始資料集轉換為模型可以理解的格式。
defprocess_data(tokenizer):
# 從JSON檔案載入資料集(僅取前1500條)
dataset = load_dataset("json", data_files=data_path, split="train[:1500]")
# 單條資料格式化函式
defformat_example(example):
# 拼接指令和答案(固定模板)
instruction = f"診斷問題:{example['Question']}\n詳細分析:{example['Complex_CoT']}"
inputs = tokenizer(
f"{instruction}\n### 答案:\n{example['Response']}<|endoftext|>", # 新增結束符
padding="max_length", # 填充至最大長度
truncation=True, # 超長截斷
max_length=512, # 最大序列長度
return_tensors="pt"# 返回PyTorch張量
)
# 返回處理後的輸入(移除batch維度)
return {"input_ids": inputs["input_ids"].squeeze(0),
"attention_mask": inputs["attention_mask"].squeeze(0)}
# 應用格式化函式並移除原始列
return dataset.map(format_example, remove_columns=dataset.column_names)
關鍵程式碼
1.拼接指令和答案
-
作用:將問題(Question)和詳細分析(Complex_CoT)拼接成一個指令。 -
示例: -
輸入:Question="發燒怎麼辦?", Complex_CoT="可能是感冒引起的。" -
輸出:"診斷問題:發燒怎麼辦?\n詳細分析:可能是感冒引起的。" -
類比:就像把問題和分析寫在一張紙上。
instruction = f"診斷問題:{example['Question']}\n詳細分析:{example['Complex_CoT']}"
2.使用分詞器處理文字
-
作用:將拼接後的文字轉換為模型可以理解的格式。 -
引數說明: -
padding="max_length":將文字填充到固定長度(512)。 -
truncation=True:如果文字超過 512 個 token,就截斷。 -
max_length=512:最大長度為 512。 -
return_tensors="pt":返回 PyTorch 張量。 -
示例: -
輸入:"診斷問題:發燒怎麼辦?\n詳細分析:可能是感冒引起的。\n### 答案:\n多喝水,休息。" -
輸出:input_ids=[101, 234, 345, …, 102], attention_mask=[1, 1, 1, …, 1] -
類比:就像把文字翻譯成機器能懂的數字。
inputs = tokenizer(
f"{instruction}\n### 答案:\n{example['Response']}<|endoftext|>", # 新增結束符
padding="max_length", # 填充至最大長度
truncation=True, # 超長截斷
max_length=512, # 最大序列長度
return_tensors="pt"# 返回PyTorch張量
)
3.返回處理後的輸入
-
作用:返回處理後的輸入資料,並移除多餘的維度。 -
引數說明: -
input_ids:文字對應的 token ID 序列。 -
attention_mask:標記哪些位置是有效 token(1 表示有效,0 表示填充)。 -
類比:就像把翻譯好的數字整理成一張表格。
return {"input_ids": inputs["input_ids"].squeeze(0),
"attention_mask": inputs["attention_mask"].squeeze(0)}
- 4.應用格式化函式
-
作用:對整個資料集應用格式化函式,並移除原始列。 -
引數說明: -
format_example:格式化函式。 -
remove_columns=dataset.column_names:移除原始列(如 Question、Complex_CoT 等)。 -
類比:就像把整本書的每一頁都翻譯成機器能懂的格式。
return dataset.map(format_example, remove_columns=dataset.column_names)
- 5. LoRA微調配置
功能總結:配置LoRA引數,指定要適配的模型模組。
peft_config = LoraConfig(
r=16, # LoRA秩(矩陣分解維度)
lora_alpha=32, # 縮放係數(控制介面卡影響強度)
target_modules=["q_proj", "v_proj"], # 要適配的注意力模組(查詢/值投影)
lora_dropout=0.05, # 防止過擬合的Dropout率
bias="none", # 不訓練偏置引數
task_type="CAUSAL_LM"# 任務型別(因果語言模型)
)
1. r=16:LoRA 的秩
-
作用:控制低秩矩陣的維度。秩越小,引數越少,計算量越小。 -
解釋: -
秩(r)是低秩矩陣的分解維度,決定了低秩矩陣的大小。 -
例如,r=16 表示低秩矩陣的維度是 16。 -
影響: -
較小的 r 會減少引數量,但可能會降低模型的表現。 -
較大的 r 會增加引數量,但可能會提高模型的表現。 -
比喻:
"相當於給AI的‘學習筆記’設定 16 頁的篇幅限制"
→ 頁數少(r小):學得快但可能漏細節
→ 頁數多(r大):學得細但速度慢
-
預設值:通常設定為 8 或 16。並非越大越好。LoRA 秩的選擇需要平衡模型的適應能力和計算效率。較大的秩可以提供更強的表達能力,但會增加計算量和視訊記憶體佔用,同時可能導致過擬合。對於簡單任務,通常推薦使用較小的秩(如 4 或 8),而對於複雜任務,可能需要更高的秩(如 16 或 32)
2. lora_alpha=32:縮放係數
-
作用:控制低秩矩陣對原始模型的影響強度。 -
解釋: -
lora_alpha 是一個縮放因子,用於調整低秩矩陣的輸出。 -
具體來說,低秩矩陣的輸出會乘以 lora_alpha / r。 -
影響: -
較大的 lora_alpha 會讓低秩矩陣的影響更強。 -
較小的 lora_alpha 會讓低秩矩陣的影響更弱。 -
比喻:
就像是,音量旋鈕的大小決定了聲音的響亮程度。如果旋鈕轉得太大,聲音可能會震耳欲聾,甚至讓人難以忍受;如果旋鈕轉得太小,聲音又可能太小,聽不清楚。
過大的 lora_alpha 可能會導致模型的訓練變得不穩定,就像聲音太大可能會讓人感到不適一樣。可能會導致過擬合,因為模型對訓練資料的細節調整過於敏感。
較小的 lora_alpha 會導致模型在訓練過程中會更保守地調整權重,訓練過程更穩定,但適應新任務的速度可能會較慢。
-
預設值:通常設定為 32。
3. target_modules=["q_proj", "v_proj"]:目標模組
-
作用:指定需要插入低秩矩陣的模型模組。 -
解釋: -
q_proj 和 v_proj 是 Transformer 模型中的注意力機制模組: -
q_proj:查詢(Query)投影矩陣。 -
v_proj:值(Value)投影矩陣。 -
LoRA 會在這兩個模組中插入低秩矩陣。 -
影響: -
選擇不同的模組會影響微調的效果。 -
通常選擇 q_proj 和 v_proj 是因為它們對模型的表現影響較大。
4. lora_dropout=0.05:Dropout 率
-
作用:防止過擬合。 -
解釋: -
Dropout 是一種正則化技術,隨機丟棄一部分神經元,防止模型過度依賴某些特徵。 -
lora_dropout=0.05 表示在訓練過程中,有 5% 的低秩矩陣引數會被隨機丟棄。 -
影響: -
較大的 Dropout 率會增加模型的魯棒性,但可能會降低訓練效率。 -
較小的 Dropout 率會減少正則化效果,但可能會提高訓練速度。
5. bias="none":偏置引數
-
作用:控制是否訓練偏置引數。偏置引數的作用是為模型的輸出提供一個基線偏移(baseline offset),使得模型能夠更好地擬合數據。 -
解釋: -
bias="none" 表示不訓練偏置引數。 -
其他選項包括 "all"(訓練所有偏置引數)和 "lora_only"(只訓練 LoRA 相關的偏置引數)。 -
影響: -
不訓練偏置引數可以減少引數量,但可能會影響模型的表現。
6. task_type="CAUSAL_LM":任務型別
-
作用:指定任務型別。 -
解釋: -
CAUSAL_LM 表示因果語言模型(Causal Language Model),即生成式任務(如 GPT)。 -
其他任務型別包括序列分類(SEQ_CLS)、序列到序列(SEQ_2_SEQ)等。 -
影響: -
不同的任務型別會影響 LoRA 的實現方式。
訓練引數配置
功能總結:設定訓練超引數和硬體相關選項。
training_args = TrainingArguments(
output_dir=output_path, # 輸出目錄(模型/日誌)
per_device_train_batch_size=2, # 單GPU批次大小(視訊記憶體最佳化)
gradient_accumulation_steps=4, # 梯度累積步數(等效batch_size=8)
num_train_epochs=3, # 訓練輪次
learning_rate=3e-4, # 初始學習率
fp16=True, # 啟用混合精度訓練(節省視訊記憶體)
logging_steps=20, # 每隔20步記錄日誌
save_strategy="no", # 不儲存中間檢查點
report_to="none", # 停用第三方報告(如W&B)
optim="adamw_torch", # 最佳化器型別
no_cuda=False, # 強制使用CUDA
dataloader_pin_memory=False, # 停用鎖頁記憶體(加速資料載入)
remove_unused_columns=False# 保留未使用的列(避免資料錯誤)
)
1. output_dir=output_path:輸出目錄
-
作用:指定訓練過程中模型和日誌的儲存路徑。此處的 output_path 之前已經寫在了最前面的變數之中。 -
解釋: -
訓練過程中生成的模型檢查點、日誌檔案等都會儲存到這個目錄。 -
示例: -
如果 output_path = "./output",所有檔案都會儲存到 ./output 目錄下。
2. per_device_train_batch_size=2:單 GPU 批次大小
-
作用:設定每個 GPU 上的訓練批次大小。 -
解釋: -
批次大小是指每次輸入模型的樣本數量。 -
較小的批次大小可以節省視訊記憶體,但可能會降低訓練速度。 -
示例: -
如果使用 1 個 GPU,每次訓練會輸入 2 條資料。
3. gradient_accumulation_steps=4:梯度累積步數

4. num_train_epochs=3:訓練輪次
-
作用:設定模型在整個資料集上訓練的輪次。 -
解釋: -
1個輪次(epoch)表示模型完整地遍歷一次訓練資料集。 -
這裡設定為 3,表示模型會訓練 3 輪。 -
示例: -
如果資料集有 1000 條資料,模型會遍歷這 1000 條資料 3 次。
5. learning_rate=3e-4:初始學習率

6. fp16=True:混合精度訓練
-
作用:啟用混合精度訓練,節省視訊記憶體並加速訓練。 -
解釋: -
混合精度訓練是指同時使用 16 位(半精度)和 32 位(單精度)浮點數。 -
16 位浮點數佔用更少的視訊記憶體,計算速度更快。 -
示例: -
如果視訊記憶體不足,啟用 fp16 可以顯著減少視訊記憶體佔用。
7. logging_steps=20:日誌記錄頻率
-
作用:設定每隔多少步記錄一次日誌。 -
解釋: -
日誌包括損失值、學習率等資訊。 -
這裡設定為 20,表示每隔 20 步記錄一次日誌。 -
示例: -
如果總訓練步數是 1000,會記錄 50 次日誌(1000 / 20 = 50)。
8. save_strategy="no":儲存策略
-
作用:設定是否儲存中間檢查點。 -
解釋: -
"no" 表示不儲存中間檢查點。 -
其他選項包括 "epoch"(每輪儲存一次)和 "steps"(每隔一定步數儲存一次)。 -
示例: -
如果設定為 "epoch",每輪訓練結束後會儲存一次模型。
9. report_to="none":停用第三方報告
-
作用:停用第三方日誌報告工具(如Weights & Biases)。 -
解釋: -
如果不需要使用第三方工具記錄日誌,可以設定為 "none"。 -
示例: -
如果設定為 "wandb",日誌會同步到 Weights & Biases平臺。
10. optim="adamw_torch":最佳化器型別
-
作用:指定最佳化器型別。 -
解釋: -
adamw_torch 是一種常用的最佳化器,結合了 Adam 和權重衰減(Weight Decay)。 -
適合大多數深度學習任務。 -
示例: -
如果訓練不穩定,可以嘗試其他最佳化器,如 sgd[Stochastic Gradient Descent(隨機梯度下降]。SGD 是一種用於最佳化模型引數的演算法,透過計算損失函式的梯度並更新引數,使損失函式最小化。
11. no_cuda=False:強制使用 CUDA
-
作用:強制使用 GPU 進行訓練。 -
解釋: -
no_cuda=False 表示使用 GPU。 -
如果設定為 True,則會使用 CPU(不推薦)。 -
示例: -
如果GPU可用,模型會自動使用 GPU 進行訓練。
12. dataloader_pin_memory=False:停用鎖頁記憶體
-
作用:設定是否使用鎖頁記憶體(Pinned Memory)加速資料載入。 -
解釋: -
鎖頁記憶體可以提高資料載入速度,但會佔用更多主機記憶體。 -
這裡設定為 False,表示停用鎖頁記憶體。 -
示例: -
如果主機記憶體充足,可以設定為 True 以加速訓練。
13. remove_unused_columns=False:保留未使用的列
-
作用:設定是否移除資料集中未使用的列。 -
解釋: -
如果設定為 True,會移除資料集中未被模型使用的列。 -
這裡設定為 False,表示保留所有列。 -
示例: -
如果資料集中包含一些額外的資訊(如 ID),可以保留這些列。
主函式(訓練流程)
功能總結:整合所有元件,執行完整訓練流程。
defmain():
# 建立輸出目錄(如果不存在)
os.makedirs(output_path, exist_ok=True)
# 載入Tokenizer並設定填充符
tokenizer = AutoTokenizer.from_pretrained(model_path)
tokenizer.pad_token = tokenizer.eos_token # 使用EOS作為填充符
# 載入預訓練模型(半精度+指定GPU)
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float16, # 半精度載入(節省視訊記憶體)
device_map={"": device} # 指定使用的GPU裝置
)
# 應用LoRA介面卡
model = get_peft_model(model, peft_config)
model.print_trainable_parameters() # 列印可訓練引數量
# 準備訓練資料集
dataset = process_data(tokenizer)
# 初始化損失記錄回撥
loss_callback = LossCallback()
# 資料整理函式(構造批次)
defdata_collator(data):
batch = {
"input_ids": torch.stack([torch.tensor(d["input_ids"]) for d in data]).to(device),
"attention_mask": torch.stack([torch.tensor(d["attention_mask"]) for d in data]).to(device),
"labels": torch.stack([torch.tensor(d["input_ids"]) for d in data]).to(device) # 標籤=輸入(因果LM任務)
}
return batch
# 初始化Trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=data_collator, # 自定義資料整理
callbacks=[loss_callback] # 添加回調
)
# 執行訓練
print("開始訓練...")
trainer.train()
# 儲存微調後的模型
trainer.model.save_pretrained(output_path)
print(f"模型已儲存至:{output_path}")
# 繪製損失曲線
plt.figure(figsize=(10, 6))
plt.plot(loss_callback.losses)
plt.title("Training Loss Curve")
plt.xlabel("Steps")
plt.ylabel("Loss")
plt.savefig(os.path.join(output_path, "loss_curve.png")) # 儲存為PNG
print("Loss曲線已儲存")
if __name__ == "__main__":
main()
關鍵程式碼:
1. 載入 Tokenizer 並設定填充符
-
作用:載入預訓練模型的分詞器,並設定填充符。 -
解釋: -
AutoTokenizer.from_pretrained:自動載入與模型匹配的分詞器。 -
tokenizer.pad_token = tokenizer.eos_token:將結束符(EOS)作為填充符(Pad Token)。 -
示例: -
如果輸入序列長度不足,會用 EOS 填充。
tokenizer = AutoTokenizer.from_pretrained(model_path)
tokenizer.pad_token = tokenizer.eos_token # 使用EOS作為填充符
- 2.載入預訓練模型
-
作用:載入預訓練的語言模型,並配置硬體相關設定。 -
解釋: -
AutoModelForCausalLM.from_pretrained:載入因果語言模型(如 GPT)。 -
torch_dtype=torch.float16:使用半精度(16 位浮點數)載入模型,節省視訊記憶體。 -
device_map={"": device}:將模型載入到指定的 GPU 裝置上。 -
示例: -
如果 device = "cuda:0",模型會載入到第一個 GPU 上。
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float16, # 半精度載入(節省視訊記憶體)
device_map={"": device} # 指定使用的GPU裝置
)
- 3.資料整理函式
-
作用:將多條資料整理成一個批次。 -
解釋: -
input_ids:輸入序列的 token ID。 -
attention_mask:標記有效 token 的位置。 -
labels:因果語言模型的標籤與輸入相同(模型需要預測下一個 token)。 -
示例: -
如果輸入是 ["診斷問題:發燒怎麼辦?", "診斷問題:頭痛怎麼辦?"],會被整理成一個批次。
def data_collator(data):
batch = {
"input_ids": torch.stack([torch.tensor(d["input_ids"]) for d indata]).to(device),
"attention_mask": torch.stack([torch.tensor(d["attention_mask"]) for d indata]).to(device),
"labels": torch.stack([torch.tensor(d["input_ids"]) for d indata]).to(device) # 標籤=輸入(因果LM任務)
}
return batch
- 4.初始化 Trainer
-
作用:建立訓練器物件,管理訓練過程。 -
解釋: -
model:要訓練的模型。 -
args:訓練引數(如批次大小、學習率等)。 -
train_dataset:訓練資料集。 -
data_collator:自定義的資料整理函式。 -
callbacks:訓練回撥(如損失記錄)。
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
data_collator=data_collator, # 自定義資料整理
callbacks=[loss_callback] # 添加回調
)
四、完結感言
非常感謝 Deepseek 官網滿血版在本章的程式碼修改、資料收集以及文章潤色方面提供的寶貴幫助!
本章的微調部分目前還較為基礎,導致損失函式的收斂效果不夠理想,仍有較大的最佳化空間。例如,資料集構建可以更加精細化,程式碼結構也有待進一步最佳化和調整。我們非常期待各位小夥伴的寶貴建議和指正,讓我們共同進步,一起在 AI 學習的道路上探索更多樂趣!
技術交流群邀請函

△長按新增小助手
掃描二維碼新增小助手微信
關於我們
