Hub documentation

DDUF

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

DDUF

Resumen

DDUF (DDUF’s Diffusion Unified Format) es un formato de archivo único para modelos de difusión que busca unificar los distintos métodos de distribución de modelos y formatos de guardado de pesos al empaquetar todos los componentes del modelo en un solo archivo. Es independiente del lenguaje y está diseñado para poder analizarse desde una ubicación remota sin necesidad de descargar el archivo completo.

Este trabajo se inspira en el formato GGUF.

Echa un vistazo a la organización DDUF para empezar a usar algunos de los modelos de difusión más populares en DDUF.

¡Aceptamos contribuciones con los brazos abiertos!

Para crear un formato de archivo ampliamente adoptado, necesitamos retroalimentación temprana de la comunidad. Nada está definido de forma definitiva y valoramos la opinión de todos. ¿Tu caso de uso no está cubierto? Por favor, infórmalo en las discusiones de la organización DDUF.

Entre sus características principales se incluyen las siguientes.

  1. Empaquetado de archivo único.
  2. Basado en el formato de archivo ZIP para aprovechar las herramientas existentes.
  3. Sin compresión, lo que garantiza la compatibilidad con mmap para una carga y un guardado rápidos.
  4. Independiente del lenguaje: las herramientas pueden implementarse en Python, JavaScript, Rust, C++, etc.
  5. Compatible con HTTP: los metadatos y la estructura de archivos se pueden obtener de forma remota mediante solicitudes HTTP Range.
  6. Flexible: cada componente del modelo se guarda en su propio directorio, siguiendo la estructura actual de Diffusers.
  7. Seguro: utiliza Safetensors como formato de guardado de pesos y prohíbe los directorios anidados para prevenir bombas ZIP.

Especificaciones técnicas

Técnicamente, un archivo .dduf es un archivo .zip. Al basarnos en un formato de archivo universalmente compatible, garantizamos que ya exista una herramienta robusta. Sin embargo, se aplican algunas restricciones para cumplir con los requisitos de los modelos de difusión:

  • Los datos deben almacenarse sin comprimir (bandera 0), lo que permite la carga diferida mediante mapeo de memoria.
  • Los datos deben almacenarse usando el protocolo ZIP64, lo que permite guardar archivos de más de 4 GB.
  • El archivo solo puede contener archivos .json, .safetensors, .model y .txt.
  • Debe estar presente un archivo model_index.json en la raíz del archivo. Debe contener un mapeo de clave-valor con metadatos sobre el modelo y sus componentes.
  • Cada componente debe almacenarse en su propio directorio (p. ej., vae/, text_encoder/). Los archivos anidados deben usar separadores de ruta de estilo UNIX (/).
  • Cada directorio debe corresponder a un componente en el índice model_index.json.
  • Cada directorio debe contener un archivo de configuración json (uno de config.json, tokenizer_config.json, preprocessor_config.json, scheduler_config.json).
  • No se permiten subdirectorios.

¿Quieres comprobar si tu archivo es válido? Revísalo usando este Space: https://huggingface.co/spaces/DDUF/dduf-check.

Uso

huggingface_hub proporciona herramientas para gestionar archivos DDUF en Python. Incluye reglas integradas para validar la integridad de los archivos y utilidades para leer y exportar archivos DDUF. El objetivo es que estas herramientas se adopten en el ecosistema de Python, como en la integración de diffusers. Se pueden desarrollar herramientas similares para otros lenguajes (JavaScript, Rust, C++, etc.).

Cómo leer un archivo DDUF?

Pasa una ruta a read_dduf_file para leer un archivo DDUF. Solo se lee la metadatos, lo que significa que es una llamada ligera que no agotará tu memoria. En el ejemplo siguiente, consideramos que ya has descargado localmente el archivo 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 devuelve un mapeo donde cada entrada corresponde a un archivo en el archivo DDUF. Un archivo se representa mediante una dataclass DDUFEntry que contiene el nombre del archivo, el desplazamiento y la longitud de la entrada en el archivo DDUF original. Esta información es útil para leer su contenido sin cargar el archivo completo. En la práctica, no tendrás que manejar la lectura a bajo nivel, sino que podrás apoyarte en funciones auxiliares.

Por ejemplo, así es como se carga el contenido de 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', ...

Para archivos binarios, querrás acceder a los bytes crudos usando as_mmap. Esto devuelve los bytes como un mapeo de memoria sobre el archivo original. El mapeo de memoria te permite leer solo los bytes que necesitas sin cargar todo en memoria. Por ejemplo, así es como se cargan los pesos de 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 debe usarse en un contexto de administrador para aprovechar las propiedades de mapeo de memoria.

Cómo escribir un archivo DDUF

Pase una ruta de carpeta a export_folder_as_dduf para exportar un archivo 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")

Esta herramienta analiza la carpeta, agrega las entradas relevantes y garantiza que el archivo exportado sea válido. Si algo sale mal durante el proceso, se lanza un DDUFExportError.

Para mayor flexibilidad, use [export_entries_as_dduf] para especificar explícitamente una lista de archivos a incluir en el archivo DDUF final:

# 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 funciona bien si ya has guardado tu modelo en el disco. Pero, ¿qué pasa si tienes un modelo cargado en memoria y quieres serializarlo directamente en un archivo DDUF? export_entries_as_dduf te permite hacerlo proporcionando un generator de Python que indica cómo serializar los datos de forma iterativa:

(...)

# 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))

Cargar un archivo DDUF con Diffusers

Diffusers tiene una integración integrada para archivos DDUF. A continuación se muestra un ejemplo de cómo cargar un pipeline desde un punto de control almacenado en el Hub:

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")

F.A.Q.

¿Por qué construir sobre ZIP?

ZIP ofrece varias ventajas:

  • Formato de archivo universalmente compatible
  • Sin dependencias adicionales para la lectura
  • Indexación de archivos integrada
  • Amplio soporte de idiomas

¿Por qué no usar un TAR con un índice al principio del archivo?

Vea la explicación en este comentario.

¿Por qué no hay compresión?

  • Permite el mapeo directo de memoria de archivos grandes
  • Garantiza un acceso a archivos remotos consistente y predecible
  • Evita la sobrecarga de CPU durante la lectura de archivos
  • Mantiene la compatibilidad con safetensors

¿Puedo modificar un archivo DDUF?

No. Por ahora, los archivos DDUF están diseñados para ser inmutables. Para actualizar un modelo, crea un nuevo archivo DDUF.

¿Qué frameworks/aplicaciones admiten DDUFs?

Estamos en contacto constante con otras bibliotecas y marcos de trabajo. Si te interesa añadir soporte a tu proyecto, abre una Discusión en la organización DDUF.

Update on GitHub