你看到「DUST 不用 Backprop 就能訓練語言模型」,直覺可能是:少一道反向傳播,GPU 應該更省吧?但如果為了找出一次更新方向,必須先試很多次,省掉一種計算,仍可能換來更大的總帳單。
這篇寫給完全沒有訓練背景、想看懂研究比較的讀者。先用調音台的比喻理解 DUST,再教你在已有的 Linux/NVIDIA GPU 環境做兩步檢查、整理兩條比較曲線。本文依截至 2026 年 10 月 7 日的官方研究與固定版本原始碼設計評估方法;AlphaLab 本次沒有執行 GPU 訓練,圖中不含自製跑分或虛構 loss 曲線。
先說結論:DUST 是什麼,該怎麼判讀?
DUST=在模型內部試小擾動+按效果估計更新方向;是否划算,要分開看資料量與計算時間。想像你要調好一張很大的調音台:Backprop 沿訊號路線算出旋鈕應怎麼轉;DUST 則試著輕推中間訊號,觀察聲音有沒有改善,再把多次試探合成下一步。
- 不用 Backprop,不等於不用梯度資訊。梯度是「往哪裡調會改善」的方向;DUST 以擾動估計它,再交給 SGD 更新。
- 同樣讀過多少 token,回答資料使用效率。同樣占用 GPU 多久,才接近你付得起的計算預算。
- 先驗流程,再談勝負。兩步 smoke test 是檢查能否跑通,不是驗證研究結論。
如果你還不熟悉 token、權重與 loss,可以先讀 AI 模型如何學習。Token 是文字被切出的處理單位;權重是模型可調的數字;loss 是這次預測的誤差分數,這裡是在同一份資料、同一種評分方式下越低越好。
DUST 的原理:五個零件,把試探變成更新
Backprop(反向傳播)用連鎖法則,把最後的誤差一路分配回各層。DUST 的零階最佳化則從函數評分推估方向。這是方法家族的區別,不是「完全隨機改參數就會變聰明」。早期的 Forward Gradient 研究也探討 activation 擾動與估計變異;不同算法、架構與任務的結果要分開看。
① Activation:「正在流動的訊號」
權重像旋鈕的位置,activation(活化值)像訊號通過某一層後的即時讀數。DUST 主要在這些讀數上加小擾動,讓模型再向前計算。想像你不拆整台機器,只在幾個測點輕推訊號,觀察下游反應。
② Perturbation:「有紀錄的小試探」
擾動是抽樣的小噪聲,不是新的訓練文章。你必須同時記住「推了哪個方向」與「評分如何變動」,才有辦法估計該往哪裡走。完整程式還會處理不同層的分工與干擾,因此這個比喻不能當作可直接替換原算法的幾行程式。
③ Population:「一次更新的試探預算」
Token 軸上的獨立擾動,讓一次向前計算能同時評估許多虛擬成員;但命令中的 --population 是另一個明確的抽樣預算。官方 recipe 與訓練程式把它定義為跨 GPU 的直接 loss draws,輸出 head 和局部 attention 還有額外 draws。因此 population 256 不是只有 256 次完整 forward,也不是多讀 256 倍新資料。
④ Credit:「改善要算誰的功勞」
某個測點的改動可能影響後面的 token。DUST 按 loss 改善替擾動打分,再組合方向;attention 內部另有局部評分安排。白話說,不只問「最後有沒有變好」,也要決定哪些試探該拿到信用。
⑤ Update:「估完方向,才轉旋鈕」
最後把估計的輸出誤差與該層輸入組合,形成權重的更新估計,再由 SGD(隨機梯度下降)動手。原始碼直接把估計值放進參數的 gradient;它避開傳統 backward 的取得方式,仍然在建立訓練方向。

