如何将密集层转换为 Keras 中的等效卷积层?
How to convert a dense layer to an equivalent convolutional layer in Keras?
我想使用 Keras 做一些类似于全卷积网络论文 (https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf) 的事情。我有一个网络,它最终将特征图展平并通过几个密集层运行它们。我想将权重从这样的网络加载到密集层被等效卷积替换的网络中。
以Keras自带的VGG16网络为例,将最后一个MaxPooling2D()的7x7x512输出拉平后进入Dense(4096)层。在这种情况下,Dense(4096) 将替换为 7x7x4096 卷积。
我的真实网络略有不同,有一个 GlobalAveragePooling2D() 层而不是 MaxPooling2D() 和 Flatten()。 GlobalAveragePooling2D() 的输出是一个二维张量,不需要额外地展平它,所以包括第一层在内的所有密集层都将被替换为 1x1 卷积。
我看过这个问题: 如果不完全相同,它看起来非常相似。问题是我无法使建议的解决方案起作用,因为 (a) 我使用 TensorFlow 作为后端,所以权重 rearrangement/filter "rotation" 不正确,并且 (b) 我无法弄清楚如何加载权重。使用 model.load_weights(by_name=True)
将旧的权重文件加载到新网络中是行不通的,因为名称不匹配(即使它们的尺寸不同)。
在使用TensorFlow的时候应该怎么重排?
如何加载权重?我是否要创建每个模型之一,在两者上调用 model.load_weights() 以加载相同的权重,然后复制一些需要重新排列的额外权重?
一个。无需进行复杂的旋转。只是重塑正在工作
b。使用 get_weights()
并初始化新层
遍历 model.layers
,使用 set_weights
或如下所示创建具有配置和负载权重的相同层。
以下一段伪代码对我有用。 (凯拉斯 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])
根据 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)
我想使用 Keras 做一些类似于全卷积网络论文 (https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf) 的事情。我有一个网络,它最终将特征图展平并通过几个密集层运行它们。我想将权重从这样的网络加载到密集层被等效卷积替换的网络中。
以Keras自带的VGG16网络为例,将最后一个MaxPooling2D()的7x7x512输出拉平后进入Dense(4096)层。在这种情况下,Dense(4096) 将替换为 7x7x4096 卷积。
我的真实网络略有不同,有一个 GlobalAveragePooling2D() 层而不是 MaxPooling2D() 和 Flatten()。 GlobalAveragePooling2D() 的输出是一个二维张量,不需要额外地展平它,所以包括第一层在内的所有密集层都将被替换为 1x1 卷积。
我看过这个问题:model.load_weights(by_name=True)
将旧的权重文件加载到新网络中是行不通的,因为名称不匹配(即使它们的尺寸不同)。
在使用TensorFlow的时候应该怎么重排?
如何加载权重?我是否要创建每个模型之一,在两者上调用 model.load_weights() 以加载相同的权重,然后复制一些需要重新排列的额外权重?
一个。无需进行复杂的旋转。只是重塑正在工作
b。使用 get_weights()
并初始化新层
遍历 model.layers
,使用 set_weights
或如下所示创建具有配置和负载权重的相同层。
以下一段伪代码对我有用。 (凯拉斯 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])
根据 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)