2016-06-16 2 views
0

Je voudrais maintenir une variable sur le GPU, et effectuer certaines opérations sur cette variable en place. L'extrait suivant est un exemple minimal de ceci.condition de la course de fixation dans tensorflow

import numpy as np 
import tensorflow as tf 

with tf.Graph().as_default(): 

    i = tf.placeholder(tf.int32, [4], name='i') 
    y = tf.placeholder(tf.float32, [4], name='y') 
    _x = tf.get_variable('x', [4], initializer=tf.random_normal_initializer()) 
    x = _x + tf.reduce_sum(tf.mul(_x,y)) 
    assign_op = tf.assign(_x, x).op 
    permute_op = tf.assign(_x, tf.gather(_x, i)) 

    ii = np.array([1,2,3,0]) 
    yy = np.random.randn(4) 

    s = tf.Session() 
    s.run(tf.initialize_all_variables()) 
    xxx0 = s.run(_x) 
    s.run([permute_op, assign_op], feed_dict={i: ii, y: yy}) 
    xxx1 = s.run(_x) 
    print('assigned then permuted', np.allclose((xxx0+np.dot(xxx0,yy))[ii], xxx1)) 
    print('permuted then assigned', np.allclose((xxx0[ii]+np.dot(xxx0[ii], yy)), xxx1)) 

Le problème est que ce programme est ambigu, en termes de l'ordre des opérations de assign_op et permute_op. Par conséquent, l'une ou l'autre des deux dernières instructions d'impression sera vraie, mais celle qui est varie de façon aléatoire entre plusieurs exécutions du programme. Je pourrais casser ceci en deux étapes, la première exécutant le permute_op et la deuxième exécutant le assign_op, mais il semble que ce soit moins efficace. Y at-il un moyen efficace de briser les conditions de concurrence et de rendre les résultats prévisibles?

Répondre

0

La méthode la plus simple pour commander les deux affectations consiste à utiliser le résultat de la première affectation en tant qu'entrée variable de la seconde. Cela crée une dépendance des données entre les affectations, ce qui leur donne un ordre déterministe. Par exemple:

assigned = tf.assign(_x, x) 
permuted = tf.assign(assigned, tf.gather(assigned, i)) 

sess.run(permuted.op) # Runs both assignments. 

Notez que je renversé l'ordre des opérations de permutation et d'affectation de ce que vous avez dit dans votre question, parce que faire la permutation d'abord, puis la mise à jour a encore une course. Même si ce n'est pas la sémantique souhaitée, le principe devrait être clair.

Une autre approche consiste à utiliser with tf.control_dependencies(ops): blocs, où ops une liste des opérations (telles que les cessions) qui doivent exécuter avant les opérations dans le bloc with. C'est un peu plus délicat à utiliser, car vous devez faire attention à en lisant la valeur mise à jour d'une variable. (Comme une variable non volatile en C, la lecture peut être mis en mémoire cache.) Le langage typique pour forcer une lecture est d'utiliser tf.identity(var.ref()), donc l'exemple ressemblerait à quelque chose comme:

assign_op = tf.assign(_x, x).op 

with tf.control_dependencies([assign_op]): 
    # Read updated value of `_x` after `assign_op`. 
    new_perm = tf.gather(tf.identity(_x.ref()), i) 
    permute_op = tf.assign(_x, new_perm).op 

sess.run(permute_op) # Runs both assignments. 
+0

explication Nice, merci. – user6473715