Python 将tensorflow梯度应用于特定输入

Python 将tensorflow梯度应用于特定输入,python,tensorflow,machine-learning,keras,Python,Tensorflow,Machine Learning,Keras,我试图创建一个雅可比矩阵,用于特定的输出变量,与keras模型中的特定输入特征有关。例如,如果我有一个具有100个输入特征和10个输出变量的模型,并且我想要创建一个输出2、3和4的雅可比矩阵,相对于输出50-70,我可以创建如下雅可比矩阵: from keras.models import Model from keras.layers import Dense, Input import tensorflow as tf import keras.backend as K import num

我试图创建一个雅可比矩阵,用于特定的输出变量,与keras模型中的特定输入特征有关。例如,如果我有一个具有100个输入特征和10个输出变量的模型,并且我想要创建一个输出2、3和4的雅可比矩阵,相对于输出50-70,我可以创建如下雅可比矩阵:

from keras.models import Model
from keras.layers import Dense, Input
import tensorflow as tf
import keras.backend as K
import numpy as np

input_ = Input(shape=(100,))
output_ = Dense(10)(input_)

model = Model(input_,output_)

x_indices = np.arange(50,70)
y_indices = [2,3,4]

y_list = tf.unstack(model.output[0])

x = np.random.random((1,100))

jacobian_matrix = []
for i in y_indices:
    J = tf.gradients(y_list[i], model.input)
    jacobian_func = K.function([model.input, K.learning_phase()], J)
    jac = jacobian_func([x, False])[0][0,x_indices]
    jacobian_matrix.append(jac)
jacobian_matrix = np.array(jacobian_matrix)
from keras.models import Model
from keras.layers import Dense, Input
import tensorflow as tf
import keras.backend as K
import numpy as np

input_ = Input(shape=(100,))
output_ = Dense(10)(input_)

model = Model(input_,output_)

x_indices = np.arange(50,60)
y_indices = [2,3,4]

y_list = tf.unstack(model.output[0])
x_list = tf.unstack(model.input[0])

x = np.random.random((1,100))

jacobian_matrix = []
for i in y_indices:
    jacobian_row = []
    for j in x_indices:
        J = tf.gradients(y_list[i], x_list[j])
        jacobian_func = K.function([model.input, K.learning_phase()], J)
        jac = jacobian_func([x, False])[0][0,:]
        jacobian_row.append(jac)
    jacobian_matrix.append(jacobian_row)

jacobian_matrix = np.array(jacobian_matrix)
但对于更复杂的模型来说,这是非常缓慢的。我只想创建上面关于感兴趣的输入的雅可比函数。我试过这样的方法:

from keras.models import Model
from keras.layers import Dense, Input
import tensorflow as tf
import keras.backend as K
import numpy as np

input_ = Input(shape=(100,))
output_ = Dense(10)(input_)

model = Model(input_,output_)

x_indices = np.arange(50,70)
y_indices = [2,3,4]

y_list = tf.unstack(model.output[0])

x = np.random.random((1,100))

jacobian_matrix = []
for i in y_indices:
    J = tf.gradients(y_list[i], model.input)
    jacobian_func = K.function([model.input, K.learning_phase()], J)
    jac = jacobian_func([x, False])[0][0,x_indices]
    jacobian_matrix.append(jac)
jacobian_matrix = np.array(jacobian_matrix)
from keras.models import Model
from keras.layers import Dense, Input
import tensorflow as tf
import keras.backend as K
import numpy as np

input_ = Input(shape=(100,))
output_ = Dense(10)(input_)

model = Model(input_,output_)

x_indices = np.arange(50,60)
y_indices = [2,3,4]

y_list = tf.unstack(model.output[0])
x_list = tf.unstack(model.input[0])

x = np.random.random((1,100))

jacobian_matrix = []
for i in y_indices:
    jacobian_row = []
    for j in x_indices:
        J = tf.gradients(y_list[i], x_list[j])
        jacobian_func = K.function([model.input, K.learning_phase()], J)
        jac = jacobian_func([x, False])[0][0,:]
        jacobian_row.append(jac)
    jacobian_matrix.append(jacobian_row)

jacobian_matrix = np.array(jacobian_matrix)
并得到了错误信息:

TypeErrorTraceback (most recent call last)
<ipython-input-33-d0d524ad0e40> in <module>()
     23     for j in x_indices:
     24         J = tf.gradients(y_list[i], x_list[j])
---> 25         jacobian_func = K.function([model.input, K.learning_phase()], J)
     26         jac = jacobian_func([x, False])[0][0,:]
     27         jacobian_row.append(jac)

/opt/conda/lib/python2.7/site-packages/keras/backend/tensorflow_backend.pyc in function(inputs, outputs, updates, **kwargs)
   2500                 msg = 'Invalid argument "%s" passed to K.function with TensorFlow backend' % key
   2501                 raise ValueError(msg)
-> 2502     return Function(inputs, outputs, updates=updates, **kwargs)
   2503 
   2504 

