基于Keras框架对抗神经网络DCGAN实践

MichaelValentine 发布于2月前
0 条问题

1. 前言

金庸小说《射雕英雄传》中,周伯通被东邪“黄药师”困在桃花岛的地洞里。为了打发时间,周伯通就用左手与右手打架,自娱自乐。其武功决窍在于要先“左手画圆、右手画方”,分心二用,保证可以同时使出两种武功,从而使得武力倍增。

于是,一位名叫伊恩·古德费洛的美国人在2014年加拿大蒙特利尔大学读博士的时候想了这样一个方案,也就是说,在两个神经网络中进行“猫和鼠游戏”,一个不断地“造假”,一个不断“验真”,彼此相互追逐,在对抗中不断提高自身的本领。

常见的应用场景:

数据生成——解决数据缺失

在特定的应用场景下,例如医疗领域、能源行业工业化生产,缺少训练数据是应用深度学习的最大障碍。数据增强的传统做法是将原图像拉伸旋转剪切,但这毕竟还是原来的图像,通过使用GAN,能够生成更多类似的数据。

图像编辑

图像编辑好比“美图秀秀”软件中的各种滤镜的升级版,给出一张原始的妹子图片,可以生成出金发版,卷发版,微笑版,还能修改图片中的环境因素。

恶意攻击检测

通过给深度神经网络一些特异生产的训练数据,深度学习生成的模型是可以被黑客攻击,利用甚至控制的。为了对抗这样的逆向攻击(adversarialattacks),可以训练对抗神经网络去生成更多的虚假训练数据作为假想敌,让模型在演习中去识别出这些虚假数据,就如同人类打疫苗,GAN生成的虚假数据让正在做分类的模型更加稳健。

注意力预测

人类在看一张图片时,往往只关注特定的部分,而通过GAN模型,可以预测出人类关心的区域在哪里。对注意力的预测,可以指导广告的投送,例如在电影中做植入广告前,可以先预测一下植入的区域是不是在注意力的热点区。

2. 关于GANs

GANs(Generative Adversarial Networks)可以说是一种强大的「万能」数据分布拟合器,主要由一个生成器(generator)和判别器(discriminator)组成。生成器主要从一个低维度的数据分布中不断拟合真实的高维数据分布,而判别器主要是为了区分数据是来源于真实数据还是生成器生成的数据,他们之间相互对抗,不断学习,最终达到Nash均衡,即任何一方的改进都不会导致总体的收益增加,这个时候判别器再也无法区分是生成器生成的数据还是真实数据。

GANs 最初由 Ian Goodfellow 于 2014 年提出,目前已经在图像、语音、文字等方面得到广泛研究和应用,特别是在图像生成方面,可谓是遍地开花,例如图像风格迁移(style transfer)、图像修复(image inpainting)、超分辨率(super resolution)等。

基于Keras框架对抗神经网络DCGAN实践 蓝色分布为生成分布,绿色分布为真实分布,D为判别器,GAN从概率分布的角度来看,就是通过D来将生成分布推向真实分布,紧接着再优化D,直至到达图(d)所示,到达Nash均衡点,从而生成分布与真实分布重叠,生成极为接近真实分布的数据。

3. 对抗神经网络

基于Keras框架对抗神经网络DCGAN实践 GANs简单的想法就是用两个模型,一个生成模型,一个判别模型。判别模型用于判断一个给定的图片是不是真实的图片(判断该图片是从数据集里获取的真实图片还是生成器生成的图片),生成模型的任务是去创造一个看起来像真的图片一样的图片,有点拗口,就是说模型自己去产生一个图片,可以和你想要的图片很像。而在开始的时候这两个模型都是没有经过训练的,这两个模型一起对抗训练,生成模型产生一张图片去欺骗判别模型,然后判别模型去判断这张图片是真是假,最终在这两个模型训练的过程中,两个模型的能力越来越强,最终达到稳态。

DCGAN实践代码 [1] ,初始化如下:

