Как получить стабильные результаты с TensorFlow, установив случайное начальное число

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

filename = create_results_file()
for i in range(3):
  g = tf.Graph()
  with g.as_default():
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)
    f, w = get_csv_writer(filename)
    w.writerow([accuracy_result, "did run %d" % i, average_error])
    f.close()

Я использую следующий код в начале моей функции train_network перед настройкой уровней и функции ошибок в моей сети:

np.random.seed(1)
tf.set_random_seed(1)

Я также пытался добавить этот код до создания графа TensorFlow, но я продолжаю получать разные решения в выводе результатов.

Я использую AdamOptimizer и инициализирую вес сети, используя tf.truncated_normal, Кроме того, я использую np.random.permutation перетасовать входящие изображения для каждой эпохи.

8 ответов

Установка текущего случайного начального числа TensorFlow влияет только на текущий график по умолчанию. Так как вы создаете новый график для вашего обучения и устанавливаете его по умолчанию (with g.as_default():), вы должны установить случайное семя в рамках этого with блок.

Например, ваш цикл должен выглядеть следующим образом:

for i in range(3):
  g = tf.Graph()
  with g.as_default():
    tf.set_random_seed(1)
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)

Обратите внимание, что это будет использовать одно и то же случайное начальное число для каждой итерации внешнего for петля. Если вы хотите использовать разные - но все еще детерминированные - начальные числа в каждой итерации, вы можете использовать tf.set_random_seed(i + 1),

Настройка бэкэнда: cuda:10.1, cudnn: 7, tensorflow-gpu: 2.1.0, keras: 2.2.4-tf, и vgg19 индивидуальная модель

Изучив проблему нестабильных результатов для бэкэнда тензорного потока с обучением графического процессора и большими моделями нейронных сетей на основе keras, я наконец смог получить воспроизводимые (стабильные) результаты следующим образом:

  1. Импортируйте только те библиотеки, которые потребуются для установки начального числа и инициализации начального значения.
      import tensorflow as tf
import os
import numpy as np
import random

SEED = 0
  1. Функция инициализации начального числа для всех библиотек, которые могут иметь стохастическое поведение
      def set_seeds(seed=SEED):
    os.environ['PYTHONHASHSEED'] = str(seed)
    random.seed(seed)
    tf.random.set_seed(seed)
    np.random.seed(seed)
  1. Активировать Tensorflow детерминированное поведение
      def set_global_determinism(seed=SEED):
    set_seeds(seed=seed)

    os.environ['TF_DETERMINISTIC_OPS'] = '1'
    os.environ['TF_CUDNN_DETERMINISTIC'] = '1'
    
    tf.config.threading.set_inter_op_parallelism_threads(1)
    tf.config.threading.set_intra_op_parallelism_threads(1)

# Call the above function with seed value
set_global_determinism(seed=SEED)

Важные заметки:

  • Пожалуйста, вызовите приведенный выше код перед выполнением любого другого кода
  • Обучение модели может стать медленнее, поскольку код детерминирован, поэтому есть компромисс.
  • Я экспериментировал несколько раз с разным количеством эпох и разными настройками (включая model.fit () с shuffle = True), и приведенный выше код дает мне воспроизводимые результаты.

Рекомендации:

  1. https://suneeta-mall.github.io/2019/12/22/Reproducible-ml-tensorflow.html
  2. https://keras.io/getting_started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development
  3. https://www.tensorflow.org/api_docs/python/tf/config/threading/set_inter_op_parallelism_threads
  4. https://www.tensorflow.org/api_docs/python/tf/random/set_seed?version=nightly

Детерминированное поведение может быть получено либо путем предоставления начального уровня на уровне графов, либо на уровне операций. Оба работали на меня. Начальное число на уровне графа может быть размещено с помощью tf.set_random_seed. Начальное число уровня операции может быть помещено, например, в переменный инициализатор, как в:

myvar = tf.Variable(tf.truncated_normal(((10,10)), stddev=0.1, seed=0))

Ответ, совместимый с Tensorflow 2.0: для версии Tensorflow выше 2.0, если мы хотим установить Global Random Seed, используется командаtf.random.set_seed.

Если мы переходим с Tensorflow Version 1.x to 2.x, мы можем использовать команду, tf.compat.v2.random.set_seed.

Обратите внимание, что tf.function в этом случае действует как повторный запуск программы.

Чтобы установить начальное значение уровня операции (как указано выше), мы можем использовать команду, tf.random.uniform([1], seed=1).

Для получения дополнительной информации обратитесь к этой странице Tensorflow.

Пожалуйста, добавьте все функции случайного семени перед вашим кодом:

tf.reset_default_graph()
tf.random.set_seed(0)
random.seed(0)
np.random.seed(0)

Я думаю, что некоторые модели в TensorFlow используют numpy или случайную функцию python.

Кажется, что ни один из этих ответов не будет работать из-за основных проблем реализации в CuDNN.

Вы можете получить немного больше детерминизма, добавив дополнительный флаг

os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # new flag present in tf 2.0+
random.seed(SEED)
np.random.seed(SEED)
tf.set_random_seed(SEED)

Но это все равно не будет полностью детерминированным. Для того, чтобы получить еще более точное решение, необходимо использовать процедуру, описанную в этом NVidia репо.

Я использую TensorFlow 2 (2.2.0) и запускаю код в JupyterLab. Я тестировал это в macOS Catalina и в Google Colab с теми же результатами. Я добавлю кое-что в ответ службы поддержки Tensorflow.

Когда я тренируюсь с использованием метода model.fit(), я делаю это в ячейке. Я занимаюсь другими делами в других камерах. Это код, который я запускаю в указанной ячейке:

# To have same results always place this on top of the cell
tf.random.set_seed(1)

(x_train, y_train), (x_test, y_test) = load_data_onehot_grayscale()
model = get_mlp_model_compiled() # Creates the model, compiles it and returns it

history = model.fit(x=x_train, y=y_train,
                    epochs=30,
                    callbacks=get_mlp_model_callbacks(),
                    validation_split=.1,
                   )

Вот что я понимаю:

  1. В TensorFlow есть несколько случайных процессов, которые происходят на разных этапах (инициализация, перемешивание, ...), каждый раз, когда эти процессы происходят, TensorFlow использует случайную функцию. Когда вы устанавливаете семя, используяtf.random.set_seed(1) вы заставляете эти процессы использовать его, и если начальное значение установлено, а процессы не меняются, результаты будут такими же.
  2. Теперь, в приведенном выше коде, если я изменю tf.random.set_seed(1) идти ниже линии model = get_mlp_model_compiled() мои результаты меняются, я думаю, это потому, что get_mlp_model_compiled() использует случайность и не использует нужное мне семя.
  3. Предостережение по поводу пункта 2: если я запускаю ячейку 3 раза подряд, я получаю те же результаты. Я считаю, что это происходит потому, что в прогоне №1get_mlp_model_compiled()не использует внутренний счетчик TensorFlow с моим семенем. В прогоне №2 он будет использовать семя, и во всех последующих прогонах он будет также использовать семя, поэтому после прогона №2 результаты будут такими же.

У меня может быть какая-то информация неверна, поэтому не стесняйтесь поправлять меня.

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

Этот ответ является дополнением к ответу Люка и для TF v2.2.0

import numpy as np
import os
import random
import tensorflow as tf # 2.2.0

SEED = 42
os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # TF 2.1+
random.seed(SEED)
np.random.seed(SEED)
tf.random.set_seed(SEED)
Другие вопросы по тегам