Calculs généreux ou discriminatoires

Pour comprendre les GAN, il faut savoir comment fonctionnent les calculs génératifs, et pour cela, les distinguer des calculs discriminants est éclairant. Les calculs discriminants tentent de caractériser les informations d’entrée, c’est-à-dire que, compte tenu des points forts d’une information, ils anticipent un nom ou une classe à laquelle cette information a sa place.

Par exemple, étant donné chacun des mots d’un courriel (l’affaire d’information), un calcul discriminatoire pourrait prévoir si le message est du spam ou non_spam. Le spam est l’un des noms, et le paquet de mots accumulés à partir du courriel est les points saillants qui constituent l’information d’entrée. Au moment où cette question est communiquée scientifiquement, le nom est appelé y et les points saillants sont appelés x. La définition p(y|x) est utilisée pour signifier “la probabilité de y étant donné x”, ce qui pour cette situation signifierait “la probabilité qu’un courriel soit un spam étant donné les mots qu’il contient”.

Ainsi, les calculs discriminants mettent en évidence les marques. Ils portent exclusivement sur ce lien. Une approche pour considérer les calculs génératifs est qu’ils font l’inverse. Plutôt que d’anticiper une marque en fonction de certains points forts, ils s’efforcent de prévoir les points forts en fonction d’un nom spécifique.

La question à laquelle un calcul génératif tente de répondre est la suivante : S’attendre à ce que ce courriel soit un spam, quelle est la probabilité que ces points saillants soient présents ? Alors que les modèles discriminants se soucient du lien entre y et x, les modèles génératifs se soucient de “comment vous obtenez x”. Ils vous permettent d’attraper p(x|y), la probabilité de x étant donné y, ou la probabilité de points forts étant donné un nom ou une classe. (Tout bien considéré, les calculs génératifs peuvent également être utilisés comme classificateurs. Pour une raison étrange, ils peuvent accomplir davantage que de commander des informations d’entrée).

Une autre approche à envisager est de reconnaître les discriminations de type génératif comme celle-ci :

Les modèles discriminants se familiarisent avec la limite entre les classes

Les modèles générateurs modélisent la dispersion des classes individuelles

Comment fonctionnent les RAG

Un dispositif neuronal, appelé générateur, crée de nouvelles occurrences d’informations, tandis que l’autre, le discriminateur, les évalue pour en déterminer la réalité ; par exemple, le discriminateur choisit si chaque occurrence d’information qu’il étudie a sa place dans le véritable ensemble de données préparatoires ou non.

Supposons que nous essayions d’accomplir quelque chose de plus banal que de copier la Joconde. Nous créerons des chiffres écrits manuellement comme ceux que l’on trouve dans l’ensemble de données du MNIST, qui est tiré de cette réalité actuelle. L’objectif du discriminateur, lorsqu’il indique une occurrence de l’ensemble de données authentique du MNIST, est de percevoir ceux qui sont de bonne foi.

Dans l’intervalle, le générateur produit de nouvelles images, qu’il envoie au discriminateur. Il le fait dans l’espoir qu’elles seront également considérées comme valables, malgré le fait qu’elles soient fausses. L’objectif du générateur est de créer une écriture tolérable par des chiffres à la main : mentir sans être obtenu. L’objectif du discriminateur est de reconnaître les images provenant du générateur comme étant fausses.

Voici les moyens que prend un GAN :

Le générateur prend un nombre arbitraire et renvoie une image.

Cette image créée est renforcée dans le discriminateur par une vague d’images prises à partir d’un ensemble de données réelles et authentiques.

Le discriminateur prend à la fois des photos authentiques et des photos contrefaites et renvoie des probabilités, un nombre compris entre 0 et 1, 1 correspondant à une attente de crédibilité et 0 à une contrefaçon.

Vous avez donc un double cercle de saisie :

Le discriminateur se trouve dans un cercle d’entrée avec la vérité de base des photos, que nous connaissons.

Le générateur se trouve dans un cercle d’entrée avec le discriminateur.

Schéma GAN
Crédit : O’Reilly

