[PYTHON] [Introduction à Pytorch] J'ai joué avec sinGAN ♬

Probablement l'une des plus grandes découvertes de l'année, alors j'ai joué avec elle en guise d'introduction à Pytorch. C'est presque la même histoire que les pionniers suivants, donc je vais me concentrer sur les difficultés d'Uwan et un petit commentaire (ce que j'ai remarqué). La référence est la suivante.

Citation
If you use this code for your research, please cite our paper:
@inproceedings{rottshaham2019singan,
  title={SinGAN: Learning a Generative Model from a Single Natural Image},
  author={Rott Shaham, Tamar and Dekel, Tali and Michaeli, Tomer},
  booktitle={Computer Vision (ICCV), IEEE International Conference on},
  year={2019}
}

【référence】 ①SinGAN: Learning a Generative Mode from a Single Natural Image@arXiv:1905.01164v2 [cs.CV] 4 Sep 2019Code available at: https://github.com/tamarott/SinGANTera était incroyable quand j'ai lu l'article de SinGAN[Explication de l'article] SinGAN: Apprendre un modèle génératif à partir d'une seule image naturelle[SinGAN] Active diverses tâches de génération d'images à partir d'une seule image

Ce que j'ai fait

・ Environnement et exécution ・ Bref commentaire sur le papier ・ À propos de la formation ・ Animation ・ Super résolution ・ Peinture à l'image

・ Environnement et exécution

Tout d'abord, téléchargez Zip à partir de Github dans Reference (2) ci-dessus et décompressez-le. Vous pouvez l'installer dans l'environnement Pytorch de l'autre jour avec la commande suivante.

Install dependencies

python -m pip install -r requirements.txt

This code was tested with python 3.6 Et ce que vous pouvez faire, c'est: (Traduction de Github ci-dessus)

Train Pour entraîner un modèle SinGAN avec votre propre image, placez l'image d'entraînement sous Input / Images et procédez comme suit:

python main_train.py --input_name <input_file_name>

Vous pouvez également utiliser le modèle entraîné résultant pour générer des échantillons aléatoires à partir de l'échelle la plus grossière (n = 0). Une fois formés, les modèles formés sont stockés pour chaque échelle de rugosité (n).

Pour exécuter ce code sur la machine CPU, spécifiez --not_cuda lors de l'appel de main_train.py

Random samples Pour générer un échantillon aléatoire à partir de l'échelle de rugosité, commencez par entraîner le modèle SinGAN de l'image souhaitée, puis procédez comme suit:

python random_samples.py --input_name <training_image_file_name> --mode random_samples --gen_start_scale <generation start scale number>

Remarque: indiquez 0 pour l'échelle de rugosité de départ lors de l'utilisation du modèle complet et 1 pour démarrer la génération à partir de la deuxième échelle. Il semble que la beauté du produit fini devrait être à l'échelle 0.

Random samples of arbitrery sizes Pour générer un échantillon aléatoire de n'importe quelle taille, commencez par entraîner le modèle SinGAN de l'image souhaitée (comme ci-dessus), puis procédez comme suit:

python random_samples.py --input_name <training_image_file_name> --mode random_samples_arbitrary_sizes --scale_h <horizontal scaling factor> --scale_v <vertical scaling factor>

Animation from a single image Pour générer une courte animation à partir d'une seule image, procédez comme suit:

python animation.py --input_name <input_file_name> 

Cela lancera automatiquement une nouvelle phase d'entraînement en mode de remplissage de bruit. Lorsque l'exécution est terminée, une animation Gif est automatiquement générée pour chaque échelle de rugosité de départ et stockée dans chaque Dir. Le changement est le plus important lorsque start_scale = 0, et le changement devient plus petit à mesure que le start_scale augmente. Harmonization Pour harmoniser l'objet collé avec l'image (voir l'exemple de la figure 13 de l'article), commencez par entraîner le modèle SinGAN pour l'image d'arrière-plan que vous voulez (comme ci-dessus), puis la référence collée naïvement Enregistrez l'image et son masque binaire dans "Input / Harmonization" (voir l'exemple dans le répertoire des fichiers de téléchargement). Ensuite, procédez comme suit:

python harmonization.py --input_name <training_image_file_name> --ref_name <naively_pasted_reference_image_file_name> --harmonization_start_scale <scale to inject>

Notez que différentes échelles d'injection produisent différents effets d'harmonie. L'échelle d'injection la plus grossière est 1.

Editing Pour éditer l'image (voir l'exemple de la figure 12 de l'article), commencez par entraîner le modèle SinGAN avec l'image non éditée souhaitée (comme ci-dessus), puis l'image éditée simple, correspondant Enregistrez-le avec la carte binaire comme image de référence sous "Entrée / Edition" (voir Exemple d'image enregistrée). Ensuite, procédez comme suit:

