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

Posted

技术标签:

【中文标题】如何将密集层转换为 Keras 中的等效卷积层?【英文标题】:How to convert a dense layer to an equivalent convolutional layer in Keras? 【发布时间】:2017-04-30 20:53:35 【问题描述】:

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

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

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

我已经看到了这个问题:Python keras how to transform a dense layer into a convolutional layer,如果不完全相同,它似乎非常相似。问题是我无法得到建议的解决方案,因为(a)我使用 TensorFlow 作为后端,所以权重重新排列/过滤器“旋转”不正确,并且(b)我想不通了解如何加载砝码。使用model.load_weights(by_name=True) 将旧权重文件加载到新网络中不起作用,因为名称不匹配(即使它们的尺寸不同)。

使用 TensorFlow 时应该如何重新排列?

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

【问题讨论】:

【参考方案1】:

根据 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)

【讨论】:

谢谢你。正是我所需要的,它可以推广到任何具有 Conv 和 Dense 层的模型。 + 1.【参考方案2】:

一个。无需进行复杂的旋转。只是重塑工作

b.使用 get_weights() 并初始化新层

遍历 model.layers,使用 set_weights 或如下所示的配置和加载权重创建相同的层。

以下一段伪代码对我有用。 (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])

【讨论】:

以上是关于如何将密集层转换为 Keras 中的等效卷积层?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Keras 中为每个时间步应用不同的密集层

如何在 keras 中拥有并行卷积层?

将张量的各个通道传递给 Keras 中的层

在密集的 Keras 层中绑定自动编码器权重

Keras 主要的层函数

Keras 主要的层函数