DCGANs源码解析(二)

model.py

DCGANs大部分都在一个叫做 DCGAN 的 Python 类(class)中(model.py)。像这样把所有东西都放在一个类中非常有用,因为训练后中间状态可以被保存起来,以便后面使用。

首先让我们定义生成器和鉴别器(上一篇已经介绍过了)。
linear, conv2d_transpose, conv2d, 和 lrelu 函数都是在 ops.py 中定义的。

1.初始化DCGAN类

我们初始化DCGAN类时,就用generator和discriminator这些函数创造了模型。

我们需要两种版本的鉴别器,他们共享同样的参数。一个用于来自真实数据分布的小批图像,另一个用于来自生成器的小批图像。下面self.D等是来自真实图片数据的判别器,self.D_等是来自生成器图片的判别器。

self.G = self.generator(self.z)
self.D, self.D_logits = self.discriminator(self.images)
self.D_, self.D_logits_ = self.discriminator(self.G, reuse=True)

2.定义损失函数

接着,我们将定义损失函数。在这里不用求和(sums),我们用D的预测和我想让它更好地工作而对它的期望之间的交叉熵( cross entropy (https://en.wikipedia.org/wiki/Cross_entropy))。

鉴别器想让来自真实数据的预测都为1,而来自生成器的假造数据都为0。生成器想让鉴别器的所有预测都为1.下面是根据这个预期定义的损失函数

#d_loss_real是真实图片输入到判别器中的结果和预期的为1的结果之间的交叉熵
self.d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits,tf.ones_like(self.D)))  
#d_loss_fake是生成器生成的图片输入到判别器中的结果和预期为0的结果之间的交叉熵
self.d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,tf.zeros_like(self.D_)))
#判别器的损失函数d_loss是d_loss_fake和d_loss_real之和
self.d_loss = self.d_loss_real + self.d_loss_fake

#生成器的损失函数d_loss是生成器生成的图片输入到判别器中的结果和预期为1的结果之间的交叉熵
self.g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,tf.ones_like(self.D_)))

3.收集变量

分别从每个模型中收集变量,让它们可以被分开训练。

t_vars = tf.trainable_variables()
self.d_vars = [var for var in t_vars if 'd_' in var.name]
self.g_vars = [var for var in t_vars if 'g_' in var.name]

4.定义优化器

现在我们准备好优化参数了,我们要用的是 ADAM (https://arxiv.org/abs/1412.6980),这是一种适应的非凸优化方法,通常用于现代深度学习中。ADAM 经常会与 SGD 竞争,而且通常不需要手动调节学习速率,动量,及其他超参数(hyper-parameter)。

d_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1) \
                  .minimize(self.d_loss, var_list=self.d_vars)
g_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1) \
                  .minimize(self.g_loss, var_list=self.g_vars)

这里优化器选择ADAM ,最终目标是要最小化d_loss和g_loss。

5.训练

我们准备好遍历数据了。在每一个时期,我们在一个小批图片中取样,运行优化器升级网络。有趣的是,如果 G 只更新了一次,鉴别器的损耗就不会为零。而且,我认为最后对 d_loss_fake 和 d_loss_real 函数的额外调用引发了一点不必要的计算,而且是多余的,因为这些值已经作为 d_optim 和 g_optim 的一部分计算过了。作为 TensorFlow 中的一项练习,你可以试着用这个部分去优化,并给原始 repo 发送一个 PR 。

for epoch in xrange(config.epoch):
    ...
    for idx in xrange(0, batch_idxs):
        batch_images = ...
        batch_z = np.random.uniform(-1, 1, [config.batch_size, self.z_dim]).astype(np.float32)

        # Update D network
        #更新一个 D 网络
        _, summary_str = self.sess.run([d_optim, self.d_sum],
            feed_dict={ self.images: batch_images, self.z: batch_z })

        # Update G network
        #更新一个 G 网络
        _, summary_str = self.sess.run([g_optim, self.g_sum],
            feed_dict={ self.z: batch_z })

        # Run g_optim twice to make sure that d_loss does not go to zero*
        # (different from paper)
       #运行两次*g_optim 以确保 d_loss 不会变成0
       #(与论文里不一样)
        _, summary_str = self.sess.run([g_optim, self.g_sum],
            feed_dict={ self.z: batch_z })

        errD_fake = self.d_loss_fake.eval({self.z: batch_z})
        errD_real = self.d_loss_real.eval({self.images: batch_images})
        errG = self.g_loss.eval({self.z: batch_z})

这里 self.sess.run()函数是执行一个会话,第一个参数是图的输出节点,第二个参数图的输入节点。如

