Keras(ディープラーニング)モデルのすべてのレイヤーの重みをリセット(ランダム化)したいです。その理由は、毎回(遅い)モデルの再コンパイルを行うことなく、異なるデータ分割でモデルを数回トレーニングできるようにすることです。
この説明 に触発されて、次のコードを試しています。
# Reset weights
for layer in KModel.layers:
if hasattr(layer,'init'):
input_dim = layer.input_shape[1]
new_weights = layer.init((input_dim, layer.output_dim),name='{}_W'.format(layer.name))
layer.trainable_weights[0].set_value(new_weights.get_value())
ただし、部分的にしか機能しません。
一部には、いくつかのlayer.get_weights()の値を検査したため、それらは変更されているようです。しかし、トレーニングを再開すると、コスト値は最初の実行時の初期コスト値よりもはるかに低くなります。ほとんどすべてのウェイトではなく、一部のウェイトのリセットに成功したようです。
私がどこに間違っているのかについてのヒントは大歓迎です。 THX..
モデルをコンパイルした直後、ただしトレーニングする前に初期重みを保存します。
model.save_weights('model.h5')
そして、トレーニング後、初期重みを再ロードしてモデルを「リセット」します。
model.load_weights('model.h5')
これにより、さまざまなデータセットを比較するためのApple to Appleモデルが提供され、モデル全体を再コンパイルするよりも高速になります。
単に初期の重みを復元するのではなく、重みを本当にランダム化したい場合は、次のことができます。コードは、TensorFlowを使用しているかTheanoを使用しているかによって若干異なります。
from keras.initializers import glorot_uniform # Or your initializer of choice
import keras.backend as K
initial_weights = model.get_weights()
backend_name = K.backend()
if backend_name == 'tensorflow':
k_eval = lambda placeholder: placeholder.eval(session=K.get_session())
Elif backend_name == 'theano':
k_eval = lambda placeholder: placeholder.eval()
else:
raise ValueError("Unsupported backend")
new_weights = [k_eval(glorot_uniform()(w.shape)) for w in initial_weights]
model.set_weights(new_weights)
初期化子をチェックして、すべてのレイヤーをリセットします。
def reset_weights(model):
session = K.get_session()
for layer in model.layers:
if hasattr(layer, 'kernel_initializer'):
layer.kernel_initializer.run(session=session)
if hasattr(layer, 'bias_initializer'):
layer.bias_initializer.run(session=session)
set_weightsを試してください。
例えば:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import numpy as np
np.random.seed(1234)
from keras.layers import Input
from keras.layers.convolutional import Convolution2D
from keras.models import Model
print("Building Model...")
inp = Input(shape=(1,None,None))
x = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(inp)
output = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(x)
model_network = Model(input=inp, output=output)
w = np.asarray([
[[[
[0,0,0],
[0,2,0],
[0,0,0]
]]]
])
for layer_i in range(len(model_network.layers)):
print (model_network.layers[layer_i])
for layer_i in range(1,len(model_network.layers)):
model_network.layers[layer_i].set_weights(w)
input_mat = np.asarray([
[[
[1.,2.,3.,10.],
[4.,5.,6.,11.],
[7.,8.,9.,12.]
]]
])
print("Input:")
print(input_mat)
print("Output:")
print(model_network.predict(input_mat))
w2 = np.asarray([
[[[
[0,0,0],
[0,3,0],
[0,0,0]
]]]
])
for layer_i in range(1,len(model_network.layers)):
model_network.layers[layer_i].set_weights(w2)
print("Output:")
print(model_network.predict(input_mat))
たとえば、2つの畳み込み層を持つモデルを構築する
print("Building Model...")
inp = Input(shape=(1,None,None))
x = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(inp)
output = Convolution2D(1, 3, 3, border_mode='same', init='normal',bias=False)(x)
model_network = Model(input=inp, output=output)
次に、重みを定義します(単純なwを使用していますが、必要に応じてnp.random.uniformなどを使用できます)
w = np.asarray([
[[[
[0,0,0],
[0,2,0],
[0,0,0]
]]]
])
モデル内のレイヤーを見てみましょう
for layer_i in range(len(model_network.layers)):
print (model_network.layers[layer_i])
各畳み込み層に各重みを設定します(最初の層が実際に入力され、それを変更したくないことがわかります。そのため、範囲はゼロではなく1から始まります)。
for layer_i in range(1,len(model_network.layers)):
model_network.layers[layer_i].set_weights(w)
テスト用の入力を生成し、モデルからの出力を予測します
input_mat = np.asarray([
[[
[1.,2.,3.,10.],
[4.,5.,6.,11.],
[7.,8.,9.,12.]
]]
])
print("Output:")
print(model_network.predict(input_mat))
必要に応じて再度変更し、出力を再度確認できます。
w2 = np.asarray([
[[[
[0,0,0],
[0,3,0],
[0,0,0]
]]]
])
for layer_i in range(1,len(model_network.layers)):
model_network.layers[layer_i].set_weights(w2)
print("Output:")
print(model_network.predict(input_mat))
サンプル出力:
Using Theano backend.
Building Model...
<keras.engine.topology.InputLayer object at 0x7fc0c619fd50>
<keras.layers.convolutional.Convolution2D object at 0x7fc0c6166250>
<keras.layers.convolutional.Convolution2D object at 0x7fc0c6150a10>
Weights after change:
[array([[[[ 0., 0., 0.],
[ 0., 2., 0.],
[ 0., 0., 0.]]]], dtype=float32)]
Input:
[[[[ 1. 2. 3. 10.]
[ 4. 5. 6. 11.]
[ 7. 8. 9. 12.]]]]
Output:
[[[[ 4. 8. 12. 40.]
[ 16. 20. 24. 44.]
[ 28. 32. 36. 48.]]]]
Output:
[[[[ 9. 18. 27. 90.]
[ 36. 45. 54. 99.]
[ 63. 72. 81. 108.]]]]
.layersのピークから、最初のレイヤーが入力であり、他のレイヤーが畳み込みレイヤーであることがわかります。
K.get_session().close()
K.set_session(tf.Session())
K.get_session().run(tf.global_variables_initializer())
TF 2.0(tf.keras)でコンパイルされたトレーニングされていないモデルの重みを「ランダム」に再初期化するには:
weights = [glorot_uniform(seed=random.randint(0, 1000))(w.shape) if w.ndim > 1 else w for w in model.get_weights()]
「if wdim> 1 else w」に注意してください。バイアスを再初期化する必要はありません(0または1のままです)。