首页 文章

Keras Conv2D自定义内核初始化

提问于
浏览
0

我需要用权重初始化自定义Conv2D内核

W = a1b1 a2b2 ...... anbn

其中W =用于初始化的Conv2D层的自定义权重

a =随机权重张量为 keras.backend.variable(np.random.uniform()) ,形状=(64,1,10)

b =定义为 keras.backend.constant(...) 的固定基过滤器,shape =(10,11,11)

W = K.sum(a [:,:,,None,None] * b [无,无,:,:,],轴= 2)#shape =(64,1,11,11)

我希望我的模型更新'W'值,只更改'a',同时保持'b'不变 .

我将自定义'W'传递给了

Conv2D(64,kernel_size =(11,11),activation ='relu',kernel_initializer = kernel_init_L1)(img)

其中 kernel_init_L1 返回 keras.backend.variable(K.reshape(w_L1, (11, 11, 1, 64)))

Problem: 我不确定这是否是正确的方法 . 是否可以在Keras中指定哪些是 trainable 哪些不是 trainable . 我知道可以设置图层 trainable = True 但我不确定重量 .

我认为实现是不正确的,因为无论是否使用自定义初始化,我都会从模型中得到类似的结果 .

如果有人可以指出我的方法中的任何错误或提供验证方法,那将是非常有帮助的 .

1 回答

  • 2

    关于形状的警告:如果你的内核大小为 (11,11) ,并且假设你有64个输入通道和1个输出通道,那么你的最终内核形状必须是 (11,11,64,1) .

    你可能应该去 a[None,None]b[:,:,:,None,None] .

    class CustomConv2D(Conv2D):
    
        def __init__(self, filters, kernel_size, kernelB = None, **kwargs):
            super(CustomConv2D, self).__init__(filters, kernel_size,**kwargs)
            self.kernelB = kernelB
    
        def build(self, input_shape):
    
    
            #use the input_shape to calculate the shapes of A and B
            #if needed, pay attention to the "data_format" used. 
    
            #this is an actual weight, because it uses `self.add_weight`   
            self.kernelA = self.add_weight(
                      shape=shape_of_kernel_A + (1,1), #or (1,1) + shape_of_A
                      initializer='glorot_uniform', #or select another
                      name='kernelA',
                      regularizer=self.kernel_regularizer,
                      constraint=self.kernel_constraint)
    
    
            #this is an ordinary var that will participate in the calculation
                #not a weight, not updated
            if self.kernelB is None:
                self.kernelB = K.constant(....) 
                #use the shape already containing the new axes
    
    
            #in the original conv layer, this property would be the actual kernel,
            #now it's just a var that will be used in the original's "call" method 
            self.kernel = K.sum(self.kernelA * self.kernelB, axis=2)  
            #important: the resulting shape should be:
                #(kernelSizeX, kernelSizeY, input_channels, output_channels)   
    
    
            #the following are remains of the original code for "build" in Conv2D
            #use_bias is True by default
            if self.use_bias:
                self.bias = self.add_weight(shape=(self.filters,),
                                        initializer=self.bias_initializer,
                                        name='bias',
                                        regularizer=self.bias_regularizer,
                                        constraint=self.bias_constraint)
            else:
                self.bias = None
            # Set input spec.
            self.input_spec = InputSpec(ndim=self.rank + 2,
                                    axes={channel_axis: input_dim})
            self.built = True
    

    自定义图层的提示

    从零创建自定义图层(从 Layer 派生)时,您应该具有以下方法:

    • __init__(self, ... parameters ...) - 这是创建者,在您创建图层的新实例时会调用它 . 在这里,您将用户传递的值存储为参数 . (在Conv2D中,init会有"filters","kernel_size"等)

    • build(self, input_shape) - 这是你应该创建权重的地方(根据输入的形状在这里创建所有可学习的变量)

    • compute_output_shape(self,input_shape) - 在此处根据输入形状返回输出形状

    • call(self,inputs) - 在这里执行实际的图层计算

    由于我们不是从零创建这个层,而是从 Conv2D 派生出来,所以一切准备就绪,我们所做的就是构建方法并替换被认为是Conv2D层的内核 .

    有关自定义图层的更多信息:https://keras.io/layers/writing-your-own-keras-layers/

    conv层的 call 方法是here in class _Conv(Layer): .

相关问题