self.sess.run([d_optim, self.d_sum], feed_dict={ self.images: batch_images, self.z: batch_z }),

上面的会话会根据输出节点d_optim, self.d_sum在图中找到最初的输入节点。

d_optim———>d_loss——->D_logits, D_logits_。

其中D_logits的输入是self.images, D_logits_的输入是self.z。因此这里run的第二个参数应该为{self.images,self.z}。

但是self.images,self.z只是个用placeholder定义的占位符,因此需要指定实际的输入。所以,这里用feed_dict指定了个字典,key值为self.images的占位符对应的值为batch_images,即加载的真实图片数据。key值为self.z的占位符对应的值为batch_z,即噪音数据。

这里看一下self.images,self.z的定义,均是用placeholder生成的占位符。

self.images = tf.placeholder(tf.float32, [self.batch_size] + [self.output_size, self.output_size, self.c_dim],
                                name='real_images')

self.z = tf.placeholder(tf.float32, [None, self.z_dim],name='z') 

介绍tensorflow

张量(Tensor)

名字就是TensorFlow,直观来看,就是张量的流动。张量(tensor),即任意维度的数据,一维、二维、三维、四维等数据统称为张量。而张量的流动则是指保持计算节点不变,让数据进行流动。

这样的设计是针对连接式的机器学习算法,比如逻辑斯底回归,神经网络等。连接式的机器学习算法可以把算法表达成一张图,张量在图中从前到后走一遍就完成了前向运算;而残差从后往前走一遍,就完成了后向传播。

算子(operation)

在TF的实现中,机器学习算法被表达成图,图中的节点是算子(operation),节点会有0到多个输出,下图是TF实现的一些算子。

每个算子都会有属性,所有的属性都在建立图的时候被确定下来,比如,最常用的属性是为了支持多态,比如加法算子既能支持float32,又能支持int32计算。

边(edge)

TF的图中的边分为两种:

正常边,正常边上可以流动数据,即正常边就是tensor

特殊边,又称作控制依赖,(control dependencies)

  1. 没有数据从特殊边上流动,但是特殊边却可以控制节点之间的依赖关系,在特殊边的起始节点完成运算之前,特殊边的结束节点不会被执行。
  2. 也不仅仅非得有依赖关系才可以用特殊边,还可以有其他用法,比如为了控制内存的时候,可以让两个实际上并没有前后依赖关系的运算分开执行。
  3. 特殊边可以在client端被直接使用

会话(Session)

客户端使用会话来和TF系统交互,一般的模式是,建立会话,此时会生成一张空图;在会话中添加节点和边,形成一张图,然后执行。

下图有一个TF的会话样例和所对应的图示。

这里写图片描述

这里写图片描述
变量(Variables)

机器学习算法都会有参数,而参数的状态是需要保存的。而参数是在图中有其固定的位置的,不能像普通数据那样正常流动。因而,TF中将Variables实现为一个特殊的算子,该算子会返回它所保存的可变tensor的句柄。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
DCGANs是一种生成对抗网络(GANs),其目的是生成逼真的图像。DCGANs的训练过程由以下步骤组成: 1. 数据预处理:将训练数据集进行预处理,使其符合GANs模型的输入要求。通常情况下,需要将图像进行缩放和归一化操作。 2. 生成器:生成器是GANs模型的一部分,其目的是生成逼真的图像。生成器接收一个随机噪声向量作为输入,并输出一张图像。生成器通常是由卷积神经网络(CNN)构成的,其输出的图像与训练数据集中的图像尽可能相似。 3. 判别器:判别器也是GANs模型的一部分,其目的是区分生成器生成的图像和训练数据集中的图像。判别器接收一张图像作为输入,并输出一个标量值,表示该图像来自于训练数据集还是生成器生成的。判别器通常也是由CNN构成的。 4. 损失函数:GANs模型的损失函数由两部分组成:生成器的损失和判别器的损失。生成器的损失通过计算生成器生成的图像与训练数据集中的图像之间的差异来构成。判别器的损失通过计算判别器在对生成器生成的图像和训练数据集中的图像进行分类时的误差来构成。 5. 训练过程:GANs模型的训练过程是一个迭代过程,每次迭代中,生成器生成一张图像,判别器对该图像进行分类,并计算相应的损失。根据损失值,使用反向传播算法更新生成器和判别器的参数,使它们更好地完成任务。 6. 生成样本:训练完成后,可以使用生成器生成新的图像样本。生成器接收一个随机噪声向量作为输入,并输出一张图像,该图像与训练数据集中的图像尽可能相似。 总之,DCGANs的训练过程是一个通过生成器和判别器相互博弈,不断优化的过程,最终得到一个可以生成逼真图像的模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值