首页 文章

如何在Keras中将密集层转换为等效的卷积层?

提问于
浏览
14

我想使用Keras做类似于完全卷积网络的文章(https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf) . 我有一个网络,它最终使特征映射变平并通过几个密集层运行它们 . 我想将这样的网络中的权重加载到一个密集层被等效卷积替换的地方 .

可以使用Keras附带的VGG16网络作为示例,其中最后一个MaxPooling2D()的7x7x512输出被展平,然后进入密集(4096)层 . 在这种情况下,密集(4096)将被7x7x4096卷积替换 .

我的真实网络略有不同,有一个GlobalAveragePooling2D()层而不是MaxPooling2D()和Flatten() . GlobalAveragePooling2D()的输出是2D张量,并且不需要额外地将其展平,因此包括第一个的所有密集层将被1x1卷积替换 .

我已经看到了这个问题:Python keras how to transform a dense layer into a convolutional layer如果不相同则看起来非常相似 . 麻烦的是我可以使用TensorFlow作为后端,所以权重重新排列/过滤"rotation"不是't right, and (b) I can' t弄清楚如何加载权重 . 将旧权重文件加载到新网络中 model.load_weights(by_name=True) 不匹配(即使它们的尺寸不同) .

使用TensorFlow时重新排列应该是什么?

如何加载重量?我是否创建了每个模型中的一个,在两者上调用model.load_weights()来加载相同的权重,然后复制一些需要重新排列的额外权重?

2 回答

  • 2

    一个 . 无需进行复杂的旋转 . 重塑正在发挥作用

    湾使用get_weights()和init新层

    通过model.layers迭代,使用set_weights创建具有config和加载权重的相同图层,如下所示 .

    以下伪代码对我有用 . (Keras 2.0)

    伪代码:

    # find input dimensions of Flatten layer
    f_dim =  flatten_layer.input_shape
    
    # Creating new Conv layer and putting dense layers weights 
    m_layer = model.get_layer(layer.name)
    input_shape = m_layer.input_shape
    output_dim =  m_layer.get_weights()[1].shape[0]
    W,b = layer.get_weights()
    if first dense layer :
        shape = (f_dim[1],f_dim[2],f_dim[3],output_dim)
        new_W = W.reshape(shape)
        new_layer = Convolution2D(output_dim,(f_dim[1],f_dim[2]),strides=(1,1),activation='relu',padding='valid',weights=[new_W,b])
    
    else: (not first dense layer)
        shape = (1,1,input_shape[1],output_dim)
        new_W = W.reshape(shape)
        new_layer = Convolution2D(output_dim,(1,1),strides=(1,1),activation='relu',padding='valid',weights=[new_W,b])
    
  • 2

    基于hars的答案,我创建了这个函数来将任意cnn转换为fcn:

    from keras.models import Sequential
    from keras.layers.convolutional import Convolution2D
    from keras.engine import InputLayer
    import keras
    
    def to_fully_conv(model):
    
        new_model = Sequential()
    
        input_layer = InputLayer(input_shape=(None, None, 3), name="input_new")
    
        new_model.add(input_layer)
    
        for layer in model.layers:
    
            if "Flatten" in str(layer):
                flattened_ipt = True
                f_dim = layer.input_shape
    
            elif "Dense" in str(layer):
    
                input_shape = layer.input_shape
                output_dim =  layer.get_weights()[1].shape[0]
                W,b = layer.get_weights()
    
                if flattened_ipt:
                    shape = (f_dim[1],f_dim[2],f_dim[3],output_dim)
                    new_W = W.reshape(shape)
                    new_layer = Convolution2D(output_dim,
                                              (f_dim[1],f_dim[2]),
                                              strides=(1,1),
                                              activation=layer.activation,
                                              padding='valid',
                                              weights=[new_W,b])
                    flattened_ipt = False
    
                else:
                    shape = (1,1,input_shape[1],output_dim)
                    new_W = W.reshape(shape)
                    new_layer = Convolution2D(output_dim,
                                              (1,1),
                                              strides=(1,1),
                                              activation=layer.activation,
                                              padding='valid',
                                              weights=[new_W,b])
    
    
            else:
                new_layer = layer
    
            new_model.add(new_layer)
    
        return new_model
    

    你可以像这样测试这个函数:

    model = keras.applications.vgg16.VGG16()
    new_model = to_fully_conv(model)
    

相关问题