python editing.py --input_name <training_image_file_name> --ref_name <edited_image_file_name> --editing_start_scale <scale to inject>

Les sorties masquées et non masquées sont enregistrées. Là encore, différentes échelles d'injection produisent différents effets d'édition. L'échelle d'injection la plus grossière est 1.

Paint to Image Pour convertir la peinture en une image réaliste (voir l'exemple de la figure 11 de l'article), commencez par entraîner le modèle SinGAN avec l'image que vous souhaitez (comme ci-dessus), puis sous "Entrée / Peinture" Enregistrez la peinture dans et procédez comme suit:

python paint2image.py --input_name <training_image_file_name> --ref_name <paint_image_file_name> --paint_start_scale <scale to inject>

Là encore, différentes échelles d'injection produisent différents effets d'édition. L'échelle d'injection la plus grossière est 1.

Advanced option: Specify quantization_flag to be True, to re-train only the injection level of the model, to get a on a color-quantized version of upsamled generated images from previous scale. For some images, this might lead to more realistic results.

Super Resolution Pour super-résolution de l'image, procédez comme suit:

python SR.py --input_name <LR_image_file_name>

Cela entraînera automatiquement le modèle SinGAN pour un facteur de suréchantillonnage 4x (s'il n'existe pas déjà). Pour différents coefficients SR, utilisez le paramètre --sr_factor lors de l'appel de la fonction. Le coefficient SR est de 4 par défaut, et plus la valeur est élevée, plus l'image finale est grande.

Les résultats SinGAN pour l'ensemble de données BSD100 peuvent être téléchargés à partir du dossier Téléchargements.

Additional Data and Functions Single Image Fréchet Inception Distance (SIFID score) Pour calculer le SIFID entre l'image réelle et le faux échantillon correspondant, procédez comme suit:

python SIFID/sifid_score.py --path2real <real images path> --path2fake <fake images path> --images_suffix <e.g. jpg, png>

Assurez-vous que chacun des faux noms de fichier image est le même que le nom de fichier image correspondant.

・ Bref commentaire sur le papier

Les références sont des articles, etc., mais je pense que l'invention de sinGAN est la suivante.

--Un apprentissage des données --Utiliser ResGAN (perte de WGAN-GP) ――Apprentissage progressif des fonctionnalités du global au local --Bonus; Prend en charge plusieurs tâches

Un apprentissage des données

Les données de Learning One sont probablement devenues très populaires récemment, mais je pense que c'est la première fois que je les apprends et les utilise.

Utiliser ResGAN (WGAN-GP Loss)

ResGAN est dans Reference ⑥, et WGAN-GP est dans Reference ⑦, et il est proposé comme méthode avec des performances de convergence élevées. 【référence】 ⑥Generative Adversarial Network based on Resnet for Conditional Image Restoration@arXiv:1707.04881v1 [cs.CV] 16 Jul 2017Improved Training of Wasserstein GANs Tout d'abord, ResGAN dans Reference ⑥ est le générateur suivant. resGAN_original.jpg

D'autre part, le Générateur de chaque étape de sinGAN est composé de ResGAN en dessous du niveau de base sauf pour le premier. Autrement dit, $ (\ bar x_ {n-1}) ↑ ^ r $, qui est une image agrandie de $ z_n $ et une image plus grossière, est utilisée comme entrée de $ G_n $, et la différence est apprise pour la rendre plus claire. Il génère l'image $ \ bar x_n $. Note) Ici, $ ↑ ^ r $ indique la montée en puissance de l'image. resGAN.jpg Au fait,

Fonction de perte ReaGAN

min_{G_n}max_{D_n}L_{adv}(G_n,D_n)+αL_{rec}(G_n)

Le premier terme est WGAN-GP de référence ⑦, qui est exprimé par la formule suivante. WGAN_loss.jpg Le deuxième terme est

L_{rec} = ||G_n(0,(\bar{x}^{rec}_{n+1}) ↑^r) − x_n||^2, 

and for n = N, we use

L_{rec} = ||G_N (z^∗) − x_N||^2

"L'image du bruit d'entrée à ce moment est $ z_n (n = 0, ..., N-1) = 0 $, et seul $ z_N $ est un nombre aléatoire fixe défini au début de l'apprentissage." (Référence ④ Plus cité)

Apprentissage progressif des fonctionnalités du global au local

