web-dev-qa-db-ja.com

Kerasで高密度レイヤーを同等の畳み込みレイヤーに変換するにはどうすればよいですか?

Kerasを使用して、Fully Convolutional Networksの論文( https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf )と同様のことをしたいと思います。私は、機能マップを平坦化し、それらをいくつかの密なレイヤーに通すネットワークを持っています。このようなネットワークから、密な層が同等の畳み込みに置き換えられたネットワークに重みをロードしたいと思います。

Kerasに付属するVGG16ネットワークを例として使用できます。ここでは、最後のMaxPooling2D()の7x7x512出力がフラット化されてから、Dense(4096)レイヤーに入ります。この場合、Dense(4096)は7x7x4096の畳み込みに置き換えられます。

私の実際のネットワークは少し異なります。MaxPooling2D()とFlatten()の代わりにGlobalAveragePooling2D()レイヤーがあります。 GlobalAveragePooling2D()の出力は2Dテンソルであり、さらに平坦化する必要がないため、最初の層を含むすべての密な層が1x1の畳み込みに置き換えられます。

私はこの質問を見ました: Python kerasは密な層を畳み込み層に変換する方法 これは同一ではないにしても非常に似ているようです。問題は、(a)TensorFlowをバックエンドとして使用しているため、ウェイトの再配置/フィルターの「回転」が正しくなく、(b)理解できないため、提案されたソリューションを機能させることができないことです。ウェイトをロードする方法を説明します。 model.load_weights(by_name=True)を使用して古いウェイトファイルを新しいネットワークにロードすることは、名前が一致しないため(また、サイズが異なっていても)機能しません。

TensorFlowを使用する場合、再配置はどのようになりますか?

ウェイトをロードするにはどうすればよいですか?各モデルの1つを作成し、両方でmodel.load_weights()を呼び出して同じウェイトをロードしてから、再配置が必要な余分なウェイトの一部をコピーしますか?

18
Alex I

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)
5
Oliver Wilken

a。複雑な回転をする必要はありません。形を変えるだけでうまくいきます

b。 get_weights()を使用して、新しいレイヤーを初期化します

Model.layersを反復処理し、set_weightsを使用するか、以下に示すように、configとloadweightsを使用して同じレイヤーを作成します。

次の擬似コードは私にとってはうまくいきます。 (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
Harsha Pokkalla