NadaGh's picture
End of training
3a25a0a verified

[[open-in-colab]]

Tour rápido

Modelos de difusão são treinados para remover o ruído Gaussiano aleatório passo a passo para gerar uma amostra de interesse, como uma imagem ou áudio. Isso despertou um tremendo interesse em IA generativa, e você provavelmente já viu exemplos de imagens geradas por difusão na internet. 🧨 Diffusers é uma biblioteca que visa tornar os modelos de difusão amplamente acessíveis a todos.

Seja você um desenvolvedor ou um usuário, esse tour rápido irá introduzir você ao 🧨 Diffusers e ajudar você a começar a gerar rapidamente! Há três componentes principais da biblioteca para conhecer:

  • O [DiffusionPipeline] é uma classe de alto nível de ponta a ponta desenhada para gerar rapidamente amostras de modelos de difusão pré-treinados para inferência.
  • Modelos pré-treinados populares e módulos que podem ser usados como blocos de construção para criar sistemas de difusão.
  • Vários Agendadores diferentes - algoritmos que controlam como o ruído é adicionado para treinamento, e como gerar imagens sem o ruído durante a inferência.

Esse tour rápido mostrará como usar o [DiffusionPipeline] para inferência, e então mostrará como combinar um modelo e um agendador para replicar o que está acontecendo dentro do [DiffusionPipeline].

Esse tour rápido é uma versão simplificada da introdução 🧨 Diffusers notebook para ajudar você a começar rápido. Se você quer aprender mais sobre o objetivo do 🧨 Diffusers, filosofia de design, e detalhes adicionais sobre a API principal, veja o notebook!

Antes de começar, certifique-se de ter todas as bibliotecas necessárias instaladas:

# uncomment to install the necessary libraries in Colab
#!pip install --upgrade diffusers accelerate transformers

DiffusionPipeline

O [DiffusionPipeline] é a forma mais fácil de usar um sistema de difusão pré-treinado para geração. É um sistema de ponta a ponta contendo o modelo e o agendador. Você pode usar o [DiffusionPipeline] pronto para muitas tarefas. Dê uma olhada na tabela abaixo para algumas tarefas suportadas, e para uma lista completa de tarefas suportadas, veja a tabela Resumo do 🧨 Diffusers.

Tarefa Descrição Pipeline
Unconditional Image Generation gera uma imagem a partir do ruído Gaussiano unconditional_image_generation
Text-Guided Image Generation gera uma imagem a partir de um prompt de texto conditional_image_generation
Text-Guided Image-to-Image Translation adapta uma imagem guiada por um prompt de texto img2img
Text-Guided Image-Inpainting preenche a parte da máscara da imagem, dado a imagem, a máscara e o prompt de texto inpaint
Text-Guided Depth-to-Image Translation adapta as partes de uma imagem guiada por um prompt de texto enquanto preserva a estrutura por estimativa de profundidade depth2img

Comece criando uma instância do [DiffusionPipeline] e especifique qual checkpoint do pipeline você gostaria de baixar. Você pode usar o [DiffusionPipeline] para qualquer checkpoint armazenado no Hugging Face Hub. Nesse quicktour, você carregará o checkpoint stable-diffusion-v1-5 para geração de texto para imagem.

Para os modelos de Stable Diffusion, por favor leia cuidadosamente a licença primeiro antes de rodar o modelo. 🧨 Diffusers implementa uma verificação de segurança: safety_checker para prevenir conteúdo ofensivo ou nocivo, mas as capacidades de geração de imagem aprimorada do modelo podem ainda produzir conteúdo potencialmente nocivo.

Para carregar o modelo com o método [~DiffusionPipeline.from_pretrained]:

>>> from diffusers import DiffusionPipeline

>>> pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", use_safetensors=True)

O [DiffusionPipeline] baixa e armazena em cache todos os componentes de modelagem, tokenização, e agendamento. Você verá que o pipeline do Stable Diffusion é composto pelo [UNet2DConditionModel] e [PNDMScheduler] entre outras coisas:

>>> pipeline
StableDiffusionPipeline {
  "_class_name": "StableDiffusionPipeline",
  "_diffusers_version": "0.13.1",
  ...,
  "scheduler": [
    "diffusers",
    "PNDMScheduler"
  ],
  ...,
  "unet": [
    "diffusers",
    "UNet2DConditionModel"
  ],
  "vae": [
    "diffusers",
    "AutoencoderKL"
  ]
}

