[Modelo de generación] Principio de difusión estable + código

inserte la descripción de la imagen aquí


prefacio

La difusión estable es un modelo de texto a imagen basado en modelos de difusión latente (LDM) . Específicamente, gracias al soporte de recursos informáticos de Stability AI y un subconjunto del entrenamiento de soporte de datos LAION-5B , se utiliza para la generación de texto.

Los modelos de difusión latente generan imágenes iterando datos de "eliminación de ruido" en un espacio de representación latente y luego decodifican los resultados de la representación en imágenes completas, lo que permite la generación de texto a imagen para generar imágenes en 10 segundos en una GPU de nivel de consumidor . Actualmente, Stable Diffusion ha lanzado la versión v2. La versión v1 es una implementación específica de Latent Diffusion Models.La arquitectura del modelo está configurada: el factor de reducción de muestreo del codificador automático es 8, el tamaño de UNet es 860M y el codificador de texto es CLIP ViT-L/14. El oficial actualmente proporciona los siguientes pesos :
inserte la descripción de la imagen aquí


提示:以下是本篇文章正文内容,下面案例可供参考

1. Espacio latente

Un espacio latente es una representación de datos comprimidos. El propósito de la compresión de datos es aprender la información más importante en los datos. Tomando la red de codificador-decodificador como ejemplo, primero use la red de red neuronal totalmente convolucional (FCN) para aprender las características de la imagen, y consideramos la reducción de la dimensionalidad de los datos en la extracción de características como una compresión con pérdida . Dado que el decodificador necesita reconstruir (reconstruir) los datos, el modelo debe aprender a almacenar toda la información relevante e ignorar el ruido. La ventaja de la compresión (reducción de la dimensión) es que puede eliminar la información redundante y centrarse en las características más críticas.

2. Codificador automático y VAE

1. Codificador automático:

(1) AE es un codificador automático preentrenado. El objetivo de optimización es comprimir los datos a través del codificador y luego restaurar los datos a través del decodificador, de modo que los datos de entrada y salida sean lo más similares posible.

(2) Para los datos de imagen, los datos restaurados por el decodificador se pueden considerar como un generador. Dado que los datos de entrada del decodificador z pertenecen al espacio R, la distribución de la entrada z no se puede fijar, por lo que la mayoría de las imágenes generadas no tienen sentido.

2 PIES:

(1) Una distribución de z dado el decodificador de entrada puede resolver los problemas anteriores Suponga un conjunto de datos X de variables aleatorias multidimensionales sujetas a la distribución gaussiana multivariante estándar y entrene la red neuronal del decodificador en función del zi obtenido al muestrear la distribución conocida , para obtener la media y varianza de la distribución gaussiana multivariante, obteniendo así con éxito una p'(X) que se aproxime a la distribución real p(X)

(2) Resolver la distribución de probabilidad de p'(X|z)
inserte la descripción de la imagen aquí
(3) Maximizar la probabilidad de p'(X) a través de la estimación de máxima verosimilitud, pero dado que la dimensión de xi es muy grande, la dimensión de zi también es grande, y es necesario encontrar con precisión zi relacionado con la distribución xi requiere una gran cantidad de muestras, por lo que es necesario introducir la distribución posterior p'(z|xi) en el codificador para asociar xi con zi

(4) Utilice el codificador para ajustar sus parámetros asumiendo la distribución de datos conocidos, para aproximar la distribución posterior real p'(z|xi).Aquí, se supone que la distribución posterior se basa en una distribución gaussiana multivariante , luego deje que el codificador genere la media de distribución y la varianza de

(5) Proceso general
inserte la descripción de la imagen aquí

3. Modelo de difusión de difusión

1. Proceso de reenvío

1. La distribución en el tiempo t es igual a la distribución en el tiempo t-1 + el ruido de distribución gaussiana aleatoria, donde α es el valor de atenuación del ruido 2. La distribución
inserte la descripción de la imagen aquí
X t en cualquier momento se puede calcular a partir de la inicial estado de X 0 y el número de pasos:
inserte la descripción de la imagen aquí

2. Proceso inverso

Conociendo X t , encuentre el estado inicial X 0 , aquí use la fórmula Bayesiana para predecir X 0 :
primero encuentre la distribución del X t conocido y obtenga la distribución en el tiempo **X t-1 ** (vea el blog anterior para derivación detallada):
inserte la descripción de la imagen aquí

