neural network - ¿Usando SparseTensor como variable entrenable?
neural-network sparse-matrix (4)
TensorFlow no admite actualmente variables de tensor dispersas. Sin embargo, admite búsquedas dispersas ( tf.embedding_lookup
) y actualizaciones de gradiente dispersas ( tf.sparse_add
) de variables densas. Sospecho que estos dos serán suficientes para su caso de uso.
Intento usar SparseTensor para representar variables de peso en una capa completamente conectada.
Sin embargo, parece que TensorFlow 0.8 no permite usar SparseTensor como tf.Variable.
¿Hay alguna forma de evitar esto?
He intentado
import tensorflow as tf
a = tf.constant(1)
b = tf.SparseTensor([[0,0]],[1],[1,1])
print a.__class__ # shows <class ''tensorflow.python.framework.ops.Tensor''>
print b.__class__ # shows <class ''tensorflow.python.framework.ops.SparseTensor''>
tf.Variable(a) # Variable is declared correctly
tf.Variable(b) # Fail
Por cierto, mi objetivo final de usar SparseTensor es enmascarar permanentemente algunas de las conexiones en forma densa. Por lo tanto, estas conexiones eliminadas se ignoran al calcular y aplicar gradientes .
En mi implementación actual de MLP, SparseTensor y su forma dispersa de matmul ops informa exitosamente salidas de inferencia. Sin embargo, los pesos declarados con SparseTensor no están entrenados como lo hacen los pasos de entrenamiento.
Como una solución a su problema, puede proporcionar un tf.Variable
(hasta Tensorflow v0.8
) para los valores de un tensor disperso. La estructura de dispersión debe predefinirse en ese caso, sin embargo, los pesos se pueden entrenar.
weights = tf.Variable(<initial-value>)
sparse_var = tf.SparseTensor(<indices>, weights, <shape>) # v0.8
sparse_var = tf.SparseTensor(<indices>, tf.identity(weights), <shape>) # v0.9
TensorFlow aún no es compatible con el entrenamiento en tensores dispersos. Puedes inicializar un tensor disperso como desees, luego convertirlo en un tensor denso y crear una variable como esta:
# You need to correctly initialize the sparse tensor with indices, values and a shape
b = tf.SparseTensor(indices, values, shape)
b_dense = tf.sparse_tensor_to_dense(b)
b_variable = tf.Variable(b_dense)
Ahora ha inicializado un tensor disperso como variable. Ahora tiene que encargarse de la actualización del degradado (en otras palabras, asegúrese de que las entradas en la variable permanezcan en 0, ya que hay un gradiente que no se desvanece calculado en el algoritmo de retropropagación para ellas al usar esto ingenuamente).
Para hacer esto, los optimizadores de TensorFlow tienen un método llamado tf.train.Optimizer.compute_gradients (loss, [list_of_variables]) . Esto calcula todos los degradados en el gráfico necesarios para minimizar la función de pérdida, pero aún no los aplica. Este método devuelve una lista de tuplas en forma de (gradientes, variable). Puede modificar estos degradados libremente, pero en su caso tiene sentido enmascarar los gradientes no necesarios a 0 (es decir, creando otro tensor disperso con valores por defecto de 0.0 y valores 1.0 donde están presentes los pesos en su red). Después de haberlos modificado, llame al método optimizador tf.train.Optimizer.apply_gradients (grads_and_vars) para aplicar realmente los degradados. Un código de ejemplo se vería así:
# Create optimizer instance
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
# Get the gradients for your weights
grads_and_vars = optimizer.compute_gradients(loss, [b_variable])
# Modify the gradients at will
# In your case it would look similar to this
modified_grads_and_vars = [(tf.multiply(gv[0], mask_tensor), gv[1] for gv in grads_and_vars]
# Apply modified gradients to your model
optimizer.apply_gradients(modified_grads_and_vars)
Esto asegura que sus entradas se mantengan 0 en su matriz de peso y no se creen conexiones no deseadas. Debes ocuparte de todos los demás degradados para todas las demás variables más adelante.
El código anterior funciona con algunas correcciones menores como esta.
def optimize (pérdida, mask_tensor): optimizer = tf.train.AdamOptimizer (0.001) grads_and_vars = optimizer.compute_gradients (loss) modified_grads_and_vars = [(tf.multiply (gv [0], mask_tensor [gv [1]]), gv [ 1]) para gv en grads_and_vars] return optimizer.apply_gradients (modified_grads_and_vars)