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()を呼び出して同じウェイトをロードしてから、再配置が必要な余分なウェイトの一部をコピーしますか?
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)
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])