Детерминизм в обновлениях градиента тензорного потока?

Итак, у меня есть очень простой скрипт NN, написанный в Tensorflow, и мне трудно отследить, откуда исходит некоторая «случайность».

я записал

  • Вес,
  • градиенты,
  • Логиты

моей сети, когда я тренируюсь, и для первой итерации ясно, что все начинается одинаково. У меня есть значение SEED как для того, как данные считываются, так и значение SEED для инициализации весов сети. Те, кого я никогда не меняю.

Моя проблема в том, что, скажем, на второй итерации каждого повторного запуска, который я делаю, я начинаю видеть, что градиенты расходятся (на небольшую величину, например, 1e-6 или около того). Однако со временем это, конечно, приводит к неповторяемому поведению.

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

Спасибо


person Spacey    schedule 08.10.2016    source источник
comment
Вы используете графический процессор? Различные операции на графическом процессоре недетерминированы из-за использования атомарных вычислений CUDA (например, tf.reduce_sum).   -  person Yaroslav Bulatov    schedule 09.10.2016
comment
Также есть некоторые оптимизации SSE, которые приводят к недетерминированным результатам, вы можете попробовать скомпилировать TensorFlow без каких-либо оптимизаций, чтобы убедиться, что это так (подробности - blog.nag.com/2011/02/wandering-precision.html)   -  person Yaroslav Bulatov    schedule 09.10.2016
comment
Привет @YaroslavBulatov да, я действительно использую графический процессор.   -  person Spacey    schedule 09.10.2016
comment
@YaroslavBulatov Интересно об оптимизации ... а также о части GPU. Означает ли это, что мы всегда можем ожидать такого поведения, будь то CPU или GPU? Как же тогда мы можем получить действительно детерминированные результаты в TF?...   -  person Spacey    schedule 09.10.2016
comment
У меня аналогичная проблема, см.: stackoverflow.com/questions/42412660/   -  person Georg    schedule 23.02.2017


Ответы (3)


Есть большая вероятность, что вы сможете получить детерминированные результаты, если запустите свою сеть на ЦП (export CUDA_VISIBLE_DEVICES=), с одним потоком в собственном пуле потоков (tf.Session(config=tf.ConfigProto(intra_op_parallelism_threads=1)), с одним потоком Python (без многопоточных обработчиков очередей, которые вы получаете от таких операций, как tf.batch). ) и единый четко определенный порядок операций. Также использование inter_op_parallelism_threads=1 может помочь в некоторых сценариях.

Одна из проблем заключается в том, что сложение/умножение с плавающей запятой не является ассоциативным, поэтому один надежный способ получить детерминированные результаты — использовать целочисленную арифметику или квантованные значения.

За исключением этого, вы можете изолировать, какая операция является недетерминированной, и попытаться избежать использования этой операции. Например, есть tf.add_n op, который ничего не говорит о порядке суммирования значений, но разные порядки дают разные результаты.

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

person Yaroslav Bulatov    schedule 08.10.2016
comment
(1/2) Спасибо, Ярослав, пара вещей: 1) однако есть ли простой способ заставить TF просто использовать процессор? (Думаю, можно немного расширить (экспорт CUDA_VISIBLE_DEVICES=))? Должен ли я просто ввести это дословно в командной строке? 2) Что касается целых чисел/значений с плавающей запятой - вы говорите, что один эксперимент, который я могу провести, это изменить все мои параметры (и связанные значения), например, на tf.int16 вместо tf.float32, как сейчас, чтобы попробовать и получить воспроизводимость, поскольку целочисленная арифметика не будет страдать от тех же проблем с плавающей запятой, которые вы указали? - person Spacey; 09.10.2016
comment
(2/2) Что касается воспроизводимости, да, я хотел попытаться получить это из-за ошибки, до которой я пытаюсь докопаться. По сути, моя потеря (данных) взрывается до очень высоких значений (иногда даже NaN) по мере продолжения моего обучения. Однако это, по-видимому, происходит только тогда, когда потеря (данных) достигает чрезвычайно низких значений для начала. Иногда сеть восстанавливается, а иногда нет, так что это собственно и есть основная проблема. :-/ Странно то, что я использую все функции TF, а график даже представляет собой скелетонизированную версию (tensorflow.org/versions/r0.11/tutorials/deep_cnn/index.html). - person Spacey; 09.10.2016
comment
Взрыв потерь - обычное явление, и это свойство стохастического градиентного спуска. Распространенным решением является снижение скорости обучения и/или добавление регуляризации. - person Yaroslav Bulatov; 09.10.2016
comment
Странно то, что эта взрывоопасная потеря, кажется, происходит, когда сама потеря (данных) действительно близка к 0 (кстати, потеря softmax), и, похоже, это не происходит так сильно, когда потери нет. Это то, что вы имеете в виду? Наконец, есть ли какие-нибудь хорошие статьи, которые вы могли бы порекомендовать о том, почему существует это явление? Спасибо Ярослав! - person Spacey; 09.10.2016
comment
Может быть, где-то знаменатель стремится к нулю? IE, если вы выполняете логистическую регрессию, и ваши данные становятся идеально классифицированными, вы получите взрыв до бесконечности. Добавление регуляризации L2 для параметров исправляет это. - person Yaroslav Bulatov; 09.10.2016
comment
Это было мое подозрение, но дело в том, что я использую один из собственных примеров TF! (tensorflow.org/versions/r0.11/tutorials/deep_cnn/index.html), и я ничего не менял в их потерях и т. д. :-/ - person Spacey; 09.10.2016
comment
Ах! Ух ты! Хорошо, спасибо!! Я больше не чувствую себя таким сумасшедшим. :) - person Spacey; 09.10.2016

Известно, что операция тензорного потока reduce_sum недетерминирована. Кроме того, reduce_sum используется для вычисления градиентов смещения.

В этом сообщении обсуждается обходной путь, позволяющий избежать использования reduce_sum (т.е. взятие скалярного произведения любого вектора с вектором всех единиц совпадает с reduce_sum)

person DankMasterDan    schedule 13.03.2018

Я столкнулся с той же проблемой. Рабочее решение для меня было:

1- используйте tf.set_random_seed(1), чтобы все функции tf имели одно и то же семя при каждом новом запуске.

2- Обучение модели с использованием ЦП, а не графического процессора, чтобы избежать недетерминированных операций графического процессора из-за точности.

person Mohamed Atef    schedule 28.05.2018