[PYTHON] [Einführung in StyleGAN] Ich habe mit style_mixing "Frau, die die Brille abnimmt" ♬ gespielt

Am zweiten Tag von StyleGAN werde ich zwei der drei Methoden der Bilderzeugung mit StyleGAN in Referenz (1) unten erläutern und verschiedene Style_Mixing-Bilderzeugungen ausprobieren. Da es in Referenz ② eine gute Erklärung zu StyleGAN gibt, ist die Erklärung dieses Artikels meiner Meinung nach leicht zu verstehen, wenn Sie darauf verweisen. 【Referenz】 ①NVlabs/styleganStyleGAN-Kommentar CVPR2019-Lesesitzung @DeNA

Was ich getan habe

・ Was sind die beiden Methoden? ・ Versuchen Sie zu codieren ・ ** Latentes Mischen **; Versuchen Sie, im latenten Raum $ z $ zu mischen ・ ** Style Mixing **; Versuchen Sie, den zugeordneten latenten Raum $ w $ zu mischen ・ ** StyleMixing_2 **; Generieren Sie ein Bild, indem Sie Stilattribute im zugeordneten latenten Raum $ w $ austauschen ・ ** StyleMixing_3 **; Mischen Sie das individuelle Style-Attribut des latenten Mapping-Raums $ w $, um ein Bild zu generieren.

・ Was sind die beiden Methoden?

Eine einfache wörtliche Übersetzung lautet wie folgt.

Es gibt drei Möglichkeiten, einen vorab trainierten Generator zu verwenden: $ 1. Verwenden Sie Gs.run () für Operationen im Sofortmodus, bei denen die Eingabe und Ausgabe Numpy-Arrays sind. $ ** Ich habe diese Technik das letzte Mal angewendet **

# Pick latent vector.
rnd = np.random.RandomState(5)
latents = rnd.randn(1, Gs.input_shape[1])
# Generate image.
fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True)
images = Gs.run(latents, None, truncation_psi=0.7, randomize_noise=True, output_transform=fmt)

Das erste Argument ist eine Reihe latenter Formvektoren [num, 512]. Das zweite Argument ist für Klassenbezeichnungen reserviert (wird in StyleGAN nicht verwendet). Die verbleibenden Schlüsselwortargumente sind optional und können verwendet werden, um die Operation weiter zu ändern (siehe unten). Die Ausgabe ist ein Stapel von Bildern, deren Format durch das Argument output_transform bestimmt wird. Die Optionen (truncation_psi = 0.7, randomize_noise = True), auf die unten verwiesen wird, finden Sie unter Referenz ①.

2.Use Gs.get_output_for() to incorporate the generator as a part of a larger TensorFlow expression: Ich werde dies überspringen, weil ich es diesmal nicht verwenden werde. ... Suchen Sie nach $ 3.Gs.components.mapping und Gs.components.synthesis $, um auf die einzelnen Subnetze des Generators zuzugreifen. Subnetze werden wie $ G $ als unabhängige Instanzen von $ dnnlib.tflib.Network $ dargestellt. :: :: ** Dieses Mal verwenden wir diese Technik beim generierten Bildmischen **

src_latents = np.stack(np.random.RandomState(seed).randn(Gs.input_shape[1]) for seed in src_seeds)
src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]
src_images = Gs.components.synthesis.run(src_dlatents, randomize_noise=False, **synthesis_kwargs)

・ Versuchen Sie zu codieren

Unter Verwendung der obigen Technik kann der tatsächlich einfachste Code wie folgt geschrieben werden:

import os
import pickle
import numpy as np
import PIL.Image
import dnnlib
import dnnlib.tflib as tflib
import config
from PIL import Image, ImageDraw
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

synthesis_kwargs = dict(output_transform=dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True), minibatch_size=8)

