【问题标题】:Why do I get different predictions using Keras sequential neural network in a loop?为什么我在循环中使用 Keras 顺序神经网络得到不同的预测?
【发布时间】:2021-07-22 18:08:33
【问题描述】:

我发现了 keras model.fit() 和 sklearn model.fit() 函数之间的奇怪区别。当在循环内调用 model.fit() 时,我使用 Keras 顺序模型得到不一致的预测。使用 sklearn 模型时并非如此。请参阅示例代码以重现该现象。

from numpy.random import seed
seed(1337)
import tensorflow as tf
tf.random.set_seed(1337)

from sklearn.linear_model import LogisticRegression

from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.layers import InputLayer

from sklearn.datasets import make_blobs
from sklearn.preprocessing import MinMaxScaler
import numpy as np

def get_sequential_dnn(NUM_COLS, NUM_ROWS):
   # code for model

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)

        # make a prediction  
        # ynew = model.predict_proba(Xnew)[:, 1]
        ynew = model.predict_proba(Xnew)
        ynew = np.array(ynew)
    
        # show the inputs and predicted outputs
        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.929209043999009
X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879
 0.12891829 0.25729677 0.69975833 0.73165292] 
 Predicted=0.04643513037543502
X=[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.929209043999009
X=[0.60876924 0.33208319 0.24770841 0.11435312 0.66211608 0.17361879
 0.12891829 0.25729677 0.69975833 0.73165292] 
 Predicted=0.04643513037543502
X=[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、敏感性、特异性值。在这些情况下,这种随机性是不可接受的。

造成这种不一致的原因是什么,解决方法是什么?

【问题讨论】:

    标签: python tensorflow machine-learning keras scikit-learn


    【解决方案1】:

    您尝试使用 keras 获得可重现结果的方式存在几个问题。

    1. 您正在调用fit(当i==1)而不是已经安装的模型(当i==0)。所以优化器在这两种情况下都会看到不同的初始权重集,所以你最终会得到两个不同的模型。 解决方案:每次都获得一个新模型。 sklearn 的情况并非如此,它每次调用 fit 时都会从新的初始化权重开始。
    2. model.fit 内部可能使用当前阶段的随机数生成器。您将其播种在循环之外,因此第二次调用 fit 时状态会有所不同。 解决方案:循环内的种子。

    有问题的示例代码

    # Issue 2 here
    tf.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 model
    
    X = np.random.randn(10,8)
    y = np.random.randn(10,1)
    
    # Issue 1 here
    model = 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]))
    

    【讨论】:

    • 非常明确的答案!非常感谢!您建议的解决方案成功了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 2019-09-10
    • 2021-01-07
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多