web-dev-qa-db-fra.com

Restauration d'un modèle Tensorflow utilisant des itérateurs

J'ai un modèle qui entraîne mon réseau à l'aide d'un itérateur; en suivant le nouveau modèle de pipeline d’API de jeux de données recommandé par Google.

Je lis des fichiers tfrecord, envoie des données au réseau, je m'entraîne bien, et tout va bien, je sauvegarde mon modèle à la fin de la formation afin de pouvoir exécuter Inference plus tard. Une version simplifiée du code est la suivante:

""" Training and saving """

training_dataset = tf.contrib.data.TFRecordDataset(training_record)
training_dataset = training_dataset.map(ds._path_records_parser)
training_dataset = training_dataset.batch(BATCH_SIZE)
with tf.name_scope("iterators"):
  training_iterator = Iterator.from_structure(training_dataset.output_types, training_dataset.output_shapes)
  next_training_element = training_iterator.get_next()
  training_init_op = training_iterator.make_initializer(training_dataset)

def train(num_epochs):
  # compute for the number of epochs
  for e in range(1, num_epochs+1):
    session.run(training_init_op) #initializing iterator here
    while True:
      try:
        images, labels = session.run(next_training_element)
        session.run(optimizer, feed_dict={x: images, y_true: labels})
      except tf.errors.OutOfRangeError:
        saver_name = './saved_models/ucf-model'
        print("Finished Training Epoch {}".format(e))
        break



    """ Restoring """
# restoring the saved model and its variables
session = tf.Session()
saver = tf.train.import_meta_graph(r'saved_models\ucf-model.meta')
saver.restore(session, tf.train.latest_checkpoint('.\saved_models'))
graph = tf.get_default_graph()

# restoring relevant tensors/ops
accuracy = graph.get_tensor_by_name("accuracy/Mean:0") #the tensor that when evaluated returns the mean accuracy of the batch
testing_iterator = graph.get_operation_by_name("iterators/Iterator") #my iterator used in testing.
next_testing_element = graph.get_operation_by_name("iterators/IteratorGetNext") #the GetNext operator for my iterator
# loading my testing set tfrecords
testing_dataset = tf.contrib.data.TFRecordDataset(testing_record_path)
testing_dataset = testing_dataset.map(ds._path_records_parser, num_threads=4, output_buffer_size=BATCH_SIZE*20)
testing_dataset = testing_dataset.batch(BATCH_SIZE)

testing_init_op = testing_iterator.make_initializer(testing_dataset) #to initialize the dataset

with tf.Session() as session:
  session.run(testing_init_op)
  while True:
    try:
      images, labels = session.run(next_testing_element)
      accuracy = session.run(accuracy, feed_dict={x: test_images, y_true: test_labels}) #error here, x, y_true not defined
    except tf.errors.OutOfRangeError:
      break

Mon problème est principalement lorsque je restaure le modèle. Comment alimenter les données de test sur le réseau? 

  • Lorsque je restaure mon Iterator en utilisant testing_iterator = graph.get_operation_by_name("iterators/Iterator"), next_testing_element = graph.get_operation_by_name("iterators/IteratorGetNext"), le message d'erreur suivant s'affiche: GetNext() failed because the iterator has not been initialized. Ensure that you have run the initializer operation for this iterator before getting the next element.
  • J'ai donc essayé d'initialiser mon jeu de données en utilisant: testing_init_op = testing_iterator.make_initializer(testing_dataset)). J'ai eu cette erreur: AttributeError: 'Operation' object has no attribute 'make_initializer'

Un autre problème réside dans le fait qu’un itérateur étant utilisé, il n’est pas nécessaire d’utiliser des espaces réservés dans le modèle training_model, car un itérateur alimente les données directement dans le graphique. Mais de cette façon, comment restaurer mes clés feed_dict de la 3ème à la dernière ligne, lorsque je transmets des données à l’opération "exactitude"?

EDIT: si quelqu'un pouvait suggérer un moyen d'ajouter des espaces réservés entre l'Iterator et l'entrée réseau, je pourrais alors essayer d'exécuter le graphique en évaluant le tenseur de "précision" tout en transmettant des données aux espaces réservés et en ignorant complètement l'itérateur.

8
Omar Hommos

Lors de la restauration d'un méta-graphe enregistré, vous pouvez restaurer l'opération d'initialisation avec le nom, puis l'utiliser à nouveau pour initialiser le pipeline d'entrée pour l'inférence. 

Autrement dit, lors de la création du graphique, vous pouvez faire

    dataset_init_op = iterator.make_initializer(dataset, name='dataset_init')