def main():
    # Initialize TensorFlow.
    tflib.init_tf()
    fpath = './weight_files/tensorflow/karras2019stylegan-ffhq-1024x1024.pkl'
    with open(fpath, mode='rb') as f:
        _G, _D, Gs = pickle.load(f)
    #Methode 1.Gs für Operationen im Sofortmodus, bei denen die Eingabe und Ausgabe Numpy-Arrays sind.Verwenden Sie run ()
    # Pick latent vector.
    rnd = np.random.RandomState(5)
    latents1 = rnd.randn(1, Gs.input_shape[1])
    # Generate image.
    fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True)
    images = Gs.run(latents1, None, truncation_psi=0.7, randomize_noise=True, output_transform=fmt)
    plt.imshow(images.reshape(1024,1024,3))
    plt.pause(1)
    plt.savefig("./results/simple1_.png ")
    plt.close()
    #Methode 3.Gs.components.Mapping und Gs.components.Suchen Sie nach einer Synthese, um auf die einzelnen Teilnetze des Generators zuzugreifen
    #Wie G ist das Subnetz dnnlib.tflib.Wird als unabhängige Instanz des Netzwerks dargestellt.
    src_seeds = [5]
    src_latents = np.stack(np.random.RandomState(seed).randn(Gs.input_shape[1]) for seed in src_seeds)
    src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]
    src_images = Gs.components.synthesis.run(src_dlatents, randomize_noise=False, **synthesis_kwargs)
    plt.imshow(src_images[0].reshape(1024,1024,3))
    plt.pause(1)
    plt.savefig("./results/simple3_.png ")
    plt.close()
    
if __name__ == "__main__":
    main()

Mit diesem Code scheinen beide Methoden das gleiche Bild zu erzeugen, aber als ich es tatsächlich ausprobierte, war es wie folgt etwas anders.

Methode 1 Methode 2
Latenter Tensor z=latents1 z=src_latents, w=src_dlatents
size (1,512) (1,512), (1,18,512)
simple1_.png simple3_.png

Diese latenten Tensoren entsprechen in der folgenden Abbildung $ z $ bzw. $ w $. Das heißt, Latent $ z $ ist ein Vektor mit 512 Parametern, und sein abbildender latenter Raum $ W $ Tensor $ w $ hat Dimensionen (18.512). Mit anderen Worten, es gibt 18 Eingänge A für das Synthesis-Netzwerk (siehe Referenz ③), und jeder dieser Eingänge ist der Tensor $ w $, der die Grundlage des Stils bildet. 【Referenz】 ③ Probieren Sie Style-Mixing aus und spielen Sie mit dem trainierten Modell von @StyleGAN styleGAN_fig1.jpg Mit anderen Worten kann die Erklärung der obigen Verfahren 1 und 3 wie folgt umformuliert werden.

--Methode 1. Das Bild wird aus dem latenten Vektor $ z $ erzeugt --Methode 2. Ermitteln Sie den Tensor $ w $ des latenten Mapping-Raums einmal aus dem latenten Vektor $ z $, suchen Sie von dort aus nach $ A $ des entsprechenden Synthesysys-Netzwerks und generieren Sie ein Bild, während Sie jedes als unabhängiges Netzwerk berechnen. Macht gerade

・ Latentes Mischen: Versuchen Sie, im latenten Raum zu mischen. Z.

Dies ist das gleiche wie beim letzten Mal, aber unter Berücksichtigung des oben Gesagten werden wir es auf zwei Arten implementieren, um den latenten Vektor $ z $ zu berechnen. Der Hauptcode ist unten.

simple_method1.py