/opt/conda/lib/python2.7/site-packages/keras/backend/tensorflow_backend.pyc in __init__(self, inputs, outputs, updates, name, **session_kwargs)
   2443         self.inputs = list(inputs)
   2444         self.outputs = list(outputs)
-> 2445         with tf.control_dependencies(self.outputs):
   2446             updates_ops = []
   2447             for update in updates:

/opt/conda/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in control_dependencies(control_inputs)
   4302   """
   4303   if context.in_graph_mode():
-> 4304     return get_default_graph().control_dependencies(control_inputs)
   4305   else:
   4306     return _NullContextmanager()

/opt/conda/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in control_dependencies(self, control_inputs)
   4015       if isinstance(c, IndexedSlices):
   4016         c = c.op
-> 4017       c = self.as_graph_element(c)
   4018       if isinstance(c, Tensor):
   4019         c = c.op

/opt/conda/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in as_graph_element(self, obj, allow_tensor, allow_operation)
   3033 
   3034     with self._lock:
-> 3035       return self._as_graph_element_locked(obj, allow_tensor, allow_operation)
   3036 
   3037   def _as_graph_element_locked(self, obj, allow_tensor, allow_operation):

/opt/conda/lib/python2.7/site-packages/tensorflow/python/framework/ops.pyc in _as_graph_element_locked(self, obj, allow_tensor, allow_operation)
   3122       # We give up!
   3123       raise TypeError("Can not convert a %s into a %s." % (type(obj).__name__,
-> 3124                                                            types_str))
   3125 
   3126   def get_operations(self):

TypeError: Can not convert a NoneType into a Tensor or Operation.

有什么想法吗?谢谢。

问题在于行J=tf.gradientsy_list[i],x_list[J]。x_列表[j]是从model.input[0]派生的,但从x_列表[j]到model.output[0]没有定向路径。您需要取消堆叠模型输入,重新堆叠然后运行模型,或者创建与整个输入相关的导数,然后从中选择第j行

第一种方式:

inputs = tf.keras.Inputs((100,))
uninteresting, interesting, more_uninteresting = tf.split(inputs, [50, 10, 40], axis=1)
inputs = tf.concat([uninteresting, interesting, more_uninteresting], axis=1)
model = Model(inputs)
...
J, = tf.gradients(y_list[i], interesting)
第二种方式:

J, = tf.gradients(y_list[i], model.input[0])
J = J[:, 50:60]

话虽如此,对于大量的y指数来说,这仍然是一个缓慢的过程,因此我强烈建议您绝对确定您需要的是雅可比矩阵本身,而不是雅可比矩阵向量积的结果。

如果有人想要一个关于@DomJacks答案的完整解决方案:

from keras.models import Model
from keras.layers import Dense, Input, Concatenate
import tensorflow as tf
import keras.backend as K
import numpy as np

num_features = 100
input_ = Input(shape=(num_features,))
output_ = Dense(10)(input_)

model = Model(input_,output_)

# input range of interest
x_range = [50,70]
# output indices of interest
y_indices = [2,3,4]

# If model is saved, you can load using: 
#model = keras.models.load_model(filepath)
# then grab the input:
input_ = model.input

# Split inputs
uninteresting, interesting, more_uninteresting = tf.split(input_, [x_range[0], 
                                                                   x_range[1]-x_range[0], 
                                                                   num_features-x_range[1]], 
                                                          axis=1)
# Create new process
inputs = Concatenate()([uninteresting, interesting, more_uninteresting])
y = model(inputs)
y_list = tf.unstack(y[0])
x = np.random.random((1,num_features))

# Create Jacobian matrix
jacobian_matrix = []
for i in y_indices:
    J = tf.gradients(y_list[i], interesting)
    jacobian_func = K.function([input_, K.learning_phase()], J)
    jac = jacobian_func([x, False])[0][0]
    jacobian_matrix.append(jac)
jacobian_matrix = np.array(jacobian_matrix)

由于某种原因,J看起来是None,这发生在前向传递中没有从输入到输出的定向路径时,就像这里的情况一样。请看下面的答案。谢谢你,杰克。你能解释一下雅可比矢量积是什么吗?我希望获得直觉,了解个别输入特征如何影响某些输出,并进一步了解神经网络发现的相关性。这能帮我实现吗?你可以近似得到雅可比向量积Jx*v=Fx+eps*v-Fx/eps。这比计算整个雅可比矩阵要便宜得多。另一方面,如果您想要向前的差异,即更改1个输入对所有输出的影响,请再次查看“谢谢”。你提到的第一种方法很有效,尽管我不知道如何使用第二种方法。对于你在评论中提到的链接中的雅可比向量积,在我的例子中,向量v是什么?v是你想要的。关键是,计算整个雅可比矩阵是昂贵的,如果你只需要矩阵向量积,也就是说,出于某种原因,你想知道Jx*v。如果不知道您的用例,很难说这是否有用。