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.
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.
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.
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. ]