def main():
    # Initialize TensorFlow.
    tflib.init_tf()
    fpath = './weight_files/tensorflow/karras2019stylegan-ffhq-1024x1024.pkl'
    with open(fpath, mode='rb') as f:
        _G, _D, Gs = pickle.load(f)

    # Pick latent vector.
    rnd = np.random.RandomState(5) #5
    latents1 = rnd.randn(1, Gs.input_shape[1])
    print(latents1.shape)
    
    # Generate image.
    fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True)
    images = Gs.run(latents1, None, truncation_psi=1, randomize_noise=False, output_transform=fmt)
    # Pick latent vector2
    src_seeds=[6]
    src_latents = np.stack(np.random.RandomState(seed).randn(Gs.input_shape[1]) for seed in src_seeds)
    # Generate image2
    src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]
    src_images = Gs.components.synthesis.run(src_dlatents, randomize_noise=False, **synthesis_kwargs)
    
    for i in range(1,101,4):
        # mixing latent vetor_1-2
        latents = i/100*latents1+(1-i/100)*src_latents[0].reshape(1,512)
        # Generate image for mixing vector by method1.
        fmt = dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True)
        images = Gs.run(latents, None, truncation_psi=1, randomize_noise=False, output_transform=fmt)
        # Save image.
        os.makedirs(config.result_dir, exist_ok=True)
        png_filename = os.path.join(config.result_dir, 'example{}.png'.format(i))
        PIL.Image.fromarray(images[0], 'RGB').save(png_filename) 

Das Ergebnis ist wie folgt.

Latent z mixing simple3_.png
simple1_.png simple_method10_1_256.gif

Hier war die Ausgabe von beiden in "Try to code" unterschiedlich, was jedoch auf die Parameter truncation_psi und randomize_noise zurückzuführen war. Um die Reproduzierbarkeit zu gewährleisten, wird sie daher auf 1 bzw. False geändert. Impressionen) Ich habe Angst, die Gesichter meiner beiden Kinder zu sehen, wenn ich mir dieses Video ansehe. .. ..

・ StyleMixing: Versuchen Sie, den abgebildeten latenten Raum w zu mischen

Machen wir jetzt dasselbe wie oben, aber mit dem latenten Mapping-Raum $ w $. Die Hauptteile des Codes sind:

simple_method2.py


synthesis_kwargs = dict(output_transform=dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True), minibatch_size=8)

def main():
    # Initialize TensorFlow.
    tflib.init_tf()
    fpath = './weight_files/tensorflow/karras2019stylegan-ffhq-1024x1024.pkl'
    with open(fpath, mode='rb') as f:
        _G, _D, Gs = pickle.load(f)

    # Pick latent vector.
    rnd = np.random.RandomState(5) #5
    latents1 = rnd.randn(1, Gs.input_shape[1])
    
    # Generate image.
    dlatents1 = Gs.components.mapping.run(latents1, None) # [seed, layer, component]
    images = Gs.components.synthesis.run(dlatents1, randomize_noise=False, **synthesis_kwargs)
    
    src_seeds=[6]
    src_latents = np.stack(np.random.RandomState(seed).randn(Gs.input_shape[1]) for seed in src_seeds)
    src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]
    src_images = Gs.components.synthesis.run(src_dlatents, randomize_noise=False, **synthesis_kwargs)
    
    for i in range(1,101,4):
        dlatents = i/100*dlatents1+(1-i/100)*src_dlatents
        # Generate image.
        images = Gs.components.synthesis.run(dlatents, randomize_noise=False, **synthesis_kwargs)
        # Save image.
        os.makedirs(config.result_dir, exist_ok=True)
        png_filename = os.path.join(config.result_dir, 'example{}.png'.format(i))
        PIL.Image.fromarray(images[0], 'RGB').save(png_filename)

Das Ergebnis ist wie folgt. Auf den ersten Blick sind die Ergebnisse unterschiedlich.

Style mixing in projected space simple3_.png
simple1_.png simple_method10_1.gif

Natürlich unterscheidet sich die lineare Interpolation mit dem latenten Eingangsvektor $ z $ von der linearen Interpolation mit jedem der Stilvektoren $ w $ in seinem nichtlinearen (mehrstufigen MLP) Abbildungsraum. Für Wan scheint das Ergebnis zu sein, dass die lineare Interpolation des Style-Vektors im Mapping-Raum in dem Sinne vorzuziehen ist, dass die Brille länger hält. Lassen Sie uns nun sehen, dass diese lineare Interpolation im Sinne der Interpolation immer noch grob ist.