On peut considérer un GAN comme la restriction d’un faussaire et d’un flic dans une ronde de félins et de souris, où le faussaire découvre comment faire passer de fausses notes, et le flic comment les reconnaître. Les deux sont dynamiques ; par exemple, le flic est en train de se préparer aussi (pour élargir la relation, il se peut que la banque nationale salue des frais qui sont passés en douce), et chaque partie en vient à se familiariser avec les techniques de l’autre dans une accélération constante.

Pour le MNIST, l’organisation discriminante est un arrangement convolutionnel standard qui peut classer les images qui lui sont renforcées, un classificateur binomial marquant les images comme authentiques ou fausses. Le générateur est un arrangement convolutionnel inverse, pourrait-on dire : Alors qu’un classificateur convolutionnel standard prend une image et la sous-échantillonne pour en déterminer la probabilité, le générateur prend un vecteur de mouvement irrégulier et le suréchantillonne pour en faire une image. Le premier rejette l’information par des stratégies de sous-échantillonnage comme le maxpooling, et le second produit de nouvelles informations.

Les deux filets tentent de rationaliser une capacité cible alternative et contradictoire, ou travail malheureux, dans un jeu de zéro-zum. Il s’agit essentiellement d’un modèle d’expert de personnage à l’écran. Lorsque le discriminateur change de comportement, le générateur change aussi, et inversement. Leurs malheurs se poussent les uns contre les autres.

GANs
GAN, Autoencodeurs et VAE

Il pourrait être utile de comparer les systèmes générateurs mal disposés avec d’autres systèmes neuronaux, par exemple les auto-codeurs et les auto-codeurs variationnels.

Les auto-codeurs codent les informations d’entrée sous forme de vecteurs. Ils constituent une représentation masquée, ou compactée, de l’information brute. Ils sont utiles pour diminuer la dimensionnalité, c’est-à-dire que le remplissage du vecteur sous forme de représentation cachée comprime l’information brute en moins de mesures remarquables. Les auto-codeurs peuvent être combinés à un supposé décodeur, ce qui permet de recréer les informations d’entrée en fonction de leur représentation cachée, comme vous le feriez avec une machine Boltzmann limitée.

schéma de l’auto-codeur
Conseils pour la préparation d’un GAN

Au moment où vous formez le discriminateur, maintenez l’estime du générateur constante ; et au moment où vous formez le générateur, maintenez le discriminateur stable. Chacun doit se préparer à affronter un ennemi statique. Par exemple, cela donne au générateur une lecture supérieure sur la pente par laquelle il doit apprendre.

De la même façon, le fait de préformer le discriminateur contre le MNIST avant de commencer à préparer le générateur permettra d’obtenir une inclinaison plus nette.

Chaque côté du GAN peut submerger l’autre. Si le discriminateur est excessivement grand, il rendra des appréciations si proches de 0 ou 1 que le générateur se battra pour parcourir l’inclinaison. Au cas où le générateur serait trop grand, il s’aventurera avec ténacité dans les lacunes du discriminateur, ce qui conduira à de faux négatifs. Ce phénomène pourrait être atténué par les taux d’apprentissage individuels des réseaux. Les deux systèmes neuronaux doivent avoir un “niveau d’aptitude” comparable. 1

Les RAG ont mis de côté un long effort de préparation. Sur un GPU solitaire, un GAN peut prendre des heures, et sur un CPU solitaire, plus d’une journée. Bien que difficiles à accorder et donc à utiliser, les GAN ont donné lieu à une tonne d’exploration et de composition fascinantes.

Voici un exemple de GAN codé en Keras, à partir duquel des modèles peuvent être importés dans Deeplearning4j.

classe GAN() :

def __init__(self) :

    self.img_rows = 28

    self.img_cols = 28

    self.channels = 1

    self.img_shape = (self.img_rows, self.img_cols, self.channels)

    optimiseur = Adam(0.0002, 0.5)

    # Construire et compiler le discriminateur

    self.discriminator = self.build_discriminator()

    self.discriminator.compile(loss='binary_crossentropy',

        optimizer=optimiseur,

        métrique= [précision])

    # Construire et compiler le générateur

    self.generator = self.build_generator()

    self.generator.compile(loss='binary_crossentropy', optimizer=optimizer)

    # Le générateur prend le bruit comme entrée et génère des imgs

    z = Entrée(forme=(100,))

    img = self.generator(z)

    # Pour le modèle combiné, nous ne formerons que le générateur

    self.discrimator.trainable = Faux

    # Le valide prend les images générées en entrée et détermine la validité

    valide = self.discriminator(img)

    # Le modèle combiné (générateur et discriminateur empilés) prend

    # bruit en entrée => génère des images => détermine la validité

    self.combined = Modèle(z, valide)

    self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)

