美文网首页
GAN(代码待修改,数学公式待整理)

GAN(代码待修改,数学公式待整理)

作者: 路过的飞碟 | 来源:发表于2020-09-19 08:43 被阅读0次

一.GAN简介:
"生成模型"可以将一个输入噪音生成和真实数据相似的数据
"判别模型"能够判断出真实数据和类真实数据。
随着博弈的进行,"生成模型"能够输出越来越接近真实数据的数据

总之GAN 网络的目标是:使得生成的数据和真实数据更接近。
(1)G(X)(生成模型网络)要学到优秀的模型参数,使得判别模型网络无法区别真实数据和类真实数据
(2)D(X)(判别模型网络)的判别能力要足够强,使得完成对数据的真实性做出很好的二分类任务。

x 代表真实数据,z 代表噪音,G(z)代表一个输入噪音通过生成网络后的输出。
一方面,要求判别网络能够准确判断出数据的真实性,即 D(x)尽可能接近 1,D(G(z))尽可能接近于 0;
另一方面,要求生成网络产生的数据非常接近真实数据,即 D(G(z))尽可能接近于 1。

损失函数

损失函数目的是:最大化 D 的区分度,最小化 G 输出和真实数据的区别。
将公式拆分
(1)判别模型:log(D1(x))+log(1-D2(G(z)))
(2)生成模型:log(D2(G(z)))
当判别模型能力强时,D1(x)->1, D2(G(z))->0,(1)式趋近于 0
当生成模型能力强时,D2(G(z))->1,(2)式趋近于 0

训练过程

其基本算法如图

解释:

GAN 的训练 在同一轮梯度反传的过程分为两步既是先训练 D 再训练 G:
注意:不是等D训练完成后开始训练G, D 的训练也需要上一轮梯度反传中 G 的输出值作为输入。
(1)训练D:上一轮G产生的图片,和真实图片,直接拼接在一起,作为 x。根据上图,按顺序摆放 0 和 1,假图对应 0,真图对应 1。x 输入生成一个 score(从 0 到 1 之间的数),通过 score 和 y 组成的损失函数,就可以进行梯度反传了。
(注意:图片上举的例子是 batch = 1,len(y)=2*batch,训练时通常可以取较大的 batch)
(2)训练G:将D和G看成整体(以下简称DG系统)DG系统输出仍是score。
DG前向过程:输入一组随机向量,在G处生成图,在D处对图打分。
score=1是优化目标,故而根据score和y=1的差异组成损失函数,从而进行反向传播梯度。
注意:此处D不可训练,保证G的训练符合D的打分标准

注意:GAN的过程都是无监督

二.数学推导:

数据集的分布 Pdata(x),其中是一个真实的图片。在GAN中,生成器G可以生成一个分布,这个分布的参数是 θ事实上,生成器可以是任何模型,如果它是一个高斯混合模型,就是其中的平均值和方差。在现在的处理中,我们更倾向于用神经网络来行使生成器的功能,因为它能形成比高斯模型复杂地多的分布。
在 Pdata(x)中进行采样,得到{x1,x2,..xm},此时在生成器中得到一个似然L=Ⅱ(m,i=1)PG(xi,θ) θ*这里需要找到一个 来最大化这个似然。

我们可以看到在寻找θ*来进行最大化似然的过程中,可以在外面套上 ㏒函数。这样做可以把相乘转化为相加,这样就近似于㏒PG在Pdata分布中的期望。期望又可以等价于求概率积分,因为这是在求 θ,可以将与其无关的项去掉,最后转化为使用KL divergence衡量的概率分布差异。最小化KL的过程就是寻找参数使得PG更接近于Pdata的过程。这里注意,PG 可以是任何模型的,这里我们就用神经网络来模拟。因为激活函数的存在,它可以你和任意的分布,我们可以用神经网络学习很复杂的分布。GAN的基本公式是:

在这里,给定一个G,最大似然V就表示了生成器输出和样本之前的差异,在这个过程中调整的是D的参数,然后找到一个最好的G使得这个最大值最小。第一项表示真实数据,此时D要让这一项的D(x)尽量大,后一项是G产生的数据,D(x)则要尽量小。
首先,对于给定的G,求解最优的D:

