Подтвердить что ты не робот

Tensorflow NaN ошибка?

Я использую TensorFlow, и я изменил пример tutorial, чтобы взять мои RGB-изображения.

Алгоритм работает безупречно из коробки на новом наборе изображений, пока внезапно (все еще сходится, обычно около 92% точности), он падает с ошибкой, что ReluGrad получил не конечные значения. Отладка показывает, что ничего необычного не происходит с числами до очень внезапного, по неизвестной причине, ошибки выдается. Добавление

print "max W vales: %g %g %g %g"%(tf.reduce_max(tf.abs(W_conv1)).eval(),tf.reduce_max(tf.abs(W_conv2)).eval(),tf.reduce_max(tf.abs(W_fc1)).eval(),tf.reduce_max(tf.abs(W_fc2)).eval())
print "max b vales: %g %g %g %g"%(tf.reduce_max(tf.abs(b_conv1)).eval(),tf.reduce_max(tf.abs(b_conv2)).eval(),tf.reduce_max(tf.abs(b_fc1)).eval(),tf.reduce_max(tf.abs(b_fc2)).eval())

в качестве кода отладки для каждого цикла, выводит следующий результат:

Step 8600
max W vales: 0.759422 0.295087 0.344725 0.583884
max b vales: 0.110509 0.111748 0.115327 0.124324
Step 8601
max W vales: 0.75947 0.295084 0.344723 0.583893
max b vales: 0.110516 0.111753 0.115322 0.124332
Step 8602
max W vales: 0.759521 0.295101 0.34472 0.5839
max b vales: 0.110521 0.111747 0.115312 0.124365
Step 8603
max W vales: -3.40282e+38 -3.40282e+38 -3.40282e+38 -3.40282e+38
max b vales: -3.40282e+38 -3.40282e+38 -3.40282e+38 -3.40282e+38

Поскольку ни одно из моих значений не очень велико, единственный способ, которым может быть NaN, - это плохо обработанная 0/0, но поскольку этот код учебника не выполняет никаких делений или подобных операций, я не вижу другого объяснения, кроме этого. это происходит из внутреннего кода TF.

Я не знаю, что с этим делать. Какие-либо предложения? Алгоритм сходится красиво, его точность на моем наборе проверки неуклонно поднималась и достигла 92,5% на итерации 8600.

4b9b3361

Ответ 1

Собственно, это оказалось чем-то глупо. Я отправляю это на случай, если кто-то другой столкнется с подобной ошибкой.

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))

на самом деле является ужасным способом вычисления кросс-энтропии. В некоторых примерах некоторые классы могут быть исключены с уверенностью через некоторое время, в результате чего y_conv = 0 для этого образца. Это обычно не проблема, так как вас это не интересует, но в том, как там написана cross_entropy, она дает 0 * log (0) для этого конкретного образца/класса. Следовательно, NaN.

Заменив его

cross_entropy = -tf.reduce_sum(y_*tf.log(tf.clip_by_value(y_conv,1e-10,1.0)))

решил все мои проблемы.

Ответ 2

Фактически, отсечение - это не очень хорошая идея, так как это предотвратит распространение градиента назад, когда достигнут порог. Вместо этого мы можем добавить немного константы к выходу softmax.

cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv + 1e-10))

Ответ 3

Альтернативная альтернатива.

Многие из других решений используют обрезку, чтобы избежать градиента undefined. В зависимости от вашей проблемы, отсечение вводит предвзятость и может быть неприемлемым во всех случаях. Как показывает следующий код, нам нужно только обрабатывать точку разрыва - не область рядом с ней.

Конкретный ответ

def cross_entropy(x, y, axis=-1):
  safe_y = tf.where(tf.equal(x, 0.), tf.ones_like(y), y)
  return -tf.reduce_sum(x * tf.log(safe_y), axis)

def entropy(x, axis=-1):
  return cross_entropy(x, x, axis)

Но это сработало?

x = tf.constant([0.1, 0.2, 0., 0.7])
e = entropy(x)
# ==> 0.80181855
g = tf.gradients(e, x)[0]
# ==> array([1.30258512,  0.60943794, 0., -0.64332503], dtype=float32)  Yay! No NaN.

