我有一个Python脚本,它使用TensorFlow创建一个多层感知器网络(带有丢失),以便进行二进制分类。即使我一直小心设置Python和TensorFlow种子,但我得到了不可重复的结果。如果我跑一次然后再跑,我会得到不同的结果。我甚至可以运行一次,退出Python,重启Python,再次运行并获得不同的结果。
我知道有些人发布了有关在TensorFlow中获取不可重复结果的问题(例如,"How to get stable results...","set_random_seed not working...","How to get reproducible result in TensorFlow"),答案通常会被证明是错误的用法/对tf.set_random_seed()
的理解。我已经确保实施所提供的解决方案,但这并没有解决我的问题。
一个常见的错误是没有意识到tf.set_random_seed()
只是一个图级别的种子,并且多次运行脚本会改变图形,解释不可重复的结果。我使用以下语句打印出整个图表并验证(通过差异)即使结果不同,图表也是相同的。
print [n.name for n in tf.get_default_graph().as_graph_def().node]
我还使用了tf.reset_default_graph()
和tf.get_default_graph().finalize()
之类的函数调用来避免对图表进行任何更改,即使这可能有点过分。
我的脚本长约360行,所以这里是相关的行(显示了剪切代码)。 ALL_CAPS中的任何项目都是在下面的Parameters
块中定义的常量。
import numpy as np
import tensorflow as tf
from copy import deepcopy
from tqdm import tqdm # Progress bar
# --------------------------------- Parameters ---------------------------------
(snip)
# --------------------------------- Functions ---------------------------------
(snip)
# ------------------------------ Obtain Train Data -----------------------------
(snip)
# ------------------------------ Obtain Test Data -----------------------------
(snip)
random.seed(12345)
tf.set_random_seed(12345)
(snip)
# ------------------------- Build the TensorFlow Graph -------------------------
tf.reset_default_graph()
with tf.Graph().as_default():
x = tf.placeholder("float", shape=[None, N_INPUT])
y_ = tf.placeholder("float", shape=[None, N_CLASSES])
# Store layers weight & bias
weights = {
'h1': tf.Variable(tf.random_normal([N_INPUT, N_HIDDEN_1])),
'h2': tf.Variable(tf.random_normal([N_HIDDEN_1, N_HIDDEN_2])),
'h3': tf.Variable(tf.random_normal([N_HIDDEN_2, N_HIDDEN_3])),
'out': tf.Variable(tf.random_normal([N_HIDDEN_3, N_CLASSES]))
}
biases = {
'b1': tf.Variable(tf.random_normal([N_HIDDEN_1])),
'b2': tf.Variable(tf.random_normal([N_HIDDEN_2])),
'b3': tf.Variable(tf.random_normal([N_HIDDEN_3])),
'out': tf.Variable(tf.random_normal([N_CLASSES]))
}
# Construct model
pred = multilayer_perceptron(x, weights, biases, USE_DROP_LAYERS, DROP_KEEP_PROB)
mean1 = tf.reduce_mean(weights['h1'])
mean2 = tf.reduce_mean(weights['h2'])
mean3 = tf.reduce_mean(weights['h3'])
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y_))
regularizers = (tf.nn.l2_loss(weights['h1']) + tf.nn.l2_loss(biases['b1']) +
tf.nn.l2_loss(weights['h2']) + tf.nn.l2_loss(biases['b2']) +
tf.nn.l2_loss(weights['h3']) + tf.nn.l2_loss(biases['b3']))
cost += COEFF_REGULAR * regularizers
optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(cost)
out_labels = tf.nn.softmax(pred)
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
tf.get_default_graph().finalize() # Lock the graph as read-only
#Print the default graph in text form
print [n.name for n in tf.get_default_graph().as_graph_def().node]
# --------------------------------- Training ----------------------------------
print "Start Training"
pbar = tqdm(total = TRAINING_EPOCHS)
for epoch in range(TRAINING_EPOCHS):
avg_cost = 0.0
batch_iter = 0
train_outfile.write(str(epoch))
while batch_iter < BATCH_SIZE:
train_features = []
train_labels = []
batch_segments = random.sample(train_segments, 20)
for segment in batch_segments:
train_features.append(segment[0])
train_labels.append(segment[1])
sess.run(optimizer, feed_dict={x: train_features, y_: train_labels})
line_out = "," + str(batch_iter) + "\n"
train_outfile.write(line_out)
line_out = ",," + str(sess.run(mean1, feed_dict={x: train_features, y_: train_labels}))
line_out += "," + str(sess.run(mean2, feed_dict={x: train_features, y_: train_labels}))
line_out += "," + str(sess.run(mean3, feed_dict={x: train_features, y_: train_labels})) + "\n"
train_outfile.write(line_out)
avg_cost += sess.run(cost, feed_dict={x: train_features, y_: train_labels})/BATCH_SIZE
batch_iter += 1
line_out = ",,,,," + str(avg_cost) + "\n"
train_outfile.write(line_out)
pbar.update(1) # Increment the progress bar by one
train_outfile.close()
print "Completed training"
# ------------------------------ Testing & Output ------------------------------
keep_prob = 1.0 # Do not use dropout when testing
print "now reducing mean"
print(sess.run(mean1, feed_dict={x: test_features, y_: test_labels}))
print "TRUE LABELS"
print(test_labels)
print "PREDICTED LABELS"
pred_labels = sess.run(out_labels, feed_dict={x: test_features})
print(pred_labels)
output_accuracy_results(pred_labels, test_labels)
sess.close()
正如您所看到的,我将每个纪元期间的结果输出到文件中,并在最后打印出精确度数字。尽管我相信我已经正确地设置了种子,但这些都不匹配从运行到运行。我已同时使用random.seed(12345)
和tf.set_random_seed(12345)
如果我需要提供更多信息,请与我们联系。并提前感谢您的帮助。
-DG
TensorFlow版本0.8.0(仅限CPU)
Enthought Canopy版本1.7.2(Python 2.7,而非3. +)
Mac OS X版本10.11.3
答案 0 :(得分:10)
除了图级种子之外,您还需要设置操作级别种子,即
tf.reset_default_graph()
a = tf.constant([1, 1, 1, 1, 1], dtype=tf.float32)
graph_level_seed = 1
operation_level_seed = 1
tf.set_random_seed(graph_level_seed)
b = tf.nn.dropout(a, 0.5, seed=operation_level_seed)
答案 1 :(得分:9)
请参阅此张量流github issue。 GPU上的某些操作并不完全确定(速度与精度)。
我还观察到,为了使种子产生任何效果,{<1}}必须在创建tf.set_random_seed(...)
之前调用。此外,您应该在每次运行代码时完全重启python解释器,或者在开始时调用Session
。
答案 2 :(得分:0)
只是要添加到Yaroslav的答案,除了操作和图级别种子之外,还应该设置numpy种子,因为一些后端操作依赖于numpy。这对我来说是np.random.seed()
Tensorflow V 1.1.0
答案 3 :(得分:0)
import os
import random
import numpy as np
import tensorflow as tf
SEED = 1 # use this constant seed everywhere
os.environ['PYTHONHASHSEED'] = str(SEED)
random.seed(SEED) # `python` built-in pseudo-random generator
np.random.seed(SEED) # numpy pseudo-random generator
tf.set_random_seed(SEED) # tensorflow pseudo-random generator
tf.reset_default_graph() # this goes before sess = tf.Session()
SEED
中使用)以下是其中一些功能:tf.nn.dropout
,tf.contrib.layers.xavier_initializer
等。
注意:由于我们已经在使用tf.set_random_seed
来为tensorflow设置种子,所以此步骤似乎不合理,但是请相信我,您需要这样做!请参阅Yaroslav的答案。
答案 4 :(得分:0)
在TensorFlow 2.0中,tf.set_random_seed(42)
已更改为tf.random.set_seed(42)
。
https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/random/set_seed
如果仅使用TensorFlow,那应该是唯一必要的种子。