Эквивалентны ли эти модели?

Главный вопрос: я определяю одну и ту же модель двумя разными способами. Почему я получаю разные результаты? Кажется, это одна и та же модель.

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

import numpy as np
np.random.seed(1)
from keras.models import Model, Sequential
from keras.layers import Input, Dense

model1= Sequential([
     Dense(20, activation='sigmoid',kernel_initializer='glorot_normal', 
               input_shape=(2,)),
     Dense(2,  activation='linear', kernel_initializer='glorot_normal'),
])

model1.compile(optimizer='adam', loss='mean_squared_error')

ipt    = Input(shape=(2,))
x      = Dense(20, activation='sigmoid', kernel_initializer='glorot_normal')(ipt)
out    = Dense(2,  activation='linear',  kernel_initializer='glorot_normal')(x)
model2 = Model(ipt, out)

model2.compile(optimizer='adam', loss='mean_squared_error')

x_train=np.array([[1,2],[3,4],[3,4]])

model1.fit(x_train, x_train,epochs=2, validation_split=0.1, shuffle=False)
model2.fit(x_train, x_train,epochs=2, validation_split=0.1, shuffle=False)

В первый раз вывод:

2/2 [==============================] - 0s 68ms/step - loss: 14.4394 - val_loss: 21.5747
Epoch 2/2

2/2 [==============================] - 0s 502us/step - loss: 14.3199 - val_loss: 21.4163
Train on 2 samples, validate on 1 samples
Epoch 1/2

2/2 [==============================] - 0s 72ms/step - loss: 11.0523 - val_loss: 17.7059
Epoch 2/2

2/2 [==============================] - 0s 491us/step - loss: 10.9833 - val_loss: 17.5785

Во второй раз вывод:

2/2 [==============================] - 0s 80ms/step - loss: 14.4394 - val_loss: 21.5747
Epoch 2/2

2/2 [==============================] - 0s 501us/step - loss: 14.3199 - val_loss: 21.4163
Train on 2 samples, validate on 1 samples
Epoch 1/2

2/2 [==============================] - 0s 72ms/step - loss: 11.0523 - val_loss: 17.6733
Epoch 2/2

2/2 [==============================] - 0s 485us/step - loss: 10.9597 - val_loss: 17.5459

Обновите после прочтения ответа: ответом ниже на один из моих вопросов был дан ответ. Я изменил начало своего кода на:

import numpy as np
np.random.seed(1)
import random
random.seed(2)
import tensorflow as tf
tf.set_random_seed(3)

И теперь я получаю те же цифры, что и раньше. Так что стабильно. Но мой главный вопрос остался без ответа. Почему каждый раз две эквивалентные модели дают разные результаты?

Вот результат, который я получаю каждый раз:

результаты 1:

Epoch 1/2

2/2 [==============================] - 0s 66ms/sample - loss: 11.9794 - val_loss: 18.9925
Epoch 2/2

2/2 [==============================] - 0s 268us/sample - loss: 11.8813 - val_loss: 18.8572

результаты 2:

Epoch 1/2

2/2 [==============================] - 0s 67ms/sample - loss: 5.4743 - val_loss: 9.3471
Epoch 2/2

2/2 [==============================] - 0s 3ms/sample - loss: 5.4108 - val_loss: 9.2497

1 ответ

Решение

Проблема коренится в ожидаемом и фактическом поведении определения модели и случайности. Чтобы увидеть, что происходит, мы должны понять, как работает "ГСЧ":

  • "Генератор случайных чисел" (ГСЧ) на самом деле является функцией, которая производит числа, которые отображаются на распределение вероятностей "в долгосрочной перспективе".
  • Когда функция ГСЧ, например RNG()вызывается, он возвращает "случайное" значение и увеличивает свой внутренний счетчик на 1. Назовите этот счетчикn - тогда: random_value = RNG(n)
  • Когда вы устанавливаете SEED, вы устанавливаете nв соответствии со значением этого семени (но не для этого семени); мы можем представить эту разницу через+ c в стойке
  • c будет константой, созданной нелинейной, но детерминированной функцией начального числа: f(seed)
import numpy as np

np.random.seed(4)         # internal counter = 0 + c
print(np.random.random()) # internal counter = 1 + c
print(np.random.random()) # internal counter = 2 + c
print(np.random.random()) # internal counter = 3 + c

np.random.seed(4)         # internal counter = 0 + c
print(np.random.random()) # internal counter = 1 + c
print(np.random.random()) # internal counter = 2 + c
print(np.random.random()) # internal counter = 3 + c
0.9670298390136767
0.5472322491757223
0.9726843599648843

0.9670298390136767
0.5472322491757223
0.9726843599648843

Предположим model1 имеет 100 весов, и вы устанавливаете семя (n = 0 + c). Послеmodel1 построен, ваш счетчик на 100 + c. Если вы не сбросите семя, даже если вы построитеmodel2с одним и тем же кодом модели будут отличаться - посколькуmodel2веса инициализируются на n из 100 + c к 200 + c.


Дополнительная информация:

Есть три семени, чтобы гарантировать лучшую случайность:

import numpy as np
np.random.seed(1)         # for Numpy ops
import random 
random.seed(2)            # for Python ops
import tensorflow as tf
tf.set_random_seed(3)     # for tensorfow ops - e.g. Dropout masks

Это даст неплохую воспроизводимость, но не идеальную, если вы используете графический процессор - из-за параллелизма операций; это видео хорошо объясняет. Для еще лучшей воспроизводимости настройтеPYHTONHASHSEED- эту и другую информацию можно найти в официальном FAQ по Keras.

"Идеальная" воспроизводимость довольно избыточна, так как ваши результаты должны совпадать в пределах 0,1% в большинстве случаев - но если вам это действительно нужно, вероятно, единственный способ в настоящее время - переключиться на ЦП и прекратить использование CUDA - но это замедлит обучение колоссально (на х10+).


Источники случайности:

  • Инициализация веса (каждый инициализатор Keras по умолчанию использует случайность)
  • Слои шума (Dropout, GaussianNoise и т. Д.)
  • Хеширование для операций на основе хэша, например, порядок элементов в наборе или dict
  • Параллелизм GPU (см. Связанное видео)

Демонстрация случайности модели:

import numpy as np
np.random.seed(4)

model1_init_weights = [np.random.random(), np.random.random(), np.random.random()]
model2_init_weights = [np.random.random(), np.random.random(), np.random.random()]
print("model1_init_weights:", model1_init_weights)
print("model2_init_weights:", model2_init_weights)
model1_init_weights: [0.9670298390136767, 0.5472322491757223, 0.9726843599648843]
model2_init_weights: [0.7148159936743647, 0.6977288245972708, 0.21608949558037638]

Перезагрузите ядро. Теперь запустите это:

import numpy as np
np.random.seed(4)

model2_init_weights = [np.random.random(), np.random.random(), np.random.random()]
model1_init_weights = [np.random.random(), np.random.random(), np.random.random()]
print("model1_init_weights:", model1_init_weights)
print("model2_init_weights:", model2_init_weights)
model1_init_weights: [0.7148159936743647, 0.6977288245972708, 0.21608949558037638]
model2_init_weights: [0.9670298390136767, 0.5472322491757223, 0.9726843599648843]

Таким образом, переворачивая порядок model1 а также model2в вашем коде также переворачивает убытки. Это связано с тем, что начальное значение не сбрасывается между определениями двух моделей, поэтому ваши инициализации веса совершенно разные.

Если вы хотите, чтобы они были одинаковыми, сбросьте начальное значение перед определением КАЖДОЙ МОДЕЛИ и перед УСТАНОВКОЙ каждой модели - и используйте удобную функцию, как показано ниже. Но лучше всего перезапустить ядро ​​и работать отдельно.py файлы.

def reset_seeds():
    np.random.seed(1)
    random.seed(2)
    tf.set_random_seed(3)
    print("RANDOM SEEDS RESET")
Другие вопросы по тегам