~/blog/verify-downloaded-models

LLM 深水區 · part 8

[Dev Workflow] 替 18 個量化模型庫補來源:下載後怎麼對版本與雜湊

❯ cat --toc

TL;DR

先找服務實際載入的檔案,再固定下載來源的完整 commit、比對 SHA-256,接著追上游與量化配方。我替自己的十八個 Hugging Face 模型庫補了來源紀錄,涵蓋 73 份權重與校準檔案;其中十七個 repo 當年的 base revision 沒有記錄。hash 能確認檔案相同,模型是否有後門仍未知。

下載的模型:從本地檔案查到量化來源與上游版本

前言

我自己也在 Hugging Face 發量化模型,帳號是 coolthor。要教人檢查第三方模型,先查自己的比較實在。這次替十八個模型 repo 補來源紀錄,也把找回的紀錄缺什麼寫清楚:十七個 repo 沒有記錄 base revision,也就是量化前那份模型的確切版本。

這跟下載者有什麼關係?同一個模型名稱,可以經過微調、合併、移除拒答傾向的 abliteration,再由別人量化。你要查的,是自己手上這份檔案經過哪些處理。如果還不熟量化,先看系列的量化演算法入門。這篇從已經下載好的檔案開始。

先找服務實際載入的檔案

先打開啟動服務的命令或設定,找到模型路徑。若服務還在跑,也可以查它開啟的檔案,對照實際檔名。介面上取的別名可能跟磁碟裡的模型不同,拿別名去搜尋,第一步就可能找錯。

如果你平常只從網頁介面選模型,先找介面背後的服務設定,再看它指向哪個目錄。這一步查的是目前正在用的東西。下載資料夾裡也許還放著好幾個版本,光找到一份同名檔案,還不能確定服務讀的就是它。

把完整路徑與檔名記下來,再找當初下載的 Hugging Face repo。repo 是誰發布的,要記帳號和 repo 名稱;只寫「Qwen 量化版」不夠。若手上只有執行框架產生的快取,也先註明這是快取。它可能經過轉換,無法直接拿來跟原始 checkpoint(公開發布的那份權重)比較。

下面這張圖把檔案比對與來源重建分開。hash 相符能確認發布檔;要查怎麼量化出來,還需要歷史來源與配方。

模型驗證順序:辨認實際檔案、固定發布版本、比較 hash、追上游與配方;各步的驗證範圍不同

第一份紀錄先寫這幾項就夠:本地檔名、直接下載來源、完整 commit、預期與實際 SHA-256。SHA-256 是從檔案內容算出來的一串值,方便比對兩份檔案是否相同。接著再查上游來源與處理步驟,別把全部問題塞給一個 hash 回答。

這份紀錄可以放在模型旁邊,讓以後換硬碟、搬服務時還找得到。對不到下載來源也先保留本地檔案的紀錄,寫「直接來源待查」。等你找到來源網址,就有東西可以接著比,不必又從辨認檔案重來一次。

固定完整 commit,再對照同一份發布檔

Hugging Face 上每個模型都是一個 repo,每次有人更新檔案,就會多一個 commit,也就是一個版本編號(一串 40 個字的英數字)。main 指的是「最新版」,會一直往前走。今天從 main 下載,過幾天再下載,拿到的內容可能不同。要留下能重查的紀錄,就把下載網址裡的版本固定成完整 commit,並保留檔名。模型卡與權重也可能分別在不同次 commit 更新,兩個版本要分開記。

下面用我的 Sulphur-2-distilled-NVFP4 模型卡示範。選它只因為檔案比較小(影片模型裡的一個元件),方便示範。先確認你有空間放這份約 1.45 GB 的檔案。

SHA-256 可以想成檔案的指紋:內容差一個位元,算出來的值就完全不同。所以只要你算出來的指紋,跟發布者公布的一字不差,就代表你拿到的是同一份檔案。接下來三步:下載這個版本的檔案、看檔案大小、算出它的指紋,再跟模型卡上寫的值比對。如果你平常只用網頁下載,可以直接在 Hugging Face 網頁上點那個 commit 的檔案,下載後用系統內建的指令算 hash,做法一樣。

