Help us understand the problem. What is going on with this article?

KerasのModelクラスに関するプロパティとメソッドまとめ

概要

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()で取得したモデルの構造をロード

プロパティ 動作確認

簡単な動作確認用のモデルを生成する。

test.py
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

各プロパティの戻り値を確認する。

test.py
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に移動する。

test.py
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になる。)

test.py
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関数。

モデル構造をプリントする。基本的にパラメータはデフォルトで困らないと思う。

test.py
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が優先される。
結果は指定したレイヤーのオブジェクトがリターンされる。

test.py
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形式のリストで返ってくる。今回は、重みを持つレイヤーがConv2DDenseの2つで、各レイヤーは重みとバイアスを持つのでリストの要素数は4で返ってくる。

test.py
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()で取得できる形式。

test.py
# 各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形式で取得できる。構造だけなので重みや学習に関する設定は取得されない。

test.py
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をする必要がある。

test.py
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 ファインチューニングするときに使用される。

test.py
# 新しいモデルを生成して重みをセーブする。
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
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away