遗传算法与深度学习实战(35)——使用遗传算法优化生成对抗网络

遗传算法与深度学习实战(35)------使用遗传算法优化生成对抗网络

    • [0. 前言](#0. 前言)
    • [1. 模型构建](#1. 模型构建)
    • [2. 进化生成对抗网络](#2. 进化生成对抗网络)
    • 小结
    • 系列链接

0. 前言

我们已经构建了用于编码深度卷积生成对抗网络 (Deep Convolutional Generative Adversarial Networks, DCGAN)的遗传编码器,优化封装的 DCGAN 类只需要定义用于演化的遗传算法参数,添加进化搜索能够对 GAN 网络进行自我优化。

1. 模型构建

(1) 导入执行遗传算法所需的库和工具:

python 复制代码
from tensorflow.keras.datasets import mnist as data
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, Dense, Activation, Flatten, Reshape, Dropout, ZeroPadding2D
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, UpSampling2D, Convolution2D
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import LeakyReLU
from tensorflow.keras.optimizers import Adam, RMSprop
from tensorflow.keras.initializers import RandomNormal
import tensorflow as tf

import tensorflow.keras.backend as K

import numpy as np
import matplotlib.pyplot as plt
from livelossplot import PlotLosses
from tqdm import tqdm_notebook
from IPython import display
from IPython.display import clear_output

import random
from tqdm.notebook import tqdm as tqdm
plt.gray()

from deap import algorithms
from deap import base
from deap import benchmarks
from deap import creator
from deap import tools

def extract(images, labels, class_):  
    labels = np.squeeze(labels)  
    idx = labels == class_  
    imgs = images[idx]
    print(imgs.shape)
return imgs

(train_images, train_labels), (test_images, test_labels) = data.load_data()

# split dataset
#train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype("float32") / 255.0
print(train_images.shape)

train_images = extract(train_images, train_labels, 5)
plt.imshow(train_images[0])

# Rescale -1 to 1
train_images = (train_images.astype(np.float32) - 127.5) / 127.5
if len(train_images.shape)<4:
    train_images = np.expand_dims(train_images, axis=3)
print(train_images.shape)

latent_dim = 100
channels = train_images.shape[3]
image_shape = (train_images.shape[1], train_images.shape[2], channels)
print(image_shape)

def clamp(num, min_value, max_value):
    return max(min(num, max_value), min_value)

def linespace(v, minv, maxv):
    range = maxv - minv 
    return v * range + minv

def linespace_int(v, minv, maxv):
    range = maxv - minv
    return clamp(int(v * range + minv), minv, maxv)

def reverse_space(x, minv, maxv):
    range = maxv - minv
    if range==0: return 0
return (x - minv) / range

FILTERS = 0
MIN_FILTERS = 16
MAX_FILTERS = 128
ALPHA = 1
MIN_ALPHA = .05
MAX_ALPHA = .5
CRITICS = 2
MIN_CRITICS = 1
MAX_CRITICS = 10
CLIP = 3
MIN_CLIP = .005
MAX_CLIP = .1
LR = 4
MIN_LR = .00000001
MAX_LR = .0001

FILTERS = 0
MIN_FILTERS = 16
MAX_FILTERS = 128
ALPHA = 1
MIN_ALPHA = .05
MAX_ALPHA = .5
CRITICS = 2
MIN_CRITICS = 1
MAX_CRITICS = 10
CLIP = 3
MIN_CLIP = .005
MAX_CLIP = .1
LR = 4
MIN_LR = .00000001
MAX_LR = .0001

(2) 构建 DCGAN 模型。在 DCGAN 类的 __init__ 函数中,基因序列定义了模型中使用的每个超参数。首先,确保 image_shape 可被四整除并且可以适合于模型的卷积架构。接下来,每个超参数值都通过将浮点数映射到相应的空间生成。同时,在零值附近初始化权重,以更好地对齐权重与裁剪函数。最后,创建优化器,并构建模型:

python 复制代码
class DCGAN:
    def __init__(self, i):  
        '''
        === GLOBAL ===
        image_shape=(32, 32, 1),
        z_size=(1, 1, latent_dim),
        === ENCODED ===
        n_filters=128,    
        alpha=0.2,
        disc_iters=5         
        clip_lower=-0.01,                
        clip_upper=0.01, 
        lr=5e-5, 
        '''
        assert image_shape[0] % 4 == 0, "Image shape must be divisible by 4."

        self.image_shape = image_shape
        self.z_size = (1, 1, latent_dim)

        self.n_filters = linespace_int(i[FILTERS], MIN_FILTERS, MAX_FILTERS)    
        self.alpha = linespace_int(i[ALPHA], MIN_ALPHA, MAX_ALPHA)
        self.lr = linespace(i[LR], MIN_LR, MAX_LR)   
        self.clip_lower = -linespace(i[CLIP], MIN_CLIP, MAX_CLIP)
        self.clip_upper = linespace(i[CLIP], MIN_CLIP, MAX_CLIP)
        self.critic_iters = linespace_int(i[CRITICS], MAX_CRITICS, MIN_CRITICS)
        self.weight_init = RandomNormal(mean=0., stddev=0.02)
        self.optimizer = tf.keras.optimizers.legacy.RMSprop(self.lr)

        self.critic = self.build_critic()    
        self.g = self.build_generator()
        self.gan = self.build_gan()    

    def build_critic(self):
        model = Sequential(name="Critic")    
        model.add(Conv2D(self.n_filters//4, kernel_size=3, strides=2, input_shape=self.image_shape, padding="same"))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Conv2D(self.n_filters//2, kernel_size=3, strides=2, padding="same"))
        model.add(ZeroPadding2D(padding=((0,1),(0,1))))
        model.add(BatchNormalization(momentum=0.8))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Conv2D(self.n_filters, kernel_size=3, strides=2, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Conv2D(self.n_filters*2, kernel_size=3, strides=1, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Flatten())
        model.add(Dense(1))

        img = Input(shape=self.image_shape)
        validity = model(img)
        model = Model(img, validity)
        model.compile(loss=self.wasserstein_loss,
                optimizer=self.optimizer,
                metrics=['accuracy'])

        return model

    def build_generator(self):
        model = Sequential(name="Generator")    
        cs = self.image_shape[1] // 4

        model.add(Dense(self.n_filters * cs * cs, activation="relu", input_dim=latent_dim))
        model.add(Reshape((cs, cs, self.n_filters)))
        model.add(UpSampling2D())
        model.add(Conv2D(self.n_filters, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(UpSampling2D())
        model.add(Conv2D(self.n_filters//2, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(Conv2D(channels, kernel_size=3, padding="same"))
        model.add(Activation("tanh"))

        noise = Input(shape=(latent_dim,))
        img = model(noise)

        return Model(noise, img)

    def build_gan(self):    
        z = Input(shape=(latent_dim,))
        img = self.g(z)

        # For the combined model we will only train the generator
        self.critic.trainable = False

        # The discriminator takes generated images as input and determines validity
        valid = self.critic(img)

        # The combined model  (stacked generator and discriminator)
        # Trains the generator to fool the discriminator
        gan = Model(z, valid)
        gan.compile(loss=self.wasserstein_loss, optimizer=self.optimizer)
        return gan

    def train(self, train_images, epochs=10, batch_size=128, verbose=0):
        #track minium/maximum losses
        min_g_loss = 1000
        min_fake_loss = 1000
        min_real_loss = 1000
        max_g_loss = -1000
        max_fake_loss = -1000
        max_real_loss = -1000

        # Adversarial ground truths
        valid = -np.ones((batch_size, 1))
        fake = np.ones((batch_size, 1))
        batches = int(train_images.shape[0] / batch_size)
        history = []

        if verbose:
            groups = { "Critic" : {"Real", "Fake"}, "Generator":{"Gen"}}
            plotlosses = PlotLosses(groups=groups)

        for e in range(epochs):
            for i in tqdm(range(batches)):
                for _ in range(self.critic_iters):
                    # ---------------------
                    #  Train critic
                    # ---------------------
                    # Select a random half of images
                    idx = np.random.randint(0, train_images.shape[0], batch_size)
                    imgs = train_images[idx]  

                    # Sample noise and generate a batch of new images
                    noise = np.random.normal(0, 1, (batch_size, latent_dim))
                    gen_imgs = self.g.predict(noise)

                    # Train the critic (real classified as ones and generated as zeros)
                    c_loss_real = self.critic.train_on_batch(imgs, valid)
                    c_loss_fake = self.critic.train_on_batch(gen_imgs, fake)
                    c_loss = 0.5 * np.add(c_loss_real, c_loss_fake)  
                    
                    #clip discriminator/critic weights
                    for l in self.critic.layers:
                        weights = l.get_weights()
                        weights = [np.clip(w, self.clip_lower, self.clip_upper) for w in weights]
                        l.set_weights(weights) 

                # ---------------------
                #  Train Generator
                # ---------------------
                # Train the generator (wants discriminator to mistake images as real)
                g_loss = self.gan.train_on_batch(noise, valid)  

                min_g_loss = min(min_g_loss, g_loss)
                min_fake_loss = min(min_fake_loss, c_loss[1])
                min_real_loss = min(min_real_loss, c_loss[0])

                max_g_loss = max(max_g_loss, g_loss)
                max_fake_loss = max(max_fake_loss, c_loss[1])
                max_real_loss = max(max_real_loss, c_loss[0])

            loss = dict(
                Real = reverse_space(c_loss[0],min_real_loss, max_real_loss), 
                Fake = reverse_space(c_loss[1],min_fake_loss, max_fake_loss),
                Gen = reverse_space(g_loss, min_g_loss, max_g_loss) )
                    
            history.append(loss) 
            if verbose: 
                plotlosses.update(loss)
                plotlosses.send()
                self.plot_generated()
                print(min_g_loss, max_g_loss, min_fake_loss, max_fake_loss, min_real_loss, max_real_loss)
        return history

    def wasserstein_loss(self, y_true, y_pred):
        return K.mean(y_true * y_pred)

    def plot_generated(self, n_ex=10, dim=(1, 10), figsize=(12, 2)):
        noise = np.random.normal(0, 1, size=(n_ex, latent_dim))
        generated_images = self.g.predict(noise)
        generated_images = generated_images.reshape(n_ex, image_shape[0], image_shape[1])

        plt.figure(figsize=figsize)
        for i in range(generated_images.shape[0]):
            plt.subplot(dim[0], dim[1], i+1)
            plt.imshow((1-generated_images[i])*255, interpolation='nearest', cmap='gray_r')
            plt.axis('off')
        plt.tight_layout()
        plt.show()

individual = np.random.random((10))
dcgan = DCGAN(individual)

dcgan.g.summary()
dcgan.critic.summary()
dcgan.gan.summary()

individual = np.random.random((5))
individual[FILTERS] = reverse_space(128, MIN_FILTERS, MAX_FILTERS)
individual[ALPHA] = reverse_space(.2, MIN_ALPHA, MAX_ALPHA)
individual[CLIP] = reverse_space(.01, MIN_CLIP, MAX_CLIP)
individual[CRITICS] = reverse_space(5, MIN_CRITICS, MAX_CRITICS)
individual[LR] = reverse_space(.00005, MIN_LR, MAX_LR)
print(individual)

dcgan = DCGAN(individual)
history = dcgan.train(train_images, verbose=1)

def loss(history, loss):  
    h = [i[loss] for i in history]  
    max_loss = max(h)
    idx = h.index(max_loss)
    return np.mean(h[idx:])  

loss(history, "Real")

2. 进化生成对抗网络

(1) 创建用于执行架构优化的遗传算法 (Genetic Algorithms, GA) 求解器,将适应度函数注册为 FunctionMin(),我们的目标是最小化适应度值:

python 复制代码
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

MIN_VALUE = 0.
MAX_VALUE = 1.
NDIM = 5

def uniform(low, up, size=None):
    try:
        return [random.uniform(a, b) for a, b in zip(low, up)]
    except TypeError:
        return [random.uniform(a, b) for a, b in zip([low] * size, [up] * size)]
toolbox = base.Toolbox()
toolbox.register("attr_float", uniform, MIN_VALUE, MAX_VALUE, NDIM)
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.attr_float)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutGaussian, mu=0.0, sigma=1, indpb=.1)
toolbox.register("select", tools.selTournament, tournsize=3)

(2) 使用评估函数评估模型的适应度。首先,将个体转换为字符串,以便用作训练字典中的索引。将值四舍五入到小数点后一位,因此,起始值 [.2345868] 变成了 [.2],这简化了字典中的条目数量,这样做是为了将训练从无限的探索空间简化为有限的空间。确切地说,通过将值四舍五入到一位小数,在基因序列长度为 5 的情况下,可以确定有 10 × 10 × 10 × 10 × 10 = 100,000 种可能的模型要测试。这样做的真正好处在于,它允许进化更大的种群,而不必重新评估相似的个体,评估每个模型需要相当长的时间:

python 复制代码
trained = {}
generation = 0

def evaluate(individual): 
    # absolute and clip values  
    ind = str([round(i, 1) for i in individual])
    if ind in trained:
        return trained[ind],  
    print(f"Generarion {generation} individual {ind}")
    dcgan = DCGAN(individual)
    history = dcgan.train(train_images, verbose=0)
    min_loss_real = 1/loss(history, "Real")
    min_loss_gen = 1/loss(history, "Gen")
    min_loss_fake = loss(history, "Fake")
    total = (min_loss_real + min_loss_gen + min_loss_fake)/3
    print(f"Min Fitness {min_loss_real}/{min_loss_gen}:{total}")
    trained[ind] = total
    return total,     

toolbox.register("evaluate", evaluate)  

(3) 优化 DCGAN 不仅仅是比较准确率的问题。我们需要考虑模型的三个损失,包括真实损失、伪造损失和生成损失。需要以不同的方式对这些损失进行优化,以将其最小化。提取每个损失,对真实损失和生成损失求倒后作为适应度的一部分,最终适应度是这两个值与伪造损失的平均值:

python 复制代码
MU = 100 #@param {type:"slider", min:1, max:100, step:1}
NGEN = 5 #@param {type:"slider", min:1, max:10, step:1}
RGEN = 1 #@param {type:"slider", min:1, max:5, step:1}
CXPB = .6
MUTPB = .3

pop = toolbox.population(n=MU)
hof = tools.HallOfFame(1)
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean)
stats.register("std", np.std)
stats.register("min", np.min)
stats.register("max", np.max)

best = None
groups = { "fitness" : {"min", "max"}}
plotlosses = PlotLosses(groups=groups)

for g in range(NGEN):
    generation = g
    pop, logbook = algorithms.eaSimple(pop, toolbox, 
                cxpb=CXPB, mutpb=MUTPB, ngen=RGEN, stats=stats, halloffame=hof, verbose=False)
    best = hof[0] 
    
    print(f"Gen ({(g+1)*RGEN})")      
    for l in logbook:
        plotlosses.update({'min': l["min"], 'max': l["max"]})
plotlosses.send()  # draw, update logs, etc

dcgan = DCGAN(best)
dcgan.train(train_images, verbose=1)

代码输出 DCGAN 进化出的最佳解决方案,进化优化需要较长时间运行,但最终会生成最佳 GAN

小结

进化对抗生成网络 (EvoGAN) 是一种结合了进化算法和对抗生成网络的模型。在本节中,我们通过优化封装的 DCGAN 类优化对抗生成网络模型。

系列链接

遗传算法与深度学习实战(1)------进化深度学习
遗传算法与深度学习实战(2)------生命模拟及其应用
遗传算法与深度学习实战(3)------生命模拟与进化论
遗传算法与深度学习实战(4)------遗传算法(Genetic Algorithm)详解与实现
遗传算法与深度学习实战(5)------遗传算法中常用遗传算子
遗传算法与深度学习实战(6)------遗传算法框架DEAP
遗传算法与深度学习实战(7)------DEAP框架初体验
遗传算法与深度学习实战(8)------使用遗传算法解决N皇后问题
遗传算法与深度学习实战(9)------使用遗传算法解决旅行商问题
遗传算法与深度学习实战(10)------使用遗传算法重建图像
遗传算法与深度学习实战(11)------遗传编程详解与实现
遗传算法与深度学习实战(12)------粒子群优化详解与实现
遗传算法与深度学习实战(13)------协同进化详解与实现
遗传算法与深度学习实战(14)------进化策略详解与实现
遗传算法与深度学习实战(15)------差分进化详解与实现
遗传算法与深度学习实战(16)------神经网络超参数优化
遗传算法与深度学习实战(17)------使用随机搜索自动超参数优化
遗传算法与深度学习实战(18)------使用网格搜索自动超参数优化
遗传算法与深度学习实战(19)------使用粒子群优化自动超参数优化
遗传算法与深度学习实战(20)------使用进化策略自动超参数优化
遗传算法与深度学习实战(21)------使用差分搜索自动超参数优化
遗传算法与深度学习实战(22)------使用Numpy构建神经网络
遗传算法与深度学习实战(23)------利用遗传算法优化深度学习模型
遗传算法与深度学习实战(24)------在Keras中应用神经进化优化
遗传算法与深度学习实战(25)------使用Keras构建卷积神经网络
遗传算法与深度学习实战(26)------编码卷积神经网络架构
遗传算法与深度学习实战(27)------进化卷积神经网络
遗传算法与深度学习实战(28)------卷积自编码器详解与实现
遗传算法与深度学习实战(29)------编码卷积自编码器架构
遗传算法与深度学习实战(30)------使用遗传算法优化自编码器模型
遗传算法与深度学习实战(31)------变分自编码器详解与实现
遗传算法与深度学习实战(32)------生成对抗网络详解与实现
遗传算法与深度学习实战(33)------WGAN详解与实现
遗传算法与深度学习实战(34)------编码WGAN

相关推荐
只是甲4 小时前
Text2SQL 系列博客 02:技术原理深度剖析 - 从自然语言到 SQL 的完整链路
人工智能·text2sql·nl2sql·ai agent·自助数据分析·data agent·agentic 数据洞察
懷淰メ4 小时前
【AI赋能】基于PyQt+YOLO+DeepSeek水上漂浮物检测系统(详细介绍)
人工智能·yolo·目标检测·计算机视觉·pyqt·漂浮物·水上漂浮物
EQUINOX14 小时前
【论文精读】| CLIP精读
大数据·人工智能
PC2005-cloud5 小时前
博文已索引但不展示:一次 Bing SEO 问题排查记录
服务器·人工智能
weixin_408099675 小时前
2026 图片去文字 API 实战:AI一键去除图片文字(附 Python / Java / PHP / JS 完整代码)
人工智能·api接口·图片去水印·石榴智能·ai图像修复·图片去文字
幻影123!5 小时前
从零训练一个会下五子棋的AI
python·深度学习·神经网络·强化学习·五子棋·alpha zero·mokugo
greenbbLV5 小时前
2026节日慰问品政策解读:合规标准升级与福利行业新趋势
人工智能·节日
奈斯先生Vector5 小时前
告别工具碎片化:基于 Nano Banana 全模态 AI 聚合架构搭建“文本-图像-视频”自动化协同生产线
运维·数据库·人工智能·架构·自动化·aigc·音视频
领麦微红外5 小时前
国产MEMS红外测温传感器:传感器+算法+产品级出厂标定一站式交付模式深度解读
人工智能·硬件工程·产品经理
mingo_敏6 小时前
DeepAgents : 检索(Retrieval)
人工智能·深度学习·langchain