python - network - tensorflow models
"Congelar" algunas variables/ámbitos en tensorflow: stop_gradient vs pasar variables para minimizar (4)
Estoy tratando de implementar Adversarial NN , que requiere ''congelar'' una u otra parte del gráfico durante alternar minibatches de entrenamiento. Es decir, hay dos subredes: G y D.
G( Z ) -> Xz
D( X ) -> Y
donde la función de pérdida de
G
depende de
D[G(Z)], D[X]
.
Primero necesito entrenar parámetros en D con todos los parámetros G fijos, y luego parámetros en G con parámetros en D fijos. La función de pérdida en el primer caso será la función de pérdida negativa en el segundo caso y la actualización tendrá que aplicarse a los parámetros de si la primera o la segunda subred.
Vi que tensorflow tiene la función
tf.stop_gradient
.
Para entrenar la subred D (aguas abajo), puedo usar esta función para bloquear el flujo de gradiente a
Z -> [ G ] -> tf.stop_gradient(Xz) -> [ D ] -> Y
tf.stop_gradient
se
tf.stop_gradient
muy sucinta sin ningún ejemplo en línea (y el ejemplo
seq2seq.py
es demasiado largo y no es tan fácil de leer), pero parece que debe llamarse durante la creación del gráfico.
¿Implica que si quiero bloquear / desbloquear el flujo de gradiente en lotes alternos, necesito volver a crear y reiniciar el modelo gráfico?
También parece que
uno no puede bloquear el gradiente que fluye a través de la red G (aguas arriba) por medio de
tf.stop_gradient
, ¿verdad?
Como alternativa, vi que se puede pasar la lista de variables a la llamada del optimizador como
opt_op = opt.minimize(cost, <list of variables>)
, lo que sería una solución fácil si se pudieran obtener todas las variables en el ámbito de cada subred.
¿Se puede obtener una
<list of variables>
para un tf.scope?
La forma más fácil de lograr esto, como mencionas en tu pregunta, es crear dos operaciones de optimizador usando llamadas separadas para
opt.minimize(cost, ...)
.
Por defecto, el optimizador usará todas las variables en
tf.trainable_variables()
.
Si desea filtrar las variables a un alcance particular, puede usar el argumento de
scope
opcional para
tf.get_collection()
siguiente manera:
optimizer = tf.train.AdagradOptimzer(0.01)
first_train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
"scope/prefix/for/first/vars")
first_train_op = optimizer.minimize(cost, var_list=first_train_vars)
second_train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
"scope/prefix/for/second/vars")
second_train_op = optimizer.minimize(cost, var_list=second_train_vars)
La respuesta de @ mrry es completamente correcta y quizás más general de lo que estoy a punto de sugerir.
Pero creo que una forma más sencilla de lograrlo es pasar la referencia de Python directamente a
var_list
:
W = tf.Variable(...)
C = tf.Variable(...)
Y_est = tf.matmul(W,C)
loss = tf.reduce_sum((data-Y_est)**2)
optimizer = tf.train.AdamOptimizer(0.001)
# You can pass the python object directly
train_W = optimizer.minimize(loss, var_list=[W])
train_C = optimizer.minimize(loss, var_list=[C])
Tengo un ejemplo autónomo aquí: https://gist.github.com/ahwillia/8cedc710352eb919b684d8848bc2df3a
No sé si mi enfoque tiene inconvenientes, pero resolví este problema por mí mismo con esta construcción:
do_gradient = <Tensor that evaluates to 0 or 1>
no_gradient = 1 - do_gradient
wrapped_op = do_gradient * original + no_gradient * tf.stop_gradient(original)
Entonces, si
do_gradient = 1
, los valores y los gradientes fluirán bien, pero si
do_gradient = 0
, entonces los valores solo fluirán a través de stop_gradient op, lo que detendrá el flujo de los gradientes.
Para mi escenario, conectar do_gradient a un índice de un tensor random_shuffle me permitió entrenar aleatoriamente diferentes partes de mi red.
Otra opción que quizás desee considerar es que puede establecer entrenable = Falso en una variable. Lo que significa que no será modificado por el entrenamiento.
tf.Variable(my_weights, trainable=False)