第六周:生成式对抗网络

第六周:生成式对抗网络
目录
  1. 视频总结
  2. 问题总结
  3. 代码练习
    • 3.1 GAN
    • 3.2 CGAN
    • 3.3 DCGAN
正文
  1. 视频总结

    • 生成式对抗网络主要是设置两个网络,其中一个是生成器,另外一个是判断器,对生成器生成的数据使用判断器进行检测,而后返回结果更新判断器,进而慢慢使得模型优化

    • GAN可以用于图像着色,图像超像素,背景模糊,人脸生成,文本生成图片,图像修复等

    • CGAN是进行条件限定的GAN,对输入的数据非但要求数据本身,而且要求数据的标签,当数据标签与数据本身不一致时,就算数据本身为真实的,也判断为错的,这样就可以对生成的数据进行控制

    • DCGAN主要是引进了卷积的结构对模型进行优化,在输入数据为图片的时候,可以得到令人满意的结果

    • 以下为GAN的目标函数

      \[\mathop{min}\limits_{G}\mathop{max}\limits_{D} V(G,D)= E_{x\sim p_{data}}[logD(x)]+E_{z\sim p_z}[log(1-D(G(z)))] \]

    • GAN的训练策略如下

    • KL散度主要是为了度量两个分布之间的差距,由于KL散度不具有对称性,所以引入了JS散度进行改进

      \[KL(P_1||P_2)=\mathbb{E}_{x\sim P_1}[log\frac{P_1}{P_2}] \\ for\ continuous,\ \ KL(P_1||P_2)==\int_xP_1(x)log\frac{P_1(x)}{P_2(x)}dx\\ for\ discrete,\ KL(P_1||P_2)=\sum_xP_1(x)log\frac{P_1(x)}{P_2(x)}dx\\ \\ JS(P_1||P_2)=\frac{1}{2}KL(P_1||\frac{P_1+P_2}{2})+\frac{1}{2}KL(P_2||\frac{P_1+P_2}{2}) \]

    • 极大似然估计实际上就是最小化KL散度的一种策略,他的思想为,既然抽样已经得到了样本,那么得到该样本观测值的概率应该是比较大的,进行多次抽样,做积式求极值得到参数

      \[\theta^*=\mathop{arg\ max}_\theta \prod_{i=1}^mP_G(x^i;\theta) \]

      接下来可以使用数理统计的方法进行推导

  2. 代码练习

    • 3.1 GAN

      • 示例代码中的网络结构是比较简单的

        生成器为

        net_G = nn.Sequential(
                    nn.Linear(z_dim,hidden_dim),
                    nn.ReLU(), 
                    nn.Linear(hidden_dim, 2))
        

        判别器为

        net_D = nn.Sequential(
                    nn.Linear(2,hidden_dim),
                    nn.ReLU(),
                    nn.Linear(hidden_dim,1),
                    nn.Sigmoid())
        

        其中

        z_dim = 32
        hidden_dim = 128
        
      • 对模型进行训练时 ,按照对抗生成式网络的训练策略,对两个模型逐次进行训练

        for e in range(nb_epochs):
        	#打乱训练数据的顺序
            np.random.shuffle(X)
            real_samples = torch.from_numpy(X).type(torch.FloatTensor)
            loss_G = 0
            loss_D = 0
            for t, real_batch in enumerate(real_samples.split(batch_size)):
                # 固定生成器G,改进判别器D
                # 使用normal_()函数生成一组随机噪声,输入G得到一组样本
                z = torch.empty(batch_size,z_dim).normal_().to(device)
                fake_batch = net_G(z)
                # 将真、假样本分别输入判别器,得到结果
                D_scores_on_real = net_D(real_batch.to(device))
                D_scores_on_fake = net_D(fake_batch)
                # 优化过程中,假样本的score会越来越小,真样本的score会越来越大,下面 loss 的定义刚好符合这一规律,
                # 要保证loss越来越小,真样本的score前面要加负号
                # 要保证loss越来越小,假样本的score前面是正号(负负得正)
                loss = -torch.mean(torch.log(1-D_scores_on_fake) + torch.log(D_scores_on_real))
                # 梯度清零
                optimizer_D.zero_grad()
                # 反向传播优化
                loss.backward()
                # 更新全部参数
                optimizer_D.step()
                loss_D += loss
                            
                # 固定判别器,改进生成器
                # 生成一组随机噪声,输入生成器得到一组假样本
                z = torch.empty(batch_size,z_dim).normal_().to(device)
                fake_batch = net_G(z)
                # 假样本输入判别器得到 score
                D_scores_on_fake = net_D(fake_batch)
                # 我们希望假样本能够骗过生成器,得到较高的分数,下面的 loss 定义也符合这一规律
                # 要保证 loss 越来越小,假样本的前面要加负号
                loss = -torch.mean(torch.log(D_scores_on_fake))
                optimizer_G.zero_grad()
                loss.backward()
                optimizer_G.step()
                loss_G += loss
        

        这里的学习率和batchsize大小对结果的影响很大

        可以看到在训练判别器的时候,牵扯到两组训练数据。分别用real和fake来表示,其中real是训练数据集中真实存在的数据,而fake则是利用生成器生成的数据,最终通过对损失函数的降低 ,使得生成器生成的结果以假乱真

    • 3.2 CGAN

      • CGAN主要是在根据标签生成结果方面对GAN进行了改进,当真实数据与标签不符时,虽然是真实的数据,但我们也将其作为错误来判断,叠加在损失函数中

      • 网络结构如下

        • 判别器

          self.model = nn.Sequential(
          			  nn.Linear(28*28+10, 512),
          			  nn.LeakyReLU(0.2, inplace=True),
          			  nn.Linear(512, 256),
          			  nn.LeakyReLU(0.2, inplace=True),
          			  nn.Linear(256, 1),
          			  nn.Sigmoid()
          		)
          
        • 生成器

          self.model = nn.Sequential(
          			  nn.Linear(z_dim+10, 128),
          			  nn.LeakyReLU(0.2, inplace=True),
          			  nn.Linear(128, 256),
          			  nn.BatchNorm1d(256, 0.8),
          			  nn.LeakyReLU(0.2, inplace=True),
          			  nn.Linear(256, 512),
          			  nn.BatchNorm1d(512, 0.8),
          			  nn.LeakyReLU(0.2, inplace=True),
          			  nn.Linear(in_features=512, out_features=28*28),
          			  nn.Tanh()
          	 	)
          
      • 训练过程为

        # 生成数据
        		# 用正态分布中采样batch_size个随机噪声
        		z = torch.randn([batch_size, z_dim]).to(device)
        		# 生成 batch_size 个 ont-hot 标签
        		c = torch.FloatTensor(batch_size, 10).zero_()
        		c = c.scatter_(dim=1, index=torch.LongTensor(np.random.choice(10, batch_size).reshape([batch_size, 1])), value=1)
        		c = c.to(device)
        		# 生成数据
        		fake_images = generator(z,c)
        
        		# 计算判别器损失,并优化判别器
        		real_loss = bce(discriminator(real_images, real_labels), ones)
        		fake_loss = bce(discriminator(fake_images.detach(), c), zeros)
        		d_loss = real_loss + fake_loss
        
        		d_optimizer.zero_grad()
        		d_loss.backward()
        		d_optimizer.step()
        
        		# 计算生成器损失,并优化生成器
        		g_loss = bce(discriminator(fake_images, c), ones)
        
        		g_optimizer.zero_grad()
        		g_loss.backward()
        		g_optimizer.step()
        

        可以看到与GAN的主要区别是在计算损失函数时考虑了labels

    • 3.3 DCGAN

      • DCGAN主要是针对图像输入 ,引入了滑动卷积操作以提高效率

      • 网络结构为

        • 判别器

          self.conv = nn.Sequential(
                      # 第一个滑动卷积层,不使用BN,LRelu激活函数
                      nn.Conv2d(in_channels=1, out_channels=16, 									kernel_size=3, stride=2, padding=1),
                      nn.LeakyReLU(0.2, inplace=True),
                      # 第二个滑动卷积层,包含BN,LRelu激活函数
                      nn.Conv2d(in_channels=16, out_channels=32, 									kernel_size=3, stride=2, padding=1),
                      nn.BatchNorm2d(32),
                      nn.LeakyReLU(0.2, inplace=True),
                      # 第三个滑动卷积层,包含BN,LRelu激活函数
                      nn.Conv2d(in_channels=32, out_channels=64, 									kernel_size=3, stride=2, padding=1),
                      nn.BatchNorm2d(64),
                      nn.LeakyReLU(0.2, inplace=True),
                      # 第四个滑动卷积层,包含BN,LRelu激活函数
                      nn.Conv2d(in_channels=64, out_channels=128, 								kernel_size=4, stride=1),
                      nn.BatchNorm2d(128),
                      nn.LeakyReLU(0.2, inplace=True)
                  )
          

          可以看到引入了卷积,而且除最后一个卷积外步长都为2,这与GAN和CGAN都不同。DCGAN可以增加效率

posted @ 2020-09-11 21:13  沙夜  阅读(212)  评论(0)    收藏  举报