Diffusers documentation

Filosofia

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

Filosofia

🧨 O Diffusers oferece modelos de difusão pré-treinados de última geração em várias modalidades. Seu objetivo é servir como uma caixa de ferramentas modular para inferência e treinamento.

Nosso objetivo é construir uma biblioteca que resista ao teste do tempo, e por isso levamos o design da API muito a sério.

Em resumo, o Diffusers foi construído para ser uma extensão natural do PyTorch. Portanto, a maioria das nossas escolhas de design é baseada nos Princípios de Design do PyTorch. Vamos revisar os mais importantes:

Usabilidade em vez de desempenho

  • Embora o Diffusers possua muitos recursos integrados para melhorar o desempenho (veja Memória e Velocidade), os modelos são sempre carregados com a maior precisão e a menor otimização. Portanto, por padrão, os pipelines de difusão são sempre instanciados na CPU com precisão float32, a menos que o usuário defina o contrário. Isso garante a usabilidade em diferentes plataformas e aceleradores e significa que nenhuma instalação complexa é necessária para executar a biblioteca.
  • Diffusers busca ser um pacote leve e, portanto, possui poucas dependências obrigatórias, mas muitas dependências opcionais que podem melhorar o desempenho (como accelerate, safetensors, onnx, etc…). Esforçamo-nos para manter a biblioteca o mais leve possível, para que possa ser adicionada como dependência de outros pacotes sem grandes preocupações.
  • Diffusers prefere código simples e autoexplicável em vez de código condensado e mágico. Isso significa que sintaxes de código abreviadas, como funções lambda, e operadores avançados do PyTorch geralmente não são desejados.

Simples e fácil

Conforme afirma o PyTorch, explícito é melhor que implícito e simples é melhor que complexo. Essa filosofia de design é refletida em várias partes da biblioteca:

  • Seguimos a API do PyTorch com métodos como DiffusionPipeline.to para permitir que o usuário gerencie os dispositivos.
  • A geração de mensagens de erro concisas é preferível à correção silenciosa de entradas incorretas. O Diffusers visa ensinar o usuário, em vez de tornar a biblioteca o mais fácil de usar possível.
  • A lógica complexa do modelo em comparação com a do agendador é exposta, em vez de ser tratada magicamente internamente. Agendadores/Amostradores são separados dos modelos de difusão, com dependências mínimas entre si. Isso obriga o usuário a escrever o loop de desruido desenrolado. No entanto, essa separação permite um depuramento mais fácil e dá ao usuário mais controle sobre a adaptação do processo de desruido ou a troca de modelos de difusão ou agendadores.
  • Os componentes treinados separadamente do pipeline de difusão, por exemplo o codificador de texto, o unet e o autoencoder variacional, cada um possui sua própria classe de modelo. Isso obriga o usuário a lidar com a interação entre os diferentes componentes do modelo, e o formato de serialização separa os componentes do modelo em arquivos diferentes. No entanto, isso permite um depuramento e personalização mais fáceis. O treinamento de DreamBooth ou Textual Inversion é muito simples graças à capacidade do Diffusers de separar componentes individuais do pipeline de difusão.

Abstração ajustável e amigável para contribuidores

Para grande parte da biblioteca, o Diffusers adota um importante princípio de design da biblioteca Transformers, que é preferir código copiado e colado a abstrações apressadas. Esse princípio de design é muito opinativo e contrasta fortemente com princípios de design populares, como Não se repita (DRY). Em resumo, assim como o Transformers faz para os arquivos de modelagem, o Diffusers prefere manter um nível de abstração extremamente baixo e um código muito autocontido para pipelines e agendadores. Funções, blocos de código longos e até mesmo classes podem ser copiados para vários arquivos, o que, à primeira vista, pode parecer uma escolha de design ruim e desleixada que torna a biblioteca impossível de manter. No entanto, esse design se provou extremamente bem-sucedido para o Transformers e faz muito sentido para bibliotecas de aprendizado de máquina abertas e impulsionadas pela comunidade, porque:

  • Machine Learning é um campo em evolução extremamente rápida, no qual paradigmas, arquiteturas de modelos e algoritmos mudam rapidamente, o que torna muito difícil definir abstrações de código duradouras.
  • Praticantes de Machine Learning gostam de poder ajustar rapidamente o código existente para ideação e pesquisa e, portanto, preferem código autossuficiente em vez de um que contenha muitas abstrações.
  • Bibliotecas de código aberto dependem de contribuições da comunidade e, portanto, devem construir uma biblioteca que seja fácil de contribuir. Quanto mais abstrato for o código, mais dependências ele terá, mais difícil será de ler e mais difícil será de contribuir. Os contribuidores simplesmente deixam de contribuir para bibliotecas muito abstratas por medo de quebrar funcionalidades vitais. Se contribuir para uma biblioteca não puder quebrar outro código fundamental, isso não apenas torna o processo mais convidativo para novos contribuidores em potencial, mas também facilita a revisão e a contribuição para múltiplas partes em paralelo.

