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/stylegan ② StyleGAN-Kommentar CVPR2019-Lesesitzung @DeNA
・ 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.
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 ①.
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)
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) |
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 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
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 | |
---|---|
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. .. ..
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 | |
---|---|
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.
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.
style_ranges=[range(0,8)]+[range(1,8)]+[range(2,8)]+[range(1,18)]+[range(4,18)]+[range(5,18)]
row_dlatents[:, style_ranges[row]] = src_dlatents[:, style_ranges[row]]
Mit anderen Worten, so viel Bildkonvertierung kann nur durch Konvertieren der folgenden Stile von oben in Stil [0,18] durchgeführt werden.[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.
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 | |
---|---|
Obwohl diesmal nicht angezeigt, können Sie mit dieser Methode beliebige Parameter im Style-Bereich mischen, um eine detailliertere Mischung durchzuführen.
・ 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