所得的D*代入:

JS Divergence也是衡量两个分布差异的指标,不同于KL,它是对称的。在上式中,找到 D后,就需要找到G来将maxDV(G,D)最小化,D0

然后更新G0为G1,可能会有V(G1,D1)>V(G0,D0)这样更新G就没达到它原来应该要的效果,如下图所示:

这时候可以控制更新的量,保证一次只做微小的改动。

三.样例介绍:
线性数据样例:
目标:
实现下图,绿线(生成网络输出数据)接近蓝线(真实数据)

(1)定义模型

def main(args):
  model = GAN(
    DataDistribution(), //真实数据真实分布
    GeneratorDistribution(range=8), //生成数据分布
    args.num_steps, //迭代次数,取 1200
    args.batch_size, //一次迭代更新 12个点的数据
    args.log_every, //每隔多少次迭代打印一次 loss 值
)
  model.train()

(2)初始化参数

def __init__(self, data, gen, num_steps, batch_size, log_every):
  self.data = data
  self.gen = gen
  self.num_steps = num_steps
  self.batch_size = batch_size
  self.log_every = log_every
  self.mlp_hidden_size = 4 //神经网络中隐藏层个数设置为 4
  self.learning_rate = 0.03 //学习率
  self._create_model()

(3) D_pre 网络
注意:判别网络D的参数不能随机初始化,必须具有一定的判别能力,所以预先使用 D_pre 网络对 D 的参数进行训练。

with tf.variable_scope('D_pre'):
  self.pre_input = tf.placeholder(tf.float32,
shape=(self.batch_size, 1))
  self.pre_labels = tf.placeholder(tf.float32,
shape=(self.batch_size, 1))
  D_pre = discriminator(self.pre_input, self.mlp_hidden_size)
  self.pre_loss = tf.reduce_mean(tf.square(D_pre -
self.pre_labels))
  self.pre_opt = optimizer(self.pre_loss, None,
self.learning_rate)
 (4)G,D网络设置

G网络:

    with tf.variable_scope('Gen'):
      self.z = tf.placeholder(tf.float32,
shape=(self.batch_size, 1)) //输入,为一个随机输入
  self.G = generator(self.z, self.mlp_hidden_size)//产生输出数据

D网络:
注意:D网络有两个输入,一个是真实数据x,另一个是生成网络的输出数据G(z)

    with tf.variable_scope('Disc') as scope:
      self.x = tf.placeholder(tf.float32,
shape=(self.batch_size, 1))
      self.D1 = discriminator(self.x, self.mlp_hidden_size)
      scope.reuse_variables()
      self.D2 = discriminator(self.G, self.mlp_hidden_size)

(5)损失函数

self.loss_d = tf.reduce_mean(-tf.log(self.D1) - tf.log(1 - self.D2))
//见(1)式,对(1)式取反
self.loss_g = tf.reduce_mean(-tf.log(self.D2))
//见(2)式

self.opt_d = optimizer(self.loss_d, self.d_params, self.learning_rate)
//使用优化器对两者的损失函数进行优化
self.opt_g = optimizer(self.loss_g, self.g_params,
self.learning_rate)

(6)训练模型

def train(self):
    with tf.Session() as session:
      tf.global_variables_initializer().run()
# pretraining discriminator
      num_pretrain_steps = 1000
      for step in range(num_pretrain_steps):
        d = (np.random.random(self.batch_size) - 0.5) * 10.0
        labels = norm.pdf(d, loc=self.data.mu,
scale=self.data.sigma)
      pretrain_loss, _ = session.run([self.pre_loss,
self.pre_opt], {
        self.pre_input: np.reshape(d, (self.batch_size,1)),
        self.pre_labels: np.reshape(labels,
(self.batch_size, 1))
})
    self.weightsD = session.run(self.d_pre_params) //将d_pre 网络的训练结果赋值
      # copy weights from pre-training over to new D network
      for i, v in enumerate(self.d_params): //将 d_pre 网
络的训练结果拷贝给 self.d_params
        session.run(v.assign(self.weightsD[i]))
