Hub 文件

DDUF

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

DDUF

概述

DDUF (DDUF's Diffusion Unified Format) 是一種用於擴散模型的單檔案格式,旨在透過將所有模型元件打包到一個檔案中,來統一不同的模型分發方法和權重儲存格式。它與語言無關,並且構建為無需下載整個檔案即可從遠端位置進行解析。

這項工作受到了 GGUF 格式的啟發。

請訪問 DDUF 組織,開始使用一些最流行的 DDUF 格式擴散模型。

我們張開雙臂歡迎貢獻!

為了建立一個被廣泛採用的檔案格式,我們需要社群的早期反饋。一切尚未定論,我們珍視每個人的意見。您的用例沒有被覆蓋到嗎?請在 DDUF 組織的討論區告訴我們。

它的主要特性包括:

  1. 單檔案打包。
  2. 基於 ZIP 檔案格式,以利用現有工具。
  3. 無壓縮,確保 mmap 相容性,以實現快速載入和儲存。
  4. 與語言無關:可以在 Python、JavaScript、Rust、C++ 等語言中實現工具。
  5. HTTP 友好:可以使用 HTTP Range 請求遠端獲取元資料和檔案結構。
  6. 靈活:每個模型元件都儲存在其自己的目錄中,遵循當前的 Diffusers 結構。
  7. 安全:使用 Safetensors 作為權重儲存格式,並禁止巢狀目錄以防止 ZIP 炸彈。

技術規範

從技術上講,一個 .dduf 檔案就是一個 .zip 歸檔檔案。透過建立在一個普遍支援的檔案格式之上,我們確保了已有強大的工具可用。然而,為滿足擴散模型的需求,強制執行了一些約束:

  • 資料必須以未壓縮方式儲存(標誌 0),允許使用記憶體對映進行惰性載入。
  • 資料必須使用 ZIP64 協議儲存,允許儲存大於 4GB 的檔案。
  • 歸檔檔案只能包含 .json.safetensors.model.txt 檔案。
  • 歸檔檔案的根目錄下必須存在一個 model_index.json 檔案。它必須包含一個鍵值對映,其中包含有關模型及其元件的元資料。
  • 每個元件必須儲存在各自的目錄中(例如,vae/text_encoder/)。巢狀檔案必須使用 UNIX 風格的路徑分隔符(/)。
  • 每個目錄必須對應於 model_index.json 索引中的一個元件。
  • 每個目錄必須包含一個 JSON 配置檔案(config.jsontokenizer_config.jsonpreprocessor_config.jsonscheduler_config.json 之一)。
  • 禁止使用子目錄。

想檢查您的檔案是否有效?請使用此 Space 進行檢查:https://huggingface.co/spaces/DDUF/dduf-check

使用方法

huggingface_hub 提供了在 Python 中處理 DDUF 檔案的工具。它包括內建的規則來驗證檔案完整性,以及用於讀取和匯出 DDUF 檔案的輔助函式。我們的目標是看到這些工具被 Python 生態系統採納,例如在 diffusers 的整合中。類似的功能也可以為其他語言(JavaScript、Rust、C++ 等)開發。

如何讀取 DDUF 檔案?

將一個路徑傳遞給 read_dduf_file 以讀取一個 DDUF 檔案。只會讀取元資料,這意味著這是一個輕量級的呼叫,不會耗盡您的記憶體。在下面的例子中,我們假設您已經將 FLUX.1-dev.dduf 檔案下載到本地。

>>> from huggingface_hub import read_dduf_file

# Read DDUF metadata
>>> dduf_entries = read_dduf_file("FLUX.1-dev.dduf")

read_dduf_file 返回一個對映,其中每個條目對應於 DDUF 歸檔中的一個檔案。一個檔案由一個 DDUFEntry 資料類表示,其中包含檔名、偏移量和條目在原始 DDUF 檔案中的長度。這些資訊對於讀取其內容而無需載入整個檔案非常有用。實際上,您不需要處理底層讀取,而是依賴於輔助函式。

例如,以下是如何載入 model_index.json 內容的方法:

>>> import json
>>> json.loads(dduf_entries["model_index.json"].read_text())
{'_class_name': 'FluxPipeline', '_diffusers_version': '0.32.0.dev0', '_name_or_path': 'black-forest-labs/FLUX.1-dev', ...

對於二進位制檔案,您會希望使用 as_mmap 來訪問原始位元組。這將返回一個對原始檔案的記憶體對映位元組。記憶體對映允許您只讀取您需要的位元組,而無需將所有內容載入到記憶體中。例如,以下是如何載入 safetensors 權重的方法:

>>> import safetensors.torch
>>> with dduf_entries["vae/diffusion_pytorch_model.safetensors"].as_mmap() as mm:
...     state_dict = safetensors.torch.load(mm) # `mm` is a bytes object

as_mmap 必須在上下文管理器中使用,以利用記憶體對映的特性。

如何寫入 DDUF 檔案?

將一個資料夾路徑傳遞給 export_folder_as_dduf 以匯出一個 DDUF 檔案。

# Export a folder as a DDUF file
>>> from huggingface_hub import export_folder_as_dduf
>>> export_folder_as_dduf("FLUX.1-dev.dduf", folder_path="path/to/FLUX.1-dev")

此工具會掃描資料夾,新增相關條目,並確保匯出的檔案是有效的。如果在過程中出現任何問題,將會引發一個 DDUFExportError

為了更靈活,可以使用 [export_entries_as_dduf] 來明確指定要包含在最終 DDUF 檔案中的檔案列表:

# Export specific files from the local disk.
>>> from huggingface_hub import export_entries_as_dduf
>>> export_entries_as_dduf(
...     dduf_path="stable-diffusion-v1-4-FP16.dduf",
...     entries=[ # List entries to add to the DDUF file (here, only FP16 weights)
...         ("model_index.json", "path/to/model_index.json"),
...         ("vae/config.json", "path/to/vae/config.json"),
...         ("vae/diffusion_pytorch_model.fp16.safetensors", "path/to/vae/diffusion_pytorch_model.fp16.safetensors"),
...         ("text_encoder/config.json", "path/to/text_encoder/config.json"),
...         ("text_encoder/model.fp16.safetensors", "path/to/text_encoder/model.fp16.safetensors"),
...         # ... add more entries here
...     ]
... )

export_entries_as_dduf 在您已經將模型儲存在磁碟上的情況下工作得很好。但是,如果您在記憶體中載入了一個模型,並希望將其直接序列化為一個 DDUF 檔案,該怎麼辦呢?export_entries_as_dduf 允許您透過提供一個 Python `generator` 來實現這一點,它告訴您如何迭代地序列化資料:

(...)

# Export state_dicts one by one from a loaded pipeline
>>> def as_entries(pipe: DiffusionPipeline) -> Generator[Tuple[str, bytes], None, None]:
...     # Build a generator that yields the entries to add to the DDUF file.
...     # The first element of the tuple is the filename in the DDUF archive. The second element is the content of the file.
...     # Entries will be evaluated lazily when the DDUF file is created (only 1 entry is loaded in memory at a time)
...     yield "vae/config.json", pipe.vae.to_json_string().encode()
...     yield "vae/diffusion_pytorch_model.safetensors", safetensors.torch.save(pipe.vae.state_dict())
...     yield "text_encoder/config.json", pipe.text_encoder.config.to_json_string().encode()
...     yield "text_encoder/model.safetensors", safetensors.torch.save(pipe.text_encoder.state_dict())
...     # ... add more entries here

>>> export_entries_as_dduf(dduf_path="my-cool-diffusion-model.dduf", entries=as_entries(pipe))

使用 Diffusers 載入 DDUF 檔案

Diffusers 內建了對 DDUF 檔案的整合。以下是如何從 Hub 上儲存的檢查點載入一個 pipeline 的示例:

from diffusers import DiffusionPipeline
import torch

pipe = DiffusionPipeline.from_pretrained(
    "DDUF/FLUX.1-dev-DDUF", dduf_file="FLUX.1-dev.dduf", torch_dtype=torch.bfloat16
).to("cuda")
image = pipe(
    "photo a cat holding a sign that says Diffusers", num_inference_steps=50, guidance_scale=3.5
).images[0]
image.save("cat.png")

常見問題

為什麼要建立在 ZIP 之上?

ZIP 提供了幾個優點:

  • 普遍支援的檔案格式
  • 讀取時無需額外依賴
  • 內建檔案索引
  • 廣泛的語言支援

為什麼不使用在歸檔開頭帶有目錄的 TAR?

請參閱此評論中的解釋。

為什麼不壓縮?

  • 允許直接記憶體對映大檔案
  • 確保一致且可預測的遠端檔案訪問
  • 防止檔案讀取期間的 CPU 開銷
  • 保持與 safetensors 的相容性

我可以修改 DDUF 檔案嗎?

不可以。目前,DDUF 檔案被設計為不可變的。要更新一個模型,請建立一個新的 DDUF 檔案。

哪些框架/應用支援 DDUF?

我們正在不斷聯絡其他庫和框架。如果您有興趣為您的專案新增支援,請在 DDUF 組織中發起一個討論。

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.