Ignorer et passer au contenu

Envoi gratuit pour toutes les commandes

Intéressant

Expliquer l'espace latent SDXL par inconnu

by unknown 07 Feb 2024

Expliquer l'espace latent SDXL

Article de blog communautaire

Publié 20 novembre 2023

TL;DR
ou consultez la démonstration interactive

Table des matières

Une courte histoire de fond
Les 4 canaux des latents SDXL
L'espace de pixels de 8 bits comporte 3 canaux
La représentation latente SDXL d'une image comporte 4 canaux
Conversion directe des latents SDXL en RVB avec une approximation linéaire
Une raison probable pour laquelle la gamme de couleurs SDXL est biaisée vers le jaune
Qu’est-ce qui doit être corrigé ?
Prenons un exemple de sortie de SDXL
Une démonstration complète
Augmentation de la gamme de couleurs / suppression des biais de couleur
De longues invites à des échelles de guidage élevées deviennent possibles

Une courte histoire de fond

Un merci spécial à : Ollin Boer Bohan Haoming , Cristina Segalin et Birchlabs pour leur aide en matière d'informations, de discussions et de connaissances !

Je créais des filtres de correction pour le processus d'inférence SDXL vers une interface utilisateur que je crée pour les modèles de diffusion.

Après avoir eu de nombreuses années d'expérience dans la correction d'images, je souhaitais disposer de la capacité fondamentale nécessaire pour améliorer la sortie réelle de SDXL. Il y avait de nombreuses techniques que je voulais disponibles dans l'UX, que j'ai décidé de corriger moi-même. J'ai remarqué que la sortie SDXL est presque toujours soit bruyante selon des modèles réguliers, soit trop fluide. L'espace colorimétrique a toujours eu besoin d'un équilibrage des blancs, avec une gamme de couleurs biaisée et restreinte, simplement à cause du fonctionnement des modèles SD.

Effectuer des corrections lors d'un post-traitement après la génération et la conversion de l'image en RVB 8 bits n'aurait que très peu de sens s'il était possible d'améliorer les informations et la gamme de couleurs avant la sortie réelle.

La chose la plus importante à savoir pour créer des filtres et des outils de correction est de comprendre les données avec lesquelles vous travaillez.

Cela m'a conduit à une exploration expérimentale des latents SDXL dans le but de les comprendre. Le tenseur, avec lequel fonctionnent les modèles de diffusion basés sur l'architecture SDXL, ressemble à ceci :

[batch_size, 4 channels, height (y), width (x)]

Ma première question était simplement « C'est quoi exactement ces 4 chaînes ? ». La plupart des réponses que j'ai reçues allaient dans le sens de "Ce n'est pas quelque chose qu'un humain peut comprendre".

Mais c’est tout à fait compréhensible. C'est même très simple à comprendre et utile à connaître.

Les 4 canaux des latents SDXL

Pour une image de 1 024 × 1 024 px générée par SDXL, le tenseur de latentes est de 128 × 128 px, où chaque pixel de l'espace latent représente 64 (8 × 8) pixels dans l'espace des pixels. Si nous générons et décodons les latents en une image jpg standard de 8 bits, alors...

L'espace de pixels de 8 bits comporte 3 canaux

Rouge (R), Vert (G) et Bleu (B), chacun avec 256 valeurs possibles comprises entre 0 et 255. Ainsi, pour stocker toutes les informations de 64 pixels, nous devons pouvoir stocker 64 × 256 = 16 384 valeurs, par canal, dans chaque pixel latent.

Cliquez sur le titre pour une démo interactive !

0 : Luminance
1 : Cyan/Rouge => équivalent à rgb(0, 255, 255)/rgb(255, 0, 0)
2 : Citron vert/Violet moyen => équivalent à rgb(127, 255, 0)/rgb(127, 0, 255)
3 : Motif/structure.

Si chaque valeur peut être comprise entre -4 et 4 au moment du décodage, alors dans un format à virgule flottante 16 bits avec demi-précision, chaque pixel latent peut contenir 16 384 valeurs distinctes pour chacun des 4 canaux.

Conversion directe des latents SDXL en RVB avec une approximation linéaire

