2016-12-15 59 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)