零基礎入門:DeepSeek微調教程來了!

MLNLP

社群是國內外知名的機器學習與自然語言處理社群,受眾覆蓋國內外NLP碩博生、高校老師以及企業研究人員。


社群的願景是促進國內外自然語言處理,機器學習學術界、產業界和廣大愛好者之間的交流和進步,特別是初學者同學們的進步。
來源 | Datawhale
作者 | 吳錦鳳
開門見山,直接給大家展示微調前後的效果。
微調前:
微調後:
在此處可以看到很明顯大模型進行微調後口吻已經發生了更改。據筆者使用下來的記錄表示,微調後的大模型思考時間更加短暫。
接下來,讓我們一起逐步完成微調實踐,共同最佳化模型效能!

一、什麼是大模型微調?

微調就像給一個“學霸”補課,讓它從“通才”變成某個領域的“專家”。
此處以本文進行微調的醫學資料進行舉例: 假設你有一個很聰明的朋友,他讀過全世界的書(相當於大模型的預訓練階段),能和你聊歷史、科學、文學等各種話題。 但如果你需要他幫你看醫學報告段),能和你聊歷史、科學、文學等各種話題。 但如果你需要他幫你看醫學報告,雖然他懂一些基礎知識,但可能不夠專業。這時候,你給他一堆醫學書籍和病例,讓他專門學習這方面的知識(這就是微調),他就會變得更擅長醫療領域的問題。

📖 故事解釋:

想象你有一個會畫小貓的機器人🤖(這就是預訓練模型)。現在你想讓它學會畫戴帽子的小貓🎩🐱。不需要從頭教它畫畫,只需要給它看很多"戴帽子小貓"的圖片,然後說:"保持原來的畫畫能力,但要學會加帽子哦!" 這就是微調!

📖 生活案例解釋:

案例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 torchimport matplotlib.pyplot as pltfrom transformers import ( AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer, TrainerCallback)from peft import LoraConfig, get_peft_modelfrom datasets import load_datasetimport os# 配置路徑(根據實際路徑修改)model_path = r"你的模型路徑"# 模型路徑data_path = r"你的資料集路徑"# 資料集路徑output_path = r"你的儲存微調後的模型路徑"# 微調後模型儲存路徑# 強制使用GPUassert torch.cuda.is_available(), //"必須使用GPU進行訓練!"device = torch.device("cuda")# 自定義回撥記錄LossclassLossCallback(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 torchimport matplotlib.pyplot as pltfrom 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 學習的道路上探索更多樂趣!
技術交流群邀請函
△長按新增小助手
掃描二維碼新增小助手微信
請備註:姓名-學校/公司-研究方向
(如:小張-哈工大-對話系統)
即可申請加入自然語言處理/Pytorch等技術交流群

關於我們

MLNLP 社群是由國內外機器學習與自然語言處理學者聯合構建的民間學術社群,目前已經發展為國內外知名的機器學習與自然語言處理社群,旨在促進機器學習,自然語言處理學術界、產業界和廣大愛好者之間的進步。
社群可以為相關從業者的深造、就業及研究等方面提供開放交流平臺。歡迎大家關注和加入我們。

相關文章