Avec cette compréhension, nous pouvons créer une fonction d'approximation qui convertit directement les latents en RVB :

 def latents_to_rgb ( latents ):
 weights = (
 ( 60 , - 60 , 25 , - 70 ),
 ( 60 , - 5 , 15 , - 50 ),
 ( 60 , 10 , - 5 , - 35 )
 )

 weights_tensor = torch.t(torch.tensor(weights, dtype=latents.dtype).to(latents.device))
 biases_tensor = torch.tensor(( 150 , 140 , 130 ), dtype=latents.dtype).to(latents.device)
 rgb_tensor = torch.einsum( "...lxy,lr -> ...rxy" , latents, weights_tensor) + biases_tensor.unsqueeze(- 1 ).unsqueeze(- 1 )
 image_array = rgb_tensor.clamp( 0 , 255 )[ 0 ].byte().cpu().numpy()
 image_array = image_array.transpose( 1 , 2 , 0 )
 
retourner Image.fromarray (image_array)

Nous avons ici le résultat latents_to_rgb et une sortie décodée régulière, redimensionnée pour comparaison :

Une raison probable pour laquelle la gamme de couleurs SDXL est biaisée vers le jaune

Relativement peu de choses dans la nature sont bleues ou blanches. Ces couleurs sont plus visibles dans le ciel, dans des conditions agréables. Ainsi, le modèle, connaissant la réalité à travers les images, pense en luminance (canal 0) cyan/rouge (canal 1) et citron vert/violet moyen (canal 2), où le rouge et le vert sont primaires et le bleu est secondaire. C'est pourquoi très souvent, les générations SDXL sont biaisées vers le jaune (rouge + vert).

Lors de l'inférence, les valeurs du tenseur commenceront à min < -30 et max > 30 et la limite min/max au moment du décodage est d'environ -4 à 4 . À guidance_scale plus élevée, les valeurs auront une différence plus élevée entre min et max .

Pour comprendre la limite, il est essentiel d’examiner ce qui se passe dans le processus de décodage :

 decoded = vae.decode(latents / vae.scaling_factor).sample
 decoded = decoded.div( 2 ).add( 0.5 ).clamp( 0 , 1 )

Si les valeurs à ce stade sont en dehors de la plage 0 à 1, certaines informations seront perdues dans la pince. Donc, si nous pouvons apporter des corrections lors du débruitage pour répondre aux attentes du VAE, nous pourrions obtenir de meilleurs résultats.

Qu’est-ce qui doit être corrigé ?

Comment affiner une image floue, équilibrer les blancs, améliorer les détails, augmenter le contraste ou augmenter la gamme de couleurs ? La meilleure façon est de commencer avec une image nette, correctement équilibrée en blancs, avec un contraste élevé, des détails nets et une plage élevée.

Il est beaucoup plus facile de flouter une image nette, de modifier la balance des couleurs, de réduire le contraste, d'obtenir des détails absurdes et de limiter la gamme de couleurs que de l'améliorer.

SDXL a une tendance très marquée à biaiser les couleurs et à placer les valeurs en dehors des limites réelles (image de gauche). Ce qui est facilement résolu en centrant les valeurs et en les plaçant dans les limites (image de droite) :

Sortie originale en dehors des limites

Correction exagérée à des fins d'illustration

 def center_tensor ( input_tensor, per_channel_shift= 1 , full_tensor_shift= 1 , channels=[ 0 , 1 , 2 , 3 ] ):
 for channel in channels: 
input_tensor[ 0 , canal] -= input_tensor[ 0 , canal].mean() * per_channel_shift
 return input_tensor - input_tensor.mean() * full_tensor_shift

Prenons un exemple de sortie de SDXL

 seed: 77777777
 guidance_scale: 20 # A high guidance scale can be fixed too
 steps with base: 23
 steps with refiner: 10

 prompt: Cinematic.Beautiful smile action woman in detailed white mecha gundam armor with red details,green details,blue details,colorful,star wars universe,lush garden,flowers,volumetric lighting,perfect eyes,perfect teeth,blue sky,bright,intricate details,extreme detail of environment,infinite focus,well lit,interesting clothes,radial gradient fade,directional particle lighting,wow
 