Et puis restaurez cette opération en faisant:

    dataset_init_op = graph.get_operation_by_name('dataset_init')

Voici un extrait de code autonome qui compare les résultats d’un modèle initialisé de manière aléatoire avant et après la restauration.

Enregistrer un itérateur

np.random.seed(42)
data = np.random.random([4, 4])
X = tf.placeholder(dtype=tf.float32, shape=[4, 4], name='X')
dataset = tf.data.Dataset.from_tensor_slices(X)
iterator = tf.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
dataset_next_op = iterator.get_next()

# name the operation
dataset_init_op = iterator.make_initializer(dataset, name='dataset_init')

w = np.random.random([1, 4])
W = tf.Variable(w, name='W', dtype=tf.float32)
output = tf.multiply(W, dataset_next_op, name='output')     
sess = tf.Session()
saver = tf.train.Saver()
sess.run(tf.global_variables_initializer())
sess.run(dataset_init_op, feed_dict={X:data})
while True:
    try:
        print(sess.run(output))
    except tf.errors.OutOfRangeError:
        saver.save(sess, 'tmp/', global_step=1002)
    break

Et vous pouvez ensuite restaurer le même modèle pour l'inférence comme suit:

Restaurer un itérateur sauvegardé

np.random.seed(42)
data = np.random.random([4, 4])
tf.reset_default_graph()
sess = tf.Session()
saver = tf.train.import_meta_graph('tmp/-1002.meta')
ckpt = tf.train.get_checkpoint_state(os.path.dirname('tmp/checkpoint'))
saver.restore(sess, ckpt.model_checkpoint_path)
graph = tf.get_default_graph()

# Restore the init operation
dataset_init_op = graph.get_operation_by_name('dataset_init')

X = graph.get_tensor_by_name('X:0')
output = graph.get_tensor_by_name('output:0')
sess.run(dataset_init_op, feed_dict={X:data})
while True:
try:
    print(sess.run(output))
except tf.errors.OutOfRangeError:
    break
10
metastableB

Je suggérerais d'utiliser tf.contrib.data.make_saveable_from_iterator , qui a été conçu précisément à cet effet. Il est beaucoup moins bavard et ne vous oblige pas à modifier le code existant, en particulier la définition de votre itérateur.

Exemple de travail, lorsque nous sauvegardons tout après l’étape 5. Notez que je ne me soucie même pas de savoir quelle graine est utilisée.

import tensorflow as tf

iterator = (
  tf.data.Dataset.range(100)
  .shuffle(10)
  .make_one_shot_iterator())
batch = iterator.get_next(name='batch')

saveable_obj = tf.contrib.data.make_saveable_from_iterator(iterator)
tf.add_to_collection(tf.GraphKeys.SAVEABLE_OBJECTS, saveable_obj)
saver = tf.train.Saver()

with tf.Session() as sess:
  tf.global_variables_initializer().run()
  for step in range(10):
    print('{}: {}'.format(step, sess.run(batch)))
    if step == 5:
      saver.save(sess, './foo', global_step=step)

# 0: 1
# 1: 6
# 2: 7
# 3: 3
# 4: 8
# 5: 10
# 6: 12
# 7: 14
# 8: 5
# 9: 17

Ensuite, si nous reprenons à partir de l'étape 6, nous obtenons le même résultat.

import tensorflow as tf

saver = tf.train.import_meta_graph('./foo-5.meta')
with tf.Session() as sess:
  saver.restore(sess, './foo-5')
  for step in range(6, 10):
    print('{}: {}'.format(step, sess.run('batch:0')))
# 6: 12
# 7: 14
# 8: 5
# 9: 17
3
P-Gn

Je ne pouvais pas résoudre le problème lié à l'initialisation de l'itérateur, mais depuis que je pré-traite mon ensemble de données en utilisant la méthode map , et que j'applique les transformations définies par les opérations Python encapsulées avec py_func ne peut pas être sérialisé pour stocker/restaurer, je devrai initialiser mon jeu de données quand je veux le restaurer quand même. 

Ainsi, le problème qui reste est de savoir comment alimenter les données en mon graphique lorsque je le restaure. J'ai placé un noeud tf.identity entre la sortie de l'itérateur et mon entrée réseau. Lors de la restauration, je transfère mes données au nœud d’identité. A meilleure solution que j'ai découverte plus tard utilise placeholder_with_default(), comme décrit dans cette réponse

1
Omar Hommos

Je suggérerais de jeter un coup d'œil à CheckpointInputPipelineHook CheckpointInputPipelineHook , qui implémente l'enregistrement de l'état d'itérateur pour une formation ultérieure avec tf.Estimator.

0
Aga