4. Atención cruzada multimodal

Introduce la atención cruzada en la capa intermedia de Unet , agrega condiciones multimodales (texto, categoría, diseño, máscara) e implementa de la siguiente manera: donde Q proviene del espacio latente , K y V provienen de otra secuencia, como texto :
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

5. Principio de difusión estable

inserte la descripción de la imagen aquí

1. Proceso de formación:

(1) Use el modelo CLIP preentrenado para generar las palabras de descripción correspondientes para los datos de imagen que necesitan ser entrenados.

(2) Use el VAE de propósito general preentrenado, primero use el codificador para reducir la imagen de entrada al espacio latente (generalmente el factor de reducción de resolución es 4-16)

(3) Ingrese el espacio latente en el modelo de difusión, realice la difusión (muestreo directo) y genere ruido paso a paso (en este proceso, controle la intensidad de la generación de ruido en cada paso a través del peso β hasta que se genere ruido puro y registre la generación de ruido en cada paso de datos, como GT

(4) Usar atención cruzada para fusionar las características del espacio latente con las características de otra secuencia modal, y agregarlo al proceso inverso del modelo de difusión, predecir inversamente el ruido que debe reducirse en cada paso a través de Unet, y utilice la función de pérdida del ruido GT y el ruido de predicción. Calcule el gradiente.

(5) La estructura de Denoising Unet es la siguiente:
inserte la descripción de la imagen aquí

Bloque Resnet

Como se muestra en la imagen pequeña en la esquina inferior izquierda, ResnetBlock acepta dos entradas: el vector latente se suma con el timestep_embedding de la proyección totalmente conectada después de la transformación de convolución, y luego se suma con el vector latente original después de la conexión de salto y se envía a otro capa de convolución para obtener la salida latente después de la transformación de codificación Resnet.

Tenga en cuenta la ligera diferencia entre el ResnetBlock de la izquierda y el ResnetBlock de la derecha. El vector latente aceptado por el bloque Resnet de la izquierda se pasa desde la capa superior de UNET, mientras que el bloque Resnet de la derecha debe aceptar la salida de la capa UNET correspondiente de la izquierda además del resultado latente de la capa superior. capa de UNET Dos concatenaciones latentes como entrada. Por lo tanto, si el resultado de salida de la capa superior de ResnetBlock a la derecha es (64, 64, 320), y el resultado de salida de la capa UNET correspondiente a la izquierda es (64, 64, 640), entonces la forma de la entrada latente obtenida por este ResnetBlock es (64, 64, 960).

Transformador espacial (atención cruzada)

Como se muestra en la imagen pequeña en la esquina inferior derecha, Spatial Transformer también acepta dos entradas: el vector latente (correspondiente al token de imagen ) procesado y transformado por el módulo de red anterior (generalmente ResnetBlock) y la incorporación de contexto correspondiente (el (a través del mecanismo de atención, la información semántica correspondiente al token se inyecta en el parche de imagen que el modelo cree que debería verse afectado). La salida de forma del Transformador espacial es la misma que la entrada, pero la información semántica se fusiona en la posición correspondiente.

Muestreo descendente/Muestreo ascendente

DownSample reduce el tamaño de los dos primeros ejes del vector latente en un 50 % y UpSample duplica el tamaño de los dos primeros ejes del vector latente. DownSample se implementa mediante una convolución bidimensional con un tamaño de paso de 2 y, al mismo tiempo, cambia el número de canal del vector latente de entrada al número de canal del vector latente de salida; UpSample se implementa mediante un algoritmo de interpolación y un El tamaño de paso de 1 se realiza después de la convolución de interpolación, al mismo tiempo, a través de una convolución bidimensional con un tamaño de paso de 1, el número de canal del vector latente de entrada se cambia al número de canal del vector latente de salida.

Cabe señalar que timestep_embedding y content embedding permanecen sin cambios durante toda la ejecución de UNET. En el proceso de ejecución repetida de UNET muchas veces, timestep_embedding cambiará cada vez, pero la incrustación de contenido siempre permanecerá sin cambios. En el proceso iterativo, la salida de noise_slice de UNET se resta cada vez del vector latente original y se usa como la entrada latente de UNET en la siguiente iteración.

2. Proceso de reenvío

Un codificador-descodificador automático de imagen, que se usa para codificar la imagen en un vector oculto
o
restaurar la imagen del vector oculto;
una estructura UNET, que usa UNET para la reducción de ruido iterativa y realiza múltiples rondas de predicción bajo la guía de el texto, y gaussiano aleatorio El ruido
se transforma en vectores latentes de imagen
.

1. Utilice un codificador de texto (CLIP's ViT-L/14) para convertir la entrada de texto rápido del usuario en incrustación de texto 2.
Genere una imagen de ruido puro de acuerdo con la distribución asumida (normalmente una distribución gaussiana multivariante)
3. Utilice El codificador VAE comprime al espacio latente;
4. Ejecute Denoising Unet, use la atención cruzada para fusionar información multimodal y prediga el ruido que debe sustraerse en cada paso:
5. Use el decodificador VAE para restaurar el tamaño de imagen original bajo el mismo distribución

*, análisis de código

1. Código general

1、prompt编码为token。编码器为FrozenCLIPEmbedde(包括1层的 CLIPTextEmbeddings 和12层的自注意力encoder)
c = self.cond_stage_model.encode(c)    # (c为输入的提示语句,重复2次)  输出:(2,77,768)
    batch_encoding = self.tokenizer(text, truncation=True, max_length=self.max_length, return_length=True,
                                        return_overflowing_tokens=False, padding="max_length", return_tensors="pt")
    # self.tokenizer来自 transformers包中的 预训练CLIPTokenizer
    tokens = batch_encoding["input_ids"].to(self.device)             # (2,77)一句话编码为77维
    outputs = self.transformer(input_ids=tokens).last_hidden_state   # 12层self-atten,结果(2777682、samples_ddim, _ = sampler.sample(S=opt.ddim_steps,
                                   conditioning=c,
                                   batch_size=opt.n_samples,
                                   shape=shape,
                                   verbose=False,
                                   unconditional_guidance_scale=opt.scale,
                                   unconditional_conditioning=uc,
                                   eta=opt.ddim_eta,
                                   x_T=start_code)
     01、self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)    # S=50
     # 这一步是ddim中,预先register超参数,如a的连乘等
     # Data shape for PLMS sampling is (2, 4, 32, 32) 
     02、samples, intermediates = self.plms_sampling(conditioning, size,
                                                callback=callback,
                                                img_callback=img_callback,
                                                quantize_denoised=quantize_x0,
                                                mask=mask, x0=x0,
                                                ddim_use_original_steps=False,
                                                noise_dropout=noise_dropout,
                                                temperature=temperature,
                                                score_corrector=score_corrector,
                                                corrector_kwargs=corrector_kwargs,
                                                x_T=x_T )
          img = torch.randn(shape, device=device)    # (2,4,32,32)
          for i, step in enumerate(iterator):
                index = total_steps - i - 1                                        # index=50-i-1, step=981
                ts = torch.full((b,), step, device=device, dtype=torch.long)       # [981,981]
                outs = self.p_sample_plms(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
                                          quantize_denoised=quantize_denoised, temperature=temperature,
                                          noise_dropout=noise_dropout, score_corrector=score_corrector,
                                          corrector_kwargs=corrector_kwargs,
                                          unconditional_guidance_scale=unconditional_guidance_scale,
                                          unconditional_conditioning=unconditional_conditioning,
                                          old_eps=old_eps, t_next=ts_next)
                    c_in = torch.cat([unconditional_conditioning, c])    # 添加一个空字符,与promt拼接
                    e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
                          t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False)    # timesteps:[981,981,981,981] -> (4,320)
                          emb = self.time_embed(t_emb)           # 2*linear:(4,320) -> (4,1280)
                          
                          # unet中带入embed与prompt,具体代码见下节
                          for module in self.input_blocks:
                              h = module(h, emb, context)        # 输入(4,4,32,32) (4,1280) (4,77,768)
                              hs.append(h)
                          h = self.middle_block(h, emb, context) 
                          for module in self.output_blocks:
                              h = th.cat([h, hs.pop()], dim=1)   # (4,1280,4,4) -> (4,2560,4,4)
                              h = module(h, emb, context)

                          return self.out(h)                     # (43203232)卷积为(4432323、e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)   # 上步中得到的结果拆开:(243232
   e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)  # 用7.5乘以二者差距,再加回空语句生成的图
   x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)                  # DDIM计算:e_t(2,4,32,32) index:49  -> (2,4,32,32)

