【问题标题】:Why VAE loss doesn’t converge to zero?为什么 VAE 损失不会收敛到零?
【发布时间】:2021-11-11 10:31:58
【问题描述】:

我正在使用变分自动编码器,这是我对损失函数的实现:

class VariationalAutoencoder(nn.Module):
    # ...some functions...

    def gaussian_likelihood(self, x_hat, logscale, x):
        scale = torch.exp(logscale)
        mean = x_hat
        dist = torch.distributions.Normal(mean, scale)
        # measure prob of seeing image under p(x|z)
        log_pxz = dist.log_prob(x)
        return log_pxz.sum(dim=(1, 2, 3))

    def forward(self, input):
        mu, logvar = self.encode(input)
        z = self.reparameterise(mu, logvar)
        return self.decoder(z), mu, logvar, z

    def loss_function(self, x_hat, x, mu, logvar, β=1):
        std = torch.exp(logvar / 2)
        q = torch.distributions.Normal(mu, std)
        z = q.rsample()

        # reconstruction loss
        recon_loss = self.gaussian_likelihood(x_hat, self.log_scale, x)

        # kl
        kl = self.kl_divergence(z, mu, std)

        # elbo
        elbo = (kl - recon_loss)
        elbo = elbo.mean()
        return elbo

    def kl_divergence(self, z, mu, std):
        # --------------------------
        # Monte carlo KL divergence
        # --------------------------
        # 1. define the first two probabilities (in this case Normal for both)
        p = torch.distributions.Normal(torch.zeros_like(mu), torch.ones_like(std))
        q = torch.distributions.Normal(mu, std)

        # 2. get the probabilities from the equation
        log_qzx = q.log_prob(z)
        log_pz = p.log_prob(z)

        # kl
        kl = (log_qzx - log_pz)
        kl = kl.sum(-1)

        return kl

我在退出解码器时使用 Sigmoid() 函数。我用这种方式训练模型:

for epoch in range(0, epochs + 1):
        if epoch > 0:  # test untrained net first
            model.train()
            train_loss = 0
            loop = tqdm(train_loader)
            optimizer = model.setOptimizer(model)
            for x in loop:
                x = x.to(device)
                x_hat, mu, logvar, features = model(x)
                loss = model.loss_function(x_hat, x, mu, logvar)
                train_loss += loss.item()
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                loop.set_postfix(loss=loss)
            train_loss = train_loss /= len(train_loader.dataset)
            print(f'====> Epoch: {epoch} Average loss: {train_loss:.4f}')

损失不是为零而是变成负数(大约-2)。如果我删除train_loss = train_loss /= len(train_loader.dataset),那就完全不同了。

如何让损失收敛到零?

【问题讨论】:

    标签: pytorch loss


    【解决方案1】:

    VAE 的损失可能是负数。它有一个对数似然——它可以是负数。这并没有错。

    【讨论】:

    • 除以数据集的长度是否正确?
    • 不确定它的用途,它甚至没有用于反向传播。你在loss 上做坏事,而不是在train_loss
    • 我已经看到这样做了,但我不确定这是正确的,因为我的损失实现不同。
    • 两目标问题肯定存在规模问题。有时您需要手动选择在两个目标之间进行权衡的加权因子。但我不认为len(dataset)elbo 上有.mean() 时特别有用。
    • 我认为将train_loss 除以数据集的长度会很有用,因为我将每个 for 循环的损失求和。否则,为最后一个 for 循环打印 loss 是否有意义?此外,最后打印math.exp(train_loss) 有意义吗?通过这种方式,我可以获得收敛为零的损失。
    猜你喜欢
    • 2020-01-08
    • 2017-02-08
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2020-11-27
    相关资源
    最近更新 更多