如何在 Keras 中找到自定义模型的导数?
How do I find the derivative of a custom model in Keras?
我有一个自定义模型,它采用任意 "hidden model" 作为输入并将其包装在另一个张量中,该张量将隐藏模型的输出视为 return 并通过添加来计算隐含输出1 乘以原始数据:
class Model(tf.keras.Model):
def __init__(self, hidden_model):
super(Model, self).__init__(name='')
self.hidden_model = hidden_model
def build(
self,
reference_price_shape,
hidden_inputs_shape):
super(Model, self).build([reference_price_shape, hidden_inputs_shape])
def call(self, inputs):
reference_prices = inputs[0]
hidden_layers_input = inputs[1]
hidden_output = self.hidden_model(hidden_layers_input)
return (hidden_output + 1) * reference_prices
def compute_output_shape(self, input_shape):
return (input_shape[0][0], 1)
但是,我现在想知道模型对每个输入的变化有多敏感。为此,我想我可以使用 keras.backend.gradients
:
rows = 10
cols = 2
hidden_model = tf.keras.Sequential()
hidden_model.add(
tf.keras.layers.Dense(
1,
name='output',
use_bias=True,
kernel_initializer=tf.constant_initializer(0.1),
bias_initializer=tf.constant_initializer(0)))
model = Model(hidden_model)
model.build(
reference_price_shape=(rows,),
hidden_inputs_shape=(rows, cols))
from tensorflow.keras import backend as K
grads = K.gradients(model.output, model.input)
但是,这 return 是一个错误:
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call
last) in
1 from tensorflow import keras
2 from tensorflow.keras import backend as K
----> 3 K.gradients(hidden_model.output, hidden_model.input)
/usr/lib64/python3.6/site-packages/tensorflow_core/python/keras/backend.py
in gradients(loss, variables) 3795 """ 3796 return
gradients_module.gradients(
-> 3797 loss, variables, colocate_gradients_with_ops=True) 3798 3799
/usr/lib64/python3.6/site-packages/tensorflow_core/python/ops/gradients_impl.py
in gradients(ys, xs, grad_ys, name, colocate_gradients_with_ops,
gate_gradients, aggregation_method, stop_gradients,
unconnected_gradients)
156 ys, xs, grad_ys, name, colocate_gradients_with_ops,
157 gate_gradients, aggregation_method, stop_gradients,
--> 158 unconnected_gradients)
159 # pylint: enable=protected-access
160
/usr/lib64/python3.6/site-packages/tensorflow_core/python/ops/gradients_util.py
in _GradientsHelper(ys, xs, grad_ys, name,
colocate_gradients_with_ops, gate_gradients, aggregation_method,
stop_gradients, unconnected_gradients, src_graph)
503 """Implementation of gradients()."""
504 if context.executing_eagerly():
--> 505 raise RuntimeError("tf.gradients is not supported when eager execution "
506 "is enabled. Use tf.GradientTape instead.")
507 if src_graph is None:
RuntimeError: tf.gradients is not supported when eager execution is
enabled. Use tf.GradientTape instead.
我查看了 tf.GradientTape 的指南,在此基础上我尝试将以下内容添加到我的代码中:
with tf.GradientTape() as g:
g.watch(x)
但是我把它放在哪里? x
是张量,我没有输入张量。我只有 inputs
,这是一个 numpy 数组数组。
只是为了增加混乱,有一个 github post here 似乎暗示这是 tensorflow 2.0
错误,添加 tf.compat.v1.disable_eager_execution()
将为我解决问题。它没有(尽管它确实得到了上述错误以更改为 Layer model_1 has no inbound nodes.
- 不确定这是向前还是向后迈出的一步)。
抱歉,我意识到这个问题几乎站不住脚,但在这一点上我真的很困惑,这可能是我能做的最好的事情,将其定义为可以回答的问题。
作为测试,我尝试用 运行ning K.gradients
代替 hidden_model
,哪种方法有效:
但我不知道该怎么办,因为我通常 运行 我的模型使用 model.predict(input_data)
- 我应该如何使用该张量获得局部导数?
所以我认为我有两个问题:
- 对于 whole 模型,我如何计算我的输出相对于我的输入的导数 - 它一直都是张量,所以
Keras
/tensorflow
即使使用我的自定义 call()
function/model. 也确实应该能够应用链式法则
- 一旦我有了导数张量,我可以用它做什么?
我最初认为我应该尝试将这些问题分开,但单独提出其中任何一个问题都可能是 XY 问题,所以我想我应该一起提问,以便为回答者提供一些背景信息。
这是可能的,但需要一些工作(显然)。希望看到更优雅的解决方案。但这对我来说是最好的了。
import tensorflow as tf
from tensorflow.keras import backend as K
import numpy as np
rows = 10
cols = 2
with tf.Graph().as_default():
hidden_model = tf.keras.Sequential()
hidden_model.add(
tf.keras.layers.Dense(
1,
name='output',
use_bias=True,
kernel_initializer=tf.constant_initializer(0.1),
bias_initializer=tf.constant_initializer(0)))
model = Model(hidden_model)
model.build(
reference_price_shape=(rows,),
hidden_inputs_shape=(rows, cols))
请注意,模型构建需要发生在您尝试在其中获取梯度的同一张图中。可能不需要是默认图,而是相同的图。
然后在图形的相同上下文中,创建一个渐变带上下文。另请注意,x
需要是 tf.Variable()
才能注册为渐变的输入。
with tf.GradientTape() as tape:
x = tf.Variable(np.random.normal(size=(10, rows, cols)), dtype=tf.float32)
out = model(x)
这样你就可以得到渐变。
grads = tape.gradient(out, x)
sess = tf.compat.v1.keras.backend.get_session()
sess.run(tf.compat.v1.global_variables_initializer())
g = sess.run(grads)
print(g)
我有一个自定义模型,它采用任意 "hidden model" 作为输入并将其包装在另一个张量中,该张量将隐藏模型的输出视为 return 并通过添加来计算隐含输出1 乘以原始数据:
class Model(tf.keras.Model):
def __init__(self, hidden_model):
super(Model, self).__init__(name='')
self.hidden_model = hidden_model
def build(
self,
reference_price_shape,
hidden_inputs_shape):
super(Model, self).build([reference_price_shape, hidden_inputs_shape])
def call(self, inputs):
reference_prices = inputs[0]
hidden_layers_input = inputs[1]
hidden_output = self.hidden_model(hidden_layers_input)
return (hidden_output + 1) * reference_prices
def compute_output_shape(self, input_shape):
return (input_shape[0][0], 1)
但是,我现在想知道模型对每个输入的变化有多敏感。为此,我想我可以使用 keras.backend.gradients
:
rows = 10
cols = 2
hidden_model = tf.keras.Sequential()
hidden_model.add(
tf.keras.layers.Dense(
1,
name='output',
use_bias=True,
kernel_initializer=tf.constant_initializer(0.1),
bias_initializer=tf.constant_initializer(0)))
model = Model(hidden_model)
model.build(
reference_price_shape=(rows,),
hidden_inputs_shape=(rows, cols))
from tensorflow.keras import backend as K
grads = K.gradients(model.output, model.input)
但是,这 return 是一个错误:
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) in 1 from tensorflow import keras 2 from tensorflow.keras import backend as K ----> 3 K.gradients(hidden_model.output, hidden_model.input)
/usr/lib64/python3.6/site-packages/tensorflow_core/python/keras/backend.py in gradients(loss, variables) 3795 """ 3796 return gradients_module.gradients( -> 3797 loss, variables, colocate_gradients_with_ops=True) 3798 3799
/usr/lib64/python3.6/site-packages/tensorflow_core/python/ops/gradients_impl.py in gradients(ys, xs, grad_ys, name, colocate_gradients_with_ops, gate_gradients, aggregation_method, stop_gradients, unconnected_gradients) 156 ys, xs, grad_ys, name, colocate_gradients_with_ops, 157 gate_gradients, aggregation_method, stop_gradients, --> 158 unconnected_gradients) 159 # pylint: enable=protected-access 160
/usr/lib64/python3.6/site-packages/tensorflow_core/python/ops/gradients_util.py in _GradientsHelper(ys, xs, grad_ys, name, colocate_gradients_with_ops, gate_gradients, aggregation_method, stop_gradients, unconnected_gradients, src_graph) 503 """Implementation of gradients().""" 504 if context.executing_eagerly(): --> 505 raise RuntimeError("tf.gradients is not supported when eager execution " 506 "is enabled. Use tf.GradientTape instead.") 507 if src_graph is None:
RuntimeError: tf.gradients is not supported when eager execution is enabled. Use tf.GradientTape instead.
我查看了 tf.GradientTape 的指南,在此基础上我尝试将以下内容添加到我的代码中:
with tf.GradientTape() as g:
g.watch(x)
但是我把它放在哪里? x
是张量,我没有输入张量。我只有 inputs
,这是一个 numpy 数组数组。
只是为了增加混乱,有一个 github post here 似乎暗示这是 tensorflow 2.0
错误,添加 tf.compat.v1.disable_eager_execution()
将为我解决问题。它没有(尽管它确实得到了上述错误以更改为 Layer model_1 has no inbound nodes.
- 不确定这是向前还是向后迈出的一步)。
抱歉,我意识到这个问题几乎站不住脚,但在这一点上我真的很困惑,这可能是我能做的最好的事情,将其定义为可以回答的问题。
作为测试,我尝试用 运行ning K.gradients
代替 hidden_model
,哪种方法有效:
但我不知道该怎么办,因为我通常 运行 我的模型使用 model.predict(input_data)
- 我应该如何使用该张量获得局部导数?
所以我认为我有两个问题:
- 对于 whole 模型,我如何计算我的输出相对于我的输入的导数 - 它一直都是张量,所以
Keras
/tensorflow
即使使用我的自定义call()
function/model. 也确实应该能够应用链式法则
- 一旦我有了导数张量,我可以用它做什么?
我最初认为我应该尝试将这些问题分开,但单独提出其中任何一个问题都可能是 XY 问题,所以我想我应该一起提问,以便为回答者提供一些背景信息。
这是可能的,但需要一些工作(显然)。希望看到更优雅的解决方案。但这对我来说是最好的了。
import tensorflow as tf
from tensorflow.keras import backend as K
import numpy as np
rows = 10
cols = 2
with tf.Graph().as_default():
hidden_model = tf.keras.Sequential()
hidden_model.add(
tf.keras.layers.Dense(
1,
name='output',
use_bias=True,
kernel_initializer=tf.constant_initializer(0.1),
bias_initializer=tf.constant_initializer(0)))
model = Model(hidden_model)
model.build(
reference_price_shape=(rows,),
hidden_inputs_shape=(rows, cols))
请注意,模型构建需要发生在您尝试在其中获取梯度的同一张图中。可能不需要是默认图,而是相同的图。
然后在图形的相同上下文中,创建一个渐变带上下文。另请注意,x
需要是 tf.Variable()
才能注册为渐变的输入。
with tf.GradientTape() as tape:
x = tf.Variable(np.random.normal(size=(10, rows, cols)), dtype=tf.float32)
out = model(x)
这样你就可以得到渐变。
grads = tape.gradient(out, x)
sess = tf.compat.v1.keras.backend.get_session()
sess.run(tf.compat.v1.global_variables_initializer())
g = sess.run(grads)
print(g)