在終端機跑下面這段,會先建立一個新的空資料夾,避免蓋到原本的檔案。權重版本固定在 d8f083b8d126bd06c292c42262588c400a8abe60。

下面第一段指令的意思是:開一個空資料夾,從 Hugging Face 下載這個版本的檔案。

workdir=$(mktemp -d)
cd "$workdir"
curl --fail --location \
  --output ltx_full_vae.safetensors \
  https://huggingface.co/coolthor/Sulphur-2-distilled-NVFP4/resolve/d8f083b8d126bd06c292c42262588c400a8abe60/ltx_full_vae.safetensors

等下載結束,先查大小:

wc -c < ltx_full_vae.safetensors

應該得到 1452240458 bytes。再依你的系統選一條命令,計算本地 SHA-256。

Linux:

sha256sum ltx_full_vae.safetensors

macOS:

shasum -a 256 ltx_full_vae.safetensors

輸出前面的完整 hash 應該是:

a48d539b06bd8628d514de36c3a3e816c08c217d2fe90534b6426978c6dca5d8

這裡要逐字比對整串,檔名和檔案大小也一起保留。模型如果拆成多份,每份都需要各自的紀錄;對完其中一份,只能確認那份檔案。

實際套到你的模型時,把範例的 repo、完整 commit 和檔名換成查到的版本,預期 hash 也要跟著換。若發布者沒有提供可比較的值,就先記下本地計算結果與缺少的資料,不能沿用這個範例的 hash。檢查完成後,把本地輸出和對照來源一起存好。

hash 相符,代表你拿到了指定發布檔

對完之後,先看你能寫下哪種結論。下面看「可以記什麼」這欄,避免把不同結果混在一起。

查到的結果可以記什麼
同一個固定版本,hash 相符本地內容與該版本發布檔相同
公開檔內容相符,下載版本沒留內容相符;取得時的 revision 未記錄
hash 不符有差異,原因待查
沒有可直接比較的上游同檔目前無法直接比對

hash 不符時,先核對 repo、commit 和檔案路徑,再確認下載有沒有完成。也要查是不是只拿到 Git LFS pointer。那是一小份用來指向大檔案的文字,拿到它,權重還沒下載到。若本地改過檔案,把修改內容記上去;差異本身還不能判定中毒。

hash 相符能證明的事有限。假設發布者的帳號遭入侵,攻擊者把權重和同頁的 checksum 一起換掉,下載者仍可能對出相同的值。你確認的是「跟這份發布檔相同」,上游是否正確、怎麼轉出來、有沒有後門,都還需要其他證據。

查量化來源時,一次追一個直接上游

找到量化 repo 後,讀模型卡的來源欄位。量化者拿到的可能已是別人微調或合併過的模型,先記那個直接來源,再往前追。你會需要來源 repo、當時的完整 commit,以及用什麼工具、什麼配方轉出來。

拿我自己的 Huihui-Qwen3.6-35B-A3B-abliterated-NVFP4-W4A4來說,量化的直接來源是 huihui-ai。查這份模型時,要把 huihui-ai 那一段留下來,才能看見量化前已經做過的處理。

遇到模型卡沒寫的地方,先記「未記錄」。如果只知道來源 repo,還不知道當年的 commit,就把這兩件事分開寫。這樣下次找到舊的下載紀錄或建置紀錄時,才知道還缺什麼。

進階:十八個 repo補了什麼,還缺什麼

不讀這節不影響前面的操作。下面保留我這次整理的範圍、數字,以及往後量化時要多記的資料。

十七個 repo 缺歷史 base revision,今天查 HEAD 補不回來

這次處理十八個自家 Hugging Face repo,只追加 README,補上來源說明與固定發布版本的檔案紀錄。涵蓋 73 份權重與校準檔案;73 筆 hash 取自固定 release 的 LFS metadata,也就是平台記錄的大檔案資訊。我沒有重新下載全部權重逐份計算,也沒有重跑量化或比較權重差異。

