动手学深度学习Task10

生成式对抗网络(GAN)

给定一个数据 x x x,预测它的标签 y y y。之前我们用神经网络来建模 x x x y y y的映射,这种模型叫判别模型。但有时候,有些数据集是没有标签的。比如给定一些照片,照片中有狗,但并没有标注狗的标签。我们无法建立判别模型,但可以学习这个数据集的分布,然后生成一些很像是来自数据集的狗的照片,它符合数据集分布,这个就是生成式学习。从数学角度解释,判别模型就是建模 p ( y ∣ x ) p(y|x) p(yx),而生成式学习是建模 p ( x ) p(x) p(x)也就是学习 x x x的分布。

GAN网络组成:一个生成器,一个分类器。生成器用于生成接近于数据集的图像,分类器用来判别图像是生成器生成的,还是来源于真实数据集的。我们的目的是使生成器生成的图片能够尽量真,而分类器能够分类的尽量准,这样就形成了一种对抗模式。

接下来我们将生成器生成的图片称为fake图片。对于判别器(分类器)而言,损失函数为最小化交叉熵损失函数,真实图像的标签为1,fake图像的标签为0。 D ( x ) D(x) D(x)是经过sigmoid函数的预测概率。
min ⁡ D { − y log ⁡ D ( x ) − ( 1 − y ) log ⁡ ( 1 − D ( x ) ) } . \min_D \{ - y \log D(\mathbf x) - (1-y)\log(1-D(\mathbf x)) \}. Dmin{ylogD(x)(1y)log(1D(x))}.

对与生成器,先由高斯分布生成一组数据 z z z,生成器经过训练后,这组数据会接近真实数据集的分布,因此得到 G ( z ) G(z) G(z)。我们希望生成器生成的fake数据能够骗过分类器,也就是说,我们希望fake数据最后的预测概率 D ( G ( z ) ) D(G(z)) D(G(z))接近与1,而它的真实标签其实为0,因此我们希望最大化损失函数
max ⁡ G { − ( 1 − y ) log ⁡ ( 1 − D ( G ( z ) ) ) } = max ⁡ G { − log ⁡ ( 1 − D ( G ( z ) ) ) } . \max_G \{ - (1-y) \log(1-D(G(\mathbf z))) \} = \max_G \{ - \log(1-D(G(\mathbf z))) \}. Gmax{(1y)log(1D(G(z)))}=Gmax{log(1D(G(z)))}.

从上面这个式子可以看出,当 D ( G ( z ) ) D(G(z)) D(G(z))接近于0的时候,损失接近于0,这会使得梯度值变化很小,不利于生成器更新。因此,如果我们将fake数据的标签给定为1的话( y = 1 y=1 y=1),那么就是希望最小化下面的损失,也就是使得fake数据的标签接近于1:
min ⁡ G { − y log ⁡ ( D ( G ( z ) ) ) } = min ⁡ G { − log ⁡ ( D ( G ( z ) ) ) } , \min_G \{ - y \log(D(G(\mathbf z))) \} = \min_G \{ - \log(D(G(\mathbf z))) \}, Gmin{ylog(D(G(z)))}=Gmin{log(D(G(z)))},

生成器和分类器的损失函数可以合写为:
m i n D m a x G { − E x ∼ Data l o g D ( x ) − E z ∼ Noise l o g ( 1 − D ( G ( z ) ) ) } . min_D max_G \{ -E_{x \sim \text{Data}} log D(\mathbf x) - E_{z \sim \text{Noise}} log(1 - D(G(\mathbf z))) \}. minDmaxG{ExDatalogD(x)EzNoiselog(1D(G(z)))}.

