李宏毅2022机器学习HW6解析

准备工作

作业六是使用GAN生成动漫人物脸,需要准备助教代码,运行代码过程中保持联网可以自动下载数据集,已经有数据集的情况可关闭助教代码中的下载数据部分。关注微信公众号,可获得代码、数据集和答案(文末有方法)。

提交地址

这次作业在NTU上面提交,没在册的学生可能提交不了,关于作业有想讨论的可进QQ群:156013866。

Simple Baseline (score>14.58)

方法:直接运行助教代码。

Medium Baseline (score>18.04)

方法:修改n_epoch+n_critic。运行更多的epoch,在config中设置epoch=50。每更新一次generator,更新两次discriminator,即设置n_critic=2。

运行后发现生成的图片先逐渐变好平稳,直到epoch 27后开始突然变坏,看不出人形。原因是loss_G在第27epoch后突然增大,loss_D接近于0,这说明后续的训练discriminator相对generator表现的太好,这与GAN的训练背道而驰,GAN训练最好的结果是loss_G小,loss_D大,也就是discriminator无法分辨generator的结果。第23epoch表现相对较好,如下图所示,不过还是有很多瑕疵,特别是眼睛大小不一。

config = {
   
       ......    "n_epoch": 50,    "n_critic": 2,    ......     }

Strong Baseline (score>25.20)

这里使用了两种方法,WGAN weight clipping和WGAN-GP。

方法一:WGAN weight clipping修改discriminator+RMSprop optimizer+loss函数+weight clipping+train longer。因为WGAN的思路是将discriminator训练为距离函数,所以discriminator不需要最后的非线性sigmoid层,需要将其从原始代码中删除。第二是WGAN weight clipping的optimizer,一般使用RMSprop效果较好。第三是将generator和discriminator中的loss函数改为距离。第四是做weight clipping操作,将助教代码中相应位置的注释去掉就好。第五需要在config中设置clip_value项,为了跟meidium baseline的DCGAN形成对比,设置n_epoch=50,n_cirtic=2。

 # 去掉discriminator最后一个sigmoid层,这里使用注释的方式。 # nn.Sigmoid()​​​​​​# 修改optimizer为RMSpropself.opt_D = torch.optim.RMSprop(self.D.parameters(), lr=self.config["lr"])self.opt_G = torch.optim.RMSprop(self.G.parameters(), lr=self.config["lr"])# 修改loss函数,loss_D, loss_Gloss_D = -torch.mean(r_logit) + torch.mean(f_logit)......loss_G = -torch.mean(self.D(f_imgs))# 参数更新后进行weight clipping操作,此操作需要config中添加clip_value项 for p in self.D.parameters():     p.data.clamp_(-self.config["clip_value"], self.config["clip_value"])# config 中添加clip_value项,同时n_epoch=50, n_critic=2config = {
   
       ......    "n_epoch": 50,    "n_critic": 2,    "clip_value": 1,    ......     }

运行后发现结果不是很稳定,某一个epoch的生成图看起来不错,下一个epoch就不行了,然后再下一个又好了,猜测是因为weight clipping的原因,参数更新不稳定。这里放一个相对较好的结果,第39个epoch的图片,相对DCGAN略好。

方法二:WGAN-GP修改discriminator+loss函数+gradient penalty+train longer。第一是WGAN-GP的discriminator仍然不需要最后的非线性sigmoid层,并且需要用nn.InstanceNorm2d层代替nn.BatchNorm2d层。第二需要将generator和discriminator中的loss函数改为距离,并且在训练generator的时候,loss函数加入graident penalty项。第三为了跟meidium baseline的DCGAN形成对比,设置n_epoch=50,n_cirtic=2。注意WGAN-GP的optimizer是Adam,而不是WGAN weight clipping使用的RMSprop。​​​​​​

# 去掉discriminator最后一个sigmoid层。# nn.Sigmoid()
# 使用nn.InstanceNorm2d层def conv_bn_lrelu(self, in_dim, out_dim):        return nn.Sequential(            nn.Conv2d(in_dim, out_dim, 4, 2, 1),            #nn.BatchNorm2d(out_dim),            nn.InstanceNorm2d(out_dim),            nn.LeakyReLU(0.2),        )

​​​​​​​# 写gp函数并添加进loss_D       def gp(self, r_imgs, f_imgs):        Tensor = torch.cuda.FloatTensor        alpha = Tensor(np.random.random((r_imgs.size(0), 1, 1, 1)))        interpolates = (alpha*r_imgs + (1 - alpha)*f_imgs).requires_grad_(True)        d_interpolates = self.D(interpolates)        fake = Variable(Tensor(r_imgs.shape[0]).fill_(1.0), requires_grad=False)        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(1, dim=1) - 1)**2).mean()        return gradient_penalty
# 修改loss函数,loss_D, loss_Ggradient_penalty = self.gp(r_imgs, f_imgs)loss_D = -torch.mean(r_logit) + torch.mean(f_logit) + gradient_penalty......loss_G = -torch.mean(self.D(f_imgs))​​​​​​​# n_epoch=50, n_critic=2config = {
   
       ......    "n_epoch": 50,    "n_critic": 2,    ......     }

运行后发现结果逐步变好趋于稳定,比DCGAN和WGAN-WC的各个epoch“过山车”一样出结果好太多了。这里放一个相对较好的结果,第43个epoch生成的图片。

Boss Baseline (acc>29.13)

方法:使用stylegan2库+kaggle平台。styelegan2的使用方法详情见 https://github.com/lucidrains/stylegan2-pytorch。具体的训练设置为: image_size=64,batch_size16, num-trian-steps=20000。最开始我先测试了下每个step需要的时间,接近2秒,而默认的train steps是150000,按默认跑的话时间太长了,经过粗略计算,我选择了train steps=20000,总训练时间接近10个小时。作业中的建议训练时间是5个小时,这对应的是train steps=10000,我们总的图片数目是7万多个,这意味着10000个step只能将整个图片集合跑2遍多一点,为了平衡时间和结果,我决定让train steps=20000,不过跑完程序后,发现其实10000个step的结果已经相当好,与20000个step相差不多。

stylegan2虽然对算力要求高,但是出来的图片确实很好,文章最开头的插值图就是训练完后生成的(方法见代码),模型最后生成的图片如下图所示,效果比前面几个模型好了很多。毕竟是显卡厂商英伟达出品,研究人员的GPU算力管饱。最近stylegan3也开源了,对算力的要求更高,该模型的研究人员在GPU集群上跑一遍模型需要的电量是核电站运行15分钟所产生的能量,大概225M瓦。​​​​​​​

# 安装stylegan2库!pip install stylegan2_pytorch#训练模型!stylegan2_pytorch --data faces --image-size 64 --batch-size 16 --num-train-steps=20000#训练结束后,利用模型生成图片,可选择使用哪个epoch的模型来生成!stylegan2_pytorch --generate --num_generate=4 --num_image_tiles=8#生成转换动画!stylegan2_pytorch --generate-interpolation --interpolation-num-steps 100

作业六答案获得方式:

  1. 关注微信公众号 “机器学习手艺人” 

  2. 后台回复关键词:202206

猜你喜欢

转载自blog.csdn.net/weixin_42369818/article/details/124222241