web-dev-qa-db-fra.com

Tensorflow minimiser par rapport à seulement certains éléments d'une variable

Est-il possible de minimiser une fonction de perte en ne modifiant que certains éléments d'une variable? En d'autres termes, si j'ai une variable X de longueur 2, comment puis-je minimiser ma fonction de perte en modifiant X[0] et en maintenant X[1] constant?

Espérons que ce code que j'ai essayé décrira mon problème:

import tensorflow as tf
import tensorflow.contrib.opt as opt

X = tf.Variable([1.0, 2.0])
X0 = tf.Variable([3.0])

Y = tf.constant([2.0, -3.0])

scatter = tf.scatter_update(X, [0], X0)

with tf.control_dependencies([scatter]):
    loss = tf.reduce_sum(tf.squared_difference(X, Y))

opt = opt.ScipyOptimizerInterface(loss, [X0])

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    opt.minimize(sess)

    print("X: {}".format(X.eval()))
    print("X0: {}".format(X0.eval()))

qui produit:

INFO:tensorflow:Optimization terminated with:
  Message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
  Objective function value: 26.000000
  Number of iterations: 0
  Number of functions evaluations: 1
X: [3. 2.]
X0: [3.]

où j'aimerais trouver la valeur optimale de X0 = 2 et donc X = [2, 2]

modifier

Motivation pour cela: je voudrais importer un graphique/modèle formé, puis modifier différents éléments de certaines variables en fonction de certaines nouvelles données dont je dispose. 

8
Jeff

Vous pouvez utiliser cette astuce pour limiter le calcul du gradient à un seul index:

import tensorflow as tf
import tensorflow.contrib.opt as opt

X = tf.Variable([1.0, 2.0])

part_X = tf.scatter_nd([[0]], [X[0]], [2])

X_2 = part_X + tf.stop_gradient(-part_X + X)

Y = tf.constant([2.0, -3.0])

loss = tf.reduce_sum(tf.squared_difference(X_2, Y))

opt = opt.ScipyOptimizerInterface(loss, [X])

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    opt.minimize(sess)

    print("X: {}".format(X.eval()))

part_X devient la valeur que vous souhaitez modifier dans un vecteur ponctuel de même forme que X. part_X + tf.stop_gradient(-part_X + X) est identique à X dans le passage en aval, puisque part_X - part_X est à 0. Toutefois, dans le passage en arrière, le tf.stop_gradient empêche tous les calculs de dégradé inutiles.

5
BlueSun

Cela devrait être assez facile à faire en utilisant le paramètre var_list de la fonction minimize.

trainable_var = X[0]
train_op = tf.train.GradientDescentOptimizer(learning_rate=1e-3).minimize(loss, var_list=[trainable_var])

Vous devriez noter que, par convention, toutes les variables pouvant être entraînées sont ajoutées à la collection par défaut tensorflow GraphKeys.TRAINABLE_VARIABLES, afin que vous puissiez obtenir une liste de toutes les variables pouvant être entraînées en utilisant:

all_trainable_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)

Ceci est juste une liste de variables que vous pouvez manipuler à votre guise et que vous utilisez comme paramètre var_list.

Pour répondre à votre question, si vous souhaitez approfondir la personnalisation du processus d'optimisation, vous pouvez également calculer les dégradés manuellement à l'aide de grads = tf.gradients(loss, var_list), manipuler les dégradés à votre guise, puis appeler tf.train.GradientDescentOptimizer(...).apply_gradients(grads_and_vars_as_list_of_tuples). Sous le capot, minimisez, vous ne faites que ces deux étapes.

Notez également que vous êtes parfaitement libre de créer différents optimiseurs pour différentes collections de variables. Vous pouvez créer un optimiseur SGD avec un taux d’apprentissage de 1e-4 pour certaines variables et un autre optimiseur Adam avec un taux d’apprentissage de 1e-2 pour un autre ensemble de variables. Ce n’est pas qu’il y ait un cas d’utilisation spécifique pour cela, je souligne simplement la flexibilité dont vous disposez maintenant.

1
David Parks

Je ne sais pas si cela est possible avec l'interface de l'optimiseur SciPy, mais en utilisant l'une des sous-classes tf.train.Optimizer habituelles, vous pouvez le faire en appelant compute_gradients , puis en masquant les gradients, puis en appelant apply_gradients , au lieu d’appeler minimize (qui, comme le dit la documentation, appelle essentiellement les précédents).

import tensorflow as tf

X = tf.Variable([3.0, 2.0])
# Select updatable parameters
X_mask = tf.constant([True, False], dtype=tf.bool)
Y = tf.constant([2.0, -3.0])
loss = tf.reduce_sum(tf.squared_difference(X, Y))
opt = tf.train.GradientDescentOptimizer(learning_rate=0.1)
# Get gradients and mask them
((X_grad, _),) = opt.compute_gradients(loss, var_list=[X])
X_grad_masked = X_grad * tf.cast(X_mask, dtype=X_grad.dtype)
# Apply masked gradients
train_step = opt.apply_gradients([(X_grad_masked, X)])

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    for i in range(10):
        _, X_val = sess.run([train_step, X])
        print("Step {}: X = {}".format(i, X_val))
    print("Final X = {}".format(X.eval()))

Sortie:

Step 0: X = [ 2.79999995  2.        ]
Step 1: X = [ 2.63999987  2.        ]
Step 2: X = [ 2.51199985  2.        ]
Step 3: X = [ 2.40959978  2.        ]
Step 4: X = [ 2.32767987  2.        ]
Step 5: X = [ 2.26214385  2.        ]
Step 6: X = [ 2.20971513  2.        ]
Step 7: X = [ 2.16777205  2.        ]
Step 8: X = [ 2.13421774  2.        ]
Step 9: X = [ 2.10737419  2.        ]
Final X = [ 2.10737419  2.        ]
1
jdehesa