把例子走完:同一小批文字先通過模型,接著換幾組小擾動重算,記下每組造成的 loss 差異;較有利的方向獲得較大權重,抵銷部分抽樣噪聲後,才做一次參數更新。增加試探有機會讓估計更穩,但計算也要付費。這就是為什麼「拿掉 backward」本身不能結算整張成本表。
DUST 單卡上手:先檢查環境,再做兩步 smoke test
以下命令固定在 官方 repository 的 b20f7c0 版本。目標是小規模學習與比較流程。已有相容 NVIDIA GPU 的讀者才進入訓練;只想理解方法的人,可先完成下一節的比較設計。
① 痛點:我的電腦能照著跑嗎?
先核對硬體與環境。官方 安裝說明要求 Linux、Python 3.10 以上與支援 BF16 的 NVIDIA GPU,並提供 CUDA 12.8 的 PyTorch 安裝方式。BF16 是儲存數字的一種精度格式,這裡的要求屬於這份實作。Mac 的 Apple GPU 與 CUDA 訓練入口不同,本篇不把 Mac 改寫成支援路徑。
在獨立工作資料夾依序執行 git clone https://github.com/qlabs-eng/dust.git、cd dust、git checkout b20f7c03eac630b6441ba6f254128c1761dc45ad,再建立隔離環境:python3 -m venv .venv、source .venv/bin/activate。依這個版本安裝 python -m pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu128 與 python -m pip install -r requirements.txt;NVIDIA driver 要與這套 CUDA 相容。
執行 nvidia-smi 保存 GPU 與 driver,再用 python -c "import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.is_bf16_supported(including_emulation=False))" 檢查 PyTorch、CUDA 可用性與硬體 BF16。PyTorch 的 BF16 檢查實作說明這個參數可排除模擬支援。兩個布林結果應為 True;仍需以接下來的實際配置確認顯存足夠,不能從「單卡」推算最低 GB。
② 痛點:選 1M,資料準備是不是很小?
先看資料管線,才估下載與等待成本。執行 python prepare_data.py --tokens 1M 可只保存 1M 訓練預算與共用驗證、測試檔。然而 資料準備程式仍先跳過 200,000 份文件,再讀取約 20.5M token 的訓練池,才取前綴並建立 held-out splits。它串流 FineWeb,選 1M 不表示網路只傳 1M token。先核對 FineWeb 資料卡、磁碟與連線條件,再開始這個階段。
完成後確認 data/train_1M.pt、data/val.pt、data/test.pt 與 data/manifest.json 都存在。保留 manifest 的雜湊(檔案指紋),兩種方法共用同一份檔案;若你重做資料,再漂亮的曲線也不能直接接在舊跑次後面。
③ 痛點:一跑就是完整研究配置?
先做兩次、各兩步的檢查。先執行 python dust.py --tokens 1M --population 256 --steps 2 --seed 42 --output runs/smoke-dust-s42;完成後再執行 python baselines/backprop.py --tokens 1M --steps 2 --seed 42 --output runs/smoke-bp-s42。這是先後跑在同一張 GPU 上,避免兩個程序競爭資源。
驗收看四件事:loss 是有限數字、驗證評分可完成、輸出目錄有 config.json/metrics.jsonl/best.pt/result.json,且兩份 config 的模型與資料雜湊相同。每次用新的空目錄。兩步成功只代表資料與執行路徑通過初步檢查;loss 是否改善、方法是否便宜,留給正式比較。
公平比較的兩條曲線:固定 token 與固定 GPU 時間
先寫問題,再畫圖。「我只有這麼多資料,誰學得好?」與「我只有這麼多 GPU 預算,誰做到哪裡?」是兩個問題。你可以用同一組跑次回答它們,但橫軸、成本邊界和可下的結論必須清楚。

