赞
踩
GAN的初衷就是生成不存在于真实世界的数据
应用场景如下:
GAN有两个网络分别为:
G(Generator),生成器: 负责凭空捏造数据出来
接收一个随机的噪声z,通过这个噪声生成图片,记做G(z)。
D(Discriminator),判别器: 负责判断数据是不是真数据
判别一张图片是不是“真实的”。它的输入参数是x,x代表一张图片,输出D(x)代表x为真实图片的概率,如果为1,就代表100%是真实的图片,而输出为0,就代表不可能是真实的图片。
基本思路,生成网络G的目标就是尽量生成真实的图片去欺骗判别网络D,而判别网络D的目标就是尽量把G生成的图片和真实的图片分别开来。这样,G和D构成了一个动态的“博弈过程”:如下图,G根据一串随机数z就可以捏造一个“假图像”出来,用这些假图去欺骗D,D负责辨别这是真图还是假图,会给出一个score。比如,G生成了一张图,在D这里得分很高,那证明G是很成功的;如果D能有效区分真假图,则G的效果还不太好,需要调整参数。
生成模型与对抗模型是完全独立的两个模型,训练采用的大原则是单独交替迭代训练。
一、判别网络训练过程:
二、生成网络训练过程:
三、在生成网络训练完后,可以根据用新的生成网络对先前的噪声Z生成新的假样本了,不出意外,这次生成的假样本会更真实。
四、有了新的真假样本集(其实是新的假样本集),就又可以重复上述过程了。
五、整个过程就叫单独交替训练。可以定义一个迭代次数,交替迭代到一定次数后停止即可。不出意外,这时噪声Z生成的假样本就会很真实了。
整个过程体现了生成网络和判别网络的博弈过程。
GAN设计的巧妙处之一,在于假样本在训练过程中的真假变换,这也是博弈得以进行的关键之处。
GAN的另一个强大之处在于可以自动定义潜在损失函数,即判别网络可以自动学习到一个好的判别方法(损失函数),来比较好或者不好的判别出来结果。
从真实数据分布中取样m个点,根据给定的参数 我们可以计算如下的概率 ,那么生成这m个样本数据的似然(likelihood)就是
L
=
∏
i
=
1
m
P
G
(
x
i
;
θ
)
L=\prod _{i=1}^mP_G(x^i;θ)
L=i=1∏mPG(xi;θ)
我们要做的就是找到
θ
∗
θ^∗
θ∗ 来最大化这个似然估计
θ
∗
=
a
r
g
max
θ
∏
i
=
1
m
p
G
(
x
i
;
θ
)
⇔
a
r
g
max
θ
l
o
g
∏
i
=
1
m
P
G
(
x
i
;
θ
)
θ^∗=arg\space \max_θ\prod_{i=1}^mp_G(x^i;θ)⇔arg\space \max_θlog\prod_{i=1}^mP_G(x^i;θ)
θ∗=arg θmaxi=1∏mpG(xi;θ)⇔arg θmaxlogi=1∏mPG(xi;θ)
= a r g max θ ∑ i m l o g P G ( x i ; θ ) =arg\space \max_θ\sum_i^mlogP_G(x^i;θ) =arg θmaxi∑mlogPG(xi;θ)
≈ a r g max θ E x ∼ P d a t a [ l o g P G ( x ; θ ) ] ≈arg \space \max_θE_{x∼P_{data}}[logP_G(x;θ)] ≈arg θmaxEx∼Pdata[logPG(x;θ)]
⇔ a r g max θ ∫ x P d a t a ( x ) l o g P G ( x ; θ ) d x − ∫ x P d a t a ( x ) l o g P d a t a ( x ) d x ⇔arg\space \max_θ∫_xP_{data}(x)logP_G(x;θ)dx−∫_xP_{data}(x)logP_{data}(x)dx ⇔arg θmax∫xPdata(x)logPG(x;θ)dx−∫xPdata(x)logPdata(x)dx
= a r g max θ ∫ x P d a t a ( x ) l o g P G ( x ; θ ) P d a t a ( x ) d x =arg\space \max_θ∫_xP_{data}(x)log\frac{P_G(x;θ)}{P_{data}(x)}dx =arg θmax∫xPdata(x)logPdata(x)PG(x;θ)dx
= a r g min θ K L ( P d a t a ( x ) ∣ ∣ P G ( x ; θ ) ) =arg\space \min_θKL(P_{data}(x)||PG(x;θ)) =arg θminKL(Pdata(x)∣∣PG(x;θ))
这里在前面添加一个负号,将log里面的分数倒一下,就变成了KL散度(KL divergence)或称相对熵
相对熵是两个随机分布间距离的度量。
P
G
(
x
)
=
∫
z
P
p
r
i
o
r
(
z
)
I
[
G
(
z
)
=
x
]
d
z
P_G(x)=∫_zP_{prior}(z)I_{[G(z)=x]}dz
PG(x)=∫zPprior(z)I[G(z)=x]dz
其 中 I G ( z ) = { 0 G ( z ) ≠ x 1 G ( z ) = x 表 示 示 性 函 数 其中I_{G(z)}=\begin {cases} 0 & G(z)≠x \\ 1 & G(z)=x \end {cases}表示示性函数 其中IG(z)={01G(z)=xG(z)=x表示示性函数
进一步地
G是生成器,给定先验分布 , 我们希望得到的生成分布是 ,这里很难通过极大似然估计得到结果;
D是一个函数,可以衡量差距,被用来取代极大似然估计;
定义函数V(G, D)如下:
V
(
D
,
G
)
=
E
x
∼
P
d
a
t
a
(
x
)
[
l
o
g
D
(
X
)
]
+
E
z
∼
P
z
(
z
)
[
l
o
g
(
1
−
D
(
G
(
z
)
)
)
]
V(D,G)=E_{x∼P_{data}(x)}[logD(X)]+E_{z∼P_{z}(z)}[log(1−D(G(z)))]
V(D,G)=Ex∼Pdata(x)[logD(X)]+Ez∼Pz(z)[log(1−D(G(z)))]
我们可以通过下面的式子求得最优的生成模型:
G
∗
=
a
r
g
min
G
max
D
V
(
D
,
G
)
=
E
x
∼
P
d
a
t
a
(
x
)
[
l
o
g
D
(
X
)
]
+
E
z
∼
P
z
(
z
)
[
l
o
g
(
1
−
D
(
G
(
z
)
)
)
]
G^∗=arg\space \min_G\max_DV(D,G) =E_{x∼P_{data}(x)}[logD(X)]+E_{z∼P_z(z)}[log(1−D(G(z)))]
G∗=arg GminDmaxV(D,G)=Ex∼Pdata(x)[logD(X)]+Ez∼Pz(z)[log(1−D(G(z)))]
这是一个最大最小优化问题,先优化D,然后再优化G,本质上是两个优化问题,拆解后得到下面两个公式:
优化D:
max
D
V
(
D
,
G
)
=
E
x
∼
p
d
a
t
a
(
x
)
[
l
o
g
(
D
(
x
)
)
]
+
E
z
∼
p
z
(
z
)
[
l
o
g
(
1
−
D
(
G
(
z
)
)
)
]
\max_{D}V(D,G)=E_{x∼p_{data}(x)}[log(D(x))]+E_{z∼p_z(z)}[log(1−D(G(z)))]
DmaxV(D,G)=Ex∼pdata(x)[log(D(x))]+Ez∼pz(z)[log(1−D(G(z)))]
优化G:
min
G
V
(
D
,
G
)
=
E
z
∼
p
z
(
z
)
[
l
o
g
(
1
−
D
(
G
(
z
)
)
)
]
\min_GV(D,G)=E_{z∼p_z(z)}[log(1−D(G(z)))]
GminV(D,G)=Ez∼pz(z)[log(1−D(G(z)))]
优化D(判别网络)时,不关生成网络的事,后面的G(z)相当于已经得到的假样本。优化D的公式的第一项,使的真样本x输入时,得到的结果越大越好,因为需要真样本的预测结果越接近于1越好。对于假样本,需要优化使其结果越小越好,也就是D(G(z))越小越好,因为它的标签为0。但是第一项越大,第二项就越小,这就矛盾了,所以把第二项改成1-D(G(z)),这样就是越大越好,两者合起来就是越大越好。
优化G(生成网络)时,不关真样本的事,所以把第一项直接去掉,只剩下假样本,这时希望假样本的标签是1,所以D(G(z))越大越好,但为了统一成1-D(G(z))的形式,就变成最小化1-D(G(z)),本质上没有区别,只是为了形式的统一。
这两个优化模型合并起来,就成了上面的最大最小目标函数了,里面既包含了判别模型的优化,同时也包含了生成模型的以假乱真的优化。
图像增强,将0-9的手写数字集,变得更清楚
程序思路:
1.加载MNIST数据:
手写数字图片,每一张都是0-9的单个数字,且每一张都是抗锯齿(Anti-aliasing)的灰度图。
2.判别网络:
判别器是一个卷积神经网络,接收图片大小为28×28×1的输入图像,之后返还一个单一标量值来描述输入图像的真伪——判断到底是来自MNIST图像集还是生成器。
它有两层特征为5×5像素特征的卷积层,还有两个全连接层按图像中每个像素计算增加权重的层。
创建了神经网络后,通常需要将权重和偏差初始化,这项任务可以在tf.get_variable中完成。权重在截断正态分布中被初始化,偏差在0处被初始化。
tf.nn.conv2d()是TensorFlow中的标准卷积函数,它包含四个参数:首个参数就是输入图像(input volume),也就是本示例中的28×28像素的图片;第二个参数是滤波器/权矩阵,最终你也可以改变卷积的“步幅”和“填充”。这两个参数控制着输出图像的尺寸大小。
# 定义判别网络 def discriminator(images, reuse_variables=None): with tf.variable_scope(tf.get_variable_scope(), reuse=reuse_variables) as scope: # 第一个卷积和池化层 # 生成32个不同的5 x 5特征 d_w1 = tf.get_variable('d_w1', [5, 5, 1, 32], initializer=tf.truncated_normal_initializer(stddev=0.02)) d_b1 = tf.get_variable('d_b1', [32], initializer=tf.constant_initializer(0)) d1 = tf.nn.conv2d(input=images, filter=d_w1, strides=[1, 1, 1, 1], padding='SAME') d1 = d1 + d_b1 d1 = tf.nn.relu(d1) # 平均池化,输出的每个条目为输入张量 中 ksize 大小的窗口所有值的平均值 d1 = tf.nn.avg_pool(d1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 第二个卷积和池化层 # 生成64个不同的5 x 5特征 d_w2 = tf.get_variable('d_w2', [5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=0.02)) d_b2 = tf.get_variable('d_b2', [64], initializer=tf.constant_initializer(0)) d2 = tf.nn.conv2d(input=d1, filter=d_w2, strides=[1, 1, 1, 1], padding='SAME') d2 = d2 + d_b2 d2 = tf.nn.relu(d2) d2 = tf.nn.avg_pool(d2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') # 第一个全连接层 d_w3 = tf.get_variable('d_w3', [7 * 7 * 64, 1024], initializer=tf.truncated_normal_initializer(stddev=0.02)) d_b3 = tf.get_variable('d_b3', [1024], initializer=tf.constant_initializer(0)) d3 = tf.reshape(d2, [-1, 7 * 7 * 64]) d3 = tf.matmul(d3, d_w3) d3 = d3 + d_b3 d3 = tf.nn.relu(d3) # 第二个全连接层 d_w4 = tf.get_variable('d_w4', [1024, 1], initializer=tf.truncated_normal_initializer(stddev=0.02)) d_b4 = tf.get_variable('d_b4', [1], initializer=tf.constant_initializer(0)) d4 = tf.matmul(d3, d_w4) + d_b4 return d4
3.生成网络
需要d维度向量,并需要将其变为28*28的图像。之后再ReLU和批量标准化用于稳定每一层的输出。
用了三个卷积层和插值,直到形成28*28像素的图像。
在输出层添加了一个tf.sigmoid() 激活函数,主要作用是将其挤压灰色呈现白色或黑色相,从而产生一个更清晰的图像。
# 定义生成网络 def generator(z, batch_size, z_dim): g_w1 = tf.get_variable('g_w1', [z_dim, 3136], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.02)) #从截断的正态分布中输出随机值,标准偏差0.02 g_b1 = tf.get_variable('g_b1', [3136], initializer=tf.truncated_normal_initializer(stddev=0.02)) g1 = tf.matmul(z, g_w1) + g_b1 g1 = tf.reshape(g1, [-1, 56, 56, 1]) g1 = tf.contrib.layers.batch_norm(g1, epsilon=1e-5, scope='g_b1') g1 = tf.nn.relu(g1) # Generate 50 features g_w2 = tf.get_variable('g_w2', [3, 3, 1, z_dim/2], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.02)) g_b2 = tf.get_variable('g_b2', [z_dim/2], initializer=tf.truncated_normal_initializer(stddev=0.02)) g2 = tf.nn.conv2d(g1, g_w2, strides=[1, 2, 2, 1], padding='SAME') g2 = g2 + g_b2 g2 = tf.contrib.layers.batch_norm(g2, epsilon=1e-5, scope='g_b2') # 批量标准化 g2 = tf.nn.relu(g2) g2 = tf.image.resize_images(g2, [56, 56]) # Generate 25 features g_w3 = tf.get_variable('g_w3', [3, 3, z_dim/2, z_dim/4], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.02)) g_b3 = tf.get_variable('g_b3', [z_dim/4], initializer=tf.truncated_normal_initializer(stddev=0.02)) g3 = tf.nn.conv2d(g2, g_w3, strides=[1, 2, 2, 1], padding='SAME') g3 = g3 + g_b3 g3 = tf.contrib.layers.batch_norm(g3, epsilon=1e-5, scope='g_b3') g3 = tf.nn.relu(g3) g3 = tf.image.resize_images(g3, [56, 56]) # Final convolution with one output channel g_w4 = tf.get_variable('g_w4', [1, 1, z_dim/4, 1], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.02)) g_b4 = tf.get_variable('g_b4', [1], initializer=tf.truncated_normal_initializer(stddev=0.02)) g4 = tf.nn.conv2d(g3, g_w4, strides=[1, 2, 2, 1], padding='SAME') g4 = g4 + g_b4 g4 = tf.sigmoid(g4) # Dimensions of g4: batch_size x 28 x 28 x 1 return g4
4.初始化
z_dimensions = 100 batch_size = 50 z_placeholder = tf.placeholder(tf.float32, [None, z_dimensions], name='z_placeholder') # z_placeholder is for feeding input noise to the generator x_placeholder = tf.placeholder(tf.float32, shape = [None,28,28,1], name='x_placeholder') # x_placeholder is for feeding input images to the discriminator Gz = generator(z_placeholder, batch_size, z_dimensions) # Gz holds the generated images Dx = discriminator(x_placeholder) # Dx will hold discriminator prediction probabilities # for the real MNIST images Dg = discriminator(Gz, reuse_variables=True) # Dg will hold discriminator prediction probabilities for generated images
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。