L'apprentissage se poursuit en répétant ResGAN comme indiqué dans la figure ci-dessous. Ici, l'apprentissage commence à partir de la ligne du bas, mais ici, seul $ z_N $ généré à partir de nombres aléatoires est entré. Dicriminator le compare à l'image réelle réduite $ x_N $ de l'image d'origine, qui est automatiquement déterminée lorsque le nombre de formations est déterminé. Après cela, entrez l'image $ (\ bar x_ {n-1}) ↑ ^ r $ et $ z_ {N-1} $ qui sont les images générées de cette manière à partir de l'image $ \ bar x_ {n-1} $. Faire. multi_resGAN.jpg De cette manière, diverses applications utilisent les paramètres d'apprentissage et les images appris.

・ À propos de la formation

Comme mentionné ci-dessus, je pense que vous pouvez apprendre. L'environnement Pytorch de Wan utilise 1060, donc la mémoire du GPU est d'environ 3 Go. Avec cela, il y avait des images telles que vaches.png qui ne pouvaient pas être apprises jusqu'à la fin. Par conséquent, j'ai essayé de réduire la taille des images initiales (Input / images), mais la taille de l'image réduite telle que n = 0 pour l'apprentissage n'a pas changé et l'erreur Memmory n'a pas disparu facilement. Quand je l'ai réduit à la 1 / 3ème place, j'ai réussi à réduire un peu la valeur finale de n et j'ai pu apprendre en toute sécurité, mais le résultat était que l'image d'apprentissage était petite et pas très intéressante.

・ Animation

C'est intéressant car il bouge, mais quand vous regardez animation.py, il semble que vous vous déplaciez en changeant la localité de l'entité (en changeant la valeur de start_scale) et en agitant des nombres aléatoires dans l'espace latent. En conséquence, vous pouvez créer une animation dans laquelle une petite valeur de n fluctue considérablement et une grande valeur de n se déplace à peine. Voici quelques exemples.

start_scale=0 start_scale=1 start_scale=2
alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif
alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif
alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif alpha=0.100000_beta=0.800000.gif

・ Super résolution

Selon le tableau ci-dessous dans le document, la précision est comparable à SRGAN, qui a été introduit par Wan l'autre jour. SR_evaluation.jpg SR_comparison.jpg Alors, j'ai essayé ce qui suit. Dans le tableau ci-dessous, la super résolution est augmentée vers la droite. Dans le même temps, la taille devient plus grande à mesure qu'elle va vers la droite. Vous pouvez sentir la taille réelle et la super résolution en cliquant dessus pour l'afficher indépendamment.

original Extension 1 Extension 2 Extension 3
mayuyu128.jpg mayuyu128_HR.png mayuyu128_HR.png mayuyu128_HR.png
33039_LR.png 33039_LR_HR.png 33039_LR_HR.png 33039_LR_HR.png
romanesco.jpg romanesco_HR.png romanesco_HR.png

・ Peinture à l'image

Cela signifie convertir une simple image en image. L'exemple suivant est publié dans l'article, ce qui signifie que si vous entraînez l'image sur le côté gauche, placez la deuxième image simple dans "Entrée / peintures" et exécutez la commande, l'image du côté droit sera sortie. Cette figure montre également que les résultats de sinGAN sont supérieurs aux autres méthodes. paint2image.jpg Le résultat de l'exécution de ce Wan est le suivant. Pour ce faire, j'ai eu une erreur de mémoire sur le 1060 et je n'ai pas pu apprendre l'image de gauche. Donc, L'image 250x141 a été réduite à 80x46. L'image Paint est de 300x200. Le résultat est trop petit, mais plus les paramètres d'apprentissage sont grossiers, plus l'image peut être reproduite grossièrement. Par contre, lorsque n = 1, une image de vache apparaît dans une certaine mesure.

L'image originale Paint n=1 n=2 n=3 n=4
cows2.png cows.png start_scale=1.png start_scale=2.png start_scale=3.png start_scale=4.png

Résumé

・ J'ai joué avec sinGAN ・ Pour le moment, j'ai compris le principe ・ J'ai pu réaliser la puissance de l'apprentissage local de toute la région en utilisant le nouveau ResGAN.

・ S'il s'agit de 1060, la taille de l'image sera limitée en raison du manque de mémoire GPU. ・ Je pense que c'est une découverte qui donne une impression de progrès

prime

Les paramètres du générateur et du Dicriminator de ResGAN sont ajustés en fonction de la taille de l'image d'entrée et ont la structure suivante.