4、x_samples_ddim = model.decode_first_stage(samples_ddim)    # (2,4,32,32)
        h = self.conv_in(z)    # 卷积4->512
        x = torch.nn.functional.interpolate(h, scale_factor=2.0, mode="nearest")  #(25126464)
        h = self.up[i_level].block[i_block](h)    # 经过几次卷积与上采样
        h = self.norm_out(h)   # (2,128,256,256)
        h = nonlinearity(h)    # x*torch.sigmoid(x)
        h = self.conv_out(h)   # conv(128,3) -》(232562565、后处理
x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
x_samples_ddim = x_samples_ddim.cpu().permute(0, 2, 3, 1).numpy()
x_checked_image, has_nsfw_concept = check_safety(x_samples_ddim)
x_checked_image_torch = torch.from_numpy(x_checked_image).permute(0, 3, 1, 2)
x_sample = 255. * rearrange(x_sample.cpu().numpy(), 'c h w -> h w c')
img = Image.fromarray(x_sample.astype(np.uint8))
img.save(os.path.join(sample_path, f"{base_count:05}.png"))

2.análisis de la red

Unet en DDIM incluye tres partes: módulo de entrada , módulo intermedio y módulo de salida :

1, self.input_blocks

Contiene 12 estructuras TimestepEmbedSequential diferentes , tres de las cuales se enumeran a continuación:

