Как получить воспроизводимые результаты в керасе

Я получаю разные результаты (точность теста) каждый раз, когда запускаю imdb_lstm.py пример из фреймворка Keras ( https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py) код содержит np.random.seed(1337) в верхней части, прежде чем импортировать любые керасы. Это должно препятствовать тому, чтобы это генерировало различные числа для каждого запуска. Что мне не хватает?

ОБНОВЛЕНИЕ: Как воспроизвести:

  1. Установите Keras ( http://keras.io/)
  2. Выполните https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py несколько раз. Он будет тренировать модель и тестировать точность результатов.
    Ожидаемый результат: Точность теста одинакова при каждом запуске.
    Фактический результат: Точность теста отличается при каждом запуске.

ОБНОВЛЕНИЕ 2: я запускаю его на Windows 8.1 с MinGW/msys, версиями модуля:
Теано 0.7.0
numpy 1.8.1
сципи 0.14.0c1

ОБНОВЛЕНИЕ 3: Я немного сузил проблему. Если я запускаю пример с графическим процессором (установите theano flag device=gpu0), то каждый раз получаю разную точность теста, но если я запускаю его на ЦП, все работает как положено. Моя видеокарта: NVIDIA GeForce GT 635)

12 ответов

Вы можете найти ответ в документах Keras: https://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development.

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

  1. Задавать PYTHONHASHSEED переменная окружения с фиксированным значением
  2. Задавать python встроенный псевдослучайный генератор с фиксированным значением
  3. Задавать numpy псевдослучайный генератор с фиксированным значением
  4. Задавать tensorflow псевдослучайный генератор с фиксированным значением
  5. Настроить новый глобальный tensorflow сессия

После Keras ссылка вверху, исходный код, который я использую, является следующим:

# Seed value
# Apparently you may use different seed values at each stage
seed_value= 0

# 1. Set `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED']=str(seed_value)

# 2. Set `python` built-in pseudo-random generator at a fixed value
import random
random.seed(seed_value)

# 3. Set `numpy` pseudo-random generator at a fixed value
import numpy as np
np.random.seed(seed_value)

# 4. Set `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.set_random_seed(seed_value)

# 5. Configure a new global `tensorflow` session
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)

Излишне говорить, что вам не нужно указывать какие-либо seed или же random_state на numpy, scikit-learn или же tensorflow/keras функции, которые вы используете в своем скрипте Python именно потому, что с исходным кодом выше мы устанавливаем для их псевдослучайных генераторов фиксированное значение.

В Tensorflow 2.0 вы можете установить случайное семя следующим образом:

import tensorflow as tf
tf.random.set_seed(221)


from tensorflow import keras
from tensorflow.keras import layers


model = keras.Sequential( [ 
layers.Dense(2,name = 'one'),
layers.Dense(3,activation = 'sigmoid', name = 'two'),
layers.Dense(2,name = 'three')])

x = tf.random.uniform((12,12))
model(x)

Документация Theano говорит о трудностях заполнения случайных величин и о том, почему они заполняют каждый экземпляр графа собственным генератором случайных чисел.

Совместное использование генератора случайных чисел между различными экземплярами {{{RandomOp}}} затрудняет создание одного и того же потока независимо от других операций в графе и сохранение {{{RandomOps}}} изолированным. Следовательно, каждый экземпляр {{{RandomOp}}} в графе будет иметь свой собственный генератор случайных чисел. Этот генератор случайных чисел является входом для функции. При обычном использовании мы будем использовать новые функции входов функций ({{{value}}}, {{{update}}}) для передачи и обновления rng для каждого {{{RandomOp}}}. Передавая RNG в качестве входных данных, можно использовать обычные методы доступа к входам функций для доступа к rng каждого {{{RandomOp}}}. В этом подходе отсутствует какой-либо ранее существующий механизм для работы с комбинированным состоянием случайных чисел всего графа. Поэтому предложение состоит в том, чтобы предоставить недостающую функциональность (последние три требования) с помощью вспомогательных функций: {{{seed, getstate, setstate}}}.

Они также предоставляют примеры того, как заполнить все генераторы случайных чисел.

Вы также можете заполнить все случайные величины, выделенные объектом RandomStreams, методом seed этого объекта. Это начальное число будет использоваться для создания временного генератора случайных чисел, который, в свою очередь, будет генерировать начальные значения для каждой из случайных величин.

>>> srng.seed(902340)  # seeds rv_u and rv_n with different seeds each

Я наконец получил воспроизводимые результаты с моим кодом. Это комбинация ответов, которые я видел в Интернете. Первое, что нужно сделать, что говорит @alex:

  1. Задавать numpy.random.seed;
  2. использование PYTHONHASHSEED=0 для Python 3.

Затем вы должны решить проблему, указанную @user2805751 в отношении cuDNN, позвонив по коду Keras с помощью следующих дополнительных THEANO_FLAGS:

  1. dnn.conv.algo_bwd_filter=deterministic,dnn.conv.algo_bwd_data=deterministic

И, наконец, вы должны исправить вашу установку Theano согласно этому комментарию, который в основном состоит из:

  1. заменить все звонки на *_dev20 Оператор по своей обычной версии в theano/sandbox/cuda/opt.py,

Это должно дать вам те же результаты для того же семени.

Обратите внимание, что может быть замедление. Я видел увеличение времени работы примерно на 10%.

