Keras:如何在编译期间输入形状未知时创建具有权重的自定义层?
Keras : How to create a custom layer with weights when the input shape is unknow during compilation?
我想在我的输入层之后定义一个预处理层,即它将使用之前计算的缩放器的均值和方差,并将其应用于我的输入,然后再将它们传递到密集网络。
Lambda 层在我的情况下不起作用,因为我想保存模型,objective 是当应用于数据时,不需要处理输入,因为它会在早期完成网络阶段。
对均值和 var 使用 K.variables 有效,但我想改用权重并设置 trainable=False。这样它们将保存在网络的权重中,我不必每次都提供它们。
class PreprocessLayer(Layer):
"""
Defines a layer that applies the preprocessing from a scaler
Needed because lambda layers are too fragile to be saved in a model
"""
def __init__(self, batch_size, mean, var, **kwargs):
self.b = batch_size
self.m = mean
self.v = var
super(PreprocessLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.mean = self.add_weight(name='mean',
shape=(self.b,input_shape[1]),
initializer=tf.constant_initializer(self.m),
trainable=False)
self.var = self.add_weight(name='var',
shape=(self.b,input_shape[1]),
initializer=tf.constant_initializer(self.v),
trainable=False)
super(PreprocessLayer, self).build(input_shape) # Be sure to call this at the end
def call(self, x):
return (x-self.mean)/self.var
def compute_output_shape(self, input_shape):
return (input_shape[0],input_shape[1])
def get_config(self):
config = super(PreprocessLayer, self).get_config()
config['mean'] = self.m
config['var'] = self.v
return config
我用
调用这一层
L0 = PreprocessLayer(batch_size=20,mean=scaler.mean_,var=scaler.scale_)(IN)
问题出现在
shape=(self.b,input_shape[1]),
哪个给我错误(当 batch_size 为 20 时)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [32,15] vs. [20,15]
[[Node: preprocess_layer_1/sub = Sub[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_IN_0_0, preprocess_layer_1/mean/read)]]
据我了解,由于我的权重(均值和 var)需要与输入 x 具有相同的形状,因此当 batch_size 不是训练大小的除数时,第一个轴会出现问题,因为它在训练期间会有不同的值。这会导致崩溃,因为形状必须在编译时确定,我不能将其留空。
有什么方法可以为 shape 的第一个值设置一个动态值吗?如果不是,请解决此问题?
我认为您不需要添加 mean
和 var
作为权重。您可以在 call
函数中计算它们。我也不完全明白为什么你想用这个而不是 BatchNormalization
但无论如何,也许你可以试试这个代码
class PreprocessLayer(Layer):
def __init__(self, eps=1e-6, **kwargs):
self.eps = eps
super(PreprocessLayer, self).__init__(**kwargs)
def build(self, input_shape):
super(PreprocessLayer, self).build(input_shape)
def call(self, x):
mean = K.mean(x, axis=-1, keepdims=True)
std = K.std(x, axis=-1, keepdims=True)
return (x - mean) / (std + self.eps)
def compute_output_shape(self, input_shape):
return input_shape
eps
是为了避免被0除。
我不保证这会奏效,但可以试一试。
对于遇到相同问题的任何人 - 这与 epoch 结束时的 batch_size 不同(由于训练和测试大小不是批量大小的倍数)导致InvalidArgumentError: Incompatible shapes
- 这是我的解决方法。
由于这个余数的大小总是小于 batch_size,我在调用函数中所做的就是像这样分割权重:
def call(self, x):
mean = self.mean[:K.shape(x)[0],:]
std = self.std[:K.shape(x)[0],:]
return (x-mean)/std
这有效,但这意味着如果使用大于初始化层的批量大小来评估模型,错误将再次弹出。
这就是我在 __init__
中输入 at 的原因:
self.b = max(32,batch_size)
.
因为predict()默认使用batch_size = 32
我想在我的输入层之后定义一个预处理层,即它将使用之前计算的缩放器的均值和方差,并将其应用于我的输入,然后再将它们传递到密集网络。
Lambda 层在我的情况下不起作用,因为我想保存模型,objective 是当应用于数据时,不需要处理输入,因为它会在早期完成网络阶段。
对均值和 var 使用 K.variables 有效,但我想改用权重并设置 trainable=False。这样它们将保存在网络的权重中,我不必每次都提供它们。
class PreprocessLayer(Layer):
"""
Defines a layer that applies the preprocessing from a scaler
Needed because lambda layers are too fragile to be saved in a model
"""
def __init__(self, batch_size, mean, var, **kwargs):
self.b = batch_size
self.m = mean
self.v = var
super(PreprocessLayer, self).__init__(**kwargs)
def build(self, input_shape):
self.mean = self.add_weight(name='mean',
shape=(self.b,input_shape[1]),
initializer=tf.constant_initializer(self.m),
trainable=False)
self.var = self.add_weight(name='var',
shape=(self.b,input_shape[1]),
initializer=tf.constant_initializer(self.v),
trainable=False)
super(PreprocessLayer, self).build(input_shape) # Be sure to call this at the end
def call(self, x):
return (x-self.mean)/self.var
def compute_output_shape(self, input_shape):
return (input_shape[0],input_shape[1])
def get_config(self):
config = super(PreprocessLayer, self).get_config()
config['mean'] = self.m
config['var'] = self.v
return config
我用
调用这一层L0 = PreprocessLayer(batch_size=20,mean=scaler.mean_,var=scaler.scale_)(IN)
问题出现在
shape=(self.b,input_shape[1]),
哪个给我错误(当 batch_size 为 20 时)
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [32,15] vs. [20,15]
[[Node: preprocess_layer_1/sub = Sub[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_IN_0_0, preprocess_layer_1/mean/read)]]
据我了解,由于我的权重(均值和 var)需要与输入 x 具有相同的形状,因此当 batch_size 不是训练大小的除数时,第一个轴会出现问题,因为它在训练期间会有不同的值。这会导致崩溃,因为形状必须在编译时确定,我不能将其留空。
有什么方法可以为 shape 的第一个值设置一个动态值吗?如果不是,请解决此问题?
我认为您不需要添加 mean
和 var
作为权重。您可以在 call
函数中计算它们。我也不完全明白为什么你想用这个而不是 BatchNormalization
但无论如何,也许你可以试试这个代码
class PreprocessLayer(Layer):
def __init__(self, eps=1e-6, **kwargs):
self.eps = eps
super(PreprocessLayer, self).__init__(**kwargs)
def build(self, input_shape):
super(PreprocessLayer, self).build(input_shape)
def call(self, x):
mean = K.mean(x, axis=-1, keepdims=True)
std = K.std(x, axis=-1, keepdims=True)
return (x - mean) / (std + self.eps)
def compute_output_shape(self, input_shape):
return input_shape
eps
是为了避免被0除。
我不保证这会奏效,但可以试一试。
对于遇到相同问题的任何人 - 这与 epoch 结束时的 batch_size 不同(由于训练和测试大小不是批量大小的倍数)导致InvalidArgumentError: Incompatible shapes
- 这是我的解决方法。
由于这个余数的大小总是小于 batch_size,我在调用函数中所做的就是像这样分割权重:
def call(self, x):
mean = self.mean[:K.shape(x)[0],:]
std = self.std[:K.shape(x)[0],:]
return (x-mean)/std
这有效,但这意味着如果使用大于初始化层的批量大小来评估模型,错误将再次弹出。
这就是我在 __init__
中输入 at 的原因:
self.b = max(32,batch_size)
.
因为predict()默认使用batch_size = 32