巧断梯度:单个loss实现GAN模型

栏目: 数据库 · 发布时间: 6年前

内容简介:我们知道普通的模型都是搭好架构,然后定义好loss,直接扔给优化器训练就行了。但是GAN不一样,一般来说它涉及有两个不同的loss,这两个loss需要交替优化。现在主流的方案是判别器和生成器都按照1:1的次数交替训练(各训练一次,必要时可以给两者设置不同的学习率,即TTUR),交替优化就意味我们需要传入两次数据(从内存传到显存)、执行两次前向传播和反向传播。如果我们能把这两步合并起来,作为一步去优化,那么肯定能节省时间的,这也就是GAN的同步训练。(注:本文不是介绍新的GAN,而是介绍GAN的新写法,这只是

我们知道普通的模型都是搭好架构,然后定义好loss,直接扔给优化器训练就行了。但是GAN不一样,一般来说它涉及有两个不同的loss,这两个loss需要交替优化。现在主流的方案是判别器和生成器都按照1:1的次数交替训练(各训练一次,必要时可以给两者设置不同的学习率,即TTUR),交替优化就意味我们需要传入两次数据(从内存传到显存)、执行两次前向传播和反向传播。

如果我们能把这两步合并起来,作为一步去优化,那么肯定能节省时间的,这也就是GAN的同步训练。

(注:本文不是介绍新的GAN,而是介绍GAN的新写法,这只是一道编程题,不是一道算法题~)

如果是在tensorflow中,实现同步训练并不困难,因为我们定义好了判别器和生成器的训练算子了(假设为 D_solverG_solver ),那么直接执行

sess.run([D_solver, G_solver], feed_dict={x_in: x_train, z_in: z_train})

就行了。这建立在我们能分别获取判别器和生成器的参数、能直接操作 sess.run 的基础上。

但是如果是Keras呢?Keras中已经把流程封装好了,一般来说我们没法去操作得如此精细。所以,下面我们介绍一个通用的技巧,只需要定义单一一个loss,然后扔给优化器,就能够实现GAN的训练。同时,从这个技巧中,我们还可以学习到如何更加灵活地操作loss来控制梯度。

我们以GAN的hinge loss为例子,它的形式是:

\begin{equation}\begin{aligned}D =& \mathop{\arg\min}_D \mathbb{E}_{x\sim p(x)}\big[\max\big(0, 1 + D(x)\big)\big]+\mathbb{E}_{z\sim q(z)}\big[\max\big(0, 1 - D(G(z))\big)\big]\\

G =& \mathop{\arg\min}_G \mathbb{E}_{z\sim q(z)}\big[D(G(z))\big]

\end{aligned}\end{equation}

注意$\mathop{\arg\min}_D$意味着要固定$G$,因为$G$本身也是有优化参数的,不固定的话就应该是$\mathop{\arg\min}_{D,G}$。

为了固定$G$,除了“把$G$的参数从优化器中去掉”这个方法之外,我们也可以利用 stop_gradient 去手动固定:

\begin{equation}D,G = \mathop{\arg\min}_{D,G} \mathbb{E}_{x\sim p(x)}\big[\max\big(0, 1 + D(x)\big)\big]+\mathbb{E}_{z\sim q(z)}\big[\max\big(0, 1 - D(G_{ng}(z))\big)\big]\label{eq:dg-d}\end{equation}

这里

\begin{equation}G_{ng}(z)=\text{stop_gradient}(G(z))\end{equation}

这样一来,在式$\eqref{eq:dg-d}$中,我们虽然同时放开了$D,G$的权重,但是不断地优化式$\eqref{eq:dg-d}$,会变的只有$D$,而$G$是不会变的,因为我们用的是基于梯度下降的优化器,而$G$的梯度已经被停止了,换句话说,我们可以理解为$G$的梯度被强行设置为0,所以它的更新量一直都是0。

现在解决了$D$的优化,那么$G$呢? stop_gradient 可以很方便地放我们固定里边部分的梯度(比如$D(G(z))$的$G(z)$),但$G$的优化是要我们去固定外边的$D$,没有函数实现它。但不要灰心,我们可以用一个数学技巧进行转化。

首先,我们要清楚,我们想要$D(G(z))$里边的$G$的梯度,不想要$D$的梯度,如果直接对$D(G(z))$求梯度,那么同时会得到$D,G$的梯度。如果直接求$D(G_{ng}(z))$的梯度呢?只能得到$D$的梯度,因为$G$已经被停止了。那么,重点来了,将这两个相减,不就得到单纯的$G$的梯度了吗!

\begin{equation}D,G = \mathop{\arg\min}_{D,G} \mathbb{E}_{z\sim q(z)}\big[D(G(z)) - D(G_{ng}(z))\big]\label{eq:dg-g}\end{equation}

现在优化式$\eqref{eq:dg-g}$,那么$D$是不会变的,改变的是$G$。

值得一提的是,直接输出这个式子,结果是恒等于0,因为两部分都是一样的,直接相减自然是0,但它的梯度不是0。也就是说,这是一个恒等于0的loss,但是梯度却不恒等于0。

好了,现在式$\eqref{eq:dg-d}$和式$\eqref{eq:dg-g}$都同时放开了$D,G$,大家都是$\arg\min$,所以可以将两步合成一个loss:

\begin{equation}\begin{aligned}D,G = \mathop{\arg\min}_{D,G}&\,\mathbb{E}_{x\sim p(x)}\big[\max\big(0, 1 + D(x)\big)\big]+\mathbb{E}_{z\sim q(z)}\big[\max\big(0, 1 - D(G_{ng}(z))\big)\big]\\

&\, + \lambda\, \mathbb{E}_{z\sim q(z)}\big[D(G(z)) - D(G_{ng}(z))\big]\label{eq:dg-dg}\end{aligned}\end{equation}

写出这个loss,就可以同时完成判别器和生成器的优化了,而不需要交替训练,但是效果基本上等效于1:1的交替训练。引入$\lambda$的作用,相当于让判别器和生成器的学习率之比为$1:\lambda$。

参考代码: https://github.com/bojone/gan/blob/master/gan_one_step_with_hinge_loss.py

文章主要介绍了实现GAN的一个小技巧,允许我们只写单个模型、用单个loss就实现GAN的训练。它本质上就是用 stop_gradient 来手动控制梯度的技巧,在其他任务上也可能用得到它。

所以,以后我写GAN都用这种写法了,省力省时~

转载到请包括本文地址: https://kexue.fm/archives/6387

如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。

如果您觉得本文还不错,欢迎/本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Tagging

Tagging

Gene Smith / New Riders / 2007-12-27 / GBP 28.99

Tagging is fast becoming one of the primary ways people organize and manage digital information. Tagging complements traditional organizational tools like folders and search on users desktops as well ......一起来看看 《Tagging》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试