2016-12-15 138 views
11

我想用类似于使用Keras的完全卷积网络论文(https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf)。我有一个网络,最终将特征映射展平,并通过多个密集层运行它们。我想从像这样的网络中加载权重到其中密集层被等值卷积替换的权重。如何将密集层转换为Keras中的等价卷积层?

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

我的真实网络略有不同,有一个GlobalAveragePooling2D()层,而不是MaxPooling2D()和平铺()。 GlobalAveragePooling2D()的输出是一个二维张量,不需要额外将其平滑,因此包括第一层的所有密集层都会被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

a。无需做复杂的旋转。只是重塑正在工作

b。

迭代通过model.layers使用get_weights()和init新层,创建使用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]) 
1

基于哈斯的回答,我创造了这个功能,任意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)