・ StyleMixing_2; Generieren Sie ein Bild, indem Sie Stilattribute im zugeordneten latenten Raum w austauschen

Diese Technik ist das bekannteste Beispiel für Bildänderungen im Papier. Ich werde Ihnen den Code sofort zeigen. Dieser Code basiert auf dem Code in Referenz ③.

ordinary_style_mixising.py


import os
import pickle
import numpy as np
import PIL.Image
import dnnlib
import dnnlib.tflib as tflib
import config
import matplotlib.pyplot as plt

synthesis_kwargs = dict(output_transform=dict(func=tflib.convert_images_to_uint8, nchw_to_nhwc=True), minibatch_size=8)

def load_Gs():
    fpath = './weight_files/tensorflow/karras2019stylegan-ffhq-1024x1024.pkl'
    with open(fpath, mode='rb') as f:
        _G, _D, Gs = pickle.load(f)
    return Gs

def draw_style_mixing_figure(png, Gs, w, h, src_seeds, dst_seeds, style_ranges):
    print(png)
    src_latents = np.stack(np.random.RandomState(seed).randn(Gs.input_shape[1]) for seed in src_seeds)
    src_dlatents = Gs.components.mapping.run(src_latents, None) # [seed, layer, component]

    # Pick latent vector.
    rnd = np.random.RandomState(5) #5
    latents1 = rnd.randn(1, Gs.input_shape[1])
    print(latents1.shape)
    
    # Generate image.
    dlatents1 = Gs.components.mapping.run(latents1, None) # [seed, layer, component]
    images = Gs.components.synthesis.run(dlatents1, randomize_noise=False, **synthesis_kwargs)

    dst_dlatents = np.zeros((6,18,512))
    for j in range(6):
        dst_dlatents[j] = dlatents1

    src_images = Gs.components.synthesis.run(src_dlatents, randomize_noise=False, **synthesis_kwargs)
    dst_images = Gs.components.synthesis.run(dst_dlatents, randomize_noise=False, **synthesis_kwargs)
    print(dst_images.shape)

    canvas = PIL.Image.new('RGB', (w * (len(src_seeds) + 1), h * (len(dst_seeds) + 1)), 'white')
    for col, src_image in enumerate(list(src_images)):
        canvas.paste(PIL.Image.fromarray(src_image, 'RGB'), ((col + 1) * w, 0))
    for row, dst_image in enumerate(list(dst_images)):
        canvas.paste(PIL.Image.fromarray(dst_image, 'RGB'), (0, (row + 1) * h))
        row_dlatents = np.stack([dst_dlatents[row]] * len(src_seeds))
        row_dlatents[:, style_ranges[row]] = src_dlatents[:, style_ranges[row]]
        row_images = Gs.components.synthesis.run(row_dlatents, randomize_noise=False, **synthesis_kwargs)
        for col, image in enumerate(list(row_images)):
            canvas.paste(PIL.Image.fromarray(image, 'RGB'), ((col + 1) * w, (row + 1) * h))
    canvas.save(png)

def main():
    tflib.init_tf()
    os.makedirs(config.result_dir, exist_ok=True)
    draw_style_mixing_figure(os.path.join(config.result_dir, 'style-mixing.png'), 
                             load_Gs(), w=1024, h=1024, src_seeds=[6,701,687,615,2268], dst_seeds=[0,0,0,0,0,0],
                             style_ranges=[range(0,8)]+[range(1,8)]+[range(2,8)]+[range(1,18)]+[range(4,18)]+[range(5,18)])

if __name__ == "__main__":
    main()

Das Ergebnis ist wie folgt.

simple3_.png
simple1_.png [range(0,8)]
Das gleiche wie oben [range(1,8)]
Das gleiche wie oben [range(2,8)]
Das gleiche wie oben [range(1,18)]
Das gleiche wie oben [range(4,18)]
Das gleiche wie oben [range(5,18)]

