如何获得可重复的结果(Keras,Tensorflow):

13

为了使结果可重复,我阅读了20多篇文章,并将尽可能多的函数添加到我的脚本中...但失败了。

在官方来源中,我看到有两种类型的种子-全局和操作性。也许,解决我的问题的关键是设置操作性种子,但我不知道在哪里应用它。

请问,您能帮助我在tensorflow(版本> 2.0)中实现可重复的结果吗?非常感谢。

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from keras.optimizers import adam
from sklearn.preprocessing import MinMaxScaler


np.random.seed(7)
import tensorflow as tf
tf.random.set_seed(7) #analogue of set_random_seed(seed_value)
import random
random.seed(7)
tf.random.uniform([1], seed=1)
tf.Graph.as_default #analogue of  tf.get_default_graph().finalize()

rng = tf.random.experimental.Generator.from_seed(1234)
rng.uniform((), 5, 10, tf.int64)  # draw a random scalar (0-D tensor) between 5 and 10

df = pd.read_csv("s54.csv", 
                 delimiter = ';', 
                 decimal=',', 
                 dtype = object).apply(pd.to_numeric).fillna(0)

#data normalization
scaler = MinMaxScaler() 
scaled_values = scaler.fit_transform(df) 
df.loc[:,:] = scaled_values


X_train, X_test, y_train, y_test = train_test_split(df.iloc[:,1:],
                                                    df.iloc[:,:1],
                                                    test_size=0.2,
                                                    random_state=7,
                                                    stratify = df.iloc[:,:1])

model = Sequential()
model.add(Dense(1200, input_dim=len(X_train.columns), activation='relu'))  
model.add(Dense(150, activation='relu'))
model.add(Dense(80, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='sigmoid')) 

loss="binary_crossentropy"
optimizer=adam(lr=0.01)
metrics=['accuracy']
epochs = 2
batch_size = 32
verbose = 0

model.compile(loss=loss,  
              optimizer=optimizer, 
              metrics=metrics) 
model.fit(X_train, y_train, epochs = epochs, batch_size=batch_size, verbose = verbose)
predictions = model.predict(X_test)
tn, fp, fn, tp = confusion_matrix(y_test, predictions>.5).ravel()

1
我不确定,但是我认为如果你尝试再次运行脚本“而不重置你的Python内核”,种子将继续迭代并产生不同的结果。我相信只有在每次运行代码时重置您的Python内核才能进行复制。 - Daniel Möller
1
如果该方法接受一个种子(而不是您在顶部设置的通用种子),那么该方法“独立”地可以在同一运行的Python内核中多次重现。 - Daniel Möller
Daniel,非常感谢您的回答。不幸的是,重新启动内核没有帮助。我认为我的方法不接受我在脚本顶部设置的种子。我确定我将相同的输入提供给模型,但种子在model.fit级别上不起作用。 - Alex Ivanov
4个回答

12

从TensorFlow 2.8开始,可以使用tf.config.experimental.enable_op_determinism()

通过此方法,即可实现在GPU上的可重复性。

import tensorflow as tf

tf.keras.utils.set_random_seed(42)  # sets seeds for base-python, numpy and tf
tf.config.experimental.enable_op_determinism()

需要注意的是,这会带来显著的性能损失。


这是解决此问题的最佳答案。我给你点赞! - Yahya
信不信由你,我的模型训练甚至变得更快了……我认为这可能与TF的多线程内部方法有关,这可能导致了很多不必要的开销! - Yahya

11

以下是对文档的参考:

依赖于随机种子的操作实际上从两个种子中派生:全局种子和操作级别种子。这将设置全局种子。

其与操作级别种子的交互如下:

  1. 如果既未设置全局种子也未设置操作级别种子:使用随机选择的种子执行此操作。
  2. 如果未设置操作级别种子但设置了全局种子:系统从由全局种子确定的一系列种子流中选择一个操作种子。
  3. 如果设置了操作级别种子,但未设置全局种子:默认的全局种子和指定的操作级别种子用于确定随机序列。
  4. 如果全局种子和操作级别种子都设置了:同时使用两个种子来确定随机序列。

第一种情况

默认情况下将选择一个随机种子。这可以通过结果轻松地注意到。 每次重新运行程序或多次调用代码都会有不同的值。

x_train = tf.random.normal((10,1), 1, 1, dtype=tf.float32)
print(x_train)

第二种情况

全局变量已设置,但操作尚未设置。 尽管它生成了与第一和第二个随机数不同的种子。如果您重新运行或重新启动代码,则两者的种子仍将相同。 它们一遍又一遍地生成相同的结果。

tf.random.set_seed(2)
first = tf.random.normal((10,1), 1, 1, dtype=tf.float32)
print(first)
sec = tf.random.normal((10,1), 1, 1, dtype=tf.float32)
print(sec)