message_prompt négatif : casque, bokeh, peinture, œuvres d'art, en bloc, flou, laid, vieux, ennuyeux, photoshoppé, fatigué, rides, cicatrice, cheveux gris, grand front, yeux croisés, stupide, stupide, arrogant, défiguré, tordu, flou, irréaliste, niveaux de gris, mauvaise anatomie, iris artificiels, pas de pupilles, yeux flous, yeux sombres, membres supplémentaires, yeux déformés et défigurés, hors cadre, pas d'iris, visage asymétrique, doigts cassés, doigts supplémentaires, mains défigurées

Notez que j'ai volontairement choisi une échelle de guidage élevée.

Comment pouvons-nous corriger cette image ? C'est moitié peinture, moitié photographie. La gamme de couleurs est orientée vers le jaune. À droite se trouve une génération fixe avec exactement les mêmes paramètres.

Mais également avec une guidance_scale raisonnable réglée sur 7,5, nous pouvons toujours conclure que la sortie fixe est meilleure, sans détails absurdes et sans balance des blancs correcte.

Il y a beaucoup de choses que nous pouvons faire dans l'espace latent pour améliorer généralement une génération et il y a des choses très simples que nous pouvons faire pour cibler des erreurs spécifiques dans une génération :

Suppression des valeurs aberrantes

Cela contrôlera la quantité de détails absurdes, en éliminant les valeurs les plus éloignées de la moyenne de la distribution. Cela aide également à générer à une échelle de guidage plus élevée.

 
def soft_clamp_tensor ( input_tensor, threshold= 3.5 , boundary= 4 ):
 if max ( abs (input_tensor. max ()), abs (input_tensor. min ())) < 4 :
 return input_tensor
 channel_dim = 1

 max_vals = input_tensor. max (channel_dim, keepdim= True )[ 0 ] 
max_replace = ((input_tensor - seuil) / (max_vals - seuil)) * (limite - seuil) + seuil
 over_mask = (input_tensor > seuil)

 min_vals = input_tensor. min (channel_dim, keepdim= True )[ 0 ]
 min_replace = ((input_tensor + seuil) / (min_vals + seuil)) * (-boundary + seuil) - seuil
 under_mask = (input_tensor < -threshold)

 return torch.where(over_mask, max_replace, torch.where(under_mask, min_replace, input_tensor))

Équilibrage des couleurs et portée accrue

J'ai deux méthodes principales pour y parvenir. La première consiste à se rapprocher de la moyenne tout en normalisant les valeurs (ce qui supprimera également les valeurs aberrantes) et la seconde consiste à corriger le moment où les valeurs sont biaisées vers une certaine couleur. Cela aide également à générer à une échelle de guidage plus élevée.

 
def center_tensor ( input_tensor, canal_shift= 1 , full_shift= 1 , canaux=[ 0 , 1 , 2 , 3 ] ) :
 pour canal dans canaux :
 input_tensor[ 0 , canal] -= input_tensor[ 0 , canal].mean() * canal_shift
 return input_tensor - input_tensor.mean() * full_shift

Maximisation du tenseur

Cela se fait essentiellement en multipliant les tenseurs par une très petite quantité comme 1e-5 pendant quelques étapes et en s'assurant que le tenseur final utilise toute la plage possible (plus proche de -4/4) avant de convertir en RVB. N'oubliez pas que dans l'espace des pixels, il est plus facile de réduire le contraste, la saturation et la netteté avec une dynamique intacte que de les augmenter.

 
def maximise_tensor ( input_tensor, border= 4 , canaux=[ 0 , 1 , 2 ] ):
 min_val = input_tensor. minutes ()
 max_val = input_tensor. maximum ()

 normalization_factor = limite / max ( abs (min_val), abs (max_val))
 input_tensor[ 0 , canaux] *= normalization_factor

 retourner input_tensor

Exemple d'implémentation de rappel

 def callback ( pipe, step_index, timestep, cbk ):
 if timestep > 950 :
 threshold = max (cbk[ "latents" ]. max (), abs (cbk[ "latents" ]. min ())) * 0.998 
