当前位置: 首页 > 面试题库 >

这些模型是否等效?

田彬郁
2023-03-14
问题内容

主要问题: 我用两种不同的方式定义相同的模型。为什么会得到不同的结果?它们似乎是相同的模型。

第二个问题(在下面回答)如果再次运行代码,则会再次得到不同的结果。我已经在开始时设置了种子以修复随机性。为什么会这样呢?

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的权重是根据nfrom100 + 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常见问题解答中设置your -that和其他信息。

“完美”的可重复性相当多余,因为您的结果应该在大部分时间的0.1%之内达成一致-
但是,如果您确实需要它,那么当前唯一的方法可能就是切换到CPU并停止使用CUDA-但这会减慢速度极大地训练(通过x10 +)。

随机性的来源

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


 类似资料:
  • 问题内容: 给定一些类,这两个方法声明是否等效? 和 问题答案: 对于呼叫者:是的,它们是等效的。 对于方法中的代码:否。 不同之处在于,在第一个示例的代码中,您可以使用类型T(例如,保存由创建的对象),而在第二个示例中,您不能使用类型T。

  • 问题内容: 我了解在单例情况下,你可以执行以下操作: 如果和是具有所有相同属性值的同一类的实例,则它将返回。在Django模型中,这是很自然的,因为除非有相同的值,否则模型的两个单独的实例将永远不会相同。 这样做的问题是,如果对实例的引用具有中间件在途中某处已更新的属性,并且尚未保存,那么你正尝试将其保存到另一个变量,该变量持有对实例的引用。相同的模型,当然会返回,因为它们对某些属性具有不同的值。

  • 本文向大家介绍训练过程中,若一个模型不收敛,那么是否说明这个模型无效?导致模型不收敛的原因有哪些?相关面试题,主要包含被问及训练过程中,若一个模型不收敛,那么是否说明这个模型无效?导致模型不收敛的原因有哪些?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 并不能说明这个模型无效,导致模型不收敛的原因可能有数据分类的标注不准确,样本的信息量太大导致模型不足以fit整个样本空间。学习率设置的太

  • 问题内容: 我来自c#领域。 在C#中,我可以使用动态类http://msdn.microsoft.com/zh- cn/library/dd264741.aspx 这使我不必使用模板/泛型类,而可以针对certian情况获得类似的感觉。 不幸的是,“动态”和“ java”关键字在动态架构上出现了许多不相关的信息,因此我在互联网搜索中一直不成功。 我在javaFX中涉猎了一点,并且有一个var类型

  • 问题内容: 我有大约五种这样的方法,但是由于seriesColors是静态的,所以想知道上面的代码是否会导致内存泄漏。 如果存在内存泄漏,那么该如何解决? 在这两个代码中,哪一个存在严重缺陷? 问题答案: 静态变量在类的所有实例之间共享。(使用“ new”运算符创建一个实例。) 在这些示例中;使用静态(实例变量)存储颜色可能不是一个好主意,因为实例之间会相互干扰。该变量应更改为“普通”实例变量。

  • 问题内容: 是否有与Java SwingWorker类等效的JavaFX? 我知道JavaFX Task,但是有了它,您只能发布String消息或进度。我只想在GUI线程中调用方法,就像使用SwingWorker一样(通过发布任意类型的消息)。 这是我的意思的一个例子: 解 非常感谢您的回答。我正在寻找的解决方案是使用Platform.runLater(Runnable guiUpdater) 。