在這次找回的紀錄中,十七個 repo 的歷史 base revision 留為 not recorded。這表示這次沒有找到可靠的歷史版本,並不能斷言其他地方完全沒有紀錄。今天來源 repo的 HEAD 指向哪裡,只能告訴你今天的版本,補不出當年量化到底讀了哪份權重。把今天查到的 commit 填進去,反而會讓後來的人以為當年已經固定過版本。

唯一留有 base pin(確切上游版本)的 repo 是 VoxCPM2-Q4_K_M-GGUF:

openbmb/VoxCPM2@32279effe8c19989596f05d353d1447f51d9e915

所以它至少查得到上游版本,但要完整重現,還缺環境與處理步驟的紀錄。我在十八個 repo 的 README 寫明目前查得到什麼,沒做過的檢查也一起寫上。

本地盤點要分開記「內容相符」與「當時版本已知」

我也盤點了本地 34 份權重與周邊檔案。這組數字只是把比對結果分類,不能拿來算模型安全率。

比對結果數量
與原廠同 revision 相符4
與第三方同 revision 相符2
與原廠公開內容相符,取得 revision 不明1
與第三方公開內容相符,取得 revision 不明13
與公開檔不符,已有本地修改紀錄2
無直接上游同檔可比較12

十二份找不到對應的上游檔案,這次沒辦法做檔案比對。

Lazarus 說明了為什麼還要看模型的工具權限

Microsoft Research 的 Lazarus 研究介紹與論文展示:在 Nemotron-Terminal-8B 裡改七個平常不活躍的神經元就能植入後門。論文有一個不需微調的解析版本;另一個用 23 個例子做梯度微調的版本(Lazarus-SGD),在錄好的觸發測試軌跡上預測出指定 payload 的比例至少 98.8%。是否真的執行,取決於 agent 後續開放的工具與權限。作者也在 Qwen3.6-27B、Gemma-4-31B-IT 上做出同樣的修改。

這些數字限於研究測過的模型與條件。我的來源整理沒有發現後門,也沒有排除後門;上面的 hash 範例更沒有測模型行為。

如果模型接了 agent 工具,我建議再看一次它能動什麼:給最小需要的權限、隔離工作目錄與憑證、限制外連,會造成重大影響的命令交給人確認。這些是建議,我自己這次還沒動手改 agent 的權限設定。

下次量化時,把輸入、處理步驟與輸出一起記

以後自己量化,紀錄要跟著工作一起產生。至少保留這些資料:

  • 實際輸入:確切來源 repo、完整 commit、每份輸入檔的 hash。經過微調、合併或 abliteration 的來源逐段記。
  • 工具與環境:工具 commit、本地 patch、完整命令列參數,以及套件環境。
  • 校準資料:資料版本、選樣方式與 seed。
  • 轉換與輸出:各段轉換、合併、拆分的步驟,最後的檔案清單與各檔 hash。
  • 實際量測範圍:測過哪些行為、用了哪些條件,尚未測的地方分開寫。

量化後的權重本來就會跟原始高精度權重不同,直接比兩者的檔案 hash,無法分辨預期的量化差異與額外修改。要查這一段,得用同樣的來源和配方重跑一次量化,再用看得懂格式的工具逐個 tensor 比對。有了這些紀錄,其他人才有條件重跑、比較差異;仍不能保證跨硬體重跑後,每個位元都相同。

同系列:量化演算法入門。

常見問題

SHA-256 相符,到底驗證了什麼?
驗證你手上的檔案與指定發布版本的檔案內容相同。它不能證明量化來源、轉換配方或模型沒有後門;發布者若同時改掉權重與 checksum,兩者仍會相符。
以前下載模型沒記 revision,現在怎麼補?
先記下本地檔名與 SHA-256,再找可比對的公開檔案。內容相符可以記錄,但取得時的 revision 仍要寫未記錄。今天的 HEAD 不能補成當年下載的 commit。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。