def build_generator(self) :

    noise_shape = (100,)

    modèle = Séquentiel()

    model.add(Dense(256, input_shape=noise_shape))

    model.add(LeakyReLU(alpha=0.2))

    model.add(BatchNormalization(momentum=0.8))

    model.add(Dense(512))

    model.add(LeakyReLU(alpha=0.2))

    model.add(BatchNormalization(momentum=0.8))

    model.add(Dense(1024))

    model.add(LeakyReLU(alpha=0.2))

    model.add(BatchNormalization(momentum=0.8))

    model.add(Dense(np.prod(self.img_shape), activation='tanh'))

    model.add(Reshape(self.img_shape))

    model.summary()

    bruit = Input(shape=noise_shape)

    img = modèle(bruit)

    Modèle de retour(bruit, img)

def build_discriminator(self) :

    img_shape = (self.img_rows, self.img_cols, self.channels)

    modèle = Séquentiel()

    model.add(Flatten(input_shape=img_shape))

    model.add(Dense(512))

    model.add(LeakyReLU(alpha=0.2))

    model.add(Dense(256))

    model.add(LeakyReLU(alpha=0.2))

    model.add(Dense(1, activation='sigmoïde'))

    model.summary()

    img = Input(shape=img_shape)

    validité = modèle(img)

    Modèle de retour(img, validité)

def train(self, epochs, batch_size=128, save_interval=50) :

    # Charger l'ensemble de données

    (X_train, _), (_, _) = mnist.load_data()

    # Rééchelonner de -1 à 1

        X_train = (X_train.astype(np.float32) - 127,5) / 127,5

        X_train = np.expand_dims(X_train, axis=3)

        half_batch = int(batch_size / 2)

        pour l'époque dans la gamme(époques) :

            # ---------------------

            # Train discriminatoire

            

            # Sélectionnez un demi lot d'images au hasard

            idx = np.random.randint(0, X_train.shape[0], half_batch)

            imgs = X_train [idx]

            bruit = np.random.normal(0, 1, (half_batch, 100))

            # Générer un demi lot de nouvelles images

            gen_imgs = self.generator.predict(noise)

            # Former le discriminateur

            d_loss_real = self.discriminator.train_on_batch(imgs, np.ones((half_batch, 1))

            d_loss_fake = self.discriminator.train_on_batch(gen_imgs, np.zeros((half_batch, 1))

            d_loss = 0,5 * np.add(d_loss_real, d_loss_fake)

            

            # Générateur de train

            

            bruit = np.random.normal(0, 1, (batch_size, 100))

            # Le générateur veut que le discriminateur étiquette les échantillons générés

            # comme valide (les)

            valid_y = np.array([1] * batch_size)

            # Former le générateur

            g_loss = self.combined.train_on_batch(noise, valid_y)

            # Tracer les progrès

            impression ("%d [D perte : %f, acc. : %.2f%%] [G perte : %f]" % (époque, d_loss [0], 100*d_loss [1], g_loss)

            # Si à l'intervalle de sauvegarde => sauvegarde des échantillons d'images générés

            si epoch % save_interval == 0 :

                self.save_imgs(epoch)

    def save_imgs(self, epoch) :

        r, c = 5, 5

        bruit = np.random.normal(0, 1, (r * c, 100))

        gen_imgs = self.generator.predict(noise)

        # Redimensionner les images 0 - 1

        gen_imgs = 0,5 * gen_imgs + 0,5

        fig, axs = plt.subplots(r, c)

        cnt = 0

        pour i dans la gamme(r) :

            pour j dans la plage(c) :

                axs[i,j].imshow(gen_imgs[cnt, :, :,0], cmap='gray')

                axs[i,j].axis('off')

                cnt += 1

        fig.savefig("gan/images/mnist_%d.png" % époque)

        plt.close()

if __name__ == '__main__' :

    gan = GAN()

    gan.train(epochs=30000, batch_size=32, save_interval=200)