Вопрос или проблема
Я изучаю вариационные автокодировщики и реализовал простой пример в 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 может указывать на несколько потенциальных проблем, включая неправильную функцию потерь, неверную нормализацию данных или числовые переполнения. Рекомендуется анализировать каждую часть модели, тестируя изменения и отслеживая их влияние на обучение. Если вы примете во внимание описанные рекомендации, это поможет вам достичь стабильного обучения и более правдоподобных оценок потерь.