如何使用 'stateful' variables/tensors 在 Keras 中创建自定义层?
How to create a custom layer in Keras with 'stateful' variables/tensors?
我想请你帮忙创建我的自定义图层。
我想做的实际上很简单:生成一个带有 'stateful' 变量的输出层,即每批更新其值的张量。
为了让一切更清楚,这里是我想做的片段:
def call(self, inputs)
c = self.constant
m = self.extra_constant
update = inputs*m + c
X_new = self.X_old + update
outputs = X_new
self.X_old = X_new
return outputs
这里的想法很简单:
X_old
在def__ init__(self, ...)
中初始化为0
update
被计算为层 输入的函数
- 计算层的输出(即
X_new
)
X_old
的值设置为等于 X_new
,以便在下一批中,X_old
不再等于零,而是等于 X_new
上一批。
我发现 K.update
可以完成这项工作,如示例所示:
X_new = K.update(self.X_old, self.X_old + update)
这里的问题是,如果我然后尝试将层的输出定义为:
outputs = X_new
return outputs
我尝试 model.fit() 时会收到以下错误:
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have
gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.
即使我施加了 layer.trainable = False
并且我没有为该层定义任何偏差或权重,但我仍然遇到此错误。另一方面,如果我只执行 self.X_old = X_new
,X_old
的值不会更新。
你们有实现这个的解决方案吗?我相信它不应该那么难,因为有状态 RNN 也有 'similar' 功能。
在此先感谢您的帮助!
有时定义自定义层会变得混乱。您覆盖的一些方法将被调用一次,但它给您的印象是就像许多其他 OO libraries/frameworks,它们将被调用多次。
这就是我的意思:当您定义一个层并在模型中使用它时,您为覆盖 call
方法而编写的 python 代码将不会在转发或向后传球。相反,它只在您调用 model.compile
时调用一次。它将 python 代码编译成计算图,而张量将在其中流动的图就是训练和预测期间的计算。
这就是为什么如果你想通过放置 print
语句来调试你的模型,它是行不通的;您需要使用 tf.print
向图形添加打印命令。
你想要的状态变量也是一样的情况。不是简单地将 old + update
分配给 new
,而是需要调用一个 Keras 函数将该操作添加到图中。
注意张量是不可变的,因此您需要在 __init__
方法中将状态定义为 tf.Variable
。
所以我相信这段代码更像您正在寻找的代码:
class CustomLayer(tf.keras.layers.Layer):
def __init__(self, **kwargs):
super(CustomLayer, self).__init__(**kwargs)
self.state = tf.Variable(tf.zeros((3,3), 'float32'))
self.constant = tf.constant([[1,1,1],[1,0,-1],[-1,0,1]], 'float32')
self.extra_constant = tf.constant([[1,1,1],[1,0,-1],[-1,0,1]], 'float32')
self.trainable = False
def call(self, X):
m = self.constant
c = self.extra_constant
outputs = self.state + tf.matmul(X, m) + c
tf.keras.backend.update(self.state, tf.reduce_sum(outputs, axis=0))
return outputs
我想请你帮忙创建我的自定义图层。 我想做的实际上很简单:生成一个带有 'stateful' 变量的输出层,即每批更新其值的张量。
为了让一切更清楚,这里是我想做的片段:
def call(self, inputs)
c = self.constant
m = self.extra_constant
update = inputs*m + c
X_new = self.X_old + update
outputs = X_new
self.X_old = X_new
return outputs
这里的想法很简单:
X_old
在def__ init__(self, ...)
中初始化为0
update
被计算为层 输入的函数
- 计算层的输出(即
X_new
) X_old
的值设置为等于X_new
,以便在下一批中,X_old
不再等于零,而是等于X_new
上一批。
我发现 K.update
可以完成这项工作,如示例所示:
X_new = K.update(self.X_old, self.X_old + update)
这里的问题是,如果我然后尝试将层的输出定义为:
outputs = X_new
return outputs
我尝试 model.fit() 时会收到以下错误:
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have
gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.
即使我施加了 layer.trainable = False
并且我没有为该层定义任何偏差或权重,但我仍然遇到此错误。另一方面,如果我只执行 self.X_old = X_new
,X_old
的值不会更新。
你们有实现这个的解决方案吗?我相信它不应该那么难,因为有状态 RNN 也有 'similar' 功能。
在此先感谢您的帮助!
有时定义自定义层会变得混乱。您覆盖的一些方法将被调用一次,但它给您的印象是就像许多其他 OO libraries/frameworks,它们将被调用多次。
这就是我的意思:当您定义一个层并在模型中使用它时,您为覆盖 call
方法而编写的 python 代码将不会在转发或向后传球。相反,它只在您调用 model.compile
时调用一次。它将 python 代码编译成计算图,而张量将在其中流动的图就是训练和预测期间的计算。
这就是为什么如果你想通过放置 print
语句来调试你的模型,它是行不通的;您需要使用 tf.print
向图形添加打印命令。
你想要的状态变量也是一样的情况。不是简单地将 old + update
分配给 new
,而是需要调用一个 Keras 函数将该操作添加到图中。
注意张量是不可变的,因此您需要在 __init__
方法中将状态定义为 tf.Variable
。
所以我相信这段代码更像您正在寻找的代码:
class CustomLayer(tf.keras.layers.Layer):
def __init__(self, **kwargs):
super(CustomLayer, self).__init__(**kwargs)
self.state = tf.Variable(tf.zeros((3,3), 'float32'))
self.constant = tf.constant([[1,1,1],[1,0,-1],[-1,0,1]], 'float32')
self.extra_constant = tf.constant([[1,1,1],[1,0,-1],[-1,0,1]], 'float32')
self.trainable = False
def call(self, X):
m = self.constant
c = self.extra_constant
outputs = self.state + tf.matmul(X, m) + c
tf.keras.backend.update(self.state, tf.reduce_sum(outputs, axis=0))
return outputs