python - 为什么我在循环中使用 Keras 顺序神经网络得到不同的预测?
问题描述
我遇到了 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、敏感性、特异性值。在这些情况下,这种随机性是不可接受的。
是什么导致了这种不一致,解决方法是什么?
解决方案
您尝试使用 keras 获得可重现结果的方式存在几个问题。
- 您在已经拟合的模型(when )上调用(when
fit
)。所以优化器在这两种情况下都会看到不同的初始权重集,所以你最终会得到两个不同的模型。解决方案:每次都获得一个新模型。sklearn 的情况并非如此,它每次调用 fit 时都会从新的初始化权重开始。i==1
i==0
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]))
推荐阅读
- c++ - 如何修改数组,从中删除空格并将其存储在新数组中?
- firebase - Cloud Firestore security rules "if exists" not working
- java - 无需安装完整容器即可运行 J2EE servlet 的简单方法
- c - 在不使用匿名函数的情况下创建函数适配器
- android-studio-3.0 - Sceneform ARCore Android 工作室
- firebase - 如何使用功能 firebase/firestore 发送通知
- r - 从 r 中类 dist 的嵌套列表中提取特定行
- azure - 使用 IdentityServer 和 Azure API 管理进行用户身份验证
- java - 使用 Java 9 及更高版本(在本例中为 JDK11)部署 JAR(JLink 混淆?)
- typescript - 强制数组在 Typescript 中至少有一个值