keras 我开发了一个用于生成图像的类,但我有一个类型问题(名称'train_step'未定义),我不能

7fyelxc5  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(107)

下面是完整的类代码及其实现示例。

import tensorflow as tf
import numpy as np
import time
from tensorflow.keras.applications.inception_v3 import InceptionV3
from tensorflow.keras.applications.inception_v3 import preprocess_input
from scipy.linalg import sqrtm

class ImageGAN:
    """
    Classe pour construire un GAN (Generative Adversarial Network) pour la génération d'images en utilisant TensorFlow.

    Paramètres :
        - generator : Modèle TensorFlow représentant le générateur du GAN.
        - discriminator : Modèle TensorFlow représentant le discriminateur du GAN.
        - noise_dim : Dimension du vecteur de bruit d'entrée du générateur.
        - batch_size : Taille des mini-lots pour l'entraînement.
        - epochs : Nombre d'epochs pour l'entraînement.
        - learning_rate : Taux d'apprentissage pour l'optimiseur.
        - verbose : Booléen indiquant s'il faut afficher les informations de progression à chaque epoch.
        - fid_samples : Nombre d'échantillons pour le calcul de la FID.
        - spectral_regularization : Booléen indiquant s'il faut appliquer la régularisation spectrale.
        - metric : Métrique d'évaluation à utiliser (parmi 'fid', 'inception_score', 'kid', 'mse').
        - conditional : Booléen indiquant si l'architecture doit être conditionnelle.
        - use_adamw : Booléen indiquant si l'optimiseur AdamW doit être utilisé.

    Méthodes :
        - fit : Entraîne le GAN sur les données fournies.
        - generate_images : Génère des images à l'aide du générateur entraîné.
        - calculate_metric : Calcule la métrique d'évaluation spécifiée entre les images réelles et générées.

    Exemple d'utilisation :

        # Création du générateur et du discriminateur basés sur StyleGAN2
        generator = build_stylegan2_generator(...)
        discriminator = build_stylegan2_discriminator(...)

        # Création de l'instance de la classe ImageGAN avec des options avancées
        gan = ImageGAN(generator, discriminator, noise_dim=512, batch_size=32, epochs=100, learning_rate=0.0002,
                       verbose=True, fid_samples=1000, spectral_regularization=True, metric='fid', conditional=False,
                       use_adamw=True)

        # Entraînement du GAN sur des données réelles
        gan.fit(real_images)

        # Génération d'images à l'aide du générateur entraîné
        generated_images = gan.generate_images(10)

        # Calcul de la métrique d'évaluation entre les images réelles et générées
        metric_score = gan.calculate_metric(real_images, num_samples=1000)

    """

    def __init__(self, generator, discriminator, noise_dim, batch_size=64, epochs=100, learning_rate=0.0002,
                 verbose=True, fid_samples=1000, spectral_regularization=True, metric='fid', conditional=False,
                 use_adamw=True):
        self.generator = generator
        self.discriminator = discriminator
        self.noise_dim = noise_dim
        self.batch_size = batch_size
        self.epochs = epochs
        self.learning_rate = learning_rate
        self.verbose = verbose
        self.fid_samples = fid_samples
        self.spectral_regularization = spectral_regularization
        self.metric = metric
        self.conditional = conditional
        self.use_adamw = use_adamw

    def generate_latent_noise(batch_size, noise_dim):
       return np.random.normal(size=(batch_size, noise_dim))

    def train_step(real_images, generator_optimizer, discriminator_optimizer, loss_fn, batch_size, noise_dim, spectral_regularization, discriminator):

       noise = generate_latent_noise(batch_size, noise_dim)

       with tf.GradientTape(persistent=True) as tape:

            generated_images = generator(noise, training=True)

            real_output = discriminator(real_images, training=True)
            generated_output = discriminator(generated_images, training=True)

            gen_loss = loss_fn(tf.ones_like(generated_output), generated_output)
            disc_loss_real = loss_fn(tf.ones_like(real_output), real_output)
            disc_loss_generated = loss_fn(tf.zeros_like(generated_output), generated_output)
            disc_loss = disc_loss_real + disc_loss_generated

            if spectral_regularization:
                disc_grads = tape.gradient(disc_loss, discriminator.trainable_variables)
                disc_grads_norm = [tf.norm(grad) for grad in disc_grads]
                disc_penalty = 10.0 * tf.reduce_mean(tf.square(disc_grads_norm))
                disc_loss += disc_penalty

       gen_gradients = tape.gradient(gen_loss, generator.trainable_variables)
       disc_gradients = tape.gradient(disc_loss, discriminator.trainable_variables)

       generator_optimizer.apply_gradients(zip(gen_gradients, generator.trainable_variables))
       discriminator_optimizer.apply_gradients(zip(disc_gradients, discriminator.trainable_variables))

       return gen_loss, disc_loss

    def fit(self, real_images):
        """
        Entraîne le GAN sur des données réelles (images réelles).

        Paramètres :
            - real_images : Tensor ou tableau numpy contenant les images réelles pour l'entraînement.

        Retourne :
            Rien.

        """

        # Préparation des données
        real_images = tf.data.Dataset.from_tensor_slices(real_images).shuffle(len(real_images)).batch(self.batch_size)

        # Fonction de perte pour le générateur et le discriminateur
        if self.conditional:
            loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
        else:
            loss_fn = tf.keras.losses.BinaryCrossentropy(from_logits=True)

        # Optimiseurs pour le générateur et le discriminateur
        if self.use_adamw:
            generator_optimizer = tf.keras.optimizers.AdamW(self.learning_rate)
            discriminator_optimizer = tf.keras.optimizers.AdamW(self.learning_rate)
        else:
            generator_optimizer = tf.keras.optimizers.Adam(self.learning_rate)
            discriminator_optimizer = tf.keras.optimizers.Adam(self.learning_rate)

        # Entraînement du GAN sur plusieurs epochs
        for epoch in range(self.epochs):
            start_time = time.time()

            gen_loss_avg = tf.keras.metrics.Mean()
            disc_loss_avg = tf.keras.metrics.Mean()

            for real_batch in real_images:
                gen_loss, disc_loss = train_step(real_batch, generator_optimizer, discriminator_optimizer, loss_fn,
                                                 self.batch_size, self.noise_dim, self.spectral_regularization, self.discriminator)
                gen_loss_avg.update_state(gen_loss)
                disc_loss_avg.update_state(disc_loss)

            duration = time.time() - start_time

            if self.verbose:
                print(f"Epoch {epoch+1}/{self.epochs}, Gen Loss: {gen_loss_avg.result():.4f}, Disc Loss: {disc_loss_avg.result():.4f}, Duration: {duration:.2f} seconds")

    def generate_images(self, num_images):
        """
        Génère des images à l'aide du générateur entraîné.

        Paramètres :
            - num_images : Nombre d'images à générer.

        Retourne :
            - Tensor : Images générées.

        """

        noise = generate_latent_noise(num_images, self.noise_dim)
        generated_images = self.generator.predict(noise)
        return generated_images

    def calculate_metric(self, real_images, num_samples=None, metric=None):
        """
        Calcule la métrique d'évaluation spécifiée entre les images réelles et générées.

        Paramètres :
            - real_images : Tensor ou tableau numpy contenant les images réelles.
            - num_samples : Nombre d'échantillons à utiliser pour le calcul de la métrique.
            - metric : Métrique d'évaluation à utiliser (parmi 'fid', 'inception_score', 'kid', 'mse').

        Retourne :
            - float : Score de la métrique.

        """

        if num_samples is None:
            num_samples = self.fid_samples

        if metric is None:
            metric = self.metric

        if self.metric == 'fid':
            return self.calculate_fid(self.generator, real_images, num_samples)
        elif self.metric == 'inception_score':
            return self.calculate_inception_score(self.generator, num_samples)
        elif self.metric == 'kid':
            return self.calculate_kid(self.generator, real_images, num_samples)
        elif self.metric == 'mse':
            return self.calculate_mse(self.generator, real_images, num_samples)
        else:
            raise ValueError("Metric not supported. Available metrics: 'fid', 'inception_score', 'kid', 'mse'")

    def calculate_fid(generator, real_images, num_samples):
        """
        Calcule la Fréchet Inception Distance (FID) entre les images réelles et générées.

        Paramètres :
            - real_images : Tensor ou tableau numpy contenant les images réelles.
            - num_samples : Nombre d'échantillons à utiliser pour le calcul de la FID.

        Retourne :
            - float : Score FID.

        """
        # Générer des images à l'aide du générateur entraîné
        noise = np.random.normal(size=(num_samples, generator.noise_dim))
        generated_images = generator.generator.predict(noise)

        # Chargement du modèle InceptionV3 pré-entraîné pour l'extraction des features
        inception_model = InceptionV3(include_top=False, pooling='avg', input_shape=(299, 299, 3))
        real_features = inception_model.predict(preprocess_input(real_images))
        generated_features = inception_model.predict(preprocess_input(generated_images))

        # Calcul des moyennes et matrices de covariance des features
        real_mean, real_cov = np.mean(real_features, axis=0), np.cov(real_features, rowvar=False)
        generated_mean, generated_cov = np.mean(generated_features, axis=0), np.cov(generated_features, rowvar=False)

        # Calcul de la distance FID
        diff = real_mean - generated_mean
        cov_sqrt, _ = sqrtm(real_cov.dot(generated_cov), disp=False)
        if np.iscomplexobj(cov_sqrt):
            cov_sqrt = cov_sqrt.real

        fid_score = np.dot(diff, diff) + np.trace(real_cov + generated_cov - 2 * cov_sqrt)

        return fid_score


    def calculate_inception_score(generator, num_samples):
        # Générer des images à l'aide du générateur entraîné
        noise = np.random.normal(size=(num_samples, generator.noise_dim))
        generated_images = generator.generator.predict(noise)

        # Charger le modèle InceptionV3 pré-entraîné
        inception_model = InceptionV3(include_top=False, pooling='avg', input_shape=(299, 299, 3))

        # Prétraitement des images pour le modèle InceptionV3
        generated_images = tf.image.resize(generated_images, (299, 299))
        generated_images = tf.image.grayscale_to_rgb(generated_images)
        generated_images = preprocess_input(generated_images)

        # Calculer les probabilités de chaque classe pour les images générées
        inception_scores = inception_model.predict(generated_images)
        inception_scores = tf.nn.softmax(inception_scores)

        # Calculer l'entropie croisée pour obtenir l'Inception Score
        entropy = -tf.reduce_sum(inception_scores * tf.math.log(inception_scores), axis=1)
        inception_score = tf.exp(tf.reduce_mean(entropy))
        return inception_score.numpy()

    def calculate_kid(generator, real_images, num_samples):
        # Générer des images à l'aide du générateur entraîné
        noise = np.random.normal(size=(num_samples, generator.noise_dim))
        generated_images = generator.generator.predict(noise)

        # Charger le modèle InceptionV3 pré-entraîné pour les features
        inception_model = InceptionV3(include_top=False, pooling='avg', input_shape=(299, 299, 3))

        # Prétraitement des images pour le modèle InceptionV3
        real_images = tf.image.resize(real_images, (299, 299))
        real_images = tf.image.grayscale_to_rgb(real_images)
        real_images = preprocess_input(real_images)

        generated_images = tf.image.resize(generated_images, (299, 299))
        generated_images = tf.image.grayscale_to_rgb(generated_images)
        generated_images = preprocess_input(generated_images)

        # Extraire les features pour les images réelles et générées
        real_features = inception_model.predict(real_images)
        generated_features = inception_model.predict(generated_images)

        # Calculer la distance euclidienne moyenne entre les features réelles et générées
        distances = tf.norm(real_features[:, np.newaxis] - generated_features, axis=2)
        kid = tf.reduce_mean(distances).numpy()
        return kid

    def calculate_mse(generator, real_images, num_samples):
        # Générer des images à l'aide du générateur entraîné
        noise = np.random.normal(size=(num_samples, generator.noise_dim))
        generated_images = generator.generator.predict(noise)

        # Calculer la Mean Squared Error (MSE) entre les images réelles et générées
        mse = tf.reduce_mean(tf.square(real_images - generated_images)).numpy()
        return mse

