赞
踩
生成式对抗网络(GAN, Generative Adversarial Networks)是一种深度学习模型。主要包括两部分:生成模型和判别模型。也就是对应神经网络的生成器与判别器:
生成器与判别器互相对抗,不断调整参数。最终的目的是使判别网络无法判断生成网络的输出结果是否真实。
生成器G是一个生成图片的网络,它接收一个随机的噪声 z z z,通过这个噪声生成图片,生成的图片记做 G ( z ) G(z) G(z)。
判别器D判别一张图片是不是“真实的”。它的输入是 x x x , x x x代表一张图片(其中, x x x包含生成图片和真实图片,对于生成图片有 x = G ( z ) x=G(z) x=G(z)),输出 D ( x ) D(x) D(x)代表 x x x为真实图片的概率,如果为1,就代表100%是真实的图片,而输出为0,就代表图片0%是真的(或者说100%是假的)
其中网络结构如下所示:
其中,真实数据分布中的数据与生成数据可以认为是相同形状的。
生成网络从隐空间(latent space)中随机采样作为输入,其输出结果需要尽量模仿训练集中的真实样本。
对抗网络也可称判别网络,判别网络的输入则为真实样本或生成网络的输出,其目的是将生成网络的输出从真实样本中尽可能分辨出来。
真实数据分布中的数据 x x x 服从分布 x ∼ P d a t a ( x ) x \sim P_{data} (x) x∼Pdata(x),生成数据分布中的数据 x x x 服从分布 x ∼ P G ( x ; θ ) x \sim P_{G} (x;\theta) x∼PG(x;θ)
那么衡量两个分布之间的差异性指标有:KL散度,JS散度,交叉熵和Wasserstein距离。
离散概率分布的KL散度计算公式:
K
L
(
p
∥
q
)
=
∑
p
(
x
)
log
p
(
x
)
q
(
x
)
K L(p \| q)=\sum p(x) \log \frac{p(x)}{q(x)}
KL(p∥q)=∑p(x)logq(x)p(x)
连续概率分布的KL散度计算公式:
K
L
(
p
∥
q
)
=
∫
p
(
x
)
log
p
(
x
)
q
(
x
)
d
x
K L(p \| q)=\int p(x) \log \frac{p(x)}{q(x)} d x
KL(p∥q)=∫p(x)logq(x)p(x)dx
J S ( p ∥ q ) = 1 2 K L ( p ∥ p + q 2 ) + 1 2 K L ( q ∥ p + q 2 ) J S(p \| q)=\frac{1}{2} K L\left(p \| \frac{p+q}{2}\right)+\frac{1}{2} K L\left(q \| \frac{p+q}{2}\right) JS(p∥q)=21KL(p∥2p+q)+21KL(q∥2p+q)
以分布的角度来看GAN网络结构,然后考虑其损失函数。
对于生成网络G,其输入的 z z z ( z ∼ N ( 0 , I ) \mathbf{z} \sim \mathcal{N}(\mathbf{0}, \mathbf{I}) z∼N(0,I),表示 z z z 服从正态分布的数据),通过训练出来的参数 θ \theta θ 的生成网络生成的图片为 G ( z , θ ) G(\mathbf{z},\theta) G(z,θ) 。
对于判别网络,可以认为是二分类问题,一类是生成网络的输出,即 x g e n e r a t i v e = G ( z , θ ) x_{generative} = G(\mathbf{z},\theta) xgenerative=G(z,θ);另一类是真实数据 x r e a l x_{real} xreal,(其中, x r e a l ∼ D r e a l x_{real} \sim D_{real} xreal∼Dreal ,表示 x r e a l x_{real} xreal 服从一种真实的分布distribution)。将 x x x (其中, x = x g e n e r a t i v e ∪ x r e a l x = x_{generative} \cup x_{real} x=xgenerative∪xreal) 数据输入到判别网络中,输出结果分别为:
分别从生成网络和判别网络的角度来看:
对于生成网络的标准就是:我希望我生成的图片越接近真实越好,那么也就是使
D
(
x
g
e
n
e
r
a
t
i
v
e
,
ϕ
)
=
D
(
G
(
z
,
θ
)
,
ϕ
)
D(\mathbf{x_{generative}}, \phi) = D(G(\mathbf{z},\theta), \phi)
D(xgenerative,ϕ)=D(G(z,θ),ϕ) 越接近1越好。也就是训练生成网络中的参数
θ
\theta
θ 满足:
max
θ
(
E
z
∼
p
(
z
)
[
log
D
(
G
(
z
;
θ
)
;
ϕ
)
]
)
\max _{\theta}\left(\mathbb{E}_{z \sim p(z)}[\log D(G(\boldsymbol{z} ; \theta) ; \phi)]\right)
θmax(Ez∼p(z)[logD(G(z;θ);ϕ)])
对于判别网络的标准就是:我能够很好的区分哪些是真的,哪些是假的。也就是说能够很好的将真的和假的区分开来。也就是希望真实数据的输出 D ( x r e a l , ϕ ) D(\mathbf{x_{real}}, \phi) D(xreal,ϕ) 越趋近于1,而生成数据的输出 D ( x g e n e r a t i v e , ϕ ) = D ( G ( z , θ ) , ϕ ) D(\mathbf{x_{generative}}, \phi) = D(G(\mathbf{z},\theta), \phi) D(xgenerative,ϕ)=D(G(z,θ),ϕ) 越趋近于0。
将其看成二分类问题,二分类问题的损失函数可以使用交叉熵损失函数来表示,对于二分类,只有正样本(label=1)与负样本(label=0)。并且两者概率之和为1。对于一个输入 x x x,经过模型输出为 p ( x ) p(x) p(x)。y是真实的标签。于是单个样本的损失函数就是:
L O S S = − y ∗ l o g ( p ( x ) ) + ( 1 − y ) l o g ( 1 − p ( x ) ) LOSS = -y * log(p(x)) + (1-y)log(1-p(x)) LOSS=−y∗log(p(x))+(1−y)log(1−p(x))
如果是计算 N 个样本的平均损失函数,只要将 N 个 Loss 叠加起来再除以N就行:
L O S S = 1 N ∑ i = 1 N y ( i ) log ( p ( x ) ( i ) ) + ( 1 − y ( i ) ) log ( 1 − p ( x ) ( i ) ) LOSS=\frac{1}{N} \sum_{i=1}^{N} y^{(i)} \log ({p(x)}^{(i)})+\left(1-y^{(i)}\right) \log \left(1-{p(x)}^{(i)}\right) LOSS=N1i=1∑Ny(i)log(p(x)(i))+(1−y(i))log(1−p(x)(i))
对于
x
∼
p
d
a
t
a
(
x
)
x \sim p_{data}(x)
x∼pdata(x) 的输出
D
(
x
;
ϕ
)
D(x; \phi)
D(x;ϕ)是真实的,也就是标签为1,那么其单个样本损失函数就是:
L
O
S
S
=
−
1
∗
log
D
(
x
;
ϕ
)
+
(
1
−
1
)
(
1
−
log
D
(
x
;
ϕ
)
)
=
−
log
D
(
x
;
ϕ
)
LOSS = -1 * \log D(\boldsymbol{x} ; \phi) + (1-1)(1- \log D(\boldsymbol{x} ; \phi)) = - \log D(\boldsymbol{x} ; \phi)
LOSS=−1∗logD(x;ϕ)+(1−1)(1−logD(x;ϕ))=−logD(x;ϕ)
平均损失函数就是(其实就是求平均):
L
O
S
S
=
−
E
x
∼
p
d
a
t
a
(
x
)
[
log
D
(
x
;
ϕ
)
]
LOSS = - \mathbb{E}_{\boldsymbol{x} \sim p_{data}(\boldsymbol{x})}[\log D(\boldsymbol{x} ; \phi)]
LOSS=−Ex∼pdata(x)[logD(x;ϕ)]
那么对于
z
∼
p
(
z
)
z \sim p(z)
z∼p(z) 的输出
D
(
G
(
z
;
θ
)
;
ϕ
)
)
D(G(\boldsymbol{z} ; \theta) ; \phi))
D(G(z;θ);ϕ))是假的,也就是标签为0,那么其单个样本损失函数就是:
L
O
S
S
=
0
∗
D
(
G
(
z
;
θ
)
;
ϕ
)
)
+
(
1
−
0
)
(
1
−
D
(
G
(
z
;
θ
)
;
ϕ
)
)
)
=
1
−
D
(
G
(
z
;
θ
)
;
ϕ
)
)
LOSS = 0*D(G(\boldsymbol{z} ; \theta) ; \phi))+(1-0)(1-D(G(\boldsymbol{z} ; \theta) ; \phi))) = 1 - D(G(\boldsymbol{z} ; \theta) ; \phi))
LOSS=0∗D(G(z;θ);ϕ))+(1−0)(1−D(G(z;θ);ϕ)))=1−D(G(z;θ);ϕ))
平均损失函数就是:
L
O
S
S
=
−
E
z
∼
p
(
z
)
[
log
(
1
−
D
(
G
(
z
;
θ
)
;
ϕ
)
)
]
LOSS = - \mathbb{E}_{\boldsymbol{z} \sim p(\boldsymbol{z})}[\log (1-D(G(\boldsymbol{z} ; \theta) ; \phi))]
LOSS=−Ez∼p(z)[log(1−D(G(z;θ);ϕ))]
由于上面损失函数是负数,并且需要最小化损失函数,那么反过来的最大化损失函数就是:
max
ϕ
E
x
∼
p
d
a
t
a
(
x
)
[
log
D
(
x
;
ϕ
)
]
+
E
z
∼
p
(
z
)
[
log
(
1
−
D
(
G
(
z
;
θ
)
;
ϕ
)
)
]
\max _{\phi} \mathbb{E}_{\boldsymbol{x} \sim p_{data}(\boldsymbol{x})}[\log D(\boldsymbol{x} ; \phi)]+\mathbb{E}_{\boldsymbol{z} \sim p(\boldsymbol{z})}[\log (1-D(G(\boldsymbol{z} ; \theta) ; \phi))]
ϕmaxEx∼pdata(x)[logD(x;ϕ)]+Ez∼p(z)[log(1−D(G(z;θ);ϕ))]
在训练过程中,当G固定的时候,有:
E
z
∼
p
(
z
)
[
log
(
1
−
D
(
G
(
z
;
θ
)
;
ϕ
)
)
]
=
E
x
∼
p
g
(
x
)
[
log
(
1
−
D
(
x
;
ϕ
)
)
]
\mathbb{E}_{\boldsymbol{z} \sim p(\boldsymbol{z})}[\log (1-D(G(\boldsymbol{z} ; \theta) ; \phi))] = \mathbb{E}_{\boldsymbol{x} \sim p_{g} (\boldsymbol{x})}[\log (1-D(x; \phi))]
Ez∼p(z)[log(1−D(G(z;θ);ϕ))]=Ex∼pg(x)[log(1−D(x;ϕ))]
全局优化首先固定G,然后优化D(这种情况也就是生成数据的分布
x
∼
p
g
(
x
)
\boldsymbol{x} \sim p_{g} (\boldsymbol{x})
x∼pg(x) 与真实分布
x
∼
p
d
a
t
a
(
x
)
\boldsymbol{x} \sim p_{data} (\boldsymbol{x})
x∼pdata(x)已知),D的最佳情况为:(推导可以看GAN入门理解及公式推导 - 知乎 (zhihu.com))
D
G
∗
(
x
)
=
p
data
(
x
)
p
data
(
x
)
+
p
g
(
x
)
D_{G}^{*}(\boldsymbol{x})=\frac{p_{\text {data }}(\boldsymbol{x})}{p_{\text {data }}(\boldsymbol{x})+p_{g}(\boldsymbol{x})}
DG∗(x)=pdata (x)+pg(x)pdata (x)
将最佳的D代入目标loss函数,有:
=
−
2
log
2
+
2
D
J
S
(
P
data
∥
P
g
)
=-2 \log 2+2 D_{JS}\left(P_{\text {data }} \| P_{g}\right)
=−2log2+2DJS(Pdata ∥Pg)
也就是说,原始GAN的loss实际上等价于JS散度。
很多的GAN网络结构代码可以参考:PyTorch-GAN
其中一个网络结构如下:
在实验中,对应的形状如下所示:
- 高斯随机变量:
torch.Size([batch_size, 100])
- 生成的fake_image, 真实image:
torch.Size([batch_size, 3,64,64])
- 判别真假:
torch.Size([batch_size, 1])
代码如下:
生成网络代码
class Generator(nn.Module): def __init__(self): super(Generator, self).__init__() def block(in_feat, out_feat, normalize=True): layers = [nn.Linear(in_feat, out_feat)] if normalize: layers.append(nn.BatchNorm1d(out_feat, 0.8)) layers.append(nn.LeakyReLU(0.2, inplace=True)) return layers self.model = nn.Sequential( *block(opt.latent_dim, 128, normalize=False), *block(128, 256), *block(256, 512), *block(512, 1024), nn.Linear(1024, int(np.prod(img_shape))), nn.Tanh() ) def forward(self, z): img = self.model(z) img = img.view(img.shape[0], *img_shape) return img
对抗网络代码
class Discriminator(nn.Module):
def __init__(self):
super(Discriminator, self).__init__()
self.model = nn.Sequential(
nn.Linear(int(np.prod(img_shape)), 512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 1),
)
然后在Anime_Faces数据集中训练,获得的1000个epochs后生成的数据有:
感觉效果不太行,估计是网络结构的局限性。
参考论文:[1701.07875] Wasserstein GAN (arxiv.org)
在生成对抗网络中,当判断网络为最优时,生成网络的优化目标是最小化真实分布 p r ( x ) p_r (x) pr(x) 和模型分布 p θ ( x ) p_θ (x) pθ(x) 之间的JS散度。当两个分布相同时,JS散度为0,最优生成网络对应的损失为−2log2。但是使用JS散度来训练生成对抗网络的一个问题是当两个分布没有重叠时,它们之间的JS散度恒等于常数log2。对生成网络来说,目标函数关于参数的梯度为0。
在GAN的基础上加入了Wasserstein距离,Wasserstein距离用于衡量两个分布之间的距离。相比KL散度和JS散度的优势在于即使两个分布没有重叠或者重叠非常少,Wasserstein距离仍然能反映两个分布的远近。其数学公式如下:
W
p
(
q
1
,
q
2
)
=
(
inf
γ
(
x
,
y
)
∈
Γ
(
q
1
,
q
2
)
E
(
x
,
y
)
∼
γ
(
x
,
y
)
[
d
(
x
,
y
)
p
]
)
1
p
W_{p}\left(q_{1}, q_{2}\right)=\left(\inf _{\gamma(x, y) \in \Gamma\left(q_{1}, q_{2}\right)} \mathbb{E}_{(x, y) \sim \gamma(x, y)}\left[d(x, y)^{p}\right]\right)^{\frac{1}{p}}
Wp(q1,q2)=(γ(x,y)∈Γ(q1,q2)infE(x,y)∼γ(x,y)[d(x,y)p])p1
其中 ,
Γ
(
q
1
,
q
2
)
\Gamma\left(q_{1}, q_{2}\right)
Γ(q1,q2) 是边际分布为
q
1
,
q
2
q_{1}, q_{2}
q1,q2 的所有可能的联合分布集合,
d
(
x
,
y
)
\mathrm{d}(\mathrm{x}, \mathrm{y})
d(x,y) 为
x
\mathrm{x}
x 和
y
\mathrm{y}
y 的 距离, 比如
ℓ
p
\ell_{p}
ℓp 距离等,
E
\mathbb{E}
E 表示期望,
inf
\inf
inf表示下确界。
下确界
,如果是一个集合的下确界, 即表示小于或等于集合E
的所有其他元素的最大元素
, 这个数不一定
在集合E中。举例来说:
- i n f { 1 , 2 , 3 } = 1 inf\{1,2,3\} = 1 inf{1,2,3}=1; 也就是说集合 { 1 , 2 , 3 } \{1,2,3\} {1,2,3}的下确界为1
- i n f { x ∈ R , 0 < x < 1 } = 0 inf\{x \in \mathbb{R}, 0<x<1 \} = 0 inf{x∈R,0<x<1}=0 ;
- i n f { ( − 1 ) n + 1 / n : n = 1 , 2 , 3 , . . . } = − 1 inf\{(-1)^{n} + 1/n : n = 1, 2, 3,...\} = -1 inf{(−1)n+1/n:n=1,2,3,...}=−1;
当然,换一种角度解读:将两个分布看作是两个土堆,联合分布 γ ( x , y ) \gamma(x, y) γ(x,y) 看作是从土堆 q 1 q_1 q1 的位置 x x x 到土堆 q 2 q_2 q2 的位置 y y y 的搬运土的数量。Wasserstein距离可以理解为搬运土堆的最小工作量,也称为推土机距离(Earth-Mover’s Distance,EMD)
参考论文:[1704.00028] Improved Training of Wasserstein GANs (arxiv.org)
WGAN还是有问题:
WGAN-GP,核心只有一个:Gradient Penalty
Gradient Penalty:判别器相对于输入的梯度的二范数要约束在1附近,这样就能够保证Lipschitz连续。
# 计算Gradient Penalty def compute_gradient_penalty(D, real_samples, fake_samples): """Calculates the gradient penalty loss for WGAN GP""" # Random weight term for interpolation between real and fake samples alpha = Tensor(np.random.random((real_samples.size(0), 1, 1, 1))) # Get random interpolation between real and fake samples interpolates = (alpha * real_samples + ((1 - alpha) * fake_samples)).requires_grad_(True) d_interpolates = D(interpolates) fake = Variable(Tensor(real_samples.shape[0], 1).fill_(1.0), requires_grad=False) # Get gradient w.r.t. interpolates gradients = autograd.grad( outputs=d_interpolates, inputs=interpolates, grad_outputs=fake, create_graph=True, retain_graph=True, only_inputs=True, )[0] gradients = gradients.view(gradients.size(0), -1) gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean() return gradient_penalty
条件GAN,顾名思义就是根据条件针对性的生成数据。具体有AC-GAN。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。