Як отримати відтворювані результати в керах


79

Я отримую різні результати (точність тесту) кожного разу, коли запускаю 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, версії модулів:
theano 0.7.0
numpy 1.8.1
scipy 0.14.0c1

UPDATE3: Я трохи звузив проблему. Якщо я запускаю приклад з графічним процесором (встановити theano flag device = gpu0), то я отримую різну точність тесту кожного разу, але якщо я запускаю його на центральному процесорі, тоді все працює, як очікувалося. Моя відеокарта: NVIDIA GeForce GT 635)


Я не можу повторити запуск коду на ubuntu 14.04
Падрайк Каннінгем,

theano -> 0.6.0, numpy -> '1.9.2',scipy -> '0.15.1'
Padraic Cunningham

Можливо, проблема в тому, що я використовую Windows. numpy.random.uniform чудово працює, завжди дає однакові результати.
Павло Сурменок

4
Код для графічного процесора повинен багато використовувати SIMDподібні інструкції. Це може призвести до виклику генератора випадкових випадкових порядків. Крім того, графічний процесор є досить автономним об'єктом, і він може використовувати власний генератор випадкових випадків. Зрештою, не тривіально запускати будь-який потрібний код на графічному процесорі.
u354356007

2
Яку версію CUDA ви використовували? Ви встановили cuDNN? Я вважаю, що останній приносить деякі жертви заради швидкості, що призводить до недетермінованої поведінки на GPU. (Мабуть невеликими, я думаю , що це має відношення до атомарним операціями розраховуються на backrprop, але ви не отримаєте таке ж значення , кожен раз.)
user2805751

Відповіді:


50

Відповідь можна знайти в документації 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 the `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED']=str(seed_value)

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

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

# 4. Set the `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.random.set_seed(seed_value)
# for later versions: 
# tf.compat.v1.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)
# for later versions:
# session_conf = tf.compat.v1.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
# sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph(), config=session_conf)
# tf.compat.v1.keras.backend.set_session(sess)

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


2
Для пізніших версій tensorflow, якщо ви стикаєтеся з помилкою, використовуйте tf.random.set_random_seed (seed_value)
Kalpit

13

Документація Теано розповідає про труднощі засівання випадкових величин і про те, чому вони породжують кожен екземпляр графа своїм власним генератором випадкових чисел.

Спільне використання генератора випадкових чисел між різними екземплярами {{{RandomOp}}} ускладнює створення одного і того ж потоку незалежно від інших операційних операцій у графіку та збереження {{{RandomOps}}} ізольованим. Тому кожен екземпляр {{{RandomOp}}} у графіку матиме власний генератор випадкових чисел. Цей генератор випадкових чисел є входом до функції. Зазвичай ми використовуємо нові функції входів функцій ({{{value}}}, {{{update}}}) для передачі та оновлення rng для кожного {{{RandomOp}}}. Передаючи RNG як вхідні дані, можна використовувати звичайні методи доступу до входів функцій для доступу до кожного {{{RandomOp}}}. У цьому підході не існує попередньо існуючого механізму роботи із комбінованим випадковим числом стану цілого графіка.

Вони також містять приклади того, як засіяти всі генератори випадкових чисел.

Ви також можете засіяти всі випадкові змінні, виділені об'єктом RandomStreams методом насіння цього об'єкта. Це насіння буде використано для зародження тимчасового генератора випадкових чисел, який, у свою чергу, генерує насіння для кожної із випадкових величин.

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

11
Але для того, щоб засіяти їх, нам потрібно мати доступ до випадкових об'єктів теано, які будуть використовувати кери. Чи можна це зробити через keras API?
більше

12

Нарешті я отримав відтворювані результати зі своїм кодом. Це поєднання відповідей, які я бачив в Інтернеті. Перше, що робить те, що каже @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%.


6

Тепер проблема вирішена в 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)

2

Я хотів би додати щось до попередніх відповідей. Якщо ви використовуєте python 3 і хочете отримати відтворювані результати для кожного запуску, вам доведеться

  1. встановіть numpy.random.seed на початку коду
  2. дайте PYTHONHASHSEED = 0 як параметр інтерпретатору python

2

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

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

Я отримую абсолютно однакові результати val_lossкожного разу, коли я тренуюсь і тестую на одних і тих же даних.


1
Ви користувались графічним процесором? Який сервер: Theano чи TensorFlow?
Павло Сурменок

Я використовував центральний процесор із серверною базою Theano.
tauseef_CuriousGuy

1
Зрозумів. Процесор прекрасно працює і для мене. У мене проблеми лише під час роботи на графічному процесорі.
Павло Сурменок

2

Це працює для мене:

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)

1

У 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)

0

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

  1. Докер . Якщо у вас Linux, дуже просто перенести своє середовище в інше місце. Також ви можете спробувати використовувати DockerHub .
  2. В'яжучий . Це хмарна платформа для відтворення наукових експериментів.
  3. Завжди . Це ще одна хмарна платформа для "багаторазової науки". Дивіться сховище проектів на Github.

Моя проблема полягає в тому, що я не можу отримати відтворювані результати навіть в одному середовищі, коли двічі проходжу тренінг.
Павло Сурменок

0

Доповідь на тему: Ініціалізація невипадкової ваги в мережах глибокого навчання для повторюваного детермінізму, дата публікації 5 червня 2019 р. , Великобританія, Ірландія та українська секція IEEE 5-7 червня 2019 р

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

показує, як отримати повторювані результати, застосовуючи критичні регіони коду.

він був розширений до журналу: Повторюваний детермінізм з використанням невипадкових ініціалізацій ваги у програмах Smart City від Deep Learning у спеціальному виданні "Журнал надійних інтелектуальних середовищ" у "Смарт-Сітіс", а також використовує кінцівки glorot xavier і досягає тієї ж точності з шари персептрона, але збільшують вагу до лінійного порядку, що може мати перевагу для вилучення правил у шарах персептрона.


0

Це легше, що здається. Поставивши лише це, це працює:

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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.