Keras:当编译期间输入形状未知时,如何创建具有权重的自定义图层?

时间:2019-04-08 08:29:47

标签: python tensorflow keras layer

我想在输入层之后定义一个预处理层,即它将使用之前计算出的定标器的均值和方差,并将其应用到我的输入中,然后再传递给密集网络。

Lambda层在我的情况下不起作用,因为我想保存模型,目的是当应用于数据时,不需要处理输入,因为它将在网络的早期完成。< / p>

使用K.variables进行均值和var工作,但我想使用权重并设置trainable = False。这样,它们将节省网络的重量,而我不必每次都提供它们。

 vm.functionName= function (ev, a,b) {
            $state.go('edit-blog', {a: a, b:b});
 };

然后我用

称为这一层
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)

哪个给我错误(batch_size为20时)

shape=(self.b,input_shape[1]),

据我了解,由于我的权重(均值和var)必须与输入x的形状相同,所以当batch_size不是训练尺寸的除数时,第一个轴会出现问题,因为在训练过程中它将具有不同的值培训。这会导致崩溃,因为形状必须在编译时确定,而我不能将其留空。

有没有办法为shape的第一个值提供动态值?如果不是,是否可以解决此问题?

2 个答案:

答案 0 :(得分:0)

我认为您不需要添加meanvar作为权重。您可以在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除。

我不保证这将起作用,但是请尝试一下。

答案 1 :(得分:0)

对于具有相同问题的任何人-与时代末尾的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__中的原因: self.b = max(32,batch_size)

因为predict()默认使用batch_size = 32