Tensorflow NaN ошибка?

Я использую TensorFlow, и я изменил пример учебника, чтобы взять мои 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.

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

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

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

Заменяя его

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

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

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

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

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

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

Альтернатива без предубеждения.

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

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

 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. 

(Примечание: удаленная перекрестная запись ).

Общий рецепт

Используйте внутренний 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 в gradleиенте, т. Е.

 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. 

Основной шаблон для избежания gradleиентов 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). 

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

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

Ниже приведена реализация бинарных (сигмовидных) и категориальных (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) 

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

  1. Градиентная обрезка не помогла мне, потому что gradleиенты превратили 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])) 
  2. Замените LSTMCell на LayerNormBasicLSTMCell – ячейку LSTM со стандартом уровня – что-то похожее на пакетную норму между timesteps.

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

     LayerNormBasicLSTMCell(neurons, dropout_keep_prob=0.8) 

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

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

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

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

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

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

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

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

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

Теперь, если некоторые данные содержат пустой список токенов (по какой-либо причине), его длина (знаменатель в fragmentе кода выше) будет равна 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.

Interesting Posts

Формула Excel для отображения FORMULA

Правильный, идиоматический способ использования настраиваемых шаблонов редактора с моделями IEnumerable в ASP.NET MVC

Почему не может быть объявлено дублируемое имя переменной во вложенной локальной области?

Определение глобальной переменной для Browserify

Как я могу получить ячейку в Excel, чтобы автоматически регулировать ее высоту, чтобы она соответствовала содержимому завернутого текста?

PCIE для USB / Thunderbolt для видеокарты

ключевое слово delegate или lambda

Как вы скрываете Finder из списка приложений, когда Command-Tabbing?

java.sql.SQLException: Доступ запрещен для пользователя ‘root’ @ ‘localhost’ (с использованием пароля: YES)

Как я могу получить подсветку синтаксиса типа C #, который снова работает в VS 2012 RC?

Невозможно просмотреть историю браузера в IE9

R tm заблокировать недопустимый ввод в ‘utf8towcs’

Объективный-C-asynchronous веб-запрос с файлами cookie

Реализации Emoji (Emoticon) View / Keyboard Layouts

Как обрезать изображение с помощью imagemagick из командной строки?

Давайте будем гением компьютера.