療領(lǐng)域LoRA微調(diào)實戰(zhàn)指南)
簡介這份資源面向具備深度學(xué)習(xí)基礎(chǔ)、熟悉Python的AI研發(fā)與NLP技術(shù)人員聚焦如何借助LlamaFactory對Qwen2.5進行高效微調(diào)使其適配法律與醫(yī)療等垂直領(lǐng)域。內(nèi)容圍繞多模型兼容、LoRA與QLoRA參數(shù)高效微調(diào)、可視化界面及全流程監(jiān)控展開覆蓋環(huán)境搭建、數(shù)據(jù)收集與預(yù)處理、配置文件編寫、模型訓(xùn)練、效果評估到服務(wù)部署的完整鏈路并通過法律判斷與醫(yī)療診斷案例對比微調(diào)前后的性能提升。資源包為1個docx文檔約39KB以圖文形式系統(tǒng)梳理微調(diào)思路與配置示例便于讀者對照實踐。目前已有94人學(xué)習(xí)。讀者可從中掌握低成本、少資源條件下的大模型定制方法理解數(shù)據(jù)質(zhì)量與微調(diào)參數(shù)對效果的影響并獲取面向法律咨詢、合同審查、醫(yī)療輔助診斷等場景的落地參考與評估合規(guī)思路。1. 法律與醫(yī)療專家模型為什么通用 Qwen2.5 直接上場會翻車很多團隊第一次做垂直領(lǐng)域大模型路徑都差不多拿一個 Qwen2.5 的通用權(quán)重寫個系統(tǒng)提示詞告訴它“你是一名資深律師”或“你是一名三甲醫(yī)院主治醫(yī)師”然后直接上線。前幾輪演示看著還行一旦進入真實業(yè)務(wù)問題就集中爆發(fā)——法條引用張冠李戴、醫(yī)療建議含糊其辭、專業(yè)術(shù)語中英混雜、該保守的地方它開始自由發(fā)揮。這不是提示詞沒寫好而是通用模型的知識分布和表達習(xí)慣跟法律、醫(yī)療這兩個領(lǐng)域的實際要求差得太遠。法律和醫(yī)療是典型的“高門檻、強規(guī)范、低容錯”場景。法律文本講究條文編號、效力層級、構(gòu)成要件醫(yī)療文本講究診斷依據(jù)、用藥禁忌、劑量單位。這些內(nèi)容在通用語料里占比極低模型沒有足夠信號去學(xué)會。想讓 Qwen2.5 真正變成能用的專家模型就得走微調(diào)這條路。而 LlamaFactory 把微調(diào)的工程復(fù)雜度壓到了很低——它統(tǒng)一了數(shù)據(jù)格式、訓(xùn)練流程和適配器管理讓一線工程師不用從零寫訓(xùn)練循環(huán)就能把 LoRA 微調(diào)跑起來。這篇筆記面向的是想用 LlamaFactory 對 Qwen2.5 做領(lǐng)域微調(diào)的從業(yè)者你可能手頭有一批法律問答或醫(yī)療病歷數(shù)據(jù)想把它變成可復(fù)現(xiàn)的訓(xùn)練流程也可能剛接觸大模型微調(diào)需要一條能照著走通的最小路徑。下面從環(huán)境、數(shù)據(jù)、參數(shù)到排錯按實際落地順序拆開講。2. 用 LlamaFactory 跑通 Qwen2.5 微調(diào)環(huán)境、數(shù)據(jù)與最小命令2.1 環(huán)境準(zhǔn)備與 Qwen2.5 權(quán)重獲取LlamaFactory 對硬件的要求取決于模型規(guī)模和微調(diào)方式。Qwen2.5 有 0.5B、1.5B、3B、7B、14B、32B、72B 等多個尺寸。做法律或醫(yī)療領(lǐng)域微調(diào)7B 是性價比比較高的起點單張 24GB 顯存的卡用 LoRA 就能跑14B 以上建議多卡或量化。先確認(rèn)你的 CUDA 版本和 PyTorch 匹配然后裝 LlamaFactory。# 建議在獨立 conda 環(huán)境中操作避免依賴沖突 conda create -n llama_factory python3.10 -y conda activate llama_factory # 安裝 LlamaFactory從源碼裝方便后續(xù)改配置 git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip install -e .[torch,metrics] # 驗證安裝 llamafactory-cli version裝完之后Qwen2.5 的權(quán)重可以從 Hugging Face 或 ModelScope 拉取。國內(nèi)網(wǎng)絡(luò)環(huán)境建議用 ModelScope速度更穩(wěn)。權(quán)重目錄結(jié)構(gòu)要記清楚后面配置里要填絕對路徑。# 以 ModelScope 為例下載 Qwen2.5-7B-Instruct pip install modelscope python -c from modelscope import snapshot_download model_dir snapshot_download(Qwen/Qwen2.5-7B-Instruct) print(model_dir) 這里的關(guān)鍵參數(shù)是model_dir它會輸出權(quán)重落盤的實際路徑比如/root/.cache/modelscope/hub/Qwen/Qwen2.5-7B-Instruct。后面在 LlamaFactory 的配置里model_name_or_path就填這個路徑。不要填成模型名否則訓(xùn)練啟動時會去聯(lián)網(wǎng)拉取容易卡住。2.2 法律與醫(yī)療數(shù)據(jù)的組織格式LlamaFactory 支持 alpaca 和 sharegpt 兩種主流數(shù)據(jù)格式。法律和醫(yī)療場景我一般用 alpaca 格式因為它的instruction / input / output三段結(jié)構(gòu)剛好對應(yīng)“問題描述 補充背景 標(biāo)準(zhǔn)回答”。比如一條法律數(shù)據(jù)可以這樣組織[ { instruction: 根據(jù)《中華人民共和國民法典》相關(guān)規(guī)定分析下列合同糾紛中違約責(zé)任應(yīng)如何認(rèn)定。, input: 甲公司與乙公司簽訂買賣合同約定乙公司于2024年3月1日前交付貨物。乙公司因自身原因延遲至3月20日交付導(dǎo)致甲公司生產(chǎn)線停工5天。合同中未約定違約金條款。, output: 本案涉及合同違約責(zé)任認(rèn)定分析如下\n1. 違約事實乙公司未按約定期限交付貨物構(gòu)成遲延履行屬于違約行為。\n2. 法律依據(jù)《民法典》第五百七十七條規(guī)定當(dāng)事人一方不履行合同義務(wù)或者履行合同義務(wù)不符合約定的應(yīng)當(dāng)承擔(dān)繼續(xù)履行、采取補救措施或者賠償損失等違約責(zé)任。\n3. 損失賠償范圍根據(jù)第五百八十四條損失賠償額應(yīng)當(dāng)相當(dāng)于因違約所造成的損失包括合同履行后可以獲得的利益但不得超過違約方訂立合同時預(yù)見到或者應(yīng)當(dāng)預(yù)見到的因違約可能造成的損失。甲公司生產(chǎn)線停工5天的實際損失屬于可預(yù)見范圍。\n4. 結(jié)論乙公司應(yīng)賠償甲公司因停工產(chǎn)生的直接經(jīng)濟損失。由于合同未約定違約金甲公司需舉證實際損失金額。 } ]醫(yī)療數(shù)據(jù)同理instruction寫臨床問題input放患者基本信息與檢查結(jié)果output寫結(jié)構(gòu)化的分析意見。數(shù)據(jù)量方面法律領(lǐng)域我建議至少 2000 到 5000 條高質(zhì)量樣本醫(yī)療領(lǐng)域因為容錯更低建議 5000 條以上并且要經(jīng)過執(zhí)業(yè)醫(yī)師審核。數(shù)據(jù)質(zhì)量比數(shù)量重要得多一條錯誤的法律條文或醫(yī)療建議可能讓模型學(xué)會錯誤的模式。把整理好的數(shù)據(jù)放到 LlamaFactory 的data目錄下然后在dataset_info.json里注冊數(shù)據(jù)集名稱。這一步不能省否則訓(xùn)練時找不到數(shù)據(jù)。{ legal_qa: { file_name: legal_qa.json, columns: { prompt: instruction, query: input, response: output } }, medical_qa: { file_name: medical_qa.json, columns: { prompt: instruction, query: input, response: output } } }columns里的映射關(guān)系要跟你的 JSON 字段名完全一致。如果字段名對不上訓(xùn)練會直接報KeyError這是新手最常見的翻車點之一。2.3 LoRA 微調(diào)的最小可跑配置LlamaFactory 支持命令行和 WebUI 兩種方式。生產(chǎn)環(huán)境我推薦用 YAML 配置文件方便版本管理和復(fù)現(xiàn)。下面是一份針對 Qwen2.5-7B 做法律領(lǐng)域 LoRA 微調(diào)的最小配置# legal_lora_sft.yaml model_name_or_path: /root/.cache/modelscope/hub/Qwen/Qwen2.5-7B-Instruct stage: sft do_train: true finetuning_type: lora lora_target: all dataset: legal_qa template: qwen cutoff_len: 2048 max_samples: 3000 overwrite_cache: true preprocessing_num_workers: 8 output_dir: saves/qwen2.5-7b-legal-lora logging_steps: 10 save_steps: 200 plot_loss: true overwrite_output_dir: true per_device_train_batch_size: 2 gradient_accumulation_steps: 8 learning_rate: 1.0e-4 num_train_epochs: 3.0 lr_scheduler_type: cosine warmup_ratio: 0.1 bf16: true ddp_timeout: 180000000啟動訓(xùn)練llamafactory-cli train legal_lora_sft.yaml這份配置里幾個參數(shù)需要重點解釋。lora_target: all表示對所有線性層掛 LoRA 適配器法律和醫(yī)療這種知識密集型任務(wù)目標(biāo)層覆蓋越全模型吸收領(lǐng)域知識的能力越強代價是顯存占用略高。cutoff_len: 2048是單條樣本的最大 token 長度法律條文和醫(yī)療分析往往較長設(shè)太小會截斷關(guān)鍵內(nèi)容設(shè)太大則顯存吃緊2048 是 7B 模型在 24GB 卡上的平衡點。learning_rate: 1.0e-4是 LoRA 微調(diào)的常用起點比全量微調(diào)高一個數(shù)量級因為 LoRA 只更新低秩矩陣需要更大的步長。gradient_accumulation_steps: 8配合per_device_train_batch_size: 2等效 batch size 是 16顯存不夠時優(yōu)先調(diào)大累積步數(shù)而不是減小 batch size。訓(xùn)練過程中重點看 loss 曲線。如果 loss 在前 100 步就降到 0.5 以下大概率是數(shù)據(jù)太單一或重復(fù)模型在死記硬背如果 loss 震蕩劇烈不下降檢查學(xué)習(xí)率是否過大或者數(shù)據(jù)里有沒有大量空 output。正常情況 loss 應(yīng)該從 2.0 左右平滑下降到 0.8 到 1.2 區(qū)間。3. 法律與醫(yī)療微調(diào)的數(shù)據(jù)工程從原始卷宗到訓(xùn)練樣本3.1 法律數(shù)據(jù)的清洗與結(jié)構(gòu)化法律領(lǐng)域的原始數(shù)據(jù)來源通常是裁判文書、法律法規(guī)庫、律所問答記錄。這些數(shù)據(jù)不能直接拿來訓(xùn)練必須先做結(jié)構(gòu)化。裁判文書里大量內(nèi)容是當(dāng)事人信息、審判程序等與法律推理無關(guān)的字段需要剝離出來只保留“案情摘要 爭議焦點 裁判理由 法律依據(jù)”這條主線。我一般用 Python 做一輪預(yù)處理把非結(jié)構(gòu)化文本轉(zhuǎn)成 alpaca 格式。下面是一個針對裁判文書的簡化清洗腳本import re import json def clean_legal_text(raw_text): 清洗裁判文書提取核心法律推理段落 # 去掉當(dāng)事人身份證號、詳細(xì)住址等隱私信息 raw_text re.sub(r\d{17}[\dXx], [身份證號], raw_text) raw_text re.sub(r住址[:].*?。, 住址[已脫敏]。, raw_text) # 按段落切分保留包含法律推理關(guān)鍵詞的段落 paragraphs raw_text.split(\n) key_markers [本院認(rèn)為, 爭議焦點, 依照, 判決如下, 法律依據(jù)] core_paragraphs [] for para in paragraphs: if any(marker in para for marker in key_markers): core_paragraphs.append(para.strip()) return \n.join(core_paragraphs) def build_legal_sample(case_text, question, answer): 組裝單條訓(xùn)練樣本 return { instruction: question, input: clean_legal_text(case_text), output: answer } # 示例批量處理 samples [] with open(raw_judgments.jsonl, r, encodingutf-8) as f: for line in f: item json.loads(line) sample build_legal_sample( case_textitem[content], question請分析本案的爭議焦點及裁判依據(jù)。, answeritem[reasoning] ) samples.append(sample) with open(legal_qa.json, w, encodingutf-8) as f: json.dump(samples, f, ensure_asciiFalse, indent2)這段腳本的核心邏輯是“脫敏 關(guān)鍵段落抽取 格式組裝”。脫敏是法律數(shù)據(jù)的硬性要求身份證號、住址、聯(lián)系方式必須處理掉否則訓(xùn)練出的模型可能泄露隱私。關(guān)鍵段落抽取依賴key_markers列表不同來源的文書標(biāo)記詞可能不同需要根據(jù)實際數(shù)據(jù)調(diào)整。build_legal_sample里的question和answer最好由法律專業(yè)人員撰寫或?qū)徍瞬灰媚P妥詣由煞駝t會引入幻覺。3.2 醫(yī)療數(shù)據(jù)的脫敏與術(shù)語標(biāo)準(zhǔn)化醫(yī)療數(shù)據(jù)的敏感度比法律更高除了患者身份信息還包括病歷號、就診時間、醫(yī)院名稱等。脫敏之后還要做術(shù)語標(biāo)準(zhǔn)化因為同一疾病在不同病歷里可能有多種寫法比如“2型糖尿病”“II型糖尿病”“T2DM”指的是同一個東西。術(shù)語不統(tǒng)一模型學(xué)到的知識就是碎片化的。import re # 醫(yī)學(xué)術(shù)語標(biāo)準(zhǔn)化映射表實際項目中應(yīng)覆蓋更多條目 TERM_MAP { II型糖尿病: 2型糖尿病, T2DM: 2型糖尿病, 高血壓病: 高血壓, 原發(fā)性高血壓: 高血壓, 心梗: 心肌梗死, 腦梗: 腦梗死 } def desensitize_medical_text(text): 醫(yī)療文本脫敏 # 去除病歷號、床號、電話 text re.sub(r病歷號[:]\s*\S, 病歷號[已脫敏], text) text re.sub(r床號[:]\s*\S, 床號[已脫敏], text) text re.sub(r1[3-9]\d{9}, [手機號], text) # 去除具體日期保留相對時間描述 text re.sub(r\d{4}年\d{1,2}月\d{1,2}日, [日期], text) return text def normalize_terms(text): 術(shù)語標(biāo)準(zhǔn)化 for raw, std in TERM_MAP.items(): text text.replace(raw, std) return text def build_medical_sample(record): 組裝醫(yī)療訓(xùn)練樣本 cleaned desensitize_medical_text(record[text]) normalized normalize_terms(cleaned) return { instruction: record[question], input: normalized, output: record[answer] }脫敏用正則表達式處理固定格式的信息術(shù)語標(biāo)準(zhǔn)化用映射表替換。TERM_MAP需要根據(jù)你的數(shù)據(jù)來源持續(xù)補充建議在項目初期就建立術(shù)語表由醫(yī)學(xué)背景的同事維護。build_medical_sample里的answer必須是經(jīng)過審核的臨床意見不能直接拿病歷里的初步診斷當(dāng)標(biāo)準(zhǔn)答案因為初步診斷可能被后續(xù)檢查推翻。3.3 訓(xùn)練集與驗證集的劃分策略法律和醫(yī)療數(shù)據(jù)都有一個特點同類樣本之間高度相似。比如一百條買賣合同糾紛案情結(jié)構(gòu)幾乎一樣只是金額和日期不同。如果隨機劃分訓(xùn)練集和驗證集驗證集里會出現(xiàn)大量跟訓(xùn)練集雷同的樣本導(dǎo)致驗證 loss 虛低模型看起來學(xué)得很好實際泛化能力很差。我的做法是按“案件類型”或“疾病科室”做分層劃分。法律數(shù)據(jù)按案由分醫(yī)療數(shù)據(jù)按科室分確保驗證集里的案件類型或疾病類型在訓(xùn)練集里也有覆蓋但具體案情不重復(fù)。LlamaFactory 本身不提供分層劃分功能需要在數(shù)據(jù)準(zhǔn)備階段就分好文件。import json from sklearn.model_selection import train_test_split # 假設(shè)每條樣本帶有 case_type 或 department 字段 with open(legal_qa_with_type.json, r, encodingutf-8) as f: data json.load(f) # 按案件類型分層劃分驗證集占 15% train_data, eval_data train_test_split( data, test_size0.15, stratify[item[case_type] for item in data], random_state42 ) # 去掉輔助字段只保留 alpaca 三列 def strip_meta(item): return { instruction: item[instruction], input: item[input], output: item[output] } with open(legal_train.json, w, encodingutf-8) as f: json.dump([strip_meta(x) for x in train_data], f, ensure_asciiFalse, indent2) with open(legal_eval.json, w, encodingutf-8) as f: json.dump([strip_meta(x) for x in eval_data], f, ensure_asciiFalse, indent2)stratify參數(shù)保證每個案件類型在訓(xùn)練集和驗證集里的比例一致。random_state42固定隨機種子保證每次劃分結(jié)果可復(fù)現(xiàn)。劃分完成后在dataset_info.json里注冊兩個數(shù)據(jù)集訓(xùn)練配置里dataset填legal_train驗證時用eval_dataset: legal_eval。驗證集的作用是觀察模型是否過擬合如果訓(xùn)練 loss 持續(xù)下降但驗證 loss 開始上升說明模型在背訓(xùn)練集需要減少 epoch 或增加數(shù)據(jù)多樣性。4. 微調(diào)參數(shù)怎么調(diào)LoRA 秩、學(xué)習(xí)率與 batch size 的取舍4.1 LoRA 秩和 alpha 的設(shè)置邏輯LoRA 的核心思想是在原模型權(quán)重旁掛一對低秩矩陣訓(xùn)練時只更新這對矩陣推理時把它們的乘積加回原權(quán)重。秩r決定這對矩陣的容量r越大能表達的變化越復(fù)雜但參數(shù)量和顯存占用也越大。法律和醫(yī)療領(lǐng)域需要模型吸收大量專業(yè)術(shù)語和推理模式r不能太小。我的經(jīng)驗值法律領(lǐng)域r16到32醫(yī)療領(lǐng)域r32到64。醫(yī)療術(shù)語更密集、表達更精細(xì)需要更大的秩。lora_alpha一般設(shè)為r的兩倍比如r32時alpha64。lora_dropout設(shè) 0.05 到 0.1防止過擬合。在 LlamaFactory 的 YAML 里加上這些參數(shù)lora_rank: 32 lora_alpha: 64 lora_dropout: 0.05 lora_target: alllora_target: all表示對所有線性層掛適配器。有些教程建議只掛q_proj和v_proj那是為了省顯存。法律和醫(yī)療任務(wù)我建議掛全因為領(lǐng)域知識不只影響注意力也影響前饋網(wǎng)絡(luò)。如果顯存實在不夠優(yōu)先保留q_proj、k_proj、v_proj、o_proj和gate_proj、up_proj、down_proj。4.2 學(xué)習(xí)率與調(diào)度器的選擇LoRA 微調(diào)的學(xué)習(xí)率比全量微調(diào)高因為低秩矩陣的梯度尺度不同。Qwen2.5-7B 做 LoRA SFT學(xué)習(xí)率從1e-4起步如果 loss 下降太慢可以提到2e-4如果 loss 震蕩就降到5e-5。調(diào)度器用 cosine 比較穩(wěn)warmup 比例設(shè) 0.1讓模型在前 10% 的步數(shù)里慢慢進入狀態(tài)。learning_rate: 1.0e-4 lr_scheduler_type: cosine warmup_ratio: 0.1 num_train_epochs: 3.0num_train_epochs設(shè) 3 是法律和醫(yī)療數(shù)據(jù)的常見值。數(shù)據(jù)量少于 2000 條時epoch 可以加到 5但要盯著驗證 loss。數(shù)據(jù)量超過 10000 條時2 個 epoch 可能就夠了。不要盲目追求低訓(xùn)練 loss法律和醫(yī)療模型寧可保守一點也不要過擬合到編造條文或診斷。4.3 batch size 與梯度累積的顯存平衡顯存是微調(diào)時最現(xiàn)實的約束。Qwen2.5-7B 用 LoRA 微調(diào)cutoff_len2048時單卡 24GB 大約能跑per_device_train_batch_size2。想增大等效 batch size就用梯度累積。per_device_train_batch_size: 2 gradient_accumulation_steps: 8等效 batch size per_device_train_batch_size × gradient_accumulation_steps × GPU數(shù)量。單卡時是 16。等效 batch size 影響梯度穩(wěn)定性太小會導(dǎo)致 loss 震蕩太大則收斂慢。16 到 32 是比較合適的區(qū)間。如果顯存報 OOM先降cutoff_len到 1536 或 1024再降 batch size。cutoff_len對顯存的影響是平方級的降它比降 batch size 更有效。另外記得開bf16: trueAmpere 架構(gòu)以上的卡都支持能省顯存且訓(xùn)練更穩(wěn)。如果卡不支持 bf16用fp16: true但要注意 fp16 容易梯度溢出需要配合fp16_opt_level之類的設(shè)置。5. 微調(diào)后的驗證與部署怎么判斷模型真的能用5.1 用領(lǐng)域測試集做人工評估訓(xùn)練 loss 和驗證 loss 只能說明模型在擬合數(shù)據(jù)不能說明它在真實業(yè)務(wù)里能用。法律和醫(yī)療模型必須過人工評估這一關(guān)。我的做法是準(zhǔn)備一個 100 到 200 條的領(lǐng)域測試集覆蓋高頻場景和邊界情況讓領(lǐng)域?qū)<抑饤l打分。評估維度包括事實準(zhǔn)確性法條引用是否正確、診斷依據(jù)是否成立、推理完整性是否覆蓋關(guān)鍵構(gòu)成要件、表達規(guī)范性術(shù)語是否標(biāo)準(zhǔn)、格式是否合規(guī)、安全性是否有不當(dāng)建議或幻覺。每條按 1 到 5 分打分平均分低于 4 分的模型不建議上線。LlamaFactory 提供了批量推理功能可以把測試集喂進去生成回答再導(dǎo)出給專家評審llamafactory-cli chat \ --model_name_or_path /root/.cache/modelscope/hub/Qwen/Qwen2.5-7B-Instruct \ --adapter_name_or_path saves/qwen2.5-7b-legal-lora \ --template qwen \ --finetuning_type lora這是交互式對話模式適合抽查。批量評估可以寫個腳本調(diào)用推理接口把測試集的instruction和input拼成 prompt收集output后跟標(biāo)準(zhǔn)答案對比。5.2 適配器合并與推理部署LoRA 訓(xùn)練出來的是適配器權(quán)重推理時需要跟基礎(chǔ)模型一起加載。LlamaFactory 支持把適配器合并回基礎(chǔ)模型生成一個完整的權(quán)重目錄方便用 vLLM 或其他推理框架部署。llamafactory-cli export \ --model_name_or_path /root/.cache/modelscope/hub/Qwen/Qwen2.5-7B-Instruct \ --adapter_name_or_path saves/qwen2.5-7b-legal-lora \ --template qwen \ --finetuning_type lora \ --export_dir saves/qwen2.5-7b-legal-merged \ --export_size 2 \ --export_legacy_format falseexport_dir是合并后的權(quán)重輸出目錄。export_size是分片大小2 表示每片 2GB方便傳輸和加載。合并后的模型可以直接用 transformers 加載也可以用 vLLM 做高并發(fā)推理。注意合并后的模型體積跟基礎(chǔ)模型一樣大7B 的 bf16 權(quán)重大約 15GB部署時要算好顯存。如果不想合并也可以在推理時動態(tài)加載適配器LlamaFactory 和 vLLM 都支持。動態(tài)加載的好處是基礎(chǔ)模型共享多個領(lǐng)域的適配器可以熱切換壞處是推理時多一層計算延遲略高。生產(chǎn)環(huán)境我一般選合并穩(wěn)定優(yōu)先。6. 避坑與排查法律醫(yī)療微調(diào)里最容易翻車的五件事6.1 數(shù)據(jù)里混入模型生成的偽標(biāo)簽現(xiàn)象訓(xùn)練 loss 降得很快但模型回答開始出現(xiàn)固定句式遇到?jīng)]見過的案情也套用同一套話術(shù)。原因數(shù)據(jù)準(zhǔn)備階段為了省事用通用模型批量生成了部分output這些偽標(biāo)簽帶有通用模型的表達習(xí)慣和幻覺被微調(diào)模型學(xué)去了。解決法律和醫(yī)療數(shù)據(jù)的output必須由人工撰寫或?qū)徍?。如果確實要用模型輔助只能用來做初稿且必須經(jīng)過領(lǐng)域?qū)<抑饤l修改。檢查方法很簡單從訓(xùn)練集里隨機抽 50 條看output里有沒有“根據(jù)我的了解”“一般來說”這類通用模型的模糊表達。6.2 cutoff_len 設(shè)太小導(dǎo)致關(guān)鍵信息被截斷現(xiàn)象模型在訓(xùn)練集上表現(xiàn)正常但推理時遇到長條文或長病歷就答非所問。原因cutoff_len設(shè)成了 512 或 1024而法律條文和醫(yī)療分析經(jīng)常超過這個長度訓(xùn)練時后半段被截掉模型沒學(xué)到完整推理鏈。解決統(tǒng)計訓(xùn)練數(shù)據(jù)里instruction input output的 token 長度分布取 95 分位數(shù)作為cutoff_len。法律和醫(yī)療數(shù)據(jù)我一般設(shè) 2048如果顯存不夠就設(shè) 1536但不要低于 1024。截斷發(fā)生在 tokenizer 階段可以在預(yù)處理時打印長度直方圖確認(rèn)。6.3 驗證集跟訓(xùn)練集同源導(dǎo)致評估虛高現(xiàn)象驗證 loss 很低但人工評估時模型在真實問題上表現(xiàn)很差。原因訓(xùn)練集和驗證集是從同一批相似數(shù)據(jù)里隨機切的驗證集樣本跟訓(xùn)練集高度雷同模型相當(dāng)于在“背答案”。解決按案件類型或疾病科室做分層劃分確保驗證集里的具體案情在訓(xùn)練集里沒出現(xiàn)過。更嚴(yán)格的做法是留出一個完整的時間段或來源的數(shù)據(jù)做驗證比如用 2024 年的裁判文書做驗證2023 年及以前的做訓(xùn)練。6.4 LoRA 秩設(shè)太小導(dǎo)致領(lǐng)域知識學(xué)不進去現(xiàn)象訓(xùn)練 loss 降到一定程度就下不去了模型回答仍然帶有通用模型的泛化風(fēng)格專業(yè)術(shù)語使用不準(zhǔn)確。原因lora_rank設(shè)成了 4 或 8低秩矩陣容量不夠無法表達法律和醫(yī)療領(lǐng)域的復(fù)雜知識。解決法律領(lǐng)域r至少 16醫(yī)療領(lǐng)域至少 32。如果顯存允許直接上 64。調(diào)大r后記得同步調(diào)大lora_alpha保持alpha 2r的比例。調(diào)大后重新訓(xùn)練觀察 loss 是否能降到更低水平。6.5 推理時 template 跟訓(xùn)練時不一致現(xiàn)象合并后的模型推理時輸出格式混亂或者回答里出現(xiàn)奇怪的標(biāo)記符號。原因訓(xùn)練時用了template: qwen推理時忘了指定或者用了默認(rèn)模板導(dǎo)致 prompt 格式跟訓(xùn)練時不一致。Qwen2.5 有特定的對話模板訓(xùn)練和推理必須嚴(yán)格對齊。解決訓(xùn)練配置和推理命令里的template必須一致。LlamaFactory 的chat和export命令都要顯式指定--template qwen。如果用的是合并后的模型在 transformers 里加載時也要用對應(yīng)的 chat template不要手動拼 prompt。7. 讓法律醫(yī)療模型更穩(wěn)的一個技巧用拒絕采樣篩訓(xùn)練數(shù)據(jù)微調(diào)做到后面你會發(fā)現(xiàn)模型能不能用八成取決于數(shù)據(jù)質(zhì)量兩成取決于參數(shù)。法律和醫(yī)療領(lǐng)域尤其如此一條錯誤的法條引用或醫(yī)療建議足以讓整個模型的可信度崩塌。我現(xiàn)在的習(xí)慣是在正式訓(xùn)練之前先做一輪拒絕采樣把訓(xùn)練數(shù)據(jù)里質(zhì)量不達標(biāo)的樣本篩掉。具體做法是用基礎(chǔ) Qwen2.5 模型對每條訓(xùn)練樣本的instruction input生成一個回答然后跟人工撰寫的output做對比。如果基礎(chǔ)模型的回答跟標(biāo)準(zhǔn)答案在關(guān)鍵事實上一致說明這條樣本的難度不夠模型已經(jīng)會了可以降低權(quán)重或剔除如果基礎(chǔ)模型的回答錯得離譜說明這條樣本包含模型完全沒掌握的知識是訓(xùn)練的重點保留并適當(dāng)增加同類樣本如果基礎(chǔ)模型的回答跟標(biāo)準(zhǔn)答案部分重合、部分偏離這種樣本最有價值因為模型處在“半懂不懂”的狀態(tài)微調(diào)能把它拉過來。from transformers import AutoModelForCausalLM, AutoTokenizer import json model_path /root/.cache/modelscope/hub/Qwen/Qwen2.5-7B-Instruct tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_path, device_mapauto, trust_remote_codeTrue ) def generate_answer(instruction, input_text): prompt f### 指令\n{instruction}\n\n### 輸入\n{input_text}\n\n### 回答\n inputs tokenizer(prompt, return_tensorspt).to(model.device) outputs model.generate(**inputs, max_new_tokens512, do_sampleFalse) return tokenizer.decode(outputs[0], skip_special_tokensTrue) def score_sample(sample): 用基礎(chǔ)模型生成回答跟標(biāo)準(zhǔn)答案做粗略對比 base_answer generate_answer(sample[instruction], sample[input]) # 實際項目中應(yīng)該用領(lǐng)域?qū)<一蚋?xì)的指標(biāo)來打分 # 這里用關(guān)鍵詞重合度做示意 gold_keywords set(sample[output][:200].split()) base_keywords set(base_answer.split()) overlap len(gold_keywords base_keywords) / max(len(gold_keywords), 1) return overlap with open(legal_train.json, r, encodingutf-8) as f: data json.load(f) scored [(item, score_sample(item)) for item in data] # 保留重合度在 0.3 到 0.7 之間的樣本這些是模型最需要學(xué)的 filtered [item for item, score in scored if 0.3 score 0.7] with open(legal_train_filtered.json, w, encodingutf-8) as f: json.dump(filtered, f, ensure_asciiFalse, indent2)這段腳本里score_sample用關(guān)鍵詞重合度做示意實際項目中應(yīng)該用更可靠的指標(biāo)比如讓領(lǐng)域?qū)<覍A(chǔ)模型的回答打分或者用專門的評估模型。0.3到0.7這個區(qū)間是經(jīng)驗值重合度太低說明樣本太難模型可能學(xué)不會太高說明樣本太簡單訓(xùn)練收益低。篩完之后數(shù)據(jù)量會減少但訓(xùn)練效率會明顯提升。我踩過的一個血淚教訓(xùn)是早期做醫(yī)療微調(diào)時為了湊數(shù)據(jù)量把大量基礎(chǔ)模型已經(jīng)能答對的簡單問答也塞進訓(xùn)練集結(jié)果模型在簡單問題上過擬合遇到復(fù)雜病例反而退化了。后來堅持做拒絕采樣數(shù)據(jù)量砍掉一半但人工評估的準(zhǔn)確率反而上去了。這個習(xí)慣我一直保留到現(xiàn)在每次微調(diào)前都會先跑一輪篩選寧可數(shù)據(jù)少一點也要保證每條樣本都在模型的“學(xué)習(xí)區(qū)”里。希望幫到你。本文還有配套的精品資源點擊獲取