GeneratorConcatSkip2CleanAdd(
  (head): ConvBlock(
    (conv): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
    (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
  )
  (body): Sequential(
    (block1): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block2): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block3): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
  )
  (tail): Sequential(
    (0): Conv2d(32, 3, kernel_size=(3, 3), stride=(1, 1))
    (1): Tanh()
  )
)
WDiscriminator(
  (head): ConvBlock(
    (conv): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1))
    (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
  )
  (body): Sequential(
    (block1): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block2): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block3): ConvBlock(
      (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
  )
  (tail): Conv2d(32, 1, kernel_size=(3, 3), stride=(1, 1))
...

GeneratorConcatSkip2CleanAdd(
  (head): ConvBlock(
    (conv): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1))
    (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
  )
  (body): Sequential(
    (block1): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block2): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block3): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
  )
  (tail): Sequential(
    (0): Conv2d(64, 3, kernel_size=(3, 3), stride=(1, 1))
    (1): Tanh()
  )
)
WDiscriminator(
  (head): ConvBlock(
    (conv): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1))
    (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
  )
  (body): Sequential(
    (block1): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block2): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
    (block3): ConvBlock(
      (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1))
      (norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (LeakyRelu): LeakyReLU(negative_slope=0.2, inplace=True)
    )
  )
  (tail): Conv2d(64, 1, kernel_size=(3, 3), stride=(1, 1))
)

Recommended Posts

[Introduction à Pytorch] J'ai joué avec sinGAN ♬
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé d'implémenter CVAE avec PyTorch
[Introduction à StyleGAN] J'ai joué avec "The Life of a Man" ♬
[Introduction à sinGAN-Tensorflow] J'ai joué avec la super-résolution "Challenge Big Imayuyu" ♬
[Introduction à Matplotlib] Axes Animation 3D: J'ai joué avec des figurines 3D Lisaju ♬
[Introduction à RasPi4] J'ai joué avec "la conversation de langue empoisonnée d'Hiroko / Hiromi" ♪
[Introduction à StyleGAN] J'ai joué avec "Une femme se transforme en Mayuyu" ♬
J'ai joué avec wordcloud!
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
[Introduction à AWS] J'ai joué avec des voix masculines et féminines avec Polly et Transcribe ♪
[Introduction à StyleGAN] J'ai joué avec style_mixing "Femme qui enlève ses lunettes" ♬
Introduction à PyTorch (1) Différenciation automatique
Introduction à l'optimisation non linéaire (I)
J'ai créé Word2Vec avec Pytorch
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
[Introduction à AWS] J'ai essayé de jouer avec la conversion voix-texte ♪
[Introduction au trading système] J'ai dessiné un oscillateur stochastique avec python et joué avec ♬
J'ai essayé de classer MNIST par GNN (avec PyTorch géométrique)
[Introduction à Pytorch] Je souhaite générer des phrases dans des articles de presse
J'ai essayé d'implémenter SSD avec PyTorch maintenant (édition du modèle)
J'ai essayé de déplacer de la nourriture avec SinGAN
J'ai essayé d'implémenter Attention Seq2Seq avec PyTorch
[Détails (?)] Introduction au pytorch ~ CNN de CIFAR10 ~
J'ai essayé d'expliquer l'ensemble de données de Pytorch
Introduction à RDB avec sqlalchemy II
J'ai essayé d'implémenter DeepPose avec PyTorch
Comment augmenter les données avec PyTorch
J'ai joué avec PyQt5 et Python3
Je veux faire ○○ avec les Pandas
J'ai joué avec Mecab (analyse morphologique)!
Je veux déboguer avec Python
J'ai essayé d'implémenter la classification des phrases par Self Attention avec PyTorch
J'ai lu "Renforcer l'apprentissage avec Python de l'introduction à la pratique" Chapitre 1
[Introduction] Je veux créer un robot Mastodon avec Python! 【Débutants】
J'ai lu "Renforcer l'apprentissage avec Python de l'introduction à la pratique" Chapitre 2
[Introduction à WordCloud] Jouez avec le scraping ♬
Je veux détecter des objets avec OpenCV
J'ai joué avec DragonRuby GTK (Game Toolkit)
J'ai essayé d'implémenter la régularisation Shake-Shake (ShakeNet) avec PyTorch
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé de visualiser AutoEncoder avec TensorFlow
J'ai essayé de commencer avec Hy
Je veux écrire un blog avec Jupyter Notebook
[Scikit-learn] J'ai joué avec la courbe ROC
Je voulais résoudre ABC160 avec Python
[PyTorch] Introduction à la classification de documents à l'aide de BERT
Je veux installer Python avec PythonAnywhere
[Introduction à Python] Utilisons foreach avec Python
Je veux analyser les journaux avec Python
Je veux jouer avec aws avec python
J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ
J'ai essayé de résoudre TSP avec QAOA
Je voulais résoudre ABC172 avec Python
Je voulais vraiment copier avec du sélénium
J'ai essayé l'analyse de données IRMf avec python (Introduction au décodage des informations cérébrales)
J'ai essayé de comparer la précision de la classification des phrases BERT japonaises et japonaises Distil BERT avec PyTorch et introduction de la technique d'amélioration de la précision BERT