(Примечание: удален dup cross-post.)

Общий рецепт

Используйте внутренний tf.where, чтобы функция не имела асимптоты. То есть, измените ввод на функцию генерации inf таким образом, чтобы никакой inf не мог быть создан. Затем используйте второй tf.where, чтобы всегда выбирать допустимый код-путь. То есть, реализуйте математическое условие так, как вы "обычно", то есть "наивную" реализацию.

В коде Python рецепт:

Вместо этого:

tf.where(x_ok, f(x), safe_f(x))

Сделайте это:

safe_x = tf.where(x_ok, x, safe_x)
tf.where(x_ok, f(safe_x), safe_f(x))

Пример

Предположим, что вы хотите вычислить:

f(x) = { 1/x, x!=0
       { 0,   x=0

Наивная реализация приводит к NaNs в градиенте, то есть

def f(x):
  x_ok = tf.not_equal(x, 0.)
  f = lambda x: 1. / x
  safe_f = tf.zeros_like
  return tf.where(x_ok, f(x), safe_f(x))

Работает ли он?

x = tf.constant([-1., 0, 1])
tf.gradients(f(x), x)[0].eval()
# ==> array([ -1.,  nan,  -1.], dtype=float32)
#  ...bah! We have a NaN at the asymptote despite not having
# an asymptote in the non-differentiated result.

Основной шаблон для избежания градиентов NaN при использовании tf.where состоит в том, чтобы дважды вызвать tf.where. Самый внутренний tf.where гарантирует, что результат f(x) всегда конечен. Самый внешний tf.where обеспечивает выбор правильного результата. Для примера выполнения трюк выглядит следующим образом:

def safe_f(x):
  x_ok = tf.not_equal(x, 0.)
  f = lambda x: 1. / x
  safe_f = tf.zeros_like
  safe_x = tf.where(x_ok, x, tf.ones_like(x))
  return tf.where(x_ok, f(safe_x), safe_f(x))

Но это сработало?

x = tf.constant([-1., 0, 1])
tf.gradients(safe_f(x), x)[0].eval()
# ==> array([-1.,  0., -1.], dtype=float32)
# ...yay! double-where trick worked. Notice that the gradient
# is now a constant at the asymptote (as opposed to being NaN).

Ответ 4

Если y_conv является результатом softmax, скажем, y_conv = tf.nn.softmax(x), то еще лучшим решением является замена его на log_softmax:

y = tf.nn.log_softmax(x)
cross_entropy = -tf.reduce_sum(y_*y)

Ответ 5

Иногда вы используете tf.sqrt() не добавляя в нее небольшую константу 1e-10, вызывая эту проблему с nan.

Ответ 6

Вы пытаетесь вычислить кросс-энтропию, используя стандартную формулу. Не только значение не определено при x=0, оно также численно неустойчиво.

Лучше использовать tf.nn.softmax_cross_entropy_with_logits или если вы действительно хотите использовать формулу, созданную вручную, до tf.clip_by_value нули до очень малого числа в журнале.

Ответ 7

Вот реализация бинарных (сигмовидных) и категориальных (softmax) потерь кросс-энтропии в TensorFlow 1.1:

Как можно видеть в двоичном случае, они рассматривают некоторые особые случаи для достижения численной устойчивости:

# The logistic loss formula from above is
#   x - x * z + log(1 + exp(-x))
# For x < 0, a more numerically stable formula is
#   -x * z + log(1 + exp(x))
# Note that these two expressions can be combined into the following:
#   max(x, 0) - x * z + log(1 + exp(-abs(x)))
# To allow computing gradients at zero, we define custom versions of max and
# abs functions.
zeros = array_ops.zeros_like(logits, dtype=logits.dtype)
cond = (logits >= zeros)
relu_logits = array_ops.where(cond, logits, zeros)
neg_abs_logits = array_ops.where(cond, -logits, logits)
return math_ops.add(relu_logits - logits * labels,
                    math_ops.log1p(math_ops.exp(neg_abs_logits)),
                    name=name)

Ответ 8

Я использовал LSTM для длинных последовательностей и получил наном градиенты. Ни один из этих ответов не помог мне. Но я придумал три собственных решения. Надеюсь, они будут полезны для других людей, которые пришли сюда из поиска Google.

  • Градиентная обрезка не помогла мне, потому что градиенты превратили nan в одно пакетное обновление. В этом случае вы можете заменить nans нулями такими строками:

    opt = tf.train.AdamOptimizer(args.lr)
    grads = opt.compute_gradients(loss)
    grads2 = [(tf.where(tf.is_nan(grad), tf.zeros(grad.shape), grad), var) for grad, var in grads]
    opt_op = opt.apply_gradients(grads2)
    

    Если вы хотите отслеживать появление nans, вы можете использовать этот код:

    was_nan = tf.reduce_any(tf.convert_to_tensor([tf.reduce_any(tf.is_nan(g)) for g in grads]))
    
  • Замените LSTMCell на LayerNormBasicLSTMCell - ячейку LSTM со стандартом уровня - что-то похожее на пакетную норму между timesteps.

  • Если вы используете регулярное повторное выпадение состояния, вы можете заменить его на "Повторное выпадение без потери памяти". Код:

    LayerNormBasicLSTMCell(neurons, dropout_keep_prob=0.8)
    

    Обратите внимание, что вы также можете включить функцию отсечки без нормализации уровня:

    LayerNormBasicLSTMCell(neurons, layer_norm=False, dropout_keep_prob=0.8)
    

Ответ 9

Помимо всех замечательных ответов выше, я добавлю свои. Это менее распространенный сценарий, но он вызывает NaN: деление на ноль.

В моей сети для задачи NLP есть уровень, который выполняет средний пул. А именно, каждая информация представляет собой последовательность токенов. Мой слой выполняет встраивание токенов, а затем вычисляет среднее значение для встроенного вектора.

Средний расчет кодируется как

tf.reduce_sum(embedded)/tf.reduce_sum(tf.not_equal(input, pad)) 

Здесь pad - это фиктивный токен, который я использую в пакетной обработке.

Теперь, если некоторые данные содержат пустой список токенов (по какой-либо причине), его длина (знаменатель в приведенном выше фрагменте кода) будет равна 0. Тогда это вызывает проблему деления на ноль, и NaN останется на всех следующих уровнях/этапах оптимизации.,

В случае, если кто-то столкнулся с этой проблемой, я использовал tf.where чтобы сгладить эту длину:

sum_embedding = tf.reduce_sum(embedded, 1)
embedding_length = tf.reduce_sum(tf.cast(tf.not_equal(input, pad), dtype=tf.float32), axis=1, keep_dims=True)
embedding_length_smoothed = tf.where(tf.greater(embedding_length, 0.0), embedding_length, tf.ones(tf.shape(embedding_length)))
avg_embedding = sum_embedding / embedding_length_smoothed

По сути, это обрабатывает все эти данные со списком токенов нулевой длины до длины 1 и позволяет избежать проблемы NaN.

Ответ 10

Иногда я получал nans, а не иногда, работая в стандартной сети прямой связи. Ранее я использовал аналогичный код TensorFlow, и он работал нормально.

Оказывается, я случайно импортировал имена переменных. Таким образом, как только в партии был выбран первый ряд (имена переменных), начались нанопотери. Может быть, следить за этим?

Ответ 11

Я добавлю сюда одну из моих предыдущих проблем с NaNs. Я использовал функцию сигмоида в качестве активации последнего уровня моей сети. Однако, функция активации сигмоида использует экспоненциальную функцию для вычисления, и я получил несколько действительно больших чисел, вводящих сигмоид.

Это привело к бесконечным градиентам, и некоторые NaN начали появляться.

Ответ 12

Я использовал Tensorflow Estimator, который, по моему мнению, учитывает это деление на ноль и другие проблемы числовой стабильности, и иногда получаю эту ошибку (ERROR:tensorflow:Model diverged with loss = NaN during training). Большую часть времени, когда я получаю это, потому что мои входные данные включают в себя nan с. Итак: убедитесь, что ваши входные фреймы данных (или что вы используете) не имеют значений NaN, скрытых где-то в них.