Gradiente de flujo tensor con respecto a la matriz.

Solo por contexto, estoy tratando de implementar un algoritmo de descenso de gradiente con Tensorflow.

Tengo una matriz X

 [ x1 x2 x3 x4 ] [ x5 x6 x7 x8 ] 

que multiplico por algún vector de característica Y para obtener Z

  [ y1 ] Z = X [ y2 ] = [ z1 ] [ y3 ] [ z2 ] [ y4 ] 

Luego puse Z a través de una función softmax, y tomo el registro. Me referiré a la matriz de salida como W.

Todo esto se implementa de la siguiente manera (se agrega un poco de repetitivo por lo que se puede ejecutar)

 sess = tf.Session() num_features = 4 num_actions = 2 policy_matrix = tf.get_variable("params", (num_actions, num_features)) state_ph = tf.placeholder("float", (num_features, 1)) action_linear = tf.matmul(params, state_ph) action_probs = tf.nn.softmax(action_linear, axis=0) action_problogs = tf.log(action_probs) 

W (correspondiente a action_problogs ) se parece a

 [ w1 ] [ w2 ] 

Me gustaría encontrar el gradiente de w1 con respecto a la matriz X , es decir, me gustaría calcular

  [ d/dx1 w1 ] d/dX w1 = . . [ d/dx8 w1 ] 

(De preferencia, todavía parece una matriz, así que puedo agregarla a X , pero realmente no me preocupa eso)

Esperaba que tf.gradients hiciera el truco. Calculé el “gradiente” como tal

 problog_gradient = tf.gradients(action_problogs, policy_matrix) 

Sin embargo, cuando inspecciono problog_gradient , esto es lo que obtengo

 [] 

Tenga en cuenta que esto tiene exactamente la misma forma que X , pero que realmente no debería. Esperaba obtener una lista de dos gradientes, cada uno con respecto a 8 elementos. Sospecho que en cambio estoy obteniendo dos gradientes, pero cada uno con respecto a cuatro elementos.

Soy muy nuevo en tensorflow, por lo que agradecería una explicación de lo que está pasando y cómo podría lograr el comportamiento que deseo.

El degradado espera una función escalar, por lo que, de forma predeterminada, resume las entradas. Ese es el comportamiento predeterminado simplemente porque todos los algoritmos de descenso de gradiente necesitan ese tipo de funcionalidad, y el descenso de gradiente estocástico (o variaciones de los mismos) son los métodos preferidos dentro de Tensorflow. No encontrará ninguno de los algoritmos más avanzados (como BFGS o algo así) porque simplemente no se han implementado todavía (y requerirían un verdadero jacobiano, que tampoco se ha implementado). Para lo que vale, aquí hay una implementación jacobiana funcional que escribí:

 def map(f, x, dtype=None, parallel_iterations=10): ''' Apply f to each of the elements in x using the specified number of parallel iterations. Important points: 1. By "elements in x", we mean that we will be applying f to x[0],...x[tf.shape(x)[0]-1]. 2. The output size of f(x[i]) can be arbitrary. However, if the dtype of that output is different than the dtype of x, then you need to specify that as an additional argument. ''' if dtype is None: dtype = x.dtype n = tf.shape(x)[0] loop_vars = [ tf.constant(0, n.dtype), tf.TensorArray(dtype, size=n), ] _, fx = tf.while_loop( lambda j, _: j < n, lambda j, result: (j + 1, result.write(j, f(x[j]))), loop_vars, parallel_iterations=parallel_iterations ) return fx.stack() def jacobian(fx, x, parallel_iterations=10): ''' Given a tensor fx, which is a function of x, vectorize fx (via tf.reshape(fx, [-1])), and then compute the jacobian of each entry of fx with respect to x. Specifically, if x has shape (m,n,...,p), and fx has L entries (tf.size(fx)=L), then the output will be (L,m,n,...,p), where output[i] will be (m,n,...,p), with each entry denoting the gradient of output[i] wrt the corresponding element of x. ''' return map(lambda fxi: tf.gradients(fxi, x)[0], tf.reshape(fx, [-1]), dtype=x.dtype, parallel_iterations=parallel_iterations) 

Si bien esta implementación funciona, no funciona cuando intenta anidarla. Por ejemplo, si intentas calcular la arpillera utilizando jacobian( jacobian( ... )) , obtendrás algunos errores extraños. Esto se está rastreando como Número 675 . Todavía estoy esperando una respuesta sobre por qué esto produce un error. Creo que hay un error muy arraigado en la implementación del bucle while o en la implementación de gradiente, pero realmente no tengo idea.

De todos modos, si solo necesitas un jacobiano, prueba el código de arriba.

tf.gradients realidad sum los ys y calcula el gradiente de eso, por lo que este problema está ocurriendo.