Diffusers documentation
Filosofia
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.topara 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çãoDiffusionPipeline.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.pyedecoders.py. Mais dois arquivos completam o pipeline.modular_blocks_<model>.pymonta as etapas, emodular_pipeline.pydefine 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), andmodular_blocks_<model>.pyassembles them into the full workflow with container classes like SequentialPipelineBlocks and AutoPipelineBlocks. This splits apart two concepts thatDiffusionPipeline 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_mapna montagem do bloco de nível superior. Um únicoModularPipelinepode suportar muitos fluxos de trabalho, como texto-para-imagem, imagem-para-imagem e inpainting, enquanto umDiffusionPipelineexecuta 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
Moduledo PyTorch, e fornecer mensagens de erro claras. - Todos os modelos herdam de
ModelMixineConfigMixin. - 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 fromem camadas que permanecem idênticas para que omake fix-copiesas 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
SchedulerMixineConfigMixin. - 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_stepse uma funçãostep.set_num_inference_steps(...)precisa ser chamado antes de todo processo de desruidamento, ou seja, antes destep(...)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
stepnã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.