VAE не учится, когда я меняю функции потерь при восстановлении F.bernoulli_nll на F.mean_squared_error в Chainer - PullRequest
0 голосов
/ 06 июня 2019

Я хочу использовать mean_squared_error вместо F.bernoulli_nll в качестве функции восстановления потери в моем VAE с использованием chainer5.0.0.

Я пользователь Chainer5.0.0.Я реализовал VAE (Variational Autoencoder).Я использовал ниже японские статьи для справки.

class VAE(chainer.Chain):

    def __init__(self, n_in, n_latent, n_h, act_func=F.tanh):
        super(VAE, self).__init__()
        self.act_func = act_func
        with self.init_scope():
            # encoder
            self.le1        = L.Linear(n_in, n_h)
            self.le2        = L.Linear(n_h,  n_h)
            self.le3_mu     = L.Linear(n_h,  n_latent)
            self.le3_ln_var = L.Linear(n_h,  n_latent)

            # decoder
            self.ld1 = L.Linear(n_latent, n_h)
            self.ld2 = L.Linear(n_h,      n_h)
            self.ld3 = L.Linear(n_h,      n_in)

    def __call__(self, x, sigmoid=True):
        return self.decode(self.encode(x)[0], sigmoid)

    def encode(self, x):
        h1 = self.act_func(self.le1(x))
        h2 = self.act_func(self.le2(h1))
        mu = self.le3_mu(h2)
        ln_var = self.le3_ln_var(h2) 
        return mu, ln_var

    def decode(self, z, sigmoid=True):
        h1 = self.act_func(self.ld1(z))
        h2 = self.act_func(self.ld2(h1))
        h3 = self.ld3(h2)
        if sigmoid:
            return F.sigmoid(h3)
        else:
            return h3

    def get_loss_func(self, C=1.0, k=1):
        def lf(x):
            mu, ln_var = self.encode(x)
            batchsize = len(mu.data)
            # reconstruction error
            rec_loss = 0
            for l in six.moves.range(k):
                z = F.gaussian(mu, ln_var)
                z.name = "z"
                rec_loss += F.bernoulli_nll(x, self.decode(z, sigmoid=False)) / (k * batchsize)
            self.rec_loss = rec_loss
            self.rec_loss.name = "reconstruction error"
            self.latent_loss = C * gaussian_kl_divergence(mu, ln_var) / batchsize
            self..name = "latent loss"
            self.loss = self.rec_loss + self.latent_loss
            self.loss.name = "loss"
            return self.loss
        return lf

Я использовал этот код, и мой VAE прошел обучение по наборам данных MNIST и Fashion-MNIST.Я проверил, чтобы мои VAE выводили похожие изображения для ввода изображений после тренировки.

rec_loss - это Reconstruct Loss, что означает, насколько далеко декодированные изображения от входного изображения.Я думаю, что мы можем использовать mean_squared_error вместо F.bernoulli_nll.

Поэтому я изменил свой код, как показано ниже.

rec_loss += F.mean_squared_error(x, self.decode(z)) / k

Но после изменения кода результат обучения выглядит странно.Выходные изображения одинаковы, что означает, что выходные изображения не зависят от входных изображений.

В чем проблема?

Я задал этот вопрос на японском языке (https://ja.stackoverflow.com/questions/55477/chainer%E3%81%A7vae%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%ABloss%E9%96%A2%E6%95%B0%E3%82%92bernoulli-nll%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8Fmse%E3%82%92%E4%BD%BF%E3%81%86%E3%81%A8%E5%AD%A6%E7%BF%92%E3%81%8C%E9%80%B2%E3%81%BE%E3%81%AA%E3%81%84). Но никто не ответил на него, поэтому я задаю этот вопрос здесь.

Решение?

Когда я заменяю

rec_loss += F.mean_squared_error(x, self.decode(z)) / k 

на

rec_loss += F.mean(F.sum((x - self.decode(z)) ** 2, axis=1))

, проблема была решена.

Но почему?

1 Ответ

0 голосов
/ 17 июня 2019

Они должны быть идентичны, за исключением того факта, что последний код, использующий F.mean(F.sum...., усредняет только по оси мини-пакета (поскольку он уже суммируется по измерению входных данных, 784 в случае сглаженного MNIST), тогда как первый усредняется поось минибата и размерность входных данных.Это означает, что последняя потеря, в случае сплющенного MNIST, в 784 раза больше?Я предполагаю, что k это 1.

...