Проблема коренится в ожидаемом против фактического поведении определения модели и случайности. Чтобы увидеть, что происходит, мы должны понять, как работает «ГСЧ»:
- «Генератор случайных чисел» (ГСЧ) на самом деле является функцией, которая генерирует числа так, что они отображаются на распределение вероятностей 'вдолгосрочный период '
- Когда вызывается функция ГСЧ, например,
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
Это даст довольно хорошую воспроизводимость, но не идеально, если вы используете GPU - из-за параллелизма операций; это видео объясняет это хорошо. Для еще лучшей воспроизводимости установите PYHTONHASHSEED
- эту и другую информацию в официальном Keras FAQ .
«Идеальная» воспроизводимость довольно избыточна, так как ваши результаты должны согласовываться в течение 0,1% времени - но если вам это действительно нужно, вероятно, единственный способ в настоящее время - это переключиться на ЦП и прекратить использование CUDA -но это сильно замедлит обучение (в x10 +).
Источники случайности :
- Весовые инициализации (каждый инициализатор Keras по умолчанию использует случайность)
- Слои шума (Dropout, GaussianNoise и т. Д.)
- Хеширование для операций на основе хеша, например, порядок элементов в наборе или в формате
- 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")