Im Gegenteil, aus der Sicht von Frauen, die den 2. und 4. Schritt betrachten, wird die Brille entfernt, nur weil es keine Reichweite gibt [0], und die Weiblichkeit wird zu einem eher jungenhaften Gefühl. Insbesondere die 4. Reihe ist bis auf den Bereich [0] dieselbe, es gibt jedoch erhebliche Änderungen.

-StyleMixing_3; Mischen des einzelnen Style-Attributs des latenten Mapping-Raums w, um ein Bild zu generieren

Lassen Sie uns diese Änderung sehen, indem Sie den Stil dieses Bereichs [0] mit dem obigen Code mischen. Dies kann erreicht werden, indem der relevante Codeteil von simple_method2.py durch den folgenden ersetzt wird.

individual_mixing_style.py


    for i in range(1,26,1):
        dlatents=src_dlatents
        dlatents[0][0] = i/100*dlatents1[0][0]+(1-i/100)*src_dlatents[0][0]
Individual style mixing in projected space simple3_.png
simple1_.png simple_method10_1_512.gif

Obwohl diesmal nicht angezeigt, können Sie mit dieser Methode beliebige Parameter im Style-Bereich mischen, um eine detailliertere Mischung durchzuführen.

Zusammenfassung

・ Ich habe versucht "eine Frau, die ihre Brille abnimmt" ・ Das Mischen kann jetzt durch Spezialisierung auf jedes Merkmal durchgeführt werden. ・ Mit dieser Methode kann dasselbe auf das von npy gegebene Bild angewendet werden.

・ Ich möchte mein eigenes Bild lernen und mein eigenes Stilbild erzeugen

Recommended Posts

[Einführung in StyleGAN] Ich habe mit style_mixing "Frau, die die Brille abnimmt" ♬ gespielt
[Einführung in StyleGAN] Ich habe mit "Eine Frau verwandelt sich in Mayuyu" gespielt ♬
[Einführung in Pytorch] Ich habe mit sinGAN ♬ gespielt
[Einführung in StyleGAN] Ich habe mit "The Life of a Man" ♬ gespielt
[Einführung in sinGAN-Tensorflow] Ich habe mit der hochauflösenden "Challenge Big Imayuyu" ♬ gespielt
[Einführung in Matplotlib] Achsen 3D-Animation: Ich habe mit 3D-Lisaju-Figuren gespielt ♬
[Einführung in RasPi4] Ich habe mit "Hiroko / Hiromis giftigem Zungengespräch" gespielt ♪
[Einführung in AWS] Ich habe mit Polly und Transcribe male mit Männer- und Frauenstimmen gespielt
[Einführung in StyleGAN2] Unabhängiges Lernen mit 10 Anime-Gesichtern ♬
[Einführung in den Systemhandel] Ich habe einen Stochastic Oscillator mit Python gezeichnet und damit gespielt ♬
[Einführung in Pytorch] Ich habe versucht, Cifar10 mit VGG16 ♬ zu kategorisieren
[Einführung in AWS] Ich habe versucht, mit der Sprach-Text-Konvertierung zu spielen ♪
Ich habe mit Wordcloud gespielt!
[Einführung in StyleGAN] Dieser "Mann, der nicht lacht" lächelte ungewollt ♬
Einführung in RDB mit sqlalchemy Ⅰ
Einführung in die nichtlineare Optimierung (I)
Ich las "Das Lernen mit Python von der Einführung bis zur Praxis stärken", Kapitel 1
[Einführung] Ich möchte mit Python einen Mastodon-Bot erstellen! 【Anfänger】
[Einführung in Style GAN] Einzigartiges Lernen von Animation mit Ihrer eigenen Maschine ♬
Ich las "Das Lernen mit Python von der Einführung bis zur Praxis stärken", Kapitel 2