Diffusers documentation

Filosofía

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.42.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Filosofía

🧨 Diffusers ofrece modelos de difusión preentrenados de última generación en múltiples modalidades. Su propósito es servir como un cajón de herramientas modular tanto para inferencia como para entrenamiento.

Nuestro objetivo es construir una biblioteca que resista el paso del tiempo, por lo que tomamos el diseño de la API muy en serio.

En pocas palabras, Diffusers está diseñado para ser una extensión natural de PyTorch. Por lo tanto, la mayoría de nuestras decisiones de diseño se basan en los Principios de diseño de PyTorch. Repasemos los más importantes:

Usabilidad por encima del rendimiento

  • Aunque Diffusers cuenta con muchas funciones integradas para mejorar el rendimiento (consulte Memoria y velocidad), los modelos siempre se cargan con la máxima precisión y la menor optimización. Por lo tanto, por defecto, los pipelines de difusión siempre se instancian en la CPU con precisión float32, a menos que el usuario defina lo contrario. Esto garantiza la usabilidad en diferentes plataformas y aceleradores y significa que no se requieren instalaciones complejas para ejecutar la biblioteca.
  • Diffusers busca ser un paquete ligero y, por lo tanto, tiene muy pocas dependencias obligatorias, pero muchas dependencias opcionales que pueden mejorar el rendimiento (como accelerate, safetensors, onnx, etc…). Nos esforzamos por mantener la biblioteca lo más ligera posible para que pueda agregarse como dependencia de otros paquetes sin mucha preocupación.
  • Diffusers prefiere un código simple y autoexplicativo frente a un código condensado y mágico. Esto significa que las sintaxis abreviadas, como las funciones lambda, y los operadores avanzados de PyTorch a menudo no son deseados.

Simple y fácil

Como afirma PyTorch, lo explícito es mejor que lo implícito y lo simple es mejor que lo complejo. Esta filosofía de diseño se refleja en varias partes de la biblioteca:

  • Seguimos la API de PyTorch con métodos como DiffusionPipeline.to para permitir que el usuario gestione los dispositivos.
  • Se prefiere lanzar mensajes de error concisos a corregir silenciosamente una entrada errónea. Diffusers busca enseñar al usuario, en lugar de hacer que la biblioteca sea lo más fácil de usar posible.
  • La lógica compleja del modelo frente al programador se expone en lugar de manejarse de forma mágica en el interior. Los programadores/muestreadores están separados de los modelos de difusión con dependencias mínimas entre sí. Esto obliga al usuario a escribir el bucle de desruido desplegado. Sin embargo, la separación permite una depuración más fácil y le da al usuario más control para adaptar el proceso de desruido o cambiar los modelos de difusión o los programadores.
  • Los componentes entrenados por separado del pipeline de difusión, por ejemplo el codificador de texto, el unet y el autoencoder variacional, tienen cada uno su propia clase de modelo. Esto obliga al usuario a gestionar la interacción entre los diferentes componentes del modelo, y el formato de serialización separa los componentes del modelo en archivos distintos. Sin embargo, esto permite una depuración y personalización más fáciles. El entrenamiento con DreamBooth o Textual Inversion es muy sencillo gracias a la capacidad de Diffusers para separar componentes individuales del pipeline de difusión.

Abstracción ajustable y amigable para los contribuyentes

Para gran parte de la biblioteca, Diffusers adopta un importante principio de diseño de la biblioteca Transformers, que es preferir el código copiado y pegado frente a abstracciones apresuradas. Este principio de diseño es muy opinado y contrasta marcadamente con principios de diseño populares como No te repitas (DRY). En pocas palabras, al igual que Transformers hace con los archivos de modelado, Diffusers prefiere mantener un nivel de abstracción extremadamente bajo y un código muy autosuficiente para los pipelines y los schedulers. Las funciones, los bloques de código largos e incluso las clases pueden copiarse en varios archivos, lo que a primera vista puede parecer una elección de diseño deficiente y descuidada que hace que la biblioteca sea inmantenible. Sin embargo, este diseño ha demostrado ser extremadamente exitoso para Transformers y tiene mucho sentido para las bibliotecas de aprendizaje automático de código abierto impulsadas por la comunidad porque:

  • El aprendizaje automático es un campo de avance extremadamente rápido en el que los paradigmas, las arquitecturas de modelos y los algoritmos cambian con rapidez, lo que dificulta enormemente la definición de abstracciones de código duraderas.
  • Los profesionales del Machine Learning suelen preferir el código autocontenido frente al que contiene muchas abstracciones, ya que les gusta poder ajustar rápidamente el código existente para la ideación y la investigación.
  • Las bibliotecas de código abierto dependen de las contribuciones de la comunidad y, por lo tanto, deben construir una biblioteca que sea fácil de contribuir. Cuanto más abstracto sea el código, más dependencias tendrá, más difícil será de leer y más difícil será contribuir. Los colaboradores simplemente dejan de contribuir a bibliotecas muy abstractas por miedo a romper funcionalidades vitales. Si contribuir a una biblioteca no puede romper otro código fundamental, no solo resulta más atractivo para los nuevos colaboradores potenciales, sino que también es más fácil de revisar y contribuir a varias partes en paralelo.