def train(net_D,net_G,data_iter,num_epochs,lr_D,lr_G,latent_dim,data):
    loss=nn.BCELoss()
    Tensor=torch.FloatTensor
    trainer_D=torch.optim.Adam(net_D.parameters(),lr=lr_D)
    trainer_G=torch.optim.Adam(net_G.parameters(),lr=lr_G)
    plt.figure(figsize=(7,4))
    d_loss_point=[]
    g_loss_point=[]
    d_loss=0
    g_loss=0
    for epoch in range(1,num_epochs+1):
        d_loss_sum=0
        g_loss_sum=0
        batch=0
        for X in data_iter:
            batch+=1
            X=Variable(X)
            batch_size=X.shape[0]
            Z=Variable(Tensor(np.random.normal(0,1,(batch_size,latent_dim))))
            trainer_D.zero_grad()
            d_loss = update_D(X, Z, net_D, net_G, loss, trainer_D)
            d_loss_sum+=d_loss
            trainer_G.zero_grad()
            g_loss = update_G(Z, net_D, net_G, loss, trainer_G)
            g_loss_sum+=g_loss
        d_loss_point.append(d_loss_sum/batch)
        g_loss_point.append(g_loss_sum/batch)

从训练函数可以看出,判别器和生成器是交替更新的。

DCGAN

首先是预处理部分。ToTensor操作将像素值转换到 [ 0 , 1 ] [0,1] [0,1]之间,但是我们的生成器运用了tanh函数,输出在 [ − 1 , 1 ] [-1,1] [1,1]之间,因此我们需要先将数据归一化(均值0.5,方差0.5),这样就可以匹配了。

其次是转置卷积层的使用。因为输入的图像size很小,利用转置卷积层可以enlarge输入的尺寸。
默认的转置卷积层网络,kernel_size k h = k w = 4 k_h = k_w = 4 kh=kw=4,步长 s h = s w = 2 s_h = s_w = 2 sh=sw=2,填充 p h = p w = 1 p_h = p_w = 1 ph=pw=1。如果输入的图像尺寸为 n h ′ × n w ′ = 16 × 16 n_h^{'} \times n_w^{'} = 16 \times 16 nh×nw=16×16,那么输出的高和宽都会翻倍。
n h ′ × n w ′ = [ ( n h k h − ( n h − 1 ) ( k h − s h ) − 2 p h ] × [ ( n w k w − ( n w − 1 ) ( k w − s w ) − 2 p w ] = [ ( k h + s h ( n h − 1 ) − 2 p h ] × [ ( k w + s w ( n w − 1 ) − 2 p w ] = [ ( 4 + 2 × ( 16 − 1 ) − 2 × 1 ] × [ ( 4 + 2 × ( 16 − 1 ) − 2 × 1 ] = 32 × 32. \begin{aligned} n_h^{'} \times n_w^{'} &= [(n_h k_h - (n_h-1)(k_h-s_h)- 2p_h] \times [(n_w k_w - (n_w-1)(k_w-s_w)- 2p_w]\\ &= [(k_h + s_h (n_h-1)- 2p_h] \times [(k_w + s_w (n_w-1)- 2p_w]\\ &= [(4 + 2 \times (16-1)- 2 \times 1] \times [(4 + 2 \times (16-1)- 2 \times 1]\\ &= 32 \times 32 .\\ \end{aligned} nh×nw=[(nhkh(nh1)(khsh)2ph]×[(nwkw(nw1)(kwsw)2pw]=[(kh+sh(nh1)2ph]×[(kw+sw(nw1)2pw]=[(4+2×(161)2×1]×[(4+2×(161)2×1]=32×32.

我们可以通过设计kernel_size以及步长、填充来得到自己想要的输出尺寸。

最后介绍leaky ReLU。
leaky ReLU ( x ) = { x if  x > 0 α x otherwise . \textrm{leaky ReLU}(x) = \begin{cases}x & \text{if}\ x > 0\\ \alpha x &\text{otherwise}\end{cases}. leaky ReLU(x)={xαxif x>0otherwise.
leaky能够解决“dying ReLU”的现象。如果一个网络的输出总是负值,那么ReLU函数就无法更新参数,leaky ReLU防止了这一问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值