再谈VAE

观代码之问题

def forward(self, x):
        mu, log_std = self.encode(x)
        z = self.reparametrize(mu, log_std)
        recon = self.decode(z)
        return recon, mu, log_std

    def loss_function(self, recon, x, mu, log_std) -> torch.Tensor:
        recon_loss = F.mse_loss(recon, x, reduction="sum")  # use "mean" may have a bad effect on gradients
        kl_loss = -0.5 * (1 + 2*log_std - mu.pow(2) - torch.exp(2*log_std))
        kl_loss = torch.sum(kl_loss)
        loss = recon_loss + kl_loss
        return loss

如果看其代码,所有的一切都很符合自然,只会问出两个问题。其一,为什么要设计两个网络分别输出 μ \mu μ σ 2 \sigma ^ 2 σ2,然后通过这两个参数经过重参数化来得到z。二是这个kl_loss是什么鬼。

解代码之问题

在经典的变分自编码器(一):原来是这么一回事一文中,作者强调市面上的错误是没有讲清楚 μ \mu μ σ \sigma σ是根据x的不同而不同的,我很怀疑作者究竟有没有看代码,对于这样的代码,输入不同的x得到不同的 μ \mu μ σ \sigma σ难道不是再自然不过的事情吗。至于loss计算中输入与输出是否对应起来更是无稽之谈。。每一次输入一个batch得到一个batch的重建图像,去计算loss难道还有不对应的可能吗。所以总感觉本文是乍一看好有道理,实际上讲的东西感觉信息量并不大。

我觉得里面的关键问题是,为什么要使用分布去输出z,而不是直接用神经网络去输出z(AE),个人理解是采样操作带来的多样性。众所周知,只有拥有一个分布才能进行随机的采样,如果像AE一样,在做生成任务时面临的第一个问题就是z从哪里来。VAE给出了答案,采样中来。那么采样从哪里采样,标准正态分布。我们什么时候把标准正态分布融入到网络中的?就在计算kl散度loss时,相当于把encoder输出的参数与标准正态分布逼近。至于是不是一定要标准正态分布,网上说什么的都有。

问题二是kl_loss的问题,这是一个推导出来的elbo损失中的一项,推导的动机是我们有一个明确的目的,但是稍微过于复杂,推来推去就成这样了,优化它会发生什么?那当然是会完成我们的动机。我们的动机是极大似然估计 p ( x ) p(x) p(x),那训练出来的网络当然可以很好的生成x。

猜你喜欢

转载自blog.csdn.net/xiufan1/article/details/128515067
VAE