第三种情况

针对这种情况,操作种子已经设置但是全局种子没有设置。 如果您重新运行代码,将会得到不同的结果,但是如果您重新启动运行时,将会得到与上一次运行相同的结果序列。

x_train = tf.random.normal((10,1), 1, 1, dtype=tf.float32, seed=2)
print(x_train)

第四种情况

两个种子将用于确定随机序列。更改全局和操作的种子将产生不同的结果,但使用相同的种子重新启动运行时仍将给出相同的结果。

tf.random.set_seed(3)
x_train = tf.random.normal((10,1), 1, 1, dtype=tf.float32, seed=1)
print(x_train) 

创建可复现的代码作为参考。通过设置全局种子,它始终给出相同的结果。

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

## GLOBAL SEED ##                                                   
tf.random.set_seed(3)
x_train = tf.random.normal((10,1), 1, 1, dtype=tf.float32)
y_train = tf.math.sin(x_train)
x_test = tf.random.normal((10,1), 2, 3, dtype=tf.float32)
y_test = tf.math.sin(x_test)

model = Sequential()
model.add(Dense(1200, input_shape=(1,), activation='relu'))  
model.add(Dense(150, activation='relu'))
model.add(Dense(80, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='sigmoid')) 

loss="binary_crossentropy"
optimizer=tf.keras.optimizers.Adam(lr=0.01)
metrics=['mse']
epochs = 5
batch_size = 32
verbose = 1

model.compile(loss=loss,  
              optimizer=optimizer, 
              metrics=metrics) 
histpry = model.fit(x_train, y_train, epochs = epochs, batch_size=batch_size, verbose = verbose)
predictions = model.predict(x_test)
print(predictions)

输入图像描述
注意:如果您正在使用TensorFlow 2及以上版本,则Keras已经包含在API中,因此您应该使用TF.Keras而不是本地版本。
所有这些都是在Google Colab上模拟的。


TF_Support,感谢您提供详细和结构化的答案。如果将您在Jupiter笔记本中提供的“可重现代码作为参考”分成两个单元格:1)除了最后3行之外的所有行;2)最后3行(从“histpry = model.fit(x_train ...)”开始),并依次运行这两个单元格,它总是显示相同的结果。但是,如果先运行第一个单元格,然后多次运行第二个单元格,它总是给出不同的结果。有趣的是,如果重新运行第一个单元格,则多次运行后第二个单元格的结果始终是可重复的。 - Alex Ivanov
有趣的是:当我在第二个单元格中多次运行以下代码时:tf.random.set_seed(3) x_train = tf.random.normal((10,1), 1, 1, dtype=tf.float32) print(x_train)。它是可重复的。但是,当我运行以下代码时:tf.random.set_seed(3) histpry = model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, verbose=verbose) predictions = model.predict(x_test) print(predictions) - 它就不可重复了。 - Alex Ivanov
每次运行第二个单元格时,是否可能看到相同的结果?我发现唯一的方法是每次从model = Sequential()重新构建模型。在此之前,需要运行tf.random.set_seed(3)。 - Alex Ivanov

0

你可以通过以下方式为所有随机数设置种子

import numpy as np
np.random.seed(0)
import random
random.seed(0)
import tensorflow
tensorflow.random.set_seed(0)
import tensorflow as tf
tf.random.set_seed(0)
tf.keras.utils.set_random_seed(0)   
tf.config.experimental.enable_op_determinism()

2
TF文档所述: “调用tf.keras.utils.set_random_seed会设置Python种子、NumPy种子和TensorFlow种子。”因此,不需要分别设置它们。 - loki

0

еҪ“жҲ‘们дҪҝз”ЁеұӮж•°вүҘ3е’ҢзҘһз»Ҹе…ғж•°вүҘ100ж—¶пјҢеӨ„зҗҶеҷЁж ёеҝғж•°йҮҸжҳҜжңүж„Ҹд№үзҡ„гҖӮжҲ‘зҡ„й—®йўҳжҳҜеңЁ2дёӘдёҚеҗҢзҡ„жңҚеҠЎеҷЁдёҠиҝҗиЎҢи„ҡжң¬пјҡ

-е…·жңү32дёӘж ёеҝғ

-е…·жңү16дёӘж ёеҝғ

еҪ“жҲ‘еңЁе…·жңү32дёӘж ёеҝғпјҲз”ҡиҮіжҳҜ32дёӘе’Ң24дёӘж ёеҝғпјүзҡ„жңҚеҠЎеҷЁдёҠиҝҗиЎҢи„ҡжң¬ж—¶пјҢз»“жһңжҳҜзӣёеҗҢзҡ„гҖӮ


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接