概要
KerasのModelクラスまわりのプロパティとメソッドをまとめ。
Modelクラスまわりのプロパティとメソッドを知ることで、以下のようなことができる。
・モデル全体をセーブ/ロード。
・モデルの重みのみをセーブ/ロード。
・モデルの構造のみをセーブ/ロード。
・モデルから特定のレイヤーを取得。
まずプロパティとメソッドの一覧を示したあとに、コードの実行結果を説明していく。
プロパティ
Properties | Description |
---|---|
model.name | modelの名前 |
model.inputs | 入力のTensorクラスのリスト |
model.outputs | 出力のTensorクラスのリスト |
model.layers | Layerクラスのリスト |
model.trainable | modelがtrainableか(boolean) |
model.input_shape | 入力のshape |
model.output_shape | 出力のshape |
model.weights | Variableクラスのリスト |
model.trainable_weights | 学習可能なVariableクラスのリスト |
model.non_trainable_weights | 学習不可能なVariableクラスのリスト |
メソッド
Methods | Description |
---|---|
model.summary(line_length=None, positions=None, print_fn=None) | model構造をプリント表示 |
model.get_layer(name=None, index=None) | 指定したLayerクラスを取得 |
model.get_weights() | 全layerの重みのリストを取得 |
model.set_weights(weight) | get_weights()で取得した各layerの重みを設定 |
model.get_config() | モデルのコンフィグを辞書形式で取得 |
model.from_config(config, custom_objects=None) | get_config()で取得したコンフィグからモデルを生成 |
model.to_json() | モデルの構造をjson形式の文字列で取得 |
model.to_yaml() | モデルの構造をYAML形式の文字列で取得 |
model.save(filepath, overwrite=True, include_optimizer=True) | モデルの構造と重みと学習に関する設定や状態を全てHDF5形式でセーブ |
model.save_weights(filepath, overwrite=True) | モデルの重みをHDF5形式でセーブ |
model.load_weights(filepath, by_name=False) | save_weights()で保存した重みをモデルにロード |
その他関連するメソッド
Methods | Description |
---|---|
keras.models.load_model(filepath,custom_objects=None,compile=True) | save()で保存されたモデルの状態をロード |
keras.models.model_from_json(json_str) | to_json()で取得したモデルの構造をロード |
keras.models.model_from_yaml(yaml_str) | to_yaml()で取得したモデルの構造をロード |
プロパティ 動作確認
簡単な動作確認用のモデルを生成する。
import keras
from keras import models
from keras.layers import Activation, Conv2D, MaxPooling2D, Flatten, Dense
def model_sequential():
model = models.Sequential()
model.add(Conv2D(32, (3, 3), padding='same', name='conv1', input_shape=(28, 28 , 1)))
model.add(Activation('relu', name='relu1'))
model.add(MaxPooling2D((2, 2), name='pool1'))
model.add(Flatten(name='flatten'))
model.add(Dense(10, name='dense2'))
model.add(Activation('softmax', name='softmax'))
return model
各プロパティの戻り値を確認する。
model = model_sequential()
print(model.name)
# -> sequential_1
print(model.inputs)
# -> [<tf.Tensor 'conv1_input:0' shape=(?, 28, 28, 1) dtype=float32>]
print(model.outputs)
# -> [<tf.Tensor 'softmax/Softmax:0' shape=(?, 10) dtype=float32>]
print(model.layers)
# -> [<keras.layers.convolutional.Conv2D object at 0x7f4b5d7de278>, <keras.layers.core.Activation object at 0x7f4b4ecd85c0>, <keras.layers.pooling.MaxPooling2D object at 0x7f4b4ecd8320>, <keras.layers.core.Flatten object at 0x7f4b4ecd8438>, <keras.layers.core.Dense object at 0x7f4b4e3f7588>, <keras.layers.core.Activation object at 0x7f4b4e417978>]
print(model.trainable)
# -> True
print(model.trainable_weights)
# -> [<tf.Variable 'conv1/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>, <tf.Variable 'conv1/bias:0' shape=(32,) dtype=float32_ref>, <tf.Variable 'dense2/kernel:0' shape=(6272, 10) dtype=float32_ref>, <tf.Variable 'dense2/bias:0' shape=(10,) dtype=float32_ref>]
print(model.non_trainable_weights)
# -> []
print(model.input_shape)
# -> (None, 28, 28, 1)
print(model.output_shape)
# -> (None, 10)
print(model.weights)
# -> [<tf.Variable 'conv1/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>, <tf.Variable 'conv1/bias:0' shape=(32,) dtype=float32_ref>, <tf.Variable 'dense2/kernel:0' shape=(6272, 10) dtype=float32_ref>, <tf.Variable 'dense2/bias:0' shape=(10,) dtype=float32_ref>]
model.trainable
model.trainable=False
に設定すると,
自動的に全てのVariableオブジェクトがmodel.non_trainable_weights
に移動する。
model = model_sequential()
model.trainable=False
print(model.trainable)
# -> False
print(model.trainable_weights)
# -> []
print(model.non_trainable_weights)
# -> [<tf.Variable 'conv1/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>, <tf.Variable 'conv1/bias:0' shape=(32,) dtype=float32_ref>, <tf.Variable 'dense2/kernel:0' shape=(6272, 10) dtype=float32_ref>, <tf.Variable 'dense2/bias:0' shape=(10,) dtype=float32_ref>]
layer単位でもtrainable
を設定できるが、model.trainable=False
の場合は、layer単位の設定は無視される。(設定が強制的にFalseになる。)
model = model_sequential()
model.trainable=False
model.layers[0].trainable=True
print(model.trainable)
# -> False
print(model.trainable_weights)
# -> []
# layer[0]をtrainable=Trueにしているがtrainable_weightsに登録されない。
print(model.non_trainable_weights)
# -> [<tf.Variable 'conv1/kernel:0' shape=(3, 3, 1, 32) dtype=float32_ref>, <tf.Variable 'conv1/bias:0' shape=(32,) dtype=float32_ref>, <tf.Variable 'dense2/kernel:0' shape=(6272, 10) dtype=float32_ref>, <tf.Variable 'dense2/bias:0' shape=(10,) dtype=float32_ref>]
メソッド 動作確認
model.summary(line_length=None, positions=None, print_fn=None)
Params | Description |
---|---|
line_length | プリントされる横幅。10を設定すると各行10文字までしか表示されない。 |
positions | よくわからない。たぶんsummaryを表示する位置に関係するもの。 |
print_fn | summaryを表示するためのprint関数。 |
モデル構造をプリントする。基本的にパラメータはデフォルトで困らないと思う。 |
model = model_sequential()
model.summary()
'''
____________________________________________________________________________________________________
Layer (type) Output Shape Param #
====================================================================================================
conv1 (Conv2D) (None, 28, 28, 32) 320
____________________________________________________________________________________________________
relu1 (Activation) (None, 28, 28, 32) 0
____________________________________________________________________________________________________
pool1 (MaxPooling2D) (None, 14, 14, 32) 0
____________________________________________________________________________________________________
flatten (Flatten) (None, 6272) 0
____________________________________________________________________________________________________
dense2 (Dense) (None, 10) 62730
____________________________________________________________________________________________________
softmax (Activation) (None, 10) 0
====================================================================================================
Total params: 63,050
Trainable params: 0
Non-trainable params: 63,050
____________________________________________________________________________________________________
'''
model.get_layer(name=None, index=None)
Params | Description |
---|---|
name | モデル構築時につけた名前で指定。 |
index | レイヤーのインデックス番号で指定。 |
両方設定するとindex が優先される。 |
|
結果は指定したレイヤーのオブジェクトがリターンされる。 |
model = model_sequential()
print(model.get_layer(name="conv1"))
# -> <keras.layers.convolutional.Conv2D at 0x7f4b5d7de278>
print(model.get_layer(index=0))
# -> <keras.layers.convolutional.Conv2D at 0x7f4b5d7de278>
print(model.layers[0])
# -> <keras.layers.convolutional.Conv2D at 0x7f4b5d7de278>
# property経由で触っても同じ結果になる。
model.get_weights()
model.get_weights()
は、モデル内の重みを全てがリターンされる。要素がndarray形式のリストで返ってくる。今回は、重みを持つレイヤーがConv2D
とDense
の2つで、各レイヤーは重みとバイアスを持つのでリストの要素数は4で返ってくる。
model = model_sequential()
w = model.get_weights()
print(len(w))
# -> 4
print(w[0].shape)
# -> (3, 3, 1, 32)
# Conv2Dの重み
print(w[1].shape)
# -> (32,)
# Conv2Dのバイアス
print(w[2].shape)
# -> (6272, 10)
# Denseの重み
print(w[3].shape)
# -> (10,)
# Denseのバイアス
model.set_weights()
model.set_weight()
は、layerの重みを設定することができる。設定する形式は、model.get_weights()
で取得できる形式。
# 各layerの新しい重みを定義
conv_weights = np.ones(w[0].shape) * 1
conv_bias = np.ones(w[1].shape) * 2
dense_weights = np.ones(w[2].shape) * 3
dense_bias = np.ones(w[3].shape) * 4
# 各layerの重みをlayerの順番でリスト化
new_weights = []
new_weights.append(conv_weights)
new_weights.append(conv_bias)
new_weights.append(dense_weights)
new_weights.append(dense_bias)
# 新しいモデルを生成
new_model = model_sequential()
# 重みをロード
new_model.set_weights(new_weights)
print(new_model.get_weights()[3])
# -> [4. 4. 4. 4. 4. 4. 4. 4. 4. 4.]
model.to_json() / model.to_yaml()
モデルの構造をjson形式、yaml形式で取得できる。構造だけなので重みや学習に関する設定は取得されない。
model = model_sequential()
# json形式でモデル構造を出力
json_str = model.to_json()
# json形式のモデル構造からモデルを再構築
new_json_model = keras.models.model_from_json(json_str)
# yaml形式でモデル構造を出力
yaml_str = model.to_yaml()
# yaml形式のモデル構造からモデルを再構築
new_yaml_model = keras.models.model_from_yaml(yaml_str)
model.save(filepath, overwrite=True, include_optimizer=True)
Params | Description |
---|---|
filepath | saveするファイルパス。 |
overwrite | 指定したfilepathが既に存在していた場合、上書きするかどうか。 |
include_optimizer | optimizerの状態もsaveするかどうか。 |
overwrite=False
にすると既に同じファイルがある場合に[WARNING] test.hdf5 already exists - overwrite? [y/n]
のように上書きするかどうか聞かれる。
include_optimizer=False
にするとoptimizer関連の情報が保存されない。なのでセーブしたファイルをロードした後にcompile
をする必要がある。
model = model_sequential()
model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])
# model情報をセーブする。optimizerの設定も保存される。
model.save("test.hdf5")
# "test.hdf5"を使ってモデルを再構築する。
# load時にcompileも実行されている
new_model = keras.models.load_model(model_path)
model.save_weights(filepath, overwrite=True)
Params | Description |
---|---|
filepath | saveするファイルパス。 |
overwrite | 指定したfilepathが既に存在していた場合、上書きするかどうか。 |
モデルの重みだけをHDF5形式で保存する。
model.load_weights(filepath, by_name=False)
Params | Description |
---|---|
filepath | saveするファイルパス。 |
by_name | 名前が一致がしたlayerだけ重みをロードするかどうか。 |
by_name=False にするとネットワーク構造に基づいて重みがロードされる。by_name=True するとlayerの名前が同じ箇所だけ重みをロードする。これは転移学習 or ファインチューニングするときに使用される。 |
# 新しいモデルを生成して重みをセーブする。
model = model_sequential()
model.save_weights("test_weights.hdf5")
# 新しいモデルを生成して重みをロードする。
new_model = model_sequential()
new_model.load_weights("test_weights.hdf5")
# 重みが一致していることを確認。
print(np.all(new_model.get_weights()[0] == model.get_weights()[0]))
# -> True
print(np.all(new_model.get_weights()[1] == model.get_weights()[1]))
# -> True
print(np.all(new_model.get_weights()[2] == model.get_weights()[2]))
# -> True
print(np.all(new_model.get_weights()[3] == model.get_weights()[3]))
# -> True