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

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

内容简介:我们知道普通的模型都是搭好架构,然后定义好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

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

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


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

查看所有标签

猜你喜欢:

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

Spring 3.x企业应用开发实战

Spring 3.x企业应用开发实战

陈雄华 / 电子工业出版社 / 2012-2-1 / 90.00元

内容简介 Spring 3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。 Spring 3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架、REST风格的Web编程模型等。这些新功能实用性强、易用性高,可大幅降低Java应用,特别是Java Web应用开发的难度,同时有效......一起来看看 《Spring 3.x企业应用开发实战》 这本书的介绍吧!

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

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具