Tensorflow minimiza con respecto a solo algunos elementos de una variable

¿Es posible minimizar una función de pérdida cambiando solo algunos elementos de una variable? En otras palabras, si tengo una variable X de longitud 2, ¿cómo puedo minimizar mi función de pérdida cambiando X[0] y manteniendo constante X[1] ?

Espero que este código que he intentado describa mi problema:

 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())) 

que produce:

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

donde me gustaría encontrar el valor óptimo de X0 = 2 y por lo tanto X = [2, 2]

editar

Motivación para hacer esto: me gustaría importar un gráfico / modelo entrenado y luego ajustar varios elementos de algunas de las variables en función de los nuevos datos que tengo.

Puedes usar este truco para restringir el cálculo del gradiente a un índice:

 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 convierte en el valor que desea cambiar en un vector de la misma forma que X. part_X + tf.stop_gradient(-part_X + X) es el mismo que X en el paso hacia adelante, ya que part_X - part_X es 0. Sin embargo en el paso hacia atrás, tf.stop_gradient evita todos los cálculos de gradiente innecesarios.

No estoy seguro de si es posible con la interfaz del optimizador SciPy, pero al usar una de las subclases tf.train.Optimizer regulares, puede hacer algo así llamando primero a compute_gradients , luego enmascarando los gradientes y luego llamando a apply_gradients , en lugar de llamar minimize (lo que, como dicen los documentos, básicamente llama a los anteriores).

 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())) 

Salida:

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

Esto debería ser bastante fácil de hacer usando el parámetro var_list de la función de minimize .

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

Debe tener en cuenta que, por convención, todas las variables entrenables se agregan a la colección predeterminada de GraphKeys.TRAINABLE_VARIABLES , para que pueda obtener una lista de todas las variables entrenables utilizando:

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

Esta es solo una lista de variables que puede manipular como mejor le parezca y use como el parámetro var_list .

Como una tangente a su pregunta, si alguna vez desea llevar un paso más el proceso de optimización de la personalización, también puede calcular los gradientes manualmente utilizando grads = tf.gradients(loss, var_list) manipule los gradientes como lo considere oportuno, luego llame a tf.train.GradientDescentOptimizer(...).apply_gradients(grads_and_vars_as_list_of_tuples) . Bajo el capó, minimizar solo está haciendo estos dos pasos por ti.

También tenga en cuenta que es perfectamente libre para crear diferentes optimizadores para diferentes colecciones de variables. Podría crear un optimizador SGD con una tasa de aprendizaje 1e-4 para algunas variables, y otro optimizador Adam con una tasa de aprendizaje 1e-2 para otro conjunto de variables. No es que exista un caso de uso específico para esto, solo estoy señalando la flexibilidad que ahora tiene.