Nós fortemente recomendamos rodar o pipeline em uma placa de vídeo, pois o modelo consiste em aproximadamente 1.4 bilhões de parâmetros. Você pode mover o objeto gerador para uma placa de vídeo, assim como você faria no PyTorch:

>>> pipeline.to("cuda")

Agora você pode passar o prompt de texto para o pipeline para gerar uma imagem, e então acessar a imagem sem ruído. Por padrão, a saída da imagem é embrulhada em um objeto PIL.Image.

>>> image = pipeline("An image of a squirrel in Picasso style").images[0]
>>> image

Salve a imagem chamando o save:

>>> image.save("image_of_squirrel_painting.png")

Pipeline local

Você também pode utilizar o pipeline localmente. A única diferença é que você precisa baixar os pesos primeiro:

!git lfs install
!git clone https://huggingface.co/runwayml/stable-diffusion-v1-5

Assim carregue os pesos salvos no pipeline:

>>> pipeline = DiffusionPipeline.from_pretrained("./stable-diffusion-v1-5", use_safetensors=True)

Agora você pode rodar o pipeline como você faria na seção acima.

Troca dos agendadores

Agendadores diferentes tem diferentes velocidades de retirar o ruído e compensações de qualidade. A melhor forma de descobrir qual funciona melhor para você é testar eles! Uma das principais características do 🧨 Diffusers é permitir que você troque facilmente entre agendadores. Por exemplo, para substituir o [PNDMScheduler] padrão com o [EulerDiscreteScheduler], carregue ele com o método [~diffusers.ConfigMixin.from_config]:

>>> from diffusers import EulerDiscreteScheduler

>>> pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", use_safetensors=True)
>>> pipeline.scheduler = EulerDiscreteScheduler.from_config(pipeline.scheduler.config)

Tente gerar uma imagem com o novo agendador e veja se você nota alguma diferença!

Na próxima seção, você irá dar uma olhada mais de perto nos componentes - o modelo e o agendador - que compõe o [DiffusionPipeline] e aprender como usar esses componentes para gerar uma imagem de um gato.

Modelos

A maioria dos modelos recebe uma amostra de ruído, e em cada timestep ele prevê o noise residual (outros modelos aprendem a prever a amostra anterior diretamente ou a velocidade ou v-prediction), a diferença entre uma imagem menos com ruído e a imagem de entrada. Você pode misturar e combinar modelos para criar outros sistemas de difusão.

Modelos são inicializados com o método [~ModelMixin.from_pretrained] que também armazena em cache localmente os pesos do modelo para que seja mais rápido na próxima vez que você carregar o modelo. Para o tour rápido, você irá carregar o [UNet2DModel], um modelo básico de geração de imagem incondicional com um checkpoint treinado em imagens de gato:

>>> from diffusers import UNet2DModel

>>> repo_id = "google/ddpm-cat-256"
>>> model = UNet2DModel.from_pretrained(repo_id, use_safetensors=True)

Para acessar os parâmetros do modelo, chame model.config:

>>> model.config

A configuração do modelo é um dicionário 🧊 congelado 🧊, o que significa que esses parâmetros não podem ser mudados depois que o modelo é criado. Isso é intencional e garante que os parâmetros usados para definir a arquitetura do modelo no início permaneçam os mesmos, enquanto outros parâmetros ainda podem ser ajustados durante a geração.

Um dos parâmetros mais importantes são:

  • sample_size: a dimensão da altura e largura da amostra de entrada.
  • in_channels: o número de canais de entrada da amostra de entrada.
  • down_block_types e up_block_types: o tipo de blocos de downsampling e upsampling usados para criar a arquitetura UNet.
  • block_out_channels: o número de canais de saída dos blocos de downsampling; também utilizado como uma order reversa do número de canais de entrada dos blocos de upsampling.
  • layers_per_block: o número de blocks ResNet presentes em cada block UNet.

Para usar o modelo para geração, crie a forma da imagem com ruído Gaussiano aleatório. Deve ter um eixo batch porque o modelo pode receber múltiplos ruídos aleatórios, um eixo channel correspondente ao número de canais de entrada, e um eixo sample_size para a altura e largura da imagem:

>>> import torch

>>> torch.manual_seed(0)

>>> noisy_sample = torch.randn(1, model.config.in_channels, model.config.sample_size, model.config.sample_size)
>>> noisy_sample.shape
torch.Size([1, 3, 256, 256])

