为什么在循环中使用Keras顺序神经网络得到不同的预测结果?

我在使用Keras的model.fit()和sklearn的model.fit()函数时发现了一个奇怪的差异。当在循环中调用model.fit()时,使用Keras顺序模型会得到不一致的预测结果,而使用sklearn模型则不会出现这种情况。请看以下示例代码以重现这一现象。

from numpy.random import seedseed(1337)import tensorflow as tftf.random.set_seed(1337)from sklearn.linear_model import LogisticRegressionfrom keras.models import Sequentialfrom keras.layers import Dense, Dropoutfrom keras.layers import InputLayerfrom sklearn.datasets import make_blobsfrom sklearn.preprocessing import MinMaxScalerimport numpy as npdef get_sequential_dnn(NUM_COLS, NUM_ROWS):   # 模型代码if __name__ == "__main__":    input_size = 10    X, y = make_blobs(n_samples=100, centers=2, n_features=input_size,                      random_state=1                      )    scalar = MinMaxScaler()    scalar.fit(X)    X = scalar.transform(X)    model = get_sequential_dnn(X.shape[1], X.shape[0])    # print(model.summary())    # model = LogisticRegression()    for i in range(2):        model.fit(X, y, epochs=100, verbose=0, shuffle=False)        # model.fit(X, y)            Xnew, _ = make_blobs(n_samples=3, centers=2, n_features=10, random_state=1)        Xnew = scalar.transform(Xnew)        # 进行预测          # ynew = model.predict_proba(Xnew)[:, 1]        ynew = model.predict_proba(Xnew)        ynew = np.array(ynew)            # 显示输入和预测输出        print('--------------')        for i in range(len(Xnew)):            print("X=%s \n Predicted=%s" % (Xnew[i], ynew[i]))

运行结果如下

--------------X=[0.32799209 0.32682211 0.62699485 0.89987274 0.59894281 0.94662653 0.77125788 0.73345369 0.2153754  0.35317172]  Predicted=[0.9931685]X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879 0.12891829 0.25729677 0.69975833 0.73165292]  Predicted=[0.35249507]X=[0.65154993 0.26153846 0.2416324  0.11793901 0.7047334  0.17706289 0.07761879 0.45189967 0.8481064  0.85092378]  Predicted=[0.35249507]--------------X=[0.32799209 0.32682211 0.62699485 0.89987274 0.59894281 0.94662653 0.77125788 0.73345369 0.2153754  0.35317172]  Predicted=[1.]X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879 0.12891829 0.25729677 0.69975833 0.73165292]  Predicted=[0.17942095]X=[0.65154993 0.26153846 0.2416324  0.11793901 0.7047334  0.17706289 0.07761879 0.45189967 0.8481064  0.85092378]  Predicted=[0.17942095]

然而,如果我使用逻辑回归(取消注释相应的代码行),预测结果是一致的:

--------------X=[0.32799209 0.32682211 0.62699485 0.89987274 0.59894281 0.94662653 0.77125788 0.73345369 0.2153754  0.35317172]  Predicted=0.929209043999009X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879 0.12891829 0.25729677 0.69975833 0.73165292]  Predicted=0.04643513037543502X=[0.65154993 0.26153846 0.2416324  0.11793901 0.7047334  0.17706289 0.07761879 0.45189967 0.8481064  0.85092378]  Predicted=0.038716408758471876--------------X=[0.32799209 0.32682211 0.62699485 0.89987274 0.59894281 0.94662653 0.77125788 0.73345369 0.2153754  0.35317172]  Predicted=0.929209043999009X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879 0.12891829 0.25729677 0.69975833 0.73165292]  Predicted=0.04643513037543502X=[0.65154993 0.26153846 0.2416324  0.11793901 0.7047334  0.17706289 0.07761879 0.45189967 0.8481064  0.85092378]  Predicted=0.038716408758471876

我明白解决这一问题的一个明显方法是在循环前拟合模型,可能Keras模型在数据和标签拟合过程中具有很强的随机性,但在某些情况下,你需要使用循环来获得预测分数。例如,如果你想对训练数据进行10折交叉验证以获取AUC、灵敏度和特异性值。在这些情况下,这种随机性是不可接受的。

是什么导致了这种不一致性?解决方案是什么?


回答:

在尝试使用Keras获得可重现结果时,您的方法存在几个问题。

  1. 您在已经拟合的模型(当i==0时)上再次调用fit(当i==1时)。因此,优化器在两种情况下看到了不同的初始权重集,因此您最终会得到两个不同的模型。解决方案:每次都获取一个新的模型。Sklearn的情况并非如此,每次调用fit时都会使用新初始化的权重开始。
  2. model.fit内部可能会使用当前阶段的随机数生成器。您在循环外设置了种子,因此当第二次调用fit时,状态会有所不同。解决方案:在循环内设置种子。

存在问题的示例代码

# 这里是问题2tf.random.set_seed(1337)def get_model():  model = Sequential()  model.add(Dense(4, input_dim=8, activation='relu'))  model.add(Dense(1, activation='sigmoid'))  model.compile(loss='binary_crossentropy', optimizer='adam')  return modelX = np.random.randn(10,8)y = np.random.randn(10,1)# 这里是问题1model = get_model()results = []for i in range(10):  model.fit(X, y, epochs=5, verbose=0, shuffle=False)  results.append(np.sum(model.predict(X)))assert np.all(np.isclose(results, results[0]))

如您所见,断言失败了

修正后的代码

results = []for i in range(10):  tf.random.set_seed(1337)  model = get_model()  model.fit(X, y, epochs=5, verbose=0, shuffle=False)  results.append(np.sum(model.predict(X)))assert np.all(np.isclose(results, results[0]))

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注