Le chiffre de ce que je faisais est facile à comprendre. En bref, le codeur compresse les informations en réduisant la dimension des données d'image, et le décodeur reconstruit l'image en utilisant les informations compressées. Calculez et optimisez la distance MAE entre les pixels de l'image d'entrée et l'image de sortie. Apprendre sans enseignant.
Maintenant, comment générer une image à l'aide de cet encodeur automatique? Tout d'abord, entraînez l'encodeur automatique à l'aide d'images. Optimiser pour que les paramètres des deux réseaux, le codeur et le décodeur, soient appropriés. Ensuite, vous pouvez avoir une idée approximative de la façon dont l'image d'entrée est exprimée dans l'espace latent. Lorsque vous l'utilisez comme modèle de génération, la partie codeur n'est pas utilisée, seuls l'espace latent et le décodeur sont utilisés.
Alors que les encodeurs automatiques ordinaires essaient d'apprendre l'espace latent sous forme de tableau, les encodeurs de variables tentent de trouver les paramètres appropriés qui définissent la distribution de l'espace latent. Ensuite, l'image est reconstruite en échantillonnant la valeur de cette distribution latente pour obtenir une valeur spécifique et en la saisissant dans le décodeur.
La gauche est un encodeur automatique normal et la droite est un encodeur variable.
Pour plus de détails, cet article est très facile à comprendre.
GAN
Veuillez vous référer à d'autres articles pour les mouvements détaillés du GAN. Ici, les propriétés caractéristiques du GAN sont décrites. Dans l'architecture GAN, le générateur et le discriminateur sont formés par la fonction de perte du discriminateur. Le propre entraînement du discriminateur tente de minimiser la perte du discriminateur pour toutes les données d'apprentissage. Le générateur, quant à lui, essaie de maximiser la perte du classificateur pour les faux échantillons qu'il produit. En d'autres termes, la formation des réseaux de neurones ordinaires est un problème d'optimisation, tandis que la formation du GAN est un jeu dans lequel les générateurs et les classificateurs sont en concurrence plutôt que l'optimisation. Il se stabilise lorsque l'équilibre Nash est atteint.
L'algorithme d'entraînement GAN peut être résumé comme suit.
Chaque étape itérative de la formation:
1.Formation des discriminateurs
a.Sélectionnez au hasard des échantillons à partir de données réelles pour créer un mini-lot X
b.Faire un mini-lot z d'un vecteur de nombre aléatoire et faire un mini-lot G composé de faux échantillons(Z)=X`faire
c. D(x)Et D(x`)Calculer la perte discriminante et mettre à jour les paramètres du classificateur en propageant l'erreur totale
2.Formation générateur
a.Faire un mini-lot z d'un vecteur de nombre aléatoire et faire un mini-lot G composé de faux échantillons(z)=X`faire
b.D(x`)L'erreur de discrimination est maximisée en calculant la perte de discrimination et en la rétropropagant pour mettre à jour les paramètres du générateur.
Notez que les paramètres du générateur ne sont pas mis à jour lors de la formation du classificateur à l'étape 1! Notez que les paramètres du classificateur ne sont pas mis à jour lors de la formation du générateur à l'étape 2!
En utilisant les connaissances de base du GAN jusqu'à présent, implémentez GAN de la manière la plus simple possible. (Une mise en œuvre plus pratique sera donnée dans un article suivant)
Cette fois, nous allons implémenter le code pour générer une image à partir de données MNIST avec l'API séquentielle de Keras.
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from keras.datasets import mnist
from keras.layers import Dense, Flatten, Reshape
from keras.layers.advanced_activations import LeakyReLU
from keras.models import Sequential
from keras.optimizers import Adam
#Paramètre de dimension d'entrée
img_rows = 28
img_cols = 28
channels = 1
img_shape = (img_rows, img_cols, channels)
#Dimension du bruit d'entrée au générateur
z_dim = 100
#Générateur
def build_generator(img_shape, z_dim):
model = Sequential()
model.add(Dense(128, input_dim=z_dim))
model.add(LeakyReLU(alpha=0.01))
model.add(Dense(28*28*1, activation='tanh'))
model.add(Reshape(img_shape))
return model
#Identifiant
def build_discriminator(image_shape):
model = Sequential()
model.add(Flatten(input_shape=img_shape))
model.add(Dense(128))
model.add(LeakyReLU(alpha=0.01))
model.add(Dense(1, activation='sigmoid'))
return model
#compiler!
def build_gan(generator, discriminator):
model = Sequential()
model.add(generator)
model.add(discriminator)
return model
#Construire et compiler un classificateur
discriminator = build_discriminator(img_shape)
discriminator.compile(loss='binary_crossentropy',
optimizer=Adam(),
metrics=["accuracy"])
#Construire un générateur
generator = build_generator(img_shape, z_dim)
#Les paramètres d'identification sont fixés pendant la construction du générateur
discriminator.trainable = False
#Construire et compiler le modèle GAN
gan = build_gan(generator, discriminator)
gan.compile(loss="binary_crossentropy",optimizer=Adam())
#Entraînement!
losses = []
accuracies = []
iteration_checkpoints = []
def train(iterations, batch_size, sample_interval):
(X_train, Y_train), (X_test, Y_test) = mnist.load_data() #X_train.shape=(60000, 28, 28)
X_train = X_train /127.5 - 1.0
X_train = np.expand_dims(X_train, axis=3)
real = np.ones((batch_size, 1))
fake = np.zeros((batch_size,1))
for iteration in range(iterations):
#Créez un lot choisi au hasard à partir d'une image réelle
idx = np.random.randint(0, X_train.shape[0],batch_size)
imgs = X_train[idx]
#Créez un lot de fausses images
z = np.random.normal(0, 1, (batch_size, 100))
gen_imgs = generator.predict(z)
#Formation des discriminateurs
d_loss_real = discriminator.train_on_batch(imgs, real)
d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)
d_loss, accuracy = 0.5 * np.add(d_loss_real, d_loss_fake)
#Créez un lot de fausses images
z = np.random.normal(0, 1, (batch_size, 100))
ge_images = generator.predict(z)
#Formation générateur
g_loss = gan.train_on_batch(z, real)
if (iteration+1) % sample_interval == 0:
#Itération Enregistrer la valeur de perte et la valeur correspondante
losses.append((d_loss, g_loss))
accuracies.append(100 * accuracy)
iteration_checkpoints.append(iteration+1)
print("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" %
(iteration + 1, d_loss, 100.0 * accuracy, g_loss))
sample_images(generator)
def sample_images(generator, image_grid_rows=4, image_grid_columns=4):
#Échantillonnage aléatoire du bruit
z = np.random.normal(0, 1, (image_grid_rows * image_grid_columns, z_dim))
gen_imgs = generator.predict(z)
#Échelle de valeur des pixels
gen_imgs = 0.5 * gen_imgs + 0.5
fig, axs = plt.subplots(image_grid_rows,
image_grid_columns,
figsize=(4, 4),
sharey=True,
sharex=True)
cnt = 0
for i in range(image_grid_rows):
for j in range(image_grid_columns):
# Output a grid of images
axs[i, j].imshow(gen_imgs[cnt, :, :, 0], cmap='gray')
axs[i, j].axis('off')
cnt += 1
iterations = 20000
batch_size = 128
sample_interval = 1000
train(iterations, batch_size, sample_interval)
1000 [D loss: 0.129656, acc.: 96.09%] [G loss: 3.387729]
2000 [D loss: 0.079047, acc.: 97.66%] [G loss: 3.964481]
3000 [D loss: 0.071152, acc.: 97.27%] [G loss: 5.072118]
4000 [D loss: 0.217956, acc.: 91.02%] [G loss: 3.993687]
5000 [D loss: 0.380112, acc.: 86.72%] [G loss: 3.941338]
6000 [D loss: 0.292950, acc.: 89.45%] [G loss: 4.491636]
7000 [D loss: 0.345073, acc.: 85.55%] [G loss: 4.056399]
8000 [D loss: 0.396545, acc.: 86.33%] [G loss: 3.101150]
9000 [D loss: 0.744731, acc.: 70.70%] [G loss: 2.761991]
10000 [D loss: 0.444913, acc.: 80.86%] [G loss: 3.474383]
11000 [D loss: 0.362310, acc.: 82.81%] [G loss: 3.101751]
12000 [D loss: 0.383188, acc.: 84.38%] [G loss: 3.111648]
13000 [D loss: 0.283140, acc.: 89.06%] [G loss: 3.082010]
14000 [D loss: 0.411019, acc.: 81.64%] [G loss: 2.747284]
15000 [D loss: 0.386751, acc.: 82.03%] [G loss: 2.795580]
16000 [D loss: 0.475734, acc.: 80.86%] [G loss: 2.436490]
17000 [D loss: 0.285364, acc.: 89.45%] [G loss: 2.764011]
18000 [D loss: 0.202013, acc.: 91.80%] [G loss: 4.058733]
19000 [D loss: 0.285773, acc.: 86.72%] [G loss: 3.038511]
20000 [D loss: 0.354960, acc.: 81.64%] [G loss: 2.719907]
↓1000iteration ↓2000iteration ↓10000iteration ↓20000iteration
Au début de l'apprentissage, c'était juste une image de type bruit, mais à la fin, il semble que même un simple générateur à deux couches puisse générer des caractères manuscrits relativement réalistes. Cependant, des points blancs apparaissent sur l'arrière-plan de l'image manuscrite générée par un simple GAN, et on remarque immédiatement qu'elle n'est pas manuscrite. Afin d'améliorer cette faiblesse, j'aimerais implémenter DCGAN en utilisant la convolution la prochaine fois!