① 固定 token:比較共同驗證集上的 loss
Smoke test 通過後,把 --steps 2 移除,先用 population 256 完成一組。DUST 指令改為 python dust.py --tokens 1M --population 256 --seed 42 --output runs/dust-p256-s42;baseline 改為 python baselines/backprop.py --tokens 1M --seed 42 --output runs/bp-s42。再依相同方式配對種子 43、44,目錄名稱也跟著換。三個種子是這份工作簿的起點,不保證統計精度。
同一種子、模型和資料順序能減少比較中不必要的差異;兩種方法的擾動、學習率與 momentum(動量)仍不同。保留各自 recipe,不要為了看起來「公平」強迫套同一學習率。若額外調參,兩邊都給事先約定的搜尋預算,並把搜尋成本另記一欄。
橫軸用 step × batch size × sequence length。此版本 batch size 是 8、sequence length 是 2,048;1M 預設 61 步,所以實際是 999,424 個 prediction tokens,不是剛好一百萬。最終仍以 config 的 training_tokens 為核對依據。縱軸選兩邊共同的 val_loss;不要把帶擾動的評分或單一訓練 batch 當成泛化成績。
② 固定時間:比較同一截止點之前做到哪裡
先決定預算與計時起終點。若只有一張 GPU,固定占用秒數可直接做配對;多卡則至少記 GPU 數 × 占用時間,且保留型號,不能把不同卡種的 GPU-hours 視為同等算力。資料準備、環境建立、訓練、驗證與存檔,哪些計入預算要在跑前寫好。
內建 elapsed_seconds 在一次更新後、當次驗證前寫入;它從初始驗證及初始存檔之後才起算。先前評估與存檔的時間會混入後續紀錄,最後 test 與程序啟動成本則未完整反映。換句話說,這條軸是訓練迴圈的紀錄,不能直接標成完整端到端成本。Baseline 計時與 checkpoint 程式可核對這個邊界。
入門版先把它命名為「內建 loop elapsed」,畫 val loss 對這個時間的圖,並另外記錄兩個程序從啟動到退出的總時間。若要嚴格驗證固定預算,須讓每個驗證完成點帶同步後的時間戳,保存該點 checkpoint,且在 deadline 前才允許入選;這屬於你要增補的計時/checkpoint 邏輯。GPU 操作有非同步特性,計時時參考 PyTorch CUDA 計時說明。
不要用殺掉程序來假裝完成固定時間實驗,也不要拿全程最佳的 best.pt 充當截止點前的最佳版本:它可能是在預算之外才產生。用原版日誌只能先比較可見的驗證曲線;嚴格的 deadline checkpoint 與它的 test loss,應在補齊保存邏輯之後另跑。
③ 把日誌轉成試算表,交出你自己的曲線
在 repository 根目錄用以下命令匯出 DUST 的驗證點;再把輸入資料夾改成 runs/bp-s42 匯出另一份。這個轉檔只讀你已完成的跑次,不會重啟訓練:
python -c 'import json,csv,sys; from pathlib import Path; p=Path("runs/dust-p256-s42"); c=json.loads((p/"config.json").read_text()); rows=[json.loads(x) for x in (p/"metrics.jsonl").read_text().splitlines()]; w=csv.writer(sys.stdout); w.writerow(["step","tokens","loop_seconds","val_loss"]); w.writerows([r["step"],r["step"]*c["training_tokens"]//c["steps"],r["elapsed_seconds"],r["val_loss"]] for r in rows if "val_loss" in r)' > dust-s42.csv
將 CSV 匯入試算表,做兩張 XY 散佈圖並連接驗證點:第一張橫軸 tokens,第二張橫軸 loop_seconds,兩張縱軸都是 val_loss。每個方法的三個種子先各畫細線,確認波動,再在共同 token 點彙整平均與範圍。時間圖的觀測點通常不對齊,不要把相同步數硬平均成同一秒;可先在事先選定的 deadline,取各跑次之前最後一個已完成的驗證點。
原版 result.json提供由 validation 選出的 checkpoint 的 test_at_best_val。Test 留到選定版本後才看,別反覆挑最低 test 的種子;否則你已把測試集當成調參資料。這份結果是完整跑次的 test,不會自動變成時間截止點的 test。
成本與判讀:先把五個坑填進紀錄

