Вариационный автокодировщик дает отрицательную потерю.

Вопрос или проблема

Я изучаю вариационные автокодировщики и реализовал простой пример в keras, сводка модели ниже. Я скопировал функцию потерь из одного из блогов Франсуа Шолле и получаю действительно очень отрицательные значения потерь. Что я упустил здесь?

    Model: "model_1"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            [(None, 224)]        0
__________________________________________________________________________________________________
encoding_flatten (Flatten)      (None, 224)          0           input_1[0][0]
__________________________________________________________________________________________________
encoding_layer_2 (Dense)        (None, 256)          57600       encoding_flatten[0][0]
__________________________________________________________________________________________________
encoding_layer_3 (Dense)        (None, 128)          32896       encoding_layer_2[0][0]
__________________________________________________________________________________________________
encoding_layer_4 (Dense)        (None, 64)           8256        encoding_layer_3[0][0]
__________________________________________________________________________________________________
encoding_layer_5 (Dense)        (None, 32)           2080        encoding_layer_4[0][0]
__________________________________________________________________________________________________
encoding_layer_6 (Dense)        (None, 16)           528         encoding_layer_5[0][0]
__________________________________________________________________________________________________
encoder_mean (Dense)            (None, 16)           272         encoding_layer_6[0][0]
__________________________________________________________________________________________________
encoder_sigma (Dense)           (None, 16)           272         encoding_layer_6[0][0]
__________________________________________________________________________________________________
lambda (Lambda)                 (None, 16)           0           encoder_mean[0][0]
                                                                 encoder_sigma[0][0]
__________________________________________________________________________________________________
decoder_layer_1 (Dense)         (None, 16)           272         lambda[0][0]
__________________________________________________________________________________________________
decoder_layer_2 (Dense)         (None, 32)           544         decoder_layer_1[0][0]
__________________________________________________________________________________________________
decoder_layer_3 (Dense)         (None, 64)           2112        decoder_layer_2[0][0]
__________________________________________________________________________________________________
decoder_layer_4 (Dense)         (None, 128)          8320        decoder_layer_3[0][0]
__________________________________________________________________________________________________
decoder_layer_5 (Dense)         (None, 256)          33024       decoder_layer_4[0][0]
__________________________________________________________________________________________________
decoder_mean (Dense)            (None, 224)          57568       decoder_layer_5[0][0]
==================================================================================================
Всего параметров: 203,744
Обучаемые параметры: 203,744
Необучаемые параметры: 0
__________________________________________________________________________________________________
Обучение на 3974 образцах, валидация на 994 образцах
Эпоха 1/10
3974/3974 [==============================] - 3s 677us/sample - loss: -28.1519 - val_loss: -33.5864
Эпоха 2/10
3974/3974 [==============================] - 1s 346us/sample - loss: -137258.8175 - val_loss: -3683802.1489
Эпоха 3/10
3974/3974 [==============================] - 1s 344us/sample - loss: -14543022903.6056 - val_loss: -107811177469.9396
Эпоха 4/10
3974/3974 [==============================] - 1s 363us/sample - loss: -3011718676570.7012 - val_loss: -13131454938476.6816
Эпоха 5/10
3974/3974 [==============================] - 1s 350us/sample - loss: -101442605943572.4844 - val_loss: -322685056398605.9375
Эпоха 6/10
3974/3974 [==============================] - 1s 344us/sample - loss: -1417424385529640.5000 - val_loss: -3687688508198145.5000
Эпоха 7/10
3974/3974 [==============================] - 1s 358us/sample - loss: -11794297368126698.0000 - val_loss: -26632844827070784.0000
Эпоха 8/10
3974/3974 [==============================] - 1s 339us/sample - loss: -69508229806130784.0000 - val_loss: -141312065640756336.0000
Эпоха 9/10
3974/3974 [==============================] - 1s 345us/sample - loss: -319838384005810432.0000 - val_loss: -599553350073361152.0000
Эпоха 10/10
3974/3974 [==============================] - 1s 342us/sample - loss: -1221653451351326464.0000 - val_loss: -2147128507956525312.0000

Функция латентного образца:

def sampling(self,args):
    """Трюк репараметризации путем выборки из изотропного единичного гауссовского распределения.
    # Аргументы
        args (tensor): среднее значение и логарифм дисперсии Q(z|X)
    # Возвращает
        z (tensor): выбранный латентный вектор
    """

    z_mean, z_log_var = args
    set = tf.shape(z_mean)[0]
    batch = tf.shape(z_mean)[1]
    dim = tf.shape(z_mean)[-1]
    # по умолчанию, random_normal имеет среднее=0 и std=1.0
    epsilon = tf.random.normal(shape=(set, dim))#tfp.distributions.Normal(mean=tf.zeros(shape=(batch, dim)),loc=tf.ones(shape=(batch, dim)))
    return z_mean + (z_log_var * epsilon)