Na Hugging Face, chamamos esse design de política de arquivo único, o que significa que quase todo o código de uma determinada classe deve ser escrito em um único arquivo autossuficiente. Para ler mais sobre a filosofia, você pode dar uma olhada em este post no blog.

No Diffusers, seguimos essa filosofia para pipelines, schedulers e modelos. Alguns modelos mais antigos antecederam essa convenção e são mantidos como estão; todas as novas arquiteturas de modelos estão em seus próprios arquivos autossuficientes. Consulte a seção Models abaixo para mais detalhes.

Ótimo, agora você deve ter compreendido em geral por que o 🧨 Diffusers é projetado da forma como é 🤗. Tentamos aplicar esses princípios de design de forma consistente em toda a biblioteca. No entanto, existem algumas pequenas exceções à filosofia ou algumas escolhas de design infelizes. Se você tiver feedback sobre o design, gostaríamos ❤️ de ouvi-lo diretamente no GitHub.

Detalhes da filosofia de design

Agora, os detalhes práticos da filosofia de design. O Diffusers oferece duas formas de compor modelos e schedulers em um fluxo de trabalho executável: os pipelines padrão, que são monolíticos, com uma tarefa por classe de pipeline, e o Modular Diffusers, que é composível e baseado em blocos. As seções a seguir abordam, em ordem, pipelines, pipelines modulares, modelos e schedulers.

Pipelines

Pipelines, padrão ou modulares, destinam-se apenas à inferência. Eles são projetados para serem fáceis de usar (portanto, não seguem Simple over easy 100%): legíveis, autoexplicativos, fáceis de ajustar e vistos idealmente como exemplos de como usar models e schedulers. Eles não possuem funcionalidade completa. Para construir interfaces de usuário com funcionalidade completa sobre o Diffusers, use Modular Diffusers.

Os seguintes princípios de design são seguidos:

  • Pipelines follow the single-file policy. All pipelines can be found in individual directories under src/diffusers/pipelines. One pipeline folder corresponds to one diffusion paper/project/release. Multiple pipeline files can be gathered in one pipeline folder, as it’s done for src/diffusers/pipelines/stable-diffusion. If pipelines share similar functionality, one can make use of the # Copied from mechanism.
  • Todos os pipelines herdam de DiffusionPipeline.
  • Cada pipeline consiste em diferentes componentes de modelo e agendador, que estão documentados no arquivo model_index.json, são acessíveis como atributos do pipeline com o mesmo nome e podem ser compartilhados entre pipelines com a função DiffusionPipeline.components.
  • Todo pipeline deve ser carregável por meio da função DiffusionPipeline.from_pretrained.
  • Cada pipeline deve ter uma única forma de ser executado por meio de um método __call__. A nomenclatura dos argumentos de __call__ deve ser consistente em todos os pipelines.
  • Os pipelines devem ser nomeados de acordo com a tarefa que se destinam a resolver.

Diffusers modulares

Modular Diffusers é a alternativa composível aos pipelines padrão. Você constrói um fluxo de trabalho a partir de blocos de pipeline reutilizáveis que podem ser combinados, trocados e compartilhados. Os pipelines padrão são exemplos de referência soltos sobre como usar modelos e agendadores. O Modular Diffusers é o caminho recomendado para construir interfaces de usuário completas em cima do Diffusers e para que a comunidade construa e compartilhe novos pipelines de forma descentralizada.