for step in range(self.num_steps):
      # update discriminator
      x = self.data.sample(self.batch_size)
//定义 x 真实数据
      z = self.gen.sample(self.batch_size)
//定义 z 噪音输入
      loss_d, _ = session.run([self.loss_d, self.opt_d], {
        self.x: np.reshape(x, (self.batch_size, 1)),
        self.z: np.reshape(z, (self.batch_size, 1))
})
# update generator
      z = self.gen.sample(self.batch_size)
      loss_g, _ = session.run([self.loss_g, self.opt_g], {
        self.z: np.reshape(z, (self.batch_size, 1))
      })
if step % self.log_every == 0:
        print('{}: {}\t{}'.format(step, loss_d, loss_g))
      if step % 100 == 0 or step==0 or step == self.num_steps
-1 :
        self._plot_distributions(session)

(以上代码仍需修改)
训练结果
1200次迭代,可知下列结果

四.小狗图片训练样例:
算法图了解结构

(1)初始化
生成器接受一个 1000 维的随机生成的数组,然后输出一个 64×64×3
通道的图片数据
生成器就是一个神经网络,或看成一个函数,低维度的向量生成一个高维度的向量。训练完成后的生成器,输入向量每一个元素可以对应图片的一个象征。

def generator_model():
      model = Sequential()
      model.add(Dense(input_dim=1000, output_dim=1024))
      model.add(Activation('tanh'))
      model.add(Dense(128 * 8 * 8))
      model.add(BatchNormalization())
      model.add(Activation('tanh'))
      model.add(Reshape((8, 8, 128), input_shape=(8 * 8 * 128,)))
      model.add(UpSampling2D(size=(4, 4)))
      model.add(Conv2D(64, (5, 5), padding='same'))
      model.add(Activation('tanh'))
      model.add(UpSampling2D(size=(2, 2)))
      model.add(Conv2D(3, (5, 5), padding='same'))
      model.add(Activation('tanh'))
      return model

(2)判别器代码与结构:

def discriminator_model():
      model = Sequential()
      model.add(Conv2D(64, (5, 5), padding='same', input_shape=(64, 64, 3)))
      model.add(Activation('tanh'))
      model.add(MaxPooling2D(pool_size=(2, 2)))
      model.add(Conv2D(128, (5, 5)))
      model.add(Activation('tanh'))
      model.add(MaxPooling2D(pool_size=(2, 2)))
      model.add(Flatten())
      model.add(Dense(1024))
      model.add(Activation('tanh'))
      model.add(Dense(1))
      model.add(Activation('sigmoid'))
      return model

输入是 64,64,3 的图片,输出是一个数 1 或者 0
(3)训练D

# 随机生成的 1000 维的噪声
noise = np.random.uniform(-1, 1, size=(BATCH_SIZE, 1000))
# X_train 是训练的图片数据,这里取出一个 batchsize 的图片用于训练,这个是真图(64张)
image_batch = X_train[index * BATCH_SIZE:(index + 1) * BATCH_SIZE]
# 这里是经过生成器生成的假图
generated_images = generator_model.predict(noise, verbose=0)
# 将真图与假图进行拼接
X = np.concatenate((image_batch, generated_images))
# 与 X 对应的标签,前 64 张图为真,标签是 1,后 64 张图是假图,标签为 0
y = [1] * BATCH_SIZE + [0] * BATCH_SIZE
# 把真图与假图的拼接训练数据 1 送入判别器进行训练判别器的准确度
d_loss = discriminator_model.train_on_batch(X, y)

(4)训练G

def generator_containing_discriminator(g, d):
  model = Sequential()
  model.add(g)
  # 判别器参数不进行修改
  d.trainable = False
  model.add(d)
  return model

这个模型上半部分是生成网络,下半部分是判别网络,生成网络首先生成假图,然后送入判别网络中进行判断,这里有一个 d.trainable=False,意思是,只调整生成器,判别的的参数不做更改。
(5)训练G