个字符
在这里你会发现在执行过程中显示的错误

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-3-fcaa091262ee> in <cell line: 19>()
     17 
     18 # Entraîner le GAN sur le jeu de données MNIST
---> 19 gan.fit(train_images)
     20 
     21 # Générer des images à l'aide du générateur entraîné

<ipython-input-1-d5bbfe93e45e> in fit(self, real_images)
    137 
    138             for real_batch in real_images:
--> 139                 gen_loss, disc_loss = train_step(real_batch, generator_optimizer, discriminator_optimizer, loss_fn,
    140                                                  self.batch_size, self.noise_dim, self.spectral_regularization, self.discriminator)
    141                 gen_loss_avg.update_state(gen_loss)

NameError: name 'train_step' is not defined


先谢谢你的帮助。我提前为评论是法语的事实道歉!!因为这是我的母语,但你可以翻译!?
为了解决这个问题,我将“generate_latent_noise”和“train_step”函数中的代码重新引入到“fit”函数中-它工作了!但我并不满意

g6baxovj

g6baxovj1#

当两个function都在同一个class下时,需要传递self参数来从另一个function调用function。你可以从这个thread中了解更多。
但是,要解决您的特定情况,请替换以下内容:

def train_step(real_images, generator_optimizer, discriminator_optimizer, loss_fn, batch_size, noise_dim, spectral_regularization, discriminator):

字符串
使用以下内容(我在这里只包含了self参数):

def train_step(self, real_images, generator_optimizer, discriminator_optimizer, loss_fn, batch_size, noise_dim, spectral_regularization, discriminator):


然后在fit函数中,使用self.train_step而不是train_step

gen_loss, disc_loss = self.train_step(real_batch, generator_optimizer, discriminator_optimizer, loss_fn,
                                             self.batch_size, self.noise_dim, self.spectral_regularization, self.discriminator)

**附加:**您需要对您的generate_latent_noise函数进行相同的更改。并在train_step函数下更改这些行:

line 78: generated_images = generator(noise, training=True)
line 94: gen_gradients = tape.gradient(gen_loss, generator.trainable_variables)
line 97: generator_optimizer.apply_gradients(zip(gen_gradients, generator.trainable_variables))


与:

line 78: generated_images = self.generator(noise, training=True)
line 94: gen_gradients = tape.gradient(gen_loss, self.generator.trainable_variables)
line 97: generator_optimizer.apply_gradients(zip(gen_gradients, self.generator.trainable_variables))

相关问题