Keras Core 0.1 : 開発者ガイド : シーケンシャル・モデル (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 07/14/2023 (0.1.0)
* 本ページは、Keras の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
- The Sequential model
(Author: fchollet ; Date created: 2020/04/12 ; Last modified: 2023/06/25)
Description: Complete guide to the Sequential model.
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- 人工知能研究開発支援
- 人工知能研修サービス(経営者層向けオンサイト研修)
- テクニカルコンサルティングサービス
- 実証実験(プロトタイプ構築)
- アプリケーションへの実装
- 人工知能研修サービス
- PoC(概念実証)を失敗させないための支援
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
- 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
- sales-info@classcat.com ; Web: www.classcat.com ; ClassCatJP
Keras 2 : ガイド : シーケンシャル・モデル
セットアップ
import keras_core as keras
from keras_core import layers
from keras_core import ops
Using TensorFlow backend
いつシーケンシャル・モデルを使用するべきか
シーケンシャル・モデルは 層の plain (平坦) なスタック のために適切です、そこでは各層は 正確に 1 つの入力テンソルと 1 つの出力テンソル を持ちます。
図式的には (= schematically)、次のシーケンシャル・モデルは :
# Define Sequential model with 3 layers
model = keras.Sequential(
[
layers.Dense(2, activation="relu", name="layer1"),
layers.Dense(3, activation="relu", name="layer2"),
layers.Dense(4, name="layer3"),
]
)
# Call model on a test input
x = ops.ones((3, 3))
y = model(x)
この関数と等値です :
# Create 3 layers
layer1 = layers.Dense(2, activation="relu", name="layer1")
layer2 = layers.Dense(3, activation="relu", name="layer2")
layer3 = layers.Dense(4, name="layer3")
# Call layers on a test input
x = ops.ones((3, 3))
y = layer3(layer2(layer1(x)))
シーケンシャル・モデルは以下の時には 適切ではありません :
- モデルが複数の入力か複数の出力を持つ。
- 層のいずれかが複数の入力か複数の出力を持つ。
- 層共有を行なうことを必要とする。
- 非線形トポロジーを望む (e.g. 残差接続、マルチ分岐 (= multi-branch) モデル)。
シーケンシャル・モデルの作成
層のリストを Sequential コンストラクタに渡すことによりシーケンシャル・モデルを作成できます :
model = keras.Sequential(
[
layers.Dense(2, activation="relu"),
layers.Dense(3, activation="relu"),
layers.Dense(4),
]
)
その層は layers 属性を通してアクセス可能です :
model.layers
[<Dense name=dense, built=False>, <Dense name=dense_1, built=False>, <Dense name=dense_2, built=False>]
add() メソッドを使用してシーケンシャル・モデルを追加的に (= incrementally) 作成することもできます :
model = keras.Sequential()
model.add(layers.Dense(2, activation="relu"))
model.add(layers.Dense(3, activation="relu"))
model.add(layers.Dense(4))
層を削除するために対応する pop() メソッドもあることに注意してください : シーケンシャル・モデルは殆ど層のリストのように動作します。
model.pop()
print(len(model.layers)) # 2
2
ちょうど Keras の任意の層やモデルのように、Sequential コンストラクタは name 引数を受け取ることにも注意してください。これは意味論的に意味がある名前で TensorBoard グラフを注釈するために有用です。
model = keras.Sequential(name="my_sequential")
model.add(layers.Dense(2, activation="relu", name="layer1"))
model.add(layers.Dense(3, activation="relu", name="layer2"))
model.add(layers.Dense(4, name="layer3"))
入力 shape を前もって指定する
一般に、Keras の総ての層はそれらの重みを作成できるように入力の shape を知る必要があります。そのためこのように層を作成するとき、初期には、それは重みを持ちません :
layer = layers.Dense(3)
layer.weights # Empty
[]
それは最初に入力上で呼び出されたときその重みを作成します、何故ならば重みの shape は入力の shape に依存するからです :
# Call layer on a test input
x = ops.ones((1, 4))
y = layer(x)
layer.weights # Now it has weights, of shape (4, 3) and (3,)
[<KerasVariable shape=(4, 3), dtype=float32, name=variable_12>, <KerasVariable shape=(3,), dtype=float32, name=variable_13>]
自然に、これはまたシーケンシャル・モデルにも適用されます。入力 shape なしに Sequential モデルをインスタンス化するとき、それは「構築 (built)」されません : それは重みを持ちません (そして model.weights の呼び出しはちょうどこれを述べるエラーという結果になります)。モデルが最初に何某かの入力データを見るときに重みが作成されます :
model = keras.Sequential(
[
layers.Dense(2, activation="relu"),
layers.Dense(3, activation="relu"),
layers.Dense(4),
]
) # No weights at this stage!
# At this point, you can't do this:
# model.weights
# You also can't do this:
# model.summary()
# Call the model on a test input
x = ops.ones((1, 4))
y = model(x)
print("Number of weights after calling the model:", len(model.weights)) # 6
Number of weights after calling the model: 6
ひとたびモデルが「構築」されれば、その内容を表示するために summary() メソッドを呼び出すことができます :
model.summary()
Model: "sequential_3" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ │ dense_7 (Dense) │ (1, 2) │ 10 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ dense_8 (Dense) │ (1, 3) │ 9 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ dense_9 (Dense) │ (1, 4) │ 16 │ └─────────────────────────────────┴───────────────────────────┴────────────┘ Total params: 35 (1.09 KB) Trainable params: 35 (1.09 KB) Non-trainable params: 0 (0.00 B)
けれども、Sequential モデルを追加的に構築するとき、現在の出力 shape も含めてそこまでのモデルの要約を表示できることは非常に有用である可能性があります。この場合、Input オブジェクトをモデルに渡すことにより最初から入力 shape を知るようにモデルを始める必要があります :
model = keras.Sequential()
model.add(keras.Input(shape=(4,)))
model.add(layers.Dense(2, activation="relu"))
model.summary()
Model: "sequential_4" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ │ dense_10 (Dense) │ (None, 2) │ 10 │ └─────────────────────────────────┴───────────────────────────┴────────────┘ Total params: 10 (320.00 B) Trainable params: 10 (320.00 B) Non-trainable params: 0 (0.00 B)
Input オブジェクトは model.layers の一部として表示されないことに注意してください、それは層ではないからです :
model.layers
[<Dense name=dense_10, built=True>]
このように事前定義された入力 shape で構築されたモデルは (どのようなデータを見る前でさえも) 常に重みを持ちそして常に定義された出力 shape を持ちます。
一般には、シーケンシャル・モデルの入力 shape を (貴方がそれが何か知るのであれば) 常に前もって指定することが推奨されるベストプラクティスです。
一般的なデバッギング・ワークフロー : add() + summary()
新しいシーケンシャル・アーキテクチャを構築するとき、add() で層を追加的にスタックして頻繁にモデル概要をプリントすることは有用です。例えば、これは Conv2D と MaxPooling2D 層のスタックが画像特徴マップをどのようにダウンサンプリングするかをモニタすることを可能にします :
model = keras.Sequential()
model.add(keras.Input(shape=(250, 250, 3))) # 250x250 RGB images
model.add(layers.Conv2D(32, 5, strides=2, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))
# Can you guess what the current output shape is at this point? Probably not.
# Let's just print it:
model.summary()
# The answer was: (40, 40, 32), so we can keep downsampling...
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(2))
# And now?
model.summary()
# Now that we have 4x4 feature maps, time to apply global max pooling.
model.add(layers.GlobalMaxPooling2D())
# Finally, we add a classification layer.
model.add(layers.Dense(10))
Model: "sequential_5" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ │ conv2d (Conv2D) │ (None, 123, 123, 32) │ 2,432 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_1 (Conv2D) │ (None, 121, 121, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 40, 40, 32) │ 0 │ └─────────────────────────────────┴───────────────────────────┴────────────┘ Total params: 11,680 (365.00 KB) Trainable params: 11,680 (365.00 KB) Non-trainable params: 0 (0.00 B) Model: "sequential_5" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩ │ conv2d (Conv2D) │ (None, 123, 123, 32) │ 2,432 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_1 (Conv2D) │ (None, 121, 121, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 40, 40, 32) │ 0 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_2 (Conv2D) │ (None, 38, 38, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_3 (Conv2D) │ (None, 36, 36, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 12, 12, 32) │ 0 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_4 (Conv2D) │ (None, 10, 10, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ conv2d_5 (Conv2D) │ (None, 8, 8, 32) │ 9,248 │ ├─────────────────────────────────┼───────────────────────────┼────────────┤ │ max_pooling2d_2 (MaxPooling2D) │ (None, 4, 4, 32) │ 0 │ └─────────────────────────────────┴───────────────────────────┴────────────┘ Total params: 48,672 (1.49 MB) Trainable params: 48,672 (1.49 MB) Non-trainable params: 0 (0.00 B)
Very practical, right?
ひとたびモデルを得たら何をするべきか
ひとたびモデル・アーキテクチャが準備できれば、以下を望むでしょう :
- モデルを訓練し、それを評価し、そして推論を実行します。training & evaluation with the built-in loops へのガイド を見てください。
- モデルをディスクにセーブしてそれをリストアします。serialization & saving へのガイド を見てください。
シーケンシャル・モデルによる特徴抽出
ひとたびシーケンシャル・モデルが構築されたならば、それは 関数型 API モデル のように動作します。これは総ての層が入力と出力属性を持つことを意味します。これらの属性はシーケンシャル・モデルの総ての中間層の出力を抽出するモデルを素早く作成するような、巧妙な (= neat) ことを行なうために利用できます :
initial_model = keras.Sequential(
[
keras.Input(shape=(250, 250, 3)),
layers.Conv2D(32, 5, strides=2, activation="relu"),
layers.Conv2D(32, 3, activation="relu"),
layers.Conv2D(32, 3, activation="relu"),
]
)
feature_extractor = keras.Model(
inputs=initial_model.inputs,
outputs=[layer.output for layer in initial_model.layers],
)
# Call feature extractor on test input.
x = ops.ones((1, 250, 250, 3))
features = feature_extractor(x)
ここに 1 つの層から特徴を抽出するだけの同様のサンプルがあります :
initial_model = keras.Sequential(
[
keras.Input(shape=(250, 250, 3)),
layers.Conv2D(32, 5, strides=2, activation="relu"),
layers.Conv2D(32, 3, activation="relu", name="my_intermediate_layer"),
layers.Conv2D(32, 3, activation="relu"),
]
)
feature_extractor = keras.Model(
inputs=initial_model.inputs,
outputs=initial_model.get_layer(name="my_intermediate_layer").output,
)
# Call feature extractor on test input.
x = ops.ones((1, 250, 250, 3))
features = feature_extractor(x)
シーケンシャル・モデルによる転移学習
転移学習はモデルのボトム層を凍結してトップ層だけを訓練することから成ります。それに馴染みがないのであれば、転移学習へのガイド を必ず読んでください。
ここにシーケンシャル・モデルを含む 2 つの一般的な転移学習ブループリント (設計図) があります。
最初に、貴方はシーケンシャル・モデルを持ち、そして総ての層を最後の 1 つを除いて凍結することを望むとします。この場合、model.layers に渡り単純に反復して (最後の 1 つを除いて) 各層で layer.trainable = False を設定します。このようにです :
model = keras.Sequential([
keras.Input(shape=(784)),
layers.Dense(32, activation='relu'),
layers.Dense(32, activation='relu'),
layers.Dense(32, activation='relu'),
layers.Dense(10),
])
# Presumably you would want to first load pre-trained weights.
model.load_weights(...)
# Freeze all layers except the last one.
for layer in model.layers[:-1]:
layer.trainable = False
# Recompile and train (this will only update the weights of the last layer).
model.compile(...)
model.fit(...)
もう一つの一般的なブループリントは事前訓練モデルと幾つかの新たに初期化された分類層をスタックするためにシーケンシャル・モデルを利用することです。このようにです :
# Load a convolutional base with pre-trained weights
base_model = keras.applications.Xception(
weights='imagenet',
include_top=False,
pooling='avg')
# Freeze the base model
base_model.trainable = False
# Use a Sequential model to add a trainable classifier on top
model = keras.Sequential([
base_model,
layers.Dense(1000),
])
# Compile & train
model.compile(...)
model.fit(...)
転移学習を行なう場合、これら 2 つのパターンを頻繁に使用することに多分気付くでしょう。
それがシーケンシャル・モデルについて貴方が知る必要があることのすべてです!
To find out more about building models in Keras, see:
以上