cbk[ "latents" ] = soft_clamp_tensor(cbk[ "latents" ], seuil* 0,998 , seuil)
 si pas de temps > 700 :
 cbk[ "latents" ] = center_tensor(cbk[ "latents" ], 0.8 , 0.8 )
 si pas de temps > 1 et pas de temps < 100 :
 cbk[ "latents" ] = center_tensor(cbk[ "latents" ], 0.6 , 1.0 )
 cbk[ "latents" ] = maximiser_tensor(cbk[ "latents" ])
 retour cbk

 image = base(
 rapide,
 guidance_scale = guidance_scale,
 callback_on_step_end=rappel,
 callback_on_step_end_inputs=[ "latents" ]
 ).images[ 0 ]

Cette mise en œuvre simple des trois méthodes est utilisée dans la dernière série d'images, avec les femmes dans le jardin .

Cliquez sur le titre ou sur ce lien pour une démo interactive !

Cette démonstration utilise une mise en œuvre plus avancée des techniques en détectant les valeurs aberrantes à l'aide du score Z, en se déplaçant dynamiquement vers la moyenne et en appliquant la force à chaque technique.

SDXL d'origine (trop jaune) et légère modification (blanc équilibré)

Modification moyenne et modification dure (les deux avec les 3 techniques appliquées)

Augmentation de la gamme de couleurs / suppression des biais de couleur

Pour les éléments ci-dessous, SDXL a limité la gamme de couleurs au rouge et au vert dans la sortie régulière. Parce que rien dans l’invite ne suggère que le bleu existe. C'est une plutôt bonne génération, mais la gamme de couleurs est devenue restreinte.

Si vous donnez à quelqu'un une palette de noir, de rouge, de vert et de jaune et que vous lui dites ensuite de peindre un ciel bleu clair, la réponse naturelle est de vous demander de fournir du bleu et du blanc.

Pour inclure le bleu dans la génération, nous pouvons simplement réaligner l'espace colorimétrique lorsqu'il est restreint et SDXL inclura de manière appropriée le spectre complet des couleurs dans la génération.

De longues invites à des échelles de guidage élevées deviennent possibles

Voici un scénario typique, dans lequel la gamme de couleurs accrue rend possible l'ensemble de l'invite.
Cet exemple applique la modification simple et matérielle présentée précédemment pour illustrer la différence plus clairement.

invite : Photographie d'une femme en robe rouge dans un jardin luxueux entouré de bleu , de jaune, de violet et de fleurs de nombreuses couleurs , photographie haut de gamme et primée, Portra 400, plein format. ciel bleu , détails complexes jusqu'à la plus petite particule, détail extrême de l'environnement, portrait net, bien éclairé , tenue intéressante , belles ombres, lumineux , qualité photo, ultra réaliste, chef-d'œuvre

Voici d'autres comparaisons sur le même concept

Gardez à l'esprit que tous utilisent simplement les mêmes modifications statiques .

Filtres de correction UDI SDXL

image/jpeg

930 x 520px

LOOKBOOK PRINTEMPS ÉTÉ

Exemple de devis de bloc

Le vestibule Praesent congue tellus à fringilla. Curabitur vitae semper sem, eu convallis est. Cras felis nunc commodo eu convallis vitae interdum non nisl. Mécène ac est sit amet augue pharetra convallis.

Exemple de texte de paragraphe

Le vestibule Praesent congue tellus à fringilla. Curabitur vitae semper sem, eu convallis est. Cras felis nunc commodo eu convallis vitae interdum non nisl. Mécène ac est sit amet augue pharetra convallis nec danos dui. Cras soupçonne quam et turpis eleifend vitae malesuada magna congue. Damus id ullamcorper neque. Sed vitae mi a mi pretium aliquet ac sed elitos. Pellentesque nulla eros accumsan quis justo at tincidunt lobortis deli denimes, suspendisse vestibulum lectus in lectus volutpate.
Prev Post
Next Post

Merci de votre inscription

Cet e-mail a été enregistré !

Shop the look

Choose Options

Artoholica
Inscrivez-vous pour des mises à jour exclusives, nouveautés et réductions réservées aux initiés

Recently Viewed

Edit Option
Notification de retour en stock
this is just a warning

Avant que tu partes...

Bénéficiez de 20% de réduction sur votre première commande

réduction de 20

Entrez le code ci-dessous lors du paiement pour bénéficier de 20 % de réduction sur votre première commande

CODEVENTE20

Continuer vos achats