tenorflow - сохранение и восстановление операций
У меня есть простая цель - обучить модель тензорного потока, сохранив и восстановив ее позже, чтобы продолжить обучение или использовать некоторые функции / операции.
Вот простой пример модели
import tensorflow as tf
import numpy as np
BATCH_SIZE = 3
VECTOR_SIZE = 1
LEARNING_RATE = 0.1
x = tf.placeholder(tf.float32, [BATCH_SIZE, VECTOR_SIZE],
name='input_placeholder')
y = tf.placeholder(tf.float32, [BATCH_SIZE, VECTOR_SIZE],
name='labels_placeholder')
W = tf.get_variable('W', [VECTOR_SIZE, BATCH_SIZE])
b = tf.get_variable('b', [VECTOR_SIZE], initializer=tf.constant_initializer(0.0))
y_hat = tf.matmul(W, x) + b
predict = tf.matmul(W, x) + b
total_loss = tf.reduce_mean(y-y_hat)
train_step = tf.train.AdagradOptimizer(LEARNING_RATE).minimize(total_loss)
X = np.ones([BATCH_SIZE, VECTOR_SIZE])
Y = np.ones([BATCH_SIZE, VECTOR_SIZE])
all_saver = tf.train.Saver()
sess= tf.Session()
sess.run(tf.global_variables_initializer())
sess.run([train_step], feed_dict = {x: X, y:Y}))
save_path = r'C:\some_path\save\\'
all_saver.save(sess,save_path)
Теперь мы восстановим это здесь:
meta_path = r'C:\some_path\save\.meta'
new_all_saver = tf.train.import_meta_graph(meta_path)
graph = tf.get_default_graph()
all_ops = graph.get_operations()
for el in all_ops:
print(el)
В восстановленной операции никто даже не мог найти predict
или же train_step
из оригинального кода. Нужно ли называть эти операции перед сохранением? Как я могу получить predict
вернуться и запустить что-то вроде этого
sess=tf.Session()
sess.run([predict], feed_dict = {x:X})
PS Я прочитал много уроков по сохранению и восстановлению в tenorflow, но все еще плохо понимаю, как все это работает.
1 ответ
1) Ваши операции выполняются в восстановленной модели, но, поскольку вы не назвали их, они будут названы в соответствии с некоторыми правилами по умолчанию. Например, так как у вас есть:
predict = tf.matmul(W, x) + b
тогда операция, представляющая predict
может выглядеть так:
name: "add"
op: "Add"
input: "MatMul"
input: "b/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
В этом примере, который печатается, когда вы делаете for el in all_ops:
и печатает результат, вы видите, что имя операции "добавить", которое было автоматически назначено; тип операции ("op") - "Добавить", что соответствует последней операции, выполненной в строке кода (это +); и входы "MatMul" и "b/read", соответствующие тому, что вы суммировали. Просто чтобы быть ясным, я не уверен, что только эта операция соответствует данной строке кода, так как другие надстройки с тем же типом входных данных присутствовали в печати, но это возможно.
Итак, подведем итоги до сих пор: ваши операции есть, и вы видите их при печати. Но почему вы не видите слово "предсказать"? Ну, потому что это не имя тензора или операции в Tensorflow Graph, это только имя переменной в вашем коде.
В дальнейшем, как вы могли бы получить доступ к этому "предсказанию"? Ответ через его имя, как указано на графике. В вышеприведенном случае имя предиката могло бы быть "добавить", если я прав в своем предположении, но давайте вместо этого назовем ваш "прогноз", чтобы вы могли легко контролировать, какая операция ему соответствует.
Чтобы назвать ваш "прогноз", давайте добавим следующую строку кода чуть ниже predict = tf.matmul(W, x) + b
:
predict_named = tf.identity(predict, "here_i_put_a_name")
Эта строка создает новую операцию, которая получает в качестве входных данных операцию, определенную в "предикате", и выдает выходные данные, равные результату входных данных. Сама операция не делает много - просто повторяет значение - но с помощью этой операции я мог бы добавить к ней имя. Теперь, если вы будете искать в вашей печати, вы сможете найти:
name: "add_1"
op: "Add"
input: "MatMul_1"
input: "b/read"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
name: "here_i_put_a_name"
op: "Identity"
input: "add_1"
attr {
key: "T"
value {
type: DT_FLOAT
}
}
Ницца! Теперь вы 1) можете получить доступ к своему "прогнозу", используя имя "here_i_put_a_name" и 2) мы можем просто подтвердить, что ваш "прогноз" на самом деле был операцией с именем "add_1" - просто проверьте над атрибутом "input" операции "here_i_put_a_name".
После этого давайте перейдем к операции "here_i_put_a_name" и сделаем несколько прогнозов. Сначала измените save_path и meta_path, поместив в конце возможное имя файла, например:
save_path = r'C:\some_path\save\my_model_name'
meta_path = r'C:\some_path\save\my_model_name.meta'
Затем в конце кода восстановления добавьте:
with tf.Session(graph=graph) as sess:
new_all_saver.restore(sess,save_path)
my_prediction = sess.run(["here_i_put_a_name:0"], feed_dict={"input_placeholder:0": [[1],[2],[3]]})
print(my_prediction)
С помощью этого блока вы создаете новый сеанс Tensorflow и используете график, хранящийся в вашей переменной "graph". Внутри этого контекста вы восстанавливаете сеанс из save_path в текущий сеанс. Затем вы выполняете прогноз, или, точнее, вы запускаете операцию "here_i_put_a_name" и получаете первый вывод этой операции (причина, по которой у нас после нее ":0"). Канал dict передает значение [[1],[2],[3]] тензору "input_placeholder:0" (опять же, ":0" показывает нам, что это тензор, а не операция).
После всего сказанного и с ответами на вопросы (надеюсь) у меня есть несколько комментариев:
1) По моему опыту, было бы неплохо использовать библиотеку tf.saved_model
для того, чтобы сохранить и восстановить модули. Но это мое личное предложение.
2) Я ограничился ответом на ваши вопросы об именовании и вызове операций, поэтому я проигнорировал процедуры обучения и прогнозирования. Но я думаю, что вы имеете дело с проблемой, когда ставите переменную X с размером BATCH_SIZE.
3) Обратите внимание на разницу между "blabla" и "blabla:0". Первый - операция, а последний - тензор.