Os seguintes princípios de design são seguidos:

  • Os pipelines modulares seguem a política de arquivo único. Cada um fica em sua própria pasta sob src/diffusers/modular_pipelines/, e a pasta divide o fluxo de trabalho em um arquivo por etapa: encoders.py, before_denoise.py, denoise.py e decoders.py. Mais dois arquivos completam o pipeline. modular_blocks_<model>.py monta as etapas, e modular_pipeline.py define a subclasse ModularPipeline específica para cada modelo. Os pipelines modulares não fazem importações cruzadas entre si.
  • 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 suportar uma nova tarefa, escreva os blocos específicos da tarefa, componha-os com os existentes e registre o fluxo de trabalho em _workflow_map na montagem do bloco de nível superior. Um único ModularPipeline pode suportar muitos fluxos de trabalho, como texto-para-imagem, imagem-para-imagem e inpainting, enquanto um DiffusionPipeline executa apenas um.

Consulte a documentação do Modular Diffusers para o guia completo de design e uso.

Modelos

Os modelos são projetados como caixas de ferramentas configuráveis que são extensões naturais da classe Module do PyTorch. Eles devem seguir a política de arquivo único. Alguns modelos mais antigos antecede essa convenção e são mantidos como estão. Trate-os como exceções legadas, não como padrões a serem seguidos para novos modelos. Por exemplo, a classe original UNet2DConditionModel foi usada para várias variações de UNet.

Os seguintes princípios de design são seguidos:

  • Cada tipo de arquitetura de modelo fica em sua própria pasta sob src/diffusers/models, por exemplo transformers/, autoencoders/ ou unets/. Cada família de modelos tem seu próprio arquivo dentro dessa pasta, como transformer_flux.py e transformer_wan.py.
  • Os modelos seguem a política de arquivo único. Cada arquivo de modelo deve ser autocontido, exceto por um pequeno número de módulos padrão que todos os modelos usam de forma idêntica, como incorporações de passo de tempo e camadas de normalização. Importe-os de embeddings.py e normalization.py.
  • Os modelos pretendem expor a complexidade, assim como a classe Module do PyTorch, e fornecer mensagens de erro claras.
  • Todos os modelos herdam de ModelMixin e ConfigMixin.
  • Os modelos podem ser otimizados para desempenho quando isso não exige alterações significativas no código, mantém a compatibilidade reversa e proporciona ganhos substanciais de memória ou de computação.
  • Os modelos devem, por padrão, ter a configuração de maior precisão e menor desempenho.
  • Para integrar uma nova arquitetura de modelo semelhante a uma existente, copie o arquivo existente como ponto de partida e adapte-o. Use as anotações # Copied from em camadas que permanecem idênticas para que o make fix-copies as mantenha sincronizadas.

Agendadores

Os Schedulers são responsáveis por orientar o processo de remoção de ruído durante a inferência, bem como por definir um cronograma de ruído para o treinamento. Eles são projetados como classes individuais com arquivos de configuração carregáveis e seguem rigorosamente a política de arquivo único.

Os seguintes princípios de design são seguidos:

  • Todos os agendadores estão em src/diffusers/schedulers.
  • Os Schedulers não podem importar de arquivos de utilitários grandes e devem ser mantidos muito autocontidos.
  • Um arquivo Python de agendador corresponde a um algoritmo de agendamento (como pode ser definido em um artigo).
  • Se os agendadores compartilham funcionalidades semelhantes, podemos fazer uso do mecanismo # Copied from.
  • Todos os Schedulers herdam de SchedulerMixin e ConfigMixin.
  • Os agendadores podem ser facilmente substituídos pelo método ConfigMixin.from_config, conforme explicado em detalhes aqui.
  • Todo scheduler precisa ter um set_num_inference_steps e uma função step. set_num_inference_steps(...) precisa ser chamado antes de todo processo de desruidamento, ou seja, antes de step(...) ser chamado.
  • Cada scheduler expõe os timesteps a serem percorridos por meio de um atributo timesteps, que é um array de timesteps em que o modelo será chamado.
  • A função step(...) recebe a saída prevista do modelo e a amostra “atual” (x_t) e retorna a amostra “anterior”, ligeiramente menos ruidosa (x_t-1).
  • Dada a complexidade dos agendadores de difusão, a função step não expõe toda essa complexidade e pode ser um pouco uma “caixa-preta”.
  • Na grande maioria dos casos, novos agendadores devem ser implementados em um novo arquivo de agendamento.
Update on GitHub