Para geração, passe a imagem com ruído para o modelo e um timestep. O timestep indica o quão ruidosa a imagem de entrada é, com mais ruído no início e menos no final. Isso ajuda o modelo a determinar sua posição no processo de difusão, se está mais perto do início ou do final. Use o método sample para obter a saída do modelo:

>>> with torch.no_grad():
...     noisy_residual = model(sample=noisy_sample, timestep=2).sample

Para geração de exemplos reais, você precisará de um agendador para guiar o processo de retirada do ruído. Na próxima seção, você irá aprender como acoplar um modelo com um agendador.

Agendadores

Agendadores gerenciam a retirada do ruído de uma amostra ruidosa para uma amostra menos ruidosa dado a saída do modelo - nesse caso, é o noisy_residual.

🧨 Diffusers é uma caixa de ferramentas para construir sistemas de difusão. Enquanto o [DiffusionPipeline] é uma forma conveniente de começar com um sistema de difusão pré-construído, você também pode escolher seus próprios modelos e agendadores separadamente para construir um sistema de difusão personalizado.

Para o tour rápido, você irá instanciar o [DDPMScheduler] com o método [~diffusers.ConfigMixin.from_config]:

>>> from diffusers import DDPMScheduler

>>> scheduler = DDPMScheduler.from_config(repo_id)
>>> scheduler
DDPMScheduler {
  "_class_name": "DDPMScheduler",
  "_diffusers_version": "0.13.1",
  "beta_end": 0.02,
  "beta_schedule": "linear",
  "beta_start": 0.0001,
  "clip_sample": true,
  "clip_sample_range": 1.0,
  "num_train_timesteps": 1000,
  "prediction_type": "epsilon",
  "trained_betas": null,
  "variance_type": "fixed_small"
}

💡 Perceba como o agendador é instanciado de uma configuração. Diferentemente de um modelo, um agendador não tem pesos treináveis e é livre de parâmetros!

Um dos parâmetros mais importante são:

  • num_train_timesteps: o tamanho do processo de retirar ruído ou em outras palavras, o número de timesteps necessários para o processo de ruídos Gausianos aleatórios dentro de uma amostra de dados.
  • beta_schedule: o tipo de agendados de ruído para o uso de geração e treinamento.
  • beta_start e beta_end: para começar e terminar os valores de ruído para o agendador de ruído.

Para predizer uma imagem com um pouco menos de ruído, passe o seguinte para o método do agendador [~diffusers.DDPMScheduler.step]: saída do modelo, timestep, e a atual amostra.

>>> less_noisy_sample = scheduler.step(model_output=noisy_residual, timestep=2, sample=noisy_sample).prev_sample
>>> less_noisy_sample.shape

O less_noisy_sample pode ser passado para o próximo timestep onde ele ficará ainda com menos ruído! Vamos juntar tudo agora e visualizar o processo inteiro de retirada de ruído.

Comece, criando a função que faça o pós-processamento e mostre a imagem sem ruído como uma PIL.Image:

>>> import PIL.Image
>>> import numpy as np


>>> def display_sample(sample, i):
...     image_processed = sample.cpu().permute(0, 2, 3, 1)
...     image_processed = (image_processed + 1.0) * 127.5
...     image_processed = image_processed.numpy().astype(np.uint8)

...     image_pil = PIL.Image.fromarray(image_processed[0])
...     display(f"Image at step {i}")
...     display(image_pil)

Para acelerar o processo de retirada de ruído, mova a entrada e o modelo para uma GPU:

>>> model.to("cuda")
>>> noisy_sample = noisy_sample.to("cuda")

Agora, crie um loop de retirada de ruído que prediz o residual da amostra menos ruidosa, e computa a amostra menos ruidosa com o agendador:

>>> import tqdm

>>> sample = noisy_sample

>>> for i, t in enumerate(tqdm.tqdm(scheduler.timesteps)):
...     # 1. predict noise residual
...     with torch.no_grad():
...         residual = model(sample, t).sample

...     # 2. compute less noisy image and set x_t -> x_t-1
...     sample = scheduler.step(residual, t, sample).prev_sample

...     # 3. optionally look at image
...     if (i + 1) % 50 == 0:
...         display_sample(sample, i + 1)

Sente-se e assista o gato ser gerado do nada além de ruído! 😻

Próximos passos

Esperamos que você tenha gerado algumas imagens legais com o 🧨 Diffusers neste tour rápido! Para suas próximas etapas, você pode