En Hugging Face, llamamos a este diseño single-file policy, lo que significa que casi todo el código de una clase determinada debe escribirse en un único archivo autocontenido. Para leer más sobre la filosofía, puedes echar un vistazo a esta publicación de blog.

En Diffusers, seguimos esta filosofía para pipelines, schedulers y modelos por igual. Algunos modelos más antiguos son anteriores a esta convención y se mantienen tal cual; todas las nuevas arquitecturas de modelos residen en sus propios archivos autocontenidos. Consulte la sección Models a continuación para más detalles.

Genial, ahora deberías haber comprendido en general por qué 🧨 Diffusers está diseñado de esta manera 🤗. Intentamos aplicar estos principios de diseño de forma coherente en toda la biblioteca. No obstante, hay algunas excepciones menores a la filosofía o algunas desafortunadas decisiones de diseño. Si tienes comentarios sobre el diseño, nos encantaría ❤️ escucharlos directamente en GitHub.

Filosofía de diseño en detalle

Ahora, los detalles concretos de la filosofía de diseño. Diffusers te ofrece dos formas de componer modelos y schedulers en un flujo de trabajo ejecutable: las pipelines estándar, que son monolíticas y tienen una tarea por clase de pipeline, y Modular Diffusers, que es componible y basado en bloques. Las secciones siguientes abordan, en orden, las pipelines, las pipelines modulares, los modelos y los schedulers.

Pipelines

Los pipelines, ya sean estándar o modulares, están diseñados únicamente para inferencia. Su objetivo es ser fáciles de usar (por lo que no siguen al 100% el principio de Simple over easy): son legibles, autoexplicativos, fáciles de ajustar y se consideran mejores como ejemplos de cómo utilizar modelos y schedulers. No son completos en funcionalidad. Para construir interfaces de usuario completas sobre Diffusers, utiliza Modular Diffusers.

Se siguen los siguientes principios de diseño:

  • Los pipelines siguen la política de archivo único. Todos los pipelines se encuentran en directorios individuales bajo src/diffusers/pipelines. Una carpeta de pipeline corresponde a un paper/proyecto/lanzamiento de difusión. Varios archivos de pipeline pueden agruparse en una sola carpeta de pipeline, como se hace en src/diffusers/pipelines/stable-diffusion. Si los pipelines comparten funcionalidad similar, se puede hacer uso del mecanismo # Copied from.
  • Todos los pipelines heredan de DiffusionPipeline.
  • Cada pipeline consta de diferentes componentes de modelo y programador, que están documentados en el archivo model_index.json, son accesibles como atributos del pipeline con el mismo nombre y pueden compartirse entre pipelines con la función DiffusionPipeline.components.
  • Cada pipeline debe poder cargarse mediante la función DiffusionPipeline.from_pretrained.
  • Cada pipeline debe tener una única forma de ejecutarse mediante un método __call__. La nomenclatura de los argumentos de __call__ debe ser coherente en todos los pipelines.
  • Los pipelines deben nombrarse según la tarea que están diseñados para resolver.

Diffusers modulares

Modular Diffusers es la alternativa componible a las pipelines estándar. Construyes un flujo de trabajo a partir de bloques de pipeline reutilizables que puedes combinar, intercambiar y compartir. Las pipelines estándar son ejemplos de referencia sueltos sobre cómo usar modelos y programadores. Modular Diffusers es la ruta recomendada para construir interfaces de usuario completas sobre Diffusers y para que la comunidad construya y comparta nuevas pipelines de forma descentralizada.

