Почему не работает пример TensorFlow при увеличении размера пакета?

Я посмотрел на пример Tensorflow MNIST для начинающих и обнаружил, что в этой части:

for i in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

изменение размера партии от 100 до значения выше 204 приводит к сближению модели. Он работает до 204, но при 205 и любом большем числе, которое я пробовал, точность будет < 10%. Это ошибка, что-то в алгоритме, что-то еще?

Это запускает их двоичную установку для OS X, похоже, версии 0.5.0.

4 ответа

Решение

Вы используете очень основную линейную модель в примере для начинающих?

Вот трюк для его отладки - наблюдайте кросс-энтропию при увеличении размера пакета (первая строка из примера, вторая я только что добавил):

cross_entropy = -tf.reduce_sum(y_*tf.log(y))
cross_entropy = tf.Print(cross_entropy, [cross_entropy], "CrossE")

При размере партии 204 вы увидите:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[92.37558]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[90.107414]

Но в 205 вы увидите последовательность, подобную этой, с самого начала:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[472.02966]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[475.11697]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1418.6655]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1546.3833]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1684.2932]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1420.02]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1796.0872]
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[nan]

Ack - появляется NaN. По сути, большой размер пакета создает такой огромный градиент, что ваша модель выходит из-под контроля - обновления, которые она применяет, слишком велики, и выходят за пределы направления, куда она должна идти, с огромным запасом.

На практике есть несколько способов исправить это. Вы можете снизить скорость обучения с 0,01 до, скажем, 0,005, что в результате дает конечную точность 0,92.

train_step = tf.train.GradientDescentOptimizer(0.005).minimize(cross_entropy)

Или вы можете использовать более сложный алгоритм оптимизации (Адам, Моментум и т. Д.), Который пытается сделать больше, чтобы выяснить направление градиента. Или вы можете использовать более сложную модель, которая имеет больше свободных параметров, чтобы распределить этот большой градиент.

@dga дал отличный ответ, но я хотел немного расширить.

Когда я написал учебник для начинающих, я реализовал функцию стоимости следующим образом:

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

Я написал это так, потому что это выглядит наиболее похожим на математическое определение кросс-энтропии. Но на самом деле может быть лучше сделать что-то вроде этого:

cross_entropy = -tf.reduce_mean (y_ * tf.log (y))

Почему может быть лучше использовать среднее вместо суммы? Что ж, если мы суммируем, то удвоение размера партии удваивает стоимость, а также удваивает величину градиента. Если мы не скорректируем нашу скорость обучения (или не используем алгоритм, который подстраивает ее для нас, как предложил @dga), наша тренировка взорвется! Но если мы используем среднее значение, то наша скорость обучения становится своего рода независимой от размера партии, что приятно.

Я бы посоветовал вам проверить Адама (tf.train.AdamOptimizer()). Часто более терпимо возиться с вещами, чем с SGD.

Nan происходит, когда 0*log(0) происходит:

заменить:

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

с:

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

@dga хорошо объяснил вам причину такого поведения (cross_entropy становится слишком большим) и, следовательно, алгоритм не сможет сходиться. Есть несколько способов исправить это. Он уже предложил снизить скорость обучения.

Градиентный спуск - самый основной алгоритм. Почти все остальные оптимизаторы будут работать правильно:

train_step = tf.train.AdagradOptimizer(0.01).minimize(cross_entropy)
train_step = tf.train.AdamOptimizer().minimize(cross_entropy)
train_step = tf.train.FtrlOptimizer(0.01).minimize(cross_entropy)
train_step = tf.train.RMSPropOptimizer(0.01, 0.1).minimize(cross_entropy)

Другой подход заключается в использовании https://www.tensorflow.org/api_docs/python/tf/nn/softmax_cross_entropy_with_logits, который обрабатывает нестабильности чисел.

Другие вопросы по тегам