Функция потерь:

def vae_loss(self,input, x_decoded_mean):
    xent_loss = tf.reduce_mean(tf.keras.backend.binary_crossentropy(input, x_decoded_mean))
    kl_loss = -0.5 * tf.reduce_sum(tf.square(self.encoded_mean) + tf.square(self.encoded_sigma) - tf.math.log(tf.square(self.encoded_sigma)) - 1, -1)
    return xent_loss + kl_loss

Еще одна реализация vae_loss:

def vae_loss(self,input, x_decoded_mean):
    gen_loss = tf.reduce_sum(tf.keras.backend.binary_crossentropy(input, x_decoded_mean))
    #gen_loss = tf.losses.mean_squared_error(input,x_decoded_mean)
    kl_loss = -0.5 * tf.reduce_sum(1 + self.encoded_sigma - tf.square(self.encoded_mean) - tf.exp(self.encoded_sigma), -1)
    return tf.reduce_mean(gen_loss + kl_loss)

kl_loss log_sigma:

kl_loss = 0.5 * tf.reduce_sum(tf.square(self.encoded_mean) + tf.square(tf.exp(self.encoded_sigma)) - self.encoded_sigma - 1, axis=-1)

Ваши данные являются двоичными. Я думаю, что функция потерь binary_crossentropy подходит для двоичного ввода. Все данные в MNIST являются двоичными. Если ваш ввод непрерывный, как цветное изображение, попробуйте использовать MSE-потери или другие.
Проверьте это здесь https://github.com/Lasagne/Recipes/issues/54

Ответ или решение

Отрицательные потери в вариационных автокодировщиках: причины и решения

Ваша проблема с получением очень низких, а порою и отрицательных значений потерь в вариационных автокодировщиках (VAE) вызывает много вопросов. Разберем несколько ключевых моментов, касающихся реализации модели, функции потерь и самого подхода.

1. Входные данные и функция потерь

Первым делом следует обратить внимание на то, как подготовлены входные данные. Если ваши данные представляют собой бинарные значения, использование функции потерь binary_crossentropy вполне оправдано. Однако, если ваши данные являются непрерывными (например, изображения в цвете), рекомендуется использовать функцию потерь среднеквадратичной ошибки (MSE) или другие методы, учитывающие специфику ваших данных.

Пример реализации:

Если у вас изображения (например, RGB), можно заменить вызов binary_crossentropy на MSE:

xent_loss = tf.reduce_mean(tf.keras.losses.mean_squared_error(input, x_decoded_mean))

2. Влияние KL-дивергенции

Вы также используете KL-дивергенцию в качестве задающего элемента в функции потерь. Ваша реализация должна быть корректной. Однако убедитесь, что значения self.encoded_sigma не выходят за допустимые пределы. Если они становятся слишком большими в процессе обучения, это может приводить к числовым переполнениям и, как следствие, негативным значениям потерь.

Проверка нормализации:

Убедитесь, что ваша encoded_sigma правильно нормализуется. Переход к логарифмическому представлению может помочь избегать числовых нестабильностей:

kl_loss = -0.5 * tf.reduce_sum(1 + self.encoded_sigma - tf.square(self.encoded_mean) - tf.exp(self.encoded_sigma), axis=-1)

3. Адаптация функции выборки

Ваша функция sampling может также повлиять на формирование потерь. Следите за тем, чтобы z_log_var соответствовал логарифму дисперсии, а также убедитесь, что стандартные отклонения вычисляются корректно:

epsilon = tf.random.normal(shape=tf.shape(z_mean))  # достаточно использовать стандартное отклонение
return z_mean + tf.exp(0.5 * z_log_var) * epsilon

4. Устранение других потенциальных ошибок

Проверьте, что:

  • Ваши данные корректно нормализованы в диапазоне (0, 1) для binary_crossentropy.
  • Ваши веса и параметры модели не инициализированы таким образом, чтобы вызвать нестабильность.

Заключение

Получение отрицательных значений потерь в VAE может указывать на несколько потенциальных проблем, включая неправильную функцию потерь, неверную нормализацию данных или числовые переполнения. Рекомендуется анализировать каждую часть модели, тестируя изменения и отслеживая их влияние на обучение. Если вы примете во внимание описанные рекомендации, это поможет вам достичь стабильного обучения и более правдоподобных оценок потерь.

Оцените материал
Добавить комментарий

Капча загружается...