1、self.input_blocks
ModuleList(
  (0): TimestepEmbedSequential(
    (0): Conv2d(4, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  )
  (1): TimestepEmbedSequential(
    (0): ResBlock(
      (in_layers): Sequential(
        (0): GroupNorm32(32, 320, eps=1e-05, affine=True)
        (1): SiLU()
        (2): Conv2d(320, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      )
      (h_upd): Identity()
      (x_upd): Identity()
      (emb_layers): Sequential(
        (0): SiLU()
        (1): Linear(in_features=1280, out_features=320, bias=True)
      )
      (out_layers): Sequential(
        (0): GroupNorm32(32, 320, eps=1e-05, affine=True)
        (1): SiLU()
        (2): Dropout(p=0, inplace=False)
        (3): Conv2d(320, 320, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
      )
      (skip_connection): Identity()
    )
    (1): SpatialTransformer(
      (norm): GroupNorm(32, 320, eps=1e-06, affine=True)
      (proj_in): Conv2d(320, 320, kernel_size=(1, 1), stride=(1, 1))
      (transformer_blocks): ModuleList(
        (0): BasicTransformerBlock(
          (attn1): CrossAttention(
            (to_q): Linear(in_features=320, out_features=320, bias=False)
            (to_k): Linear(in_features=320, out_features=320, bias=False)
            (to_v): Linear(in_features=320, out_features=320, bias=False)
            (to_out): Sequential(
              (0): Linear(in_features=320, out_features=320, bias=True)
              (1): Dropout(p=0.0, inplace=False)
            )
          )
          (ff): FeedForward(
            (net): Sequential(
              (0): GEGLU(
                (proj): Linear(in_features=320, out_features=2560, bias=True)
              )
              (1): Dropout(p=0.0, inplace=False)
              (2): Linear(in_features=1280, out_features=320, bias=True)
            )
          )
          (attn2): CrossAttention(
            (to_q): Linear(in_features=320, out_features=320, bias=False)
            (to_k): Linear(in_features=768, out_features=320, bias=False)
            (to_v): Linear(in_features=768, out_features=320, bias=False)
            (to_out): Sequential(
              (0): Linear(in_features=320, out_features=320, bias=True)
              (1): Dropout(p=0.0, inplace=False)
            )
          )
          (norm1): LayerNorm((320,), eps=1e-05, elementwise_affine=True)
          (norm2): LayerNorm((320,), eps=1e-05, elementwise_affine=True)
          (norm3): LayerNorm((320,), eps=1e-05, elementwise_affine=True)
        )
      )
      (proj_out): Conv2d(320, 320, kernel_size=(1, 1), stride=(1, 1))
    )
  )

  (6): TimestepEmbedSequential(
    (0): Downsample(
      (op): Conv2d(640, 640, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
    )
  )

Proceso de reenvío :
agregue emb a h y cruce la atención con propmt, que se ejecutará varias veces

emb_out = self.emb_layers(emb)      # (41280)卷积为(4320)
h = h + emb_out                     # (43203232+432011)

x = self.attn1(self.norm1(x)) + x                     # 自注意力:x(41024320)映射到qkv,均320维
x = self.attn2(self.norm2(x), context=context) + x    # 交叉注意力:context(4,77,768)映射到kv的320维
x = self.ff(self.norm3(x)) + x

La imagen de ruido h(4, 4, 32, 32) cambia en ella a: (4, 320, 32, 32) (4, 320, 16, 16) (4, 640, 16, 16) (4, 1280, 8 , 8) (4, 1280, 4, 4)

2, bloques_medios

TimestepEmbedSequential(
  (0): ResBlock(
    (in_layers): Sequential(
      (0): GroupNorm32(32, 1280, eps=1e-05, affine=True)
      (1): SiLU()
      (2): Conv2d(1280, 1280, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    )
    (h_upd): Identity()
    (x_upd): Identity()
    (emb_layers): Sequential(
      (0): SiLU()
      (1): Linear(in_features=1280, out_features=1280, bias=True)
    )
    (out_layers): Sequential(
      (0): GroupNorm32(32, 1280, eps=1e-05, affine=True)
      (1): SiLU()
      (2): Dropout(p=0, inplace=False)
      (3): Conv2d(1280, 1280, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    )
    (skip_connection): Identity()
  )
  (1): SpatialTransformer(
    (norm): GroupNorm(32, 1280, eps=1e-06, affine=True)
    (proj_in): Conv2d(1280, 1280, kernel_size=(1, 1), stride=(1, 1))
    (transformer_blocks): ModuleList(
      (0): BasicTransformerBlock(
        (attn1): CrossAttention(
          (to_q): Linear(in_features=1280, out_features=1280, bias=False)
          (to_k): Linear(in_features=1280, out_features=1280, bias=False)
          (to_v): Linear(in_features=1280, out_features=1280, bias=False)
          (to_out): Sequential(
            (0): Linear(in_features=1280, out_features=1280, bias=True)
            (1): Dropout(p=0.0, inplace=False)
          )
        )
        (ff): FeedForward(
          (net): Sequential(
            (0): GEGLU(
              (proj): Linear(in_features=1280, out_features=10240, bias=True)
            )
            (1): Dropout(p=0.0, inplace=False)
            (2): Linear(in_features=5120, out_features=1280, bias=True)
          )
        )
        (attn2): CrossAttention(
          (to_q): Linear(in_features=1280, out_features=1280, bias=False)
          (to_k): Linear(in_features=768, out_features=1280, bias=False)
          (to_v): Linear(in_features=768, out_features=1280, bias=False)
          (to_out): Sequential(
            (0): Linear(in_features=1280, out_features=1280, bias=True)
            (1): Dropout(p=0.0, inplace=False)
          )
        )
        (norm1): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)
        (norm2): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)
        (norm3): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)
      )
    )
    (proj_out): Conv2d(1280, 1280, kernel_size=(1, 1), stride=(1, 1))
  )
  (2): ResBlock(
    (in_layers): Sequential(
      (0): GroupNorm32(32, 1280, eps=1e-05, affine=True)
      (1): SiLU()
      (2): Conv2d(1280, 1280, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    )
    (h_upd): Identity()
    (x_upd): Identity()
    (emb_layers): Sequential(
      (0): SiLU()
      (1): Linear(in_features=1280, out_features=1280, bias=True)
    )
    (out_layers): Sequential(
      (0): GroupNorm32(32, 1280, eps=1e-05, affine=True)
      (1): SiLU()
      (2): Dropout(p=0, inplace=False)
      (3): Conv2d(1280, 1280, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    )
    (skip_connection): Identity()
  )

3, self.output_blocks

Igual que el módulo de entrada, que contiene 12 TimestepEmbedSequential en orden inverso


Resumir

整体结构比较简单,先用预训练CLIP将prompt变为token; DDIM模型将噪音与token逆扩散为图像;再采用VAE的decoder将图像复原到正常大小:

Supongo que te gusta

Origin blog.csdn.net/qq_45752541/article/details/129082742
Recomendado
Clasificación