我可以在 Keras 中定义两个不同的调用函数,一个用于正向映射,另一个用于反向映射
Can I define two different call functions in Keras, one for a foward map and another for an inverse map
我正在尝试使用 this paper 中描述的结构来实现 INN(可逆神经网络)。
我想知道是否可以创建一个块(如论文中所建议的那样)作为具有两个不同调用函数的自定义 keras 层。
基本结构如下所示:
import tensorflow as tf
import tensorflow.keras.layers as layers
class INNBlock(tf.keras.Model):
#inheriting from model instead of keras.layers.Layer, because I want manage the
#underlying layer as well
def __init__(self, size):
super(INNBlock, self).__init__(name='innblock')
#define layers
self.denseL1 = layers.Dense(size,activation='relu')
def call(self, inputs):
#define the relationship between the layers for a foward call
out = self.denseL1(inputs)
return out
def inverse_call(self, inputs):
#define inverse relationship between the layer
out = -self.denseL1(inputs) #use the same weights as the foward call
return out
class INN(tf.keras.Model):
def __init__(self,kenel_size,input_dim,min_clip,max_clip):
super(INN, self).__init__()
self.block_1 = INNBlock(size)
self.block_2 = INNBlock(size)
def call(self, inputs):
x = self.block_1(inputs)
x = self.block_2.inverse_call(y)
x = self.block_1.inverse_call(x)
return (y,x)
我已经想到的解决方案(但不是特别喜欢):
为反向调用创建新层,并赋予它们与正向调用中的层相同的权重。
给输入增加一个维度,里面有一个变量,决定是否执行反向调用或正向调用(但我不知道这是否会是keras 允许)
我希望有人知道,是否有办法实现这个。
提前谢谢你:)
您的代码没有任何问题。你可以试一下,它会正常运行。
call
方法是您只需执行 model_instance(input_tensor)
或 layer_instance(input_tensor)
时的标准方法。
但是如果您定义另一个方法并在模型的调用方法中使用该方法也没有错。将会发生的只是:
- 如果您使用
the_block(input_tensor)
,它将使用 the_block.call(input_tensor)
。
- 如果你在 layer/model 之外的某个地方使用
the_block.inverse_call(input_tensor)
,它将无法构建 Keras 模型(任何东西都不能在层之外)
- 如果你在layer/model中使用
the_block.inverse_call(input_tensor)
(这就是你在做的),它和直接写操作是完全一样的。您只是将它包装在另一个函数中。
对于Keras/Tensorflow来说,inverse_call
没有什么特别的。您可以在任何可以使用任何其他 keras/tensorflow 函数的地方使用它。
梯度会更新两次吗?
不完全是两次,但是肯定会算进去的。系统在计算loss相对于权重的梯度时,如果loss是用inverse_call
构建的,那么它将参与梯度计算。
但像往常一样,每批更新一次。
我正在尝试使用 this paper 中描述的结构来实现 INN(可逆神经网络)。
我想知道是否可以创建一个块(如论文中所建议的那样)作为具有两个不同调用函数的自定义 keras 层。
基本结构如下所示:
import tensorflow as tf
import tensorflow.keras.layers as layers
class INNBlock(tf.keras.Model):
#inheriting from model instead of keras.layers.Layer, because I want manage the
#underlying layer as well
def __init__(self, size):
super(INNBlock, self).__init__(name='innblock')
#define layers
self.denseL1 = layers.Dense(size,activation='relu')
def call(self, inputs):
#define the relationship between the layers for a foward call
out = self.denseL1(inputs)
return out
def inverse_call(self, inputs):
#define inverse relationship between the layer
out = -self.denseL1(inputs) #use the same weights as the foward call
return out
class INN(tf.keras.Model):
def __init__(self,kenel_size,input_dim,min_clip,max_clip):
super(INN, self).__init__()
self.block_1 = INNBlock(size)
self.block_2 = INNBlock(size)
def call(self, inputs):
x = self.block_1(inputs)
x = self.block_2.inverse_call(y)
x = self.block_1.inverse_call(x)
return (y,x)
我已经想到的解决方案(但不是特别喜欢):
为反向调用创建新层,并赋予它们与正向调用中的层相同的权重。
给输入增加一个维度,里面有一个变量,决定是否执行反向调用或正向调用(但我不知道这是否会是keras 允许)
我希望有人知道,是否有办法实现这个。 提前谢谢你:)
您的代码没有任何问题。你可以试一下,它会正常运行。
call
方法是您只需执行 model_instance(input_tensor)
或 layer_instance(input_tensor)
时的标准方法。
但是如果您定义另一个方法并在模型的调用方法中使用该方法也没有错。将会发生的只是:
- 如果您使用
the_block(input_tensor)
,它将使用the_block.call(input_tensor)
。 - 如果你在 layer/model 之外的某个地方使用
the_block.inverse_call(input_tensor)
,它将无法构建 Keras 模型(任何东西都不能在层之外) - 如果你在layer/model中使用
the_block.inverse_call(input_tensor)
(这就是你在做的),它和直接写操作是完全一样的。您只是将它包装在另一个函数中。
对于Keras/Tensorflow来说,inverse_call
没有什么特别的。您可以在任何可以使用任何其他 keras/tensorflow 函数的地方使用它。
梯度会更新两次吗?
不完全是两次,但是肯定会算进去的。系统在计算loss相对于权重的梯度时,如果loss是用inverse_call
构建的,那么它将参与梯度计算。
但像往常一样,每批更新一次。