Se siguen los siguientes principios de diseño:

  • Los pipelines modulares siguen la política de archivo único. Cada uno se encuentra en su propia carpeta bajo src/diffusers/modular_pipelines/, y la carpeta divide el flujo de trabajo en un archivo por etapa: encoders.py, before_denoise.py, denoise.py y decoders.py. Dos archivos más completan el pipeline. modular_blocks_<model>.py ensambla las etapas y modular_pipeline.py define la subclase ModularPipeline específica de cada modelo. Los pipelines modulares no se importan entre sí.
  • Each modular pipeline is defined as a set of ModularPipelineBlocks. Leaf blocks live in the stage files (encoders.py, before_denoise.py, denoise.py, decoders.py), and modular_blocks_<model>.py assembles them into the full workflow with container classes like SequentialPipelineBlocks and AutoPipelineBlocks. This splits apart two concepts that DiffusionPipeline combines. A block is a pure definition. It declares inputs, outputs, and component dependencies, but holds no weights and can’t run. A ModularPipeline, created with .init_pipeline(repo_id), is the runnable counterpart. Keeping blocks stateless and weight-free is what makes them freely composable, swappable, and shareable across workflows.
  • Para admitir una nueva tarea, escriba los bloques específicos de la tarea, compóngalos con los existentes y registre el flujo de trabajo en _workflow_map en el ensamblaje de bloques de nivel superior. Un único ModularPipeline puede admitir muchos flujos de trabajo, como texto a imagen, imagen a imagen e inpainting, mientras que un DiffusionPipeline solo ejecuta uno.

Consulte la documentación de Modular Diffusers para obtener la guía completa de diseño y uso.

Modelos

Los modelos están diseñados como cajas de herramientas configurables que son extensiones naturales de la clase Module de PyTorch. Deben seguir la política de un solo archivo. Algunos modelos más antiguos preceden a esta convención y se mantienen tal cual. Trátelos como excepciones de legado, no como patrones a seguir para nuevos modelos. Por ejemplo, la clase original UNet2DConditionModel se utilizó para varias variaciones de UNet.

Se siguen los siguientes principios de diseño:

  • Cada tipo de arquitectura de modelo se encuentra en su propia carpeta bajo src/diffusers/models, por ejemplo transformers/, autoencoders/ o unets/. Cada familia de modelos tiene su propio archivo dentro de esa carpeta, como transformer_flux.py y transformer_wan.py.
  • Los modelos siguen la política de archivo único. Cada archivo de modelo debe ser autosuficiente, excepto por un pequeño número de módulos estándar que todos los modelos utilizan de forma idéntica, como las incrustaciones de paso temporal y las capas de normalización. Importa esos desde embeddings.py y normalization.py.
  • Los modelos buscan exponer la complejidad, al igual que la clase Module de PyTorch, y proporcionar mensajes de error claros.
  • Todos los modelos heredan de ModelMixin y ConfigMixin.
  • Los modelos pueden optimizarse para el rendimiento cuando no requieren cambios importantes en el código, mantienen la compatibilidad hacia atrás y ofrecen ganancias significativas en memoria o cómputo.
  • Los modelos deben tener, por defecto, la configuración de mayor precisión y menor rendimiento.
  • Para integrar una nueva arquitectura de modelo similar a una existente, copia el archivo existente como punto de partida y adáptalo. Usa las anotaciones # Copied from en las capas que permanecen idénticas para que make fix-copies las mantenga sincronizadas.

Planificadores

Los Schedulers son responsables de guiar el proceso de desruido para la inferencia, así como de definir un calendario de ruido para el entrenamiento. Están diseñados como clases individuales con archivos de configuración cargables y siguen estrictamente la política de archivo único.

Se siguen los siguientes principios de diseño:

  • Todos los programadores se encuentran en src/diffusers/schedulers.
  • Los Schedulers no están permitidos para importar desde archivos de utilidades grandes y deben mantenerse muy autocontenidos.
  • Un archivo Python de programador corresponde a un algoritmo de programador (tal como podría definirse en un artículo).
  • Si los programadores comparten funcionalidades similares, podemos hacer uso del mecanismo # Copied from.
  • Todos los Schedulers heredan de SchedulerMixin y ConfigMixin.
  • Los programadores se pueden intercambiar fácilmente con el método ConfigMixin.from_config, como se explica en detalle aquí.
  • Cada scheduler debe tener un set_num_inference_steps y una función step. set_num_inference_steps(...) debe llamarse antes de cada proceso de desruido, es decir, antes de que se llame a step(...).
  • Cada programador expone los pasos de tiempo sobre los que se debe iterar mediante un atributo timesteps, que es un array de pasos de tiempo en los que se llamará al modelo.
  • La función step(...) toma la salida predicha del modelo y la muestra “actual” (x_t) y devuelve la muestra “anterior”, ligeramente menos ruidosa (x_t-1).
  • Dada la complejidad de los programadores de difusión, la función step no expone toda esa complejidad y puede resultar algo como una “caja negra”.
  • En casi todos los casos, los programadores nuevos deben implementarse en un archivo de programación nuevo.
Update on GitHub