- 只記訓練 token:同一批文字可以被多次擾動重算。另記 population、GPU 數與 loop/完整作業耗時。
- 只記最高顯存:高顯存與長時間是不同成本;保存 GPU 型號、抽樣頻率和
nvidia-smi的監測紀錄。抽樣最大值要標成「觀測峰值」,別冒充精確 allocator peak。 - 只挑一條漂亮線:保留三個種子的曲線與結果;失敗、非有限 loss、記憶體不足也列入,別默默換掉失敗跑次。
- 只看預設 population:小 population 的結果不能外推大 population;改 population 也會選到另一套 tuned recipe,不能把變化全部歸因於抽樣數。
- 只看最小 repository 的速度:官方說明它省略完整實驗中的執行最佳化。因此你的單卡時間回答這個版本與環境的問題,不能替論文完整配置報一張速度成績單。
要不要做這個實驗?若你要理解訓練方向如何取得、手上已有合適 GPU,從兩步檢查開始;若你要決定實際訓練預算,先建立相同硬體、相同成本邊界的 Backprop 基線,再用 DUST 對照。若你的問題是「怎麼從零訓練自己的小模型」,MiniMind 從零訓練教學更貼近那個目標。
研究閱讀也有一個界線:Q Labs 原始研究把大 population 的表現與更多計算放在一起,並明說目前目標不是讓 DUST 的計算效率足以取代 Backprop。本文因此不把同 token 的較低 loss,翻譯成同時間更便宜或大型語言模型已換掉訓練方式。
DUST 常見問題:八個新手判斷
不用 Backprop 就完全沒有梯度嗎?
不是。DUST 用擾動與評分估計更新方向,程式再把估計值交給 SGD;改變的是方向的取得方法。
Population 256 是 256 個模型嗎?
不是這份實作的計數方式。它是直接 loss draws 的配置,token 軸另有虛擬成員,head 與局部 attention draws 另外計算。
單卡成功能算重現整篇論文嗎?
不能這樣判定。小 population、最小實作與完整實驗配置有差異;你能交付的是自己配置的結果與限制。
兩步 smoke test 的 loss 降了,就贏了嗎?
還不能。它先驗資料、數值與輸出流程;正式勝負需要共同驗證集、完整配置、成本與重複種子。
我應該看 train loss 還是 val loss?
跨方法先看共同的 val loss。Train loss 描述當下那批資料,validation 才幫你比較選模;test 留給選定版本。
同 token 更好就是更省錢嗎?
不一定。同一批文字可能被重算很多次;用同 GPU 預算的曲線與完整成本回答省錢問題。
直接加一個固定秒數參數就行嗎?
這個版本的 CLI 提供 steps,不提供秒數截止旗標。嚴格時間比較需增補 deadline、完成時間戳與 checkpoint 保存,原版日誌只支持有限的回看。
現在應該把所有 Backprop 訓練改成 DUST 嗎?
先保留基線。研究方法的價值要在你的模型、資料與預算下驗;從小配置建立可比證據,再決定是否擴大。
給新手的三個重點
- 把「不用 backward」與「不用估計方向」分開,才看得懂 DUST 的技術主張。
- 把「看了多少文字」與「重算了多久」分開,才看得懂效率。
- 先留下版本、配置、資料指紋、共同驗證點和完整成本,再用曲線做決定。
接著閱讀
左右滑動查看更多推薦
下一步:先寫你的比較問題
記住最初那句話:DUST 用試探估方向,效率要同時對帳資料與計算。今天先在工作紙寫下模型版本、共用資料、選模規則與 GPU 預算;環境合適,再做兩步 smoke test。你要交出的第一份成果,是可核對的紀錄,接著才是你自己的兩條曲線。想把這種拆問題的方法用在更多 AI 工作流,可到 AI 文章總覽挑下一個主題,或從 AlphaLab 課程繼續學習。