# 训练一个 batchsize 里面的数据
for index in range(int(X_train.shape[0]/BATCH_SIZE)):
    # 产生随机噪声
    noise = np.random.uniform(-1, 1, size=(BATCH_SIZE, 1000))
    # 这里面都是真图片
    image_batch = X_train[index*BATCH_SIZE:(index+1)*BATCH_SIZE]
    # 这里产生假图片
    generated_images = g.predict(noise, verbose=0)
    #  将真图片与假图片拼接在一起
    X = np.concatenate((image_batch, generated_images))
    # 前 64 张图片标签为 1,即真图,后 64 张照片为假图
    y = [1] * BATCH_SIZE + [0] * BATCH_SIZE
    # 对于判别器进行训练,不断提高判别器的识别精度
    d_loss = d.train_on_batch(X, y)
    # 再次产生随机噪声
    noise = np.random.uniform(-1, 1, (BATCH_SIZE, 1000))
    # 设置判别器的参数不可调整
    d.trainable = False
# ××××××××××××××××××××××××××××××××××××××××××××××
# 在此输入噪声,并认为这些噪声是真实的标签
g_loss = generator_containing_discriminator.train_on_batch(noise, [1] *
BATCH_SIZE)
# ××××××××××××××××××××××××××××××××××××××××××××××

    # 此时设置判别器可以被训练,参数可以被修改
    d.trainable = True
    # 打印损失值
    print("batch %d d_loss : %s, g_loss : %f" % (index, d_loss, g_loss))

(此处在前文已经介绍过工作过程,如果已经了解过程可以不看)
先输入生成器中,然后生成器生成图片之后,把图片输入判别器中,标签此刻输入的是 1,真实的图片,但实际上是假图,此刻判别器就会判断为假图,然后模型就会不断调整生成器参数,此时判别器的参数被设置为为不可调整,
d.trainable=False所以为了不断降低 loss 值,模型就会一直调整生成器的参数,直到判别器认为这是真图。此时判别器与生成器达到了一个平衡。也就是说生成器产生的假图,判别器已经分辨不出来了。所以继续迭代,提高判别器精度,如此往复循环,直到个人满意。

训练结果


1.参考https://www.pianshen.com/article/2495690365/;jsessionid=A929EB195A785EF5D377012CF21FB7FF
2.参考:
https://www.pianshen.com/article/3628327017/
3.参考:
https://github.com/jensleeGit/Kaggle_self_use/tree/master/Generative Dog Images
4.参考:
https://zhuanlan.zhihu.com/p/44218749
5.参考百度百科

相关文章

  • GAN(代码待修改,数学公式待整理)

    一.GAN简介:"生成模型"可以将一个输入噪音生成和真实数据相似的数据"判别模型"能够判断出真实数据和类真实数据。...

  • GCN原理篇(代码待修改,数学公式待整理)

    新人想初步了解可以下载这个PPT(百度网盘):链接:https://pan.baidu.com/s/1Ta4MYO...

  • 待修改

    近来,茜蕊的日子越发的难熬,越来感觉自己在公司里混不下去了。好友汪君是公司的精英,领导的宠儿,无可奈何的说了句:“...

  • 待修改

    时间:2019-10-289 主题:阴瑜伽-肝胆经络 导师:妮颜老师 一、收获 (1)感觉自己在纠正学员时比以前有...

  • 待修改

    待修改

  • 待整理…

    2018.08.12 坐标德州 天气 晴 周记第9篇,原创第27篇,本周发朋友圈15条。 1.工作 这一周出图比较...

  • 待 整理

    乱弹及其他 1/3 2/31 牧荣萌2017-08-02 06:42 · 字数 688 · 阅读 2 · 日记本...

  • 待整理

    原文地址打包 原文地址

  • 待整理

    环境、行为、能力是下三层;信念、身份、精神(就是上面的三角,指的是你的焦点,你内在的驱动力)。 信念即三观的部分,...

  • 待整理

    01紧迫的事情 Linux命令整理 tomcat知识 nginx知识点梳理掌握 apache正向代理 英语 02遗...

网友评论

      本文标题:GAN(代码待修改,数学公式待整理)

      本文链接:https://www.haomeiwen.com/subject/ffteyktx.html