使用梯度胶带作为 LSTM 模型的雅可比行列式 - Python

问题描述

我正在使用 LSTM 构建一个序列到一个模型的预测。我的数据有 4 个输入变量和 1 个需要预测的输出变量。数据是时间序列数据。数据的总长度为 38265(总时间步数)。总数据在大小为 38265 *5 的 Data Frame 中

我想使用 4 个输入变量的前 20 个时间步数据来预测我的输出变量。为此,我正在使用以下代码

model = Sequential()

model.add(LSTM(units = 120,activation ='relu',return_sequences = False,input_shape = 
(train_in.shape[1],5)))
model.add(Dense(100,activation='relu'))
model.add(Dense(50,activation='relu'))

model.add(Dense(1))

我想使用 tf.Gradient Tape 计算输出变量 w.r.t LSTM 模型函数的雅可比矩阵 .. 谁能帮我解决这个问题??

解决方法

分离输出相对于 LSTM 输入的雅可比行列式的解决方案可以如下完成:

  1. 使用 tf.GradientTape(),我们可以计算梯度流产生的雅可比行列式。

  2. 然而,为了获得 Jacobian ,输入需要采用 tf.EagerTensor 的形式,当我们想要查看输出的 Jacobian 时(在执行 y=model(x) 之后),它通常可用。以下代码片段分享了这个想法:

#Get the Jacobian for each persistent gradient evaluation
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(2,activation='relu'))
model.add(tf.keras.layers.Dense(2,activation='relu'))
x = tf.constant([[5.,6.,3.]])

with tf.GradientTape(persistent=True,watch_accessed_variables=True) as tape:
  # Forward pass
  tape.watch(x)
  y = model(x)
  loss = tf.reduce_mean(y**2)
print('Gradients\n')
jacobian_wrt_loss=tape.jacobian(loss,x)
print(f'{jacobian_wrt_loss}\n')
jacobian_wrt_y=tape.jacobian(y,x)
print(f'{jacobian_wrt_y}\n')
  1. 但是为了获得中间输出,例如在这种情况下,已经有很多使用 Keras 的样本。当我们将来自 model.layers.output 的输出分开时,我们得到的类型是 Keras.Tensor 而不是 EagerTensor。 然而,为了创建雅可比矩阵,我们需要 Eager Tensor。 (在多次尝试使用 @tf.function 包装失败后,因为 TF>2.0 中已经存在急切执行)

  2. 因此,或者,可以使用所需的层(在这种情况下,只有 Input 和 LSTM 层)创建辅助模型。该模型的输出将是一个 tf.EagerTensor,这对 Jacobian 矩阵很有用张量创建。此代码段中显示了以下内容:

#General Syntax for getting jacobians for each layer output
import numpy as np
import tensorflow as tf
tf.executing_eagerly()
x=tf.constant([[15.,60.,32.]])
x_inp = tf.keras.layers.Input(tensor=tf.constant([[15.,32.]]))
model=tf.keras.Sequential()
model.add(tf.keras.layers.Dense(2,activation='relu',name='dense_1'))
model.add(tf.keras.layers.Dense(2,name='dense_2'))

aux_model=tf.keras.Sequential()
aux_model.add(tf.keras.layers.Dense(2,name='dense_1'))
#model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

with tf.GradientTape(persistent=True,watch_accessed_variables=True) as tape:
  # Forward pass
  tape.watch(x)
  x_y = model(x)
  act_y=aux_model(x)
  print(x_y,type(x_y))
  ops=[layer.output for layer in model.layers]
    
# ops=[layer.output for layer in model.layers]
# inps=[layer.input for layer in model.layers]
print('Jacobian of Full FFNN\n')
jacobian=tape.jacobian(x_y,x)
print(f'{jacobian[0]}\n')

print('Jacobian of FFNN with Just first Dense\n')
jacobian=tape.jacobian(act_y,x)
print(f'{jacobian[0]}\n')

这里我使用了一个由 2 个 Dense 层组成的简单 FFNN,但我想评估第一个 Dense 层的输出。因此,我创建了一个只有 1 个 Dense 层的辅助模型,并从中确定了雅可比矩阵的输出。

详情见here

,

在@Abhilash Majumder 的帮助下,我已经这样做了。我把它张贴在这里,以便将来可能对某人有所帮助。 将 numpy 导入为 np 将熊猫导入为 pd 将张量流导入为 tf tf.compat.v1.enable_eager_execution() #这将启用急切执行,这是必须的。

tf.executing_eagerly() #check if eager execution is enabled or not. Should give "True"

data = pd.read_excel("FileName or Location ")
#My data is in the from of dataframe with 127549 rows and 5 columns(127549*5)

a = data[:20]  #shape is (20,5)
b = data[50:70] # shape is (20,5)
A = [a,b]  # making a list
A = np.array(A) # convert into array size (2,20,5) 

At = tf.convert_to_tensor(A,np.float32) #convert into tensor
At.shape # TensorShape([Dimension(2),Dimension(20),Dimension(5)])

model = load_model('EKF-LSTM-1.h5') # Load the trained model
# I have a trained model which is shown in the question above. 
# Output of this model is a single value

with tf.GradientTape(persistent=True,watch_accessed_variables=True) as tape:

tape.watch(At)
y1 = model(At) #defining your output as a function of input variables
print(y1,type(y1)

#output 
tf.Tensor([[0.04251503],[0.04634088]],shape=(2,1),dtype=float32) <class 
'tensorflow.python.framework.ops.EagerTensor'>

jacobian=tape.jacobian(y1,At) #jacobian of output w.r.t both inputs
jacobian.shape 

输出

TensorShape([Dimension(2),Dimension(1),Dimension(2),Dimension(5)])

这里我计算了 Jacobian w.r.t 2 个输入,每个输入的大小为 (20,5)。如果您只想将 w.r.t 计算为大小为 (20,5) 的一个输入,请使用此

jacobian=tape.jacobian(y1,At[0]) #jacobian of output w.r.t only 1st input in 'At'
jacobian.shape 

输出

TensorShape([Dimension(1),Dimension(5)])

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...