Теперь проблема решена в Tensorflow 2.0! У меня была такая же проблема с TF 1.x (см. Если результаты Keras не воспроизводятся, как лучше всего сравнивать модели и выбирать гиперпараметры?), Но

import os
####*IMPORANT*: Have to do this line *before* importing tensorflow
os.environ['PYTHONHASHSEED']=str(1)

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers 
import random
import pandas as pd
import numpy as np

def reset_random_seeds():
   os.environ['PYTHONHASHSEED']=str(1)
   tf.random.set_seed(1)
   np.random.seed(1)
   random.seed(1)

#make some random data
reset_random_seeds()
NUM_ROWS = 1000
NUM_FEATURES = 10
random_data = np.random.normal(size=(NUM_ROWS, NUM_FEATURES))
df = pd.DataFrame(data=random_data, columns=['x_' + str(ii) for ii in range(NUM_FEATURES)])
y = df.sum(axis=1) + np.random.normal(size=(NUM_ROWS))

def run(x, y):
    reset_random_seeds()

    model = keras.Sequential([
            keras.layers.Dense(40, input_dim=df.shape[1], activation='relu'),
            keras.layers.Dense(20, activation='relu'),
            keras.layers.Dense(10, activation='relu'),
            keras.layers.Dense(1, activation='linear')
        ])
    NUM_EPOCHS = 500
    model.compile(optimizer='adam', loss='mean_squared_error')
    model.fit(x, y, epochs=NUM_EPOCHS, verbose=0)
    predictions = model.predict(x).flatten()
    loss = model.evaluate(x,  y) #This prints out the loss by side-effect

#With Tensorflow 2.0 this is now reproducible! 
run(df, y)
run(df, y)
run(df, y)

Это работает для меня:

SEED = 123456
import os
import random as rn
import numpy as np
from tensorflow import set_random_seed

os.environ['PYTHONHASHSEED']=str(SEED)
np.random.seed(SEED)
set_random_seed(SEED)
rn.seed(SEED)

Так проще, чем кажется. Ставлю только это, работает:

import numpy as np
import tensorflow as tf
import random as python_random

def reset_seeds():
   np.random.seed(123) 
   python_random.seed(123)
   tf.random.set_seed(1234)

reset_seeds() 

КЛЮЧ к вопросу, ОЧЕНЬ ВАЖНО, - вызывать функцию reset_seeds() каждый раз перед запуском модели. Таким образом вы получите воспроизводимые результаты, как я проверяю в Google Collab.

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

import numpy as np
seed = 7
np.random.seed(seed)

Я получаю точно такие же результаты val_loss Каждый раз я тренируюсь и проверяю одни и те же данные.

Я хотел бы добавить что-то к предыдущим ответам. Если вы используете Python 3 и хотите получать воспроизводимые результаты для каждого запуска, вам необходимо

  1. установите numpy.random.seed в начале вашего кода
  2. дать PYTHONHASHSEED=0 в качестве параметра для интерпретатора Python

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

  1. Докер Если у вас Linux, это очень легко перенести вашу среду в другое место. Также вы можете попробовать использовать DockerHub.
  2. Связующее. Это облачная платформа для воспроизведения научных экспериментов.
  3. Everware. Это еще одна облачная платформа для "многоразовой науки". Смотрите репозиторий проекта на Github.

В отличие от того, что было сказано ранее, только семя Tensorflow влияет на случайную генерацию весов (последняя версия Tensorflow 2.6.0 и Keras 2.6.0)

Here is a small test you can run to check the influence of each seed (with np being numpy, tf being tensorflow and random the Python random library):

      # Testing how seeds influence results
# -----------------------------------

print("Seed specification")

my_seed = 36
# To vary python hash, numpy random, python random and tensorflow random seeds
a, b, c, d = 0, 0, 0, 0

os.environ['PYTHONHASHSEED'] = str(my_seed+a) # Has no effect
np.random.seed(my_seed+b) # Has no effect
random.seed(my_seed+c) # Has no effect
tf.random.set_seed(my_seed+d) # Has an effect

print("Making ML model")

keras.mixed_precision.set_global_policy('float64')

model = keras.Sequential([
    layers.Dense(2, input_shape=input_shape),#, activation='relu'),
    layers.Dense(output_nb, activation=None),
    ])
#
weights_save = model.get_weights()

print("Some weights:", weights_save[0].flatten())

We notice that variables a, b, c have no effect on the results. Only d has an effect on the results.

So, in the latest versions of Tensorflow, only tensorflow random seed has an influence on the random choice of weights.

Документ конференции: Инициализация неслучайного веса в сетях глубокого обучения для повторяемого детерминизма, дата публикации 5 июня 2019 г., представленный на 10-й Международной конференции IEEE по надежным системам, сервисам и технологиям (DESSERT-19) в Университете Лидса Беккета (LBU), Великобритания, Великобритания, Ирландия и украинская секция IEEE 5-7 июня 2019 г.

https://ieeexplore.ieee.org/document/8770007

показывает, как получить повторяемые результаты, задействуя критические области кода.

он был расширен до Journal Paper: Repeatable Determinism using Non-random Weight Initialisations in Smart City Applications of Deep Learning публикации в специальном выпуске Journal of Reliable Intelligent Environments in Smart Cities, в котором используются ограничения glorot xavier и достигается та же точность с слои перцептрона, но увеличивают вес в линейном порядке, что может иметь преимущество при извлечении правил в слоях перцептрона.

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