from __future__ import print_function, division
from datasource0 import load_dataset   # 自定义数据源,提供学习样本图片
from keras.layers import Input, Dense, Reshape, Flatten, Dropout
from keras.layers import BatchNormalization, Activation, ZeroPadding2D
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D, Conv2D
from keras.models import Sequential, Model
from keras.optimizers import Adam
import matplotlib.pyplot as plt
import numpy as np
class DCGAN():
    def __init__(self):
        # Input shape
        self.img_rows = 128  # 图像的高
        self.img_cols = 160  # 图像的宽
        self.channels = 3    # 彩色图像
        self.img_shape = (self.img_rows, self.img_cols, self.channels)
        self.latent_dim = 100   #输入100维度输入
        # 设置学习率为0.0001
        optimizer = Adam(0.0001, 0.5)
        # Build and compile the discriminator
        self.discriminator = self.build_discriminator()
        self.discriminator.compile(loss='binary_crossentropy',
            optimizer=optimizer,
            metrics=['accuracy'])
        # Build the generator
        self.generator = self.build_generator()
        # The generator takes noise as input and generates imgs
        z = Input(shape=(self.latent_dim,))
        img = self.generator(z)
        # For the combined model we will only train the generator
        self.discriminator.trainable = False
        # The discriminator takes generated images as input and determines validity
        valid = self.discriminator(img)
        # The combined model  (stacked generator and discriminator)
        # Trains the generator to fool the discriminator
        self.combined = Model(z, valid)
        self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)

3.1. 生成模型

基于Keras框架对抗神经网络DCGAN实践

(上文中的生成模型图引自[2])G网中使用ReLU作为激活函数,最后一层使用Tanh作为激活函数。

去掉了FC层,使网络变为全卷积网络

def build_generator(self):
        # 模型到深度及设置
        depths = [1024,512,256,128,3]
        model = Sequential()
        model.add(Dense(512 * 8 * 10, activation="relu", input_dim=self.latent_dim))
        model.add(Reshape((8, 10, 512)))
        model.add(UpSampling2D())
        model.add(Conv2D(256, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(UpSampling2D()) 
        model.add(Conv2D(128, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(UpSampling2D()) 
        model.add(Conv2D(64, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(UpSampling2D())        
        model.add(Conv2D(32, kernel_size=3, padding="same"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Activation("relu"))
        model.add(Conv2D(self.channels, kernel_size=3, padding="same"))
        model.add(Activation("tanh"))
        model.summary()
        noise = Input(shape=(self.latent_dim,))
        img = model(noise)
        return Model(noise, img)

3.2. 判别模型

基于Keras框架对抗神经网络DCGAN实践

D中取消所有的池化层,使用转置卷积(transposed convolutional layer)并且步长大于等于2进行上采样。

D网中也加入stride的卷积代替pooling。

def build_discriminator(self):
        model = Sequential()
        model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=self.img_shape, padding="same"))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Conv2D(64, 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(128, 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(256, 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(512, 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(Flatten())
        model.add(Dense(1, activation='sigmoid'))
        model.summary()
        img = Input(shape=self.img_shape)
        validity = model(img)
        return Model(img, validity)

在D网和G网中均使用批量归一化(batch normalization),而在最后一层时通常不会使用batch normalization,这是为了保证模型能够学习到数据的正确均值和方差。

D网络中使用LeakyReLU作为激活函数。

DCGAN中换成了两个卷积神经网络(CNN)的G和D,可以刚好的学习对输入图像层次化的表示,尤其在生成器部分会有更好的模拟效果。DCGAN在训练过程中会使用Adam优化算法。

3.3. 训练模型

def train(self, epochs, batch_size=128, save_interval=50):
        # Load the dataset
        X_train,y1, x0, y0 ,num= load_dataset()
        valid = np.ones((batch_size, 1))
        fake = np.zeros((batch_size, 1))
        for epoch in range(epochs):
            # ---------------------
            #  Train Discriminator
            # Select a random half of images
            idx = np.random.randint(0, X_train.shape[0], batch_size)
            imgs = X_train[idx]
            # Sample noise and generate a batch of new images
            noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
            gen_imgs = self.generator.predict(noise)
            # Train the discriminator (real classified as ones and generated as zeros)
            d_loss_real = self.discriminator.train_on_batch(imgs, valid)
            d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake)
            d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
            # ---------------------
            #  Train Generator
            # ---------------------
            # Train the generator (wants discriminator to mistake images as real)
            g_loss = self.combined.train_on_batch(noise, valid)
            # Plot the progress
            print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss))
            # If at save interval => save generated image samples
            if epoch % save_interval == 0:
                self.save_imgs(epoch)

3.4. 生成以假乱真的图片

def save_imgs(self, epoch):
        r, c = 5, 5
        noise = np.random.normal(0, 1, (r * c, self.latent_dim))
        gen_imgs = self.generator.predict(noise)
        # Rescale images 0 - 1
        gen_imgs = 0.5 * gen_imgs + 0.5
        fig, axs = plt.subplots(r, c)
        cnt = 0
        for i in range(r):
            for j in range(c):
                axs[i,j].imshow(gen_imgs[cnt, :,:,:])
                axs[i,j].axis('off')
                cnt += 1
        fig.savefig("images0617/img_%d.png" % epoch)
        plt.close()
if __name__ == '__main__':
    dcgan = DCGAN()
    dcgan.train(epochs=10000, batch_size=50, save_interval=50)

4. 实践成果及经验

4.1. 成果展示

如下图所示,左侧5列为原始真实的样本,右侧5列是生成图像。

基于Keras框架对抗神经网络DCGAN实践

直接使用源代码,三层网络结构,刚刚开始的效果,如下图所示。

基于Keras框架对抗神经网络DCGAN实践

网上学习资源,多数是手写数字、灰度图片生成样例,使用其浅层CNN(一般为3到4层)即可达到要求,而对于较大的、彩色图片,往往是上图的效果,与实际要求差距较大,为此需要加深网络。

如果要实现更好的深度学习效果,应该采用类似ResNe等深度网络,后续,本人将采用ResNet网络结构。

4.2. 经验

网络深度问题

最开始,直接使用源码的网络设计,进行的对抗训练,效果不好,后通过增加卷积层来改善来效果。

图像格式问题

由于使用cv2读取样本,cv2的格式是BGR,而plt使用的格式为RGB,需要矩阵翻转,对正彩图的数据通道。

#gen_imgs = gen_imgs[:,:,::-1]  # cv2的BGR 翻转为RGB,矩阵翻转

OOM问题

batch_size,源代码给出是32,设置为batch_size超过100,有可能出现OOM问题;以及其他网络深度、神经元数量都将影响OOM。

5. Keras参考

5.1. 关于Keras模型

Keras有两种类型的模型,顺序模型(Sequential)和泛型模型(Model),两类模型有一些方法是相同的:

model.summary():打印出模型概况

model.get_config():返回包含模型配置信息的Python字典。模型也可以从它的config信息中重构回去

泛型模型接口

Keras的泛型模型为Model,即广义的拥有输入和输出的模型。

常用Model属性

model.layers:组成模型图的各个层

model.inputs:模型的输入张量列表

model.outputs:模型的输出张量列表

Model模型方法

compile

compile(self, optimizer, loss, metrics=[], loss_weights=None, sample_weight_mode=None)

本函数编译模型以供训练,参数有:

optimizer:优化器,为预定义优化器名或优化器对象,参考优化器

loss:目标函数,为预定义损失函数名或一个目标函数,参考目标函数

metrics:列表,包含评估模型在训练和测试时的性能的指标,典型用法是metrics=[‘accuracy’]如果要在多输出模型中为不同的输出指定不同的指标,可像该参数传递一个字典,例如metrics={‘ouput_a’: ‘accuracy’}

predict

predict(self, x, batch_size=32, verbose=0)

本函数按batch获得输入数据对应的输出,其参数有:

函数的返回值是预测值的numpy array

train_on_batch

train_on_batch(self, x, y, class_weight=None, sample_weight=None)

本函数在一个batch的数据上进行一次参数更新

函数返回训练误差的标量值或标量值的list,与evaluate的情形相同。

5.2. 关于优化器

优化器optimizers,优化器是编译Keras模型必要的两个参数之一,可以在调用model.compile()之前初始化一个优化器对象,然后传入该函数(如上所示),也可以在调用model.compile()时传递一个预定义优化器名。在后者情形下,优化器的参数将使用默认值。

keras.optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)

Adam 优化器,默认参数遵循原论文中提供的值,参数:

lr: float >= 0. 学习率。

beta_1: float, 0 < beta < 1. 通常接近于 1。

beta_2: float, 0 < beta < 1. 通常接近于 1。

epsilon: float >= 0. 模糊因子. 若为 None, 默认为 K.epsilon()。

decay: float >= 0. 每次参数更新后学习率衰减值。

amsgrad: boolean. 是否应用此算法的 AMSGrad 变种,来自论文 “On the Convergence of Adam and Beyond”。

5.3. 其他

UpSampling2D

keras.layers.UpSampling2D(size=(2, 2), data_format=None, interpolation=‘nearest’)

2D 输入的上采样层,沿着数据的行和列分别重复 size[0] 和 size[1] 次,参数:

size: 整数,或 2 个整数的元组。 行和列的上采样因子。

data_format: 字符串, channels_last (默认) 或 channels_first 之一, 表示输入中维度的顺序。channels_last 对应输入尺寸为 (batch, height, width, channels), channels_first 对应输入尺寸为 (batch, channels, height, width)。 它默认为从 Keras 配置文件 ~/.keras/keras.json 中 找到的 image_data_format 值。 如果你从未设置它,将使用 “channels_last”。

interpolation: 字符串,nearest 或 bilinear 之一。 注意 CNTK 暂不支持 bilinear upscaling, 以及对于 Theano,只可以使用 size=(2, 2)。

输入尺寸

如果 data_format 为 “channels_last”, 输入 4D 张量,尺寸为 (batch, rows, cols, channels)。

如果 data_format 为 “channels_first”, 输入 4D 张量,尺寸为 (batch, channels, rows, cols)。

输出尺寸

如果 data_format 为 “channels_last”, 输出 4D 张量,尺寸为 (batch, upsampled_rows, upsampled_cols, channels)。

如果 data_format 为 “channels_first”, 输出 4D 张量,尺寸为 (batch, channels, upsampled_rows, upsampled_cols)。

[1] 源代码:https://github.com/eriklindernoren/Keras-GAN Erik Linder-Norén eriklindernoren

[2]《对抗神经网络(二)——DCGAN》 CSDN博客 全部梭哈一夜暴富 2019年3月

[3]《用Keras搭建GAN:图像去模糊中的应用(附代码)》 (原文:GAN with Keras: Application to Image Deblurring,作者为Raphaël Meudec。)雷锋网,雷锋字幕组编译 2018年4月

[4]《生成式对抗网络模型综述:一文看懂各种GAN模型原理》

[5]《 互怼的艺术:从零直达WGAN-GP》 科学空间 苏剑林 2017年6月

[6]《能量视角下的GAN模型(一):GAN=“挖坑”+“跳坑”》 科学空间 苏剑林 2019年1月

[7]《基于Keras的DCGAN实现》 CSDN博客 TheOneGIS 2018年4月

[8]《生成对抗网络GANs理解(附代码)》 CSDN博客 DivinerShi 2017年1月

[9]《学习基于Keras框架的ResNet网络及实践笔记》 CSDN博客 肖永威 2019年6月

收集的资源:

https://www.leiphone.com/news/201705/JTSEJKDHeETcYORh.html

https://mp.weixin.qq.com/s/mT1Uz5i1XlqWCDxJlR927Q

https://blog.csdn.net/qq_31804159/article/details/88559101

https://blog.csdn.net/nima1994/article/details/83620725

https://keras.io/zh/getting-started/faq/#how-can-i-freeze-keras-layers

查看原文: 基于Keras框架对抗神经网络DCGAN实践

  • organicbird
  • purplegorilla
  • whiteladybug
  • heavykoala
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。