TensorFlow: Не повторяющиеся результаты
Проблема
У меня есть Python script, который использует TensorFlow для создания многослойной сети персептрона (с выпадением), чтобы выполнять двоичную классификацию. Несмотря на то, что я старался установить как семена Python, так и TensorFlow, я получаю неповторимые результаты. Если я запускаю один раз, а затем снова запускаю, то получаю разные результаты. Я могу даже запустить один раз, выйти из Python, перезапустить Python, запустить снова и получить разные результаты.
Что я пробовал
Я знаю, что некоторые люди задавали вопросы о получении неповторяющихся результатов в TensorFlow (например, "Как получить стабильные результаты..." , "set_random_seed не работает..." , "Как получить воспроизводимый результат в TensorFlow" ), и ответы обычно оказываются быть неправильным использованием/пониманием tf.set_random_seed()
. Я постарался реализовать предоставленные решения, но это не решило мою проблему.
Общей ошибкой не является осознание того, что tf.set_random_seed()
- это только семя уровня графа, и что запуск script несколько раз изменит график, объясняя неповторяющиеся результаты. Я использовал следующий оператор, чтобы распечатать весь граф и проверить (через diff), что график тот же, даже когда результаты разные.
print [n.name for n in tf.get_default_graph().as_graph_def().node]
Я также использовал вызовы функций, такие как tf.reset_default_graph()
и tf.get_default_graph().finalize()
, чтобы избежать каких-либо изменений в графике, хотя это, вероятно, слишком велико.
Код (релевантный)
Мой script составляет ~ 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 (только для процессора)
Enthought Canopy версия 1.7.2 (Python 2.7, а не 3. +)
Версия Mac OS X 10.11.3
Ответы
Ответ 1
Вам нужно установить начальное значение уровня процесса в дополнение к семантике уровня графа, т.е.
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)
Ответ 2
Смотрите этот тензор проблема github. Некоторые операции на графическом процессоре не полностью детерминированы (скорость и точность).
Я также заметил, что для того, чтобы семя имело какой-либо эффект, tf.set_random_seed(...)
нужно вызвать до создания Session
. А также вы должны либо полностью перезапустить интерпретатор python при каждом запуске своего кода, либо вызвать tf.reset_default_graph()
в начале.
Ответ 3
Просто добавьте в Yaroslav ответ, вы также должны установить семя numpy в дополнение к семенам операций и графа, поскольку некоторые операции с базой данных зависят от numpy. Это сделало трюк для меня np.random.seed()
с Tensorflow V 1.1.0
Ответ 4
Что я сделал, чтобы получить воспроизводимые результаты обучения и тестирования огромной сети с использованием тензорного потока.
- Это проверено на Ubuntu 16.04, tenorflow 1.9.0, python 2.7, как на GPU, так и на CPU
- Добавьте эти строки кода, прежде чем делать что-либо в вашем коде (первые несколько строк основной функции)
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 в качестве аргумента, поместите ваше постоянное seed во все из них (в моем коде используется
SEED
)
Вот несколько из этих функций: tf.nn.dropout
, tf.contrib.layers.xavier_initializer
и т.д.
Примечание. Этот шаг может показаться неоправданным, потому что мы уже используем tf.set_random_seed
для установки начального числа для тензорного потока, но, поверьте мне, вам это нужно! Смотри ответ Ярослава.
Ответ 5
В tf.set_random_seed(42)
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.