持續預訓練是三階段裡最花時間、最吃資料、但概念最單純的一段。單純不代表容易——它的難處全部在資料工程上。
流程是:清洗 → 切塊 → 混合 → 訓練 → 監控。
Day 5 提過 FineWeb 這類網路語料自帶格式雜訊。我實際用的清洗規則分四類:
一、樣板文字移除 導覽列、頁尾、Cookie 提示、「分享到 Facebook」、「訂閱電子報」、版權宣告。這些用規則就能清掉大部分。
二、長度過濾 設下限與上限。下限的目的是砍掉純片段(一行標題、一個按鈕文字),上限的目的是砍掉爬蟲把整站合併成一頁的情況。
三、重複內容去除 同一段文字在不同頁面重複出現是網路語料的常態。我做了兩層:完全相同的直接去重,高度相似的用 MinHash 這類方法抓。
為什麼重複這麼重要? 因為重複資料在訓練時等於變相加重了那段文字的權重。如果某個常見的樣板句出現了幾萬次,模型會非常確信那句話很重要。
四、語言判定 我的資料混了英文與繁體中文。要標記語言,因為後面混合比例要控制。這裡有個小坑:簡繁混雜的文本會讓自動判定失準,我額外加了一層繁簡比例的檢查。
清洗完的文本要切成固定長度的訓練樣本。最粗暴的做法是把所有文本接起來然後每 N 個 token 切一刀——快,但會在句子中間、甚至詞中間切斷。
我用的是尊重文件邊界的打包:以文件為單位,能塞進一個樣本就塞,塞不下的做溢出處理,短文件之間用分隔標記串接但不跨文件產生語意混淆。
代價是有一些 padding 浪費。但資安文本的結構性很強(一篇威脅分析有它的起承轉合),從中間切斷會破壞這個結構。
Day 5 說過三類資料要混。比例怎麼定?
我的原則是:
實務上我是先設一組比例,跑一小段看 loss 與抽樣輸出,再調整。這裡沒有理論最佳解,就是實驗。
一個重要的檢查:混合之後抽樣讀幾十筆。你會很快發現比例是不是歪了——如果連抽十筆都是同一類,比例就有問題。
CPT 的參數設定跟一般的預訓練接近,幾個關鍵:
學習率:要比原始預訓練小很多。模型已經訓練好了,你是在微調它的分佈,不是從頭學。學習率設太大,模型會忘掉原本的通用能力(就是災難性遺忘)。我從一個保守值開始,觀察 loss 與通用能力是否劣化。
Warmup:一定要有。突然施加梯度更新對已訓練模型的傷害很大。
學習率排程:cosine 衰減是安全選擇。
訓練步數 / epoch 數:CPT 通常跑 1 個 epoch 就夠了,甚至不到。反覆多輪會導致過擬合到訓練語料的表面特徵。
訓練跑起來之後,我固定盯三件事:
第一,訓練 loss。 應該平穩下降。如果劇烈震盪,通常是學習率太大或 batch 太小;如果完全不動,通常是學習率太小或資料有問題。
第二,held-out perplexity。 用一批沒參與訓練的資安文本算 perplexity。這是判斷「有沒有真的學到領域語言」的直接指標,比訓練 loss 可靠。
第三,通用能力的劣化檢查。 我每隔一定步數就跑一組簡單的通用測試(常識問答、基本推理、中文流暢度)。如果這條線開始下滑,就是災難性遺忘在發生,要降學習率或加入通用資料混合。
【此處貼 loss 曲線與 perplexity 曲線截圖】
三個手段,我全用了:
第三點是保險。訓練跑幾十小時,如果沒有中途 checkpoint,發現壞掉時你只能整個重來。
跑完之後,照 Day 7 的表格跑一次完整評測。
這時候的分數,我建議你不要有太高期待。 CPT 改變的是語域,而多選題 benchmark 測的是知識,兩者的關聯本來就不強。CPT 後 benchmark 沒什麼變化是正常的,甚至微幅下降也在合理範圍。
真正該看的是 perplexity 與抽樣輸出的「像不像資安人在講話」。
明天做 SFT,那才是行為開始改變的地方。
Instagram: @aid3fend — AI 資安實戰紀錄,歡迎追蹤交流。