• 学习笔记TF051:生成式对抗网络


    生成式对抗网络(gennerative adversarial network,GAN),谷歌2014年提出网络模型。灵感自二人博弈的零和博弈,目前最火的非监督深度学习。GAN之父,Ian J.Goodfellow,公认人工智能顶级专家。

    原理。
    生成式对搞网络包含一个生成模型(generative model,G)和一个判别模型(discriminative model,D)。Ian J.Goodfellow、Jean Pouget-Abadie、Mehdi Mirza、Bing Xu、David Warde-Farley、Sherjil Ozair、Aaron Courville、Yoshua Bengio论文,《Generative Adversarial Network》,https://arxiv.org/abs/1406.2661 。
    生成式对抗网络结构:
    噪声数据->生成模型->假图片---|
    |->判别模型->真/假
    打乱训练数据->训练集->真图片-|
    生成式对抗网络主要解决如何从训练样本中学习出新样本。生成模型负责训练出样本的分布,如果训练样本是图片就生成相似的图片,如果训练样本是文章名子就生成相似的文章名子。判别模型是一个二分类器,用来判断输入样本是真实数据还是训练生成的样本。
    生成式对抗网络优化,是一个二元极小极大博弈(minimax two-player game)问题。使生成模型输出在输入给判别模型时,判断模型秀难判断是真实数据还是虚似数据。训练好的生成模型,能把一个噪声向量转化成和训练集类似的样本。Argustus Odena、Christopher Olah、Jonathon Shlens论文《Coditional Image Synthesis with Auxiliary Classifier GANs》。
    辅助分类器生成式对抗网络(auxiliary classifier GAN,AC-GAN)实现。

    生成式对抗网络应用。生成数字,生成人脸图像。

    生成式对抗网络实现。https://github.com/fchollet/keras/blob/master/examples/mnist_acgan.py 。
    Augustus Odena、Chistopher Olah和Jonathon Shlens 论文《Conditional Image Synthesis With Auxiliary Classifier GANs》。
    通过噪声,让生成模型G生成虚假数据,和真实数据一起送到判别模型D,判别模型一方面输出数据真/假,一方面输出图片分类。
    首先定义生成模型,目的是生成一对(z,L)数据,z是噪声向量,L是(1,28,28)的图像空间。

    def build_generator(latent_size):
    cnn = Sequential()
    cnn.add(Dense(1024, input_dim=latent_size, activation='relu'))
    cnn.add(Dense(128 * 7 * 7, activation='relu'))
    cnn.add(Reshape((128, 7, 7)))
    #上采样,图你尺寸变为 14X14
    cnn.add(UpSampling2D(size=(2,2)))
    cnn.add(Convolution2D(256, 5, 5, border_mode='same', activation='relu', init='glorot_normal'))
    #上采样,图像尺寸变为28X28
    cnn.add(UpSampling2D(size=(2,2)))
    cnn.add(Convolution2D(128, 5, 5, border_mode='same', activation='relu', init='glorot_normal'))
    #规约到1个通道
    cnn.add(Convolution2D(1, 2, 2, border_mode='same', activation='tanh', init='glorot_normal'))
    #生成模型输入层,特征向量
    latent = Input(shape=(latent_size, ))
    #生成模型输入层,标记
    image_class = Input(shape=(1,), dtype='int32')
    cls = Flatten()(Embedding(10, latent_size, init='glorot_normal')(image_class))
    h = merge([latent, cls], mode='mul')
    fake_image = cnn(h) #输出虚假图片
    return Model(input=[latent, image_class], output=fake_image)
    定义判别模型,输入(1,28,28)图片,输出两个值,一个是判别模型认为这张图片是否是虚假图片,另一个是判别模型认为这第图片所属分类。

    def build_discriminator();
    #采用激活函数Leaky ReLU来替换标准的卷积神经网络中的激活函数
    cnn = Wequential()
    cnn.add(Convolution2D(32, 3, 3, border_mode='same', subsample=(2, 2), input_shape=(1, 28, 28)))
    cnn.add(LeakyReLU())
    cnn.add(Dropout(0.3))
    cnn.add(Convolution2D(64, 3, 3, border_mode='same', subsample=(1, 1)))
    cnn.add(LeakyReLU())
    cnn.add(Dropout(0.3))
    cnn.add(Convolution2D(128, 3, 3, border_mode='same', subsample=(1, 1)))
    cnn.add(LeakyReLU())
    cnn.add(Dropout(0.3))
    cnn.add(Convolution2D(256, 3, 3, border_mode='same', subsample=(1, 1)))
    cnn.add(LeakyReLU())
    cnn.add(Dropout(0.3))
    cnn.add(Flatten())
    image = Input(shape=(1, 28, 28))
    features = cnn(image)
    #有两个输出
    #输出真假值,范围在0~1
    fake = Dense(1, activation='sigmoid',name='generation')(features)
    #辅助分类器,输出图片分类
    aux = Dense(10, activation='softmax', name='auxiliary')(features)
    return Model(input=image, output=[fake, aux])
    训练过程,50轮(epoch),把权重保存,每轮把虚假数据生成图处保存,观察虚假数据演化过程。

    if __name__ =='__main__':
    #定义超参数
    nb_epochs = 50
    batch_size = 100
    latent_size = 100
    #优化器学习率
    adam_lr = 0.0002
    adam_beta_l = 0.5
    #构建判别网络
    discriminator = build_discriminator()
    discriminator.compile(optimizer=adam(lr=adam_lr, beta_l=adam_beta_l), loss='binary_crossentropy')
    latent = Input(shape=(lastent_size, ))
    image_class = Input(shape-(1, ), dtype='int32')
    #生成组合模型
    discriminator.trainable = False
    fake, aux = discriminator(fake)
    combined = Model(input=[latent, image_class], output=[fake, aux])
    combined.compile(optimizer=Adam(lr=adam_lr, beta_l=adam_beta_1), loss=['binary_crossentropy', 'sparse_categorical_crossentropy'])
    #将mnist数据转化为(...,1,28,28)维度,取值范围为[-1,1]
    (X_train,y_train),(X_test,y_test) = mnist.load_data()
    X_train = (X_train.astype(np.float32) - 127.5) / 127.5
    X_train = np.expand_dims(X_train, axis=1)
    X_test = (X_test.astype(np.float32) - 127.5) / 127.5
    X_test = np.expand_dims(X_test, axis=1)
    num_train, num_test = X_train.shape[0], X_test.shape[0]
    train_history = defaultdict(list)
    test_history = defaultdict(list)
    for epoch in range(epochs):
    print('Epoch {} of {}'.format(epoch + 1, epochs))
    num_batches = int(X_train.shape[0] / batch_size)
    progress_bar = Progbar(target=num_batches)
    epoch_gen_loss = []
    epoch_disc_loss = []
    for index in range(num_batches):
    progress_bar.update(index)
    #产生一个批次的噪声数据
    noise = np.random.uniform(-1, 1, (batch_size, latent_size))
    # 获取一个批次的真实数据
    image_batch = X_train[index * batch_size:(index + 1) * batch_size]
    label_batch = y_train[index * batch_size:(index + 1) * batch_size]
    # 生成一些噪声标记
    sampled_labels = np.random.randint(0, 10, batch_size)
    # 产生一个批次的虚假图片
    generated_images = generator.predict(
    [noise, sampled_labels.reshape((-1, 1))], verbose=0)
    X = np.concatenate((image_batch, generated_images))
    y = np.array([1] * batch_size + [0] * batch_size)
    aux_y = np.concatenate((label_batch, sampled_labels), axis=0)
    epoch_disc_loss.append(discriminator.train_on_batch(X, [y, aux_y]))
    # 产生两个批次噪声和标记
    noise = np.random.uniform(-1, 1, (2 * batch_size, latent_size))
    sampled_labels = np.random.randint(0, 10, 2 * batch_size)
    # 训练生成模型来欺骗判别模型,输出真/假都设为真
    trick = np.ones(2 * batch_size)
    epoch_gen_loss.append(combined.train_on_batch(
    [noise, sampled_labels.reshape((-1, 1))],
    [trick, sampled_labels]))
    print(' Testing for epoch {}:'.format(epoch + 1))
    # 评估测试集,产生一个新批次噪声数据
    noise = np.random.uniform(-1, 1, (num_test, latent_size))
    sampled_labels = np.random.randint(0, 10, num_test)
    generated_images = generator.predict(
    [noise, sampled_labels.reshape((-1, 1))], verbose=False)
    X = np.concatenate((X_test, generated_images))
    y = np.array([1] * num_test + [0] * num_test)
    aux_y = np.concatenate((y_test, sampled_labels), axis=0)
    # 判别模型是否能判别
    discriminator_test_loss = discriminator.evaluate(
    X, [y, aux_y], verbose=False)
    discriminator_train_loss = np.mean(np.array(epoch_disc_loss), axis=0)
    # 创建两个批次新噪声数据
    noise = np.random.uniform(-1, 1, (2 * num_test, latent_size))
    sampled_labels = np.random.randint(0, 10, 2 * num_test)
    trick = np.ones(2 * num_test)
    generator_test_loss = combined.evaluate(
    [noise, sampled_labels.reshape((-1, 1))],
    [trick, sampled_labels], verbose=False)
    generator_train_loss = np.mean(np.array(epoch_gen_loss), axis=0)
    # 损失值等性能指标记录下来,并输出
    train_history['generator'].append(generator_train_loss)
    train_history['discriminator'].append(discriminator_train_loss)
    test_history['generator'].append(generator_test_loss)
    test_history['discriminator'].append(discriminator_test_loss)
    print('{0:<22s} | {1:4s} | {2:15s} | {3:5s}'.format(
    'component', *discriminator.metrics_names))
    print('-' * 65)
    ROW_FMT = '{0:<22s} | {1:<4.2f} | {2:<15.2f} | {3:<5.2f}'
    print(ROW_FMT.format('generator (train)',
    *train_history['generator'][-1]))
    print(ROW_FMT.format('generator (test)',
    *test_history['generator'][-1]))
    print(ROW_FMT.format('discriminator (train)',
    *train_history['discriminator'][-1]))
    print(ROW_FMT.format('discriminator (test)',
    *test_history['discriminator'][-1]))
    # 每个epoch保存一次权重
    generator.save_weights(
    'params_generator_epoch_{0:03d}.hdf5'.format(epoch), True)
    discriminator.save_weights(
    'params_discriminator_epoch_{0:03d}.hdf5'.format(epoch), True)
    # 生成一些可视化虚假数字看演化过程
    noise = np.random.uniform(-1, 1, (100, latent_size))
    sampled_labels = np.array([
    [i] * 10 for i in range(10)
    ]).reshape(-1, 1)
    generated_images = generator.predict(
    [noise, sampled_labels], verbose=0)
    # 整理到一个方格
    img = (np.concatenate([r.reshape(-1, 28)
    for r in np.split(generated_images, 10)
    ], axis=-1) * 127.5 + 127.5).astype(np.uint8)
    Image.fromarray(img).save(
    'plot_epoch_{0:03d}_generated.png'.format(epoch))
    pickle.dump({'train': train_history, 'test': test_history},
    open('acgan-history.pkl', 'wb'))

    训练结束,创建3类文件。params_discriminator_epoch_{{epoch_number}}.hdf5,判别模型权重参数。params_generator_epoch_{{epoch_number}}.hdf5,生成模型权重参数。plot_epoch_{{epoch_number}}_generated.png 。

    生成式对抗网络改进。生成式对抗网络(generative adversarial network,GAN)在无监督学习非常有效。常规生成式对抗网络判别器使用Sigmoid交叉熵损失函数,学习过程梯度消失。Wasserstein生成式对抗网络(Wasserstein generative adversarial network,WGAN),使用Wasserstein距离度量,而不是Jensen-Shannon散度(Jensen-Shannon divergence,JSD)。使用最小二乘生成式对抗网络(least squares generative adversarial network,LSGAN),判别模型用最小平方损失小函数(least squares loss function)。Sebastian Nowozin、Botond Cseke、Ryota Tomioka论文《f-GAN: Training Generative Neural Samplers using Variational Divergence Minimization》。

    参考资料:
    《TensorFlow技术解析与实战》

    欢迎付费咨询(150元每小时),我的微信:qingxingfengzi

  • 相关阅读:
    springmvc log4j 配置
    intellij idea maven springmvc 环境搭建
    spring,property not found on type
    intellij idea maven 工程生成可执行的jar
    device eth0 does not seem to be present, delaying initialization
    macos ssh host配置及免密登陆
    centos7 搭建 docker 环境
    通过rest接口获取自增id (twitter snowflake算法)
    微信小程序开发体验
    gitbook 制作 beego 参考手册
  • 原文地址:https://www.cnblogs.com/libinggen/p/7421110.html
Copyright © 2020-2023  润新知