python - 这些模型是否等效?

标签 python tensorflow keras neural-network

Main question: I define the same model in two different ways. Why do I get different results? They seem to be the same model.

次要问题(在下面回答)如果我再次运行代码,我会再次得到不同的结果。我在一开始就设置了种子来修复随机性。为什么会这样?

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

最佳答案

问题的根源在于模型定义和随机性的预期与实际行为。要了解发生了什么,我们必须了解“RNG”的工作原理:

  • “随机数生成器”(RNG) 实际上是一个函数,它生成的数字映射到“长期”的概率分布上
  • 当 RNG 功能时,例如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 的权重根据 n100 + c200 + 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,则不是完美的 - 由于操作的并行性; this video解释得很好。为了获得更好的重现性,请设置您的 PYHTONHASHSEED - 以及官方 Keras FAQ 中的其他信息.

“完美”的可重复性是多余的,因为您的结果在大多数情况下应该在 .1% 以内一致 - 但如果您真的需要它,目前唯一的方法可能是切换到 CPU 并停止使用 CUDA - 但那'会大大减慢训练速度(x10+)。


随机性来源:

  • 权重初始化(每个默认的 Keras 初始化器都使用随机性)
  • 噪声层(Dropout、GaussianNoise 等)
  • > Hashing用于基于散列的操作,例如集合或字典中的项目顺序
  • 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]

因此,翻转代码中 model1model2 的顺序也会翻转损失。这是因为种子不会在两个模型的定义之间自行重置,因此您的权重初始化完全不同。

如果您希望它们相同,请在定义每个模型之前以及在拟合每个模型之前重置种子 - 并使用如下所示的方便函数。但最好的办法是重新启动内核并在单独的 .py 文件中工作。

def reset_seeds():
    np.random.seed(1)
    random.seed(2)
    tf.set_random_seed(3)
    print("RANDOM SEEDS RESET")

关于python - 这些模型是否等效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58210700/

相关文章:

python - Keras 中的自定义损失函数

python - 在 SQLite3 DELETE 语句中引用 python 变量

python - 文本小部件内 Tkinter 中的滚动条

python - 为 TensorFlow reshape Gym 数组

python - SKLearn NMF 与自定义 NMF

python - 如何强制 tensorflow 和 Keras 在 GPU 上运行?

python - Keras 当我尝试训练模型时出现 "<no registered kernels>"错误

python - 'csrf_tokan',预期为 'endblock' 。您是否忘记注册或加载此标签?

python - 类型错误 : __init__() got multiple values for argument 'scoring' at Santander Customer Transaction database

tensorflow - 在 Keras 和 Tensorflow 中使用稀疏矩阵