TensorFlow 2.4 : ガイド : Keras – シーケンシャル・モデル (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 01/09/2021
* 本ページは、TensorFlow org サイトの Guide – Keras の以下のページを翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。 |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
ガイド : Keras – シーケンシャル・モデル
セットアップ
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers
いつシーケンシャル・モデルを使用するべきか
シーケンシャル・モデルは 層の平易な (= plain) スタック のために適切です、そこでは各層は 正確に 1 つの入力 tensor と 1 つの出力 tensor を持ちます。
図式的には (= 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 = tf.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 = tf.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), ] )
その層は層属性を通してアクセス可能です :
model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f0b1d3b9898>, <tensorflow.python.keras.layers.core.Dense at 0x7f0b1d3da278>, <tensorflow.python.keras.layers.core.Dense at 0x7f0adf113978>]
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 = tf.ones((1, 4)) y = layer(x) layer.weights # Now it has weights, of shape (4, 3) and (3,)
[<tf.Variable 'dense_6/kernel:0' shape=(4, 3) dtype=float32, numpy= array([[ 0.45486438, 0.38934755, -0.7173875 ], [-0.6566295 , -0.10407549, 0.5983287 ], [-0.05668062, 0.49586964, 0.66319096], [-0.85785586, 0.09025455, 0.5556363 ]], dtype=float32)>, <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]
自然に、これはまたシーケンシャル・モデルにも適用されます。入力 shape なしに Sequential モデルをインスタンス化するとき、それは「構築」されません : それは重みを持ちません (そして 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 = tf.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_6" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_16 (Dense) (1, 2) 10 _________________________________________________________________ dense_17 (Dense) (1, 3) 9 _________________________________________________________________ dense_18 (Dense) (1, 4) 16 ================================================================= Total params: 35 Trainable params: 35 Non-trainable params: 0
けれども、Sequential モデルを追加的に構築するとき、現在の出力 shape も含めてそこまでのモデルの要約を表示できることは非常に有用である可能性があります。この場合、Input オブジェクトをモデルに渡すことにより最初から入力 shape を知るようにモデルを始めるべきです :
model = keras.Sequential() model.add(keras.Input(shape=(4,))) model.add(layers.Dense(2, activation="relu")) model.summary()
Model: "sequential_7" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_19 (Dense) (None, 2) 10 ================================================================= Total params: 10 Trainable params: 10 Non-trainable params: 0 _________________________________________________________________
Input オブジェクトは model.layers の一部として表示されないことに注意してください、それは層ではないからです :
model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f446d8d1860>]
単純な代替は最初の層に input_shape 引数を単に渡すことです :
model = keras.Sequential() model.add(layers.Dense(2, activation="relu", input_shape=(4,))) model.summary()
Model: "sequential_5" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_11 (Dense) (None, 2) 10 ================================================================= Total params: 10 Trainable params: 10 Non-trainable params: 0 _________________________________________________________________
このように事前定義された入力 shape で構築されたモデルは (どのようなデータを見る前でさえも) 常に重みを持ちそして常に定義された出力 shape を持ちます。
一般には、シーケンシャル・モデルの入力 shape を (それが何か知るのであれば) 常に前もって指定することが推奨されるベストプラクティスです。
一般的なデバッギング・ワークフロー : add() + summary()
新しいシーケンシャル・アーキテクチャを構築するとき、add() で層を追加的にスタックして頻繁にモデル要約 (= summary) をプリントすることは有用です。例えば、これは 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_6" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 123, 123, 32) 2432 _________________________________________________________________ conv2d_1 (Conv2D) (None, 121, 121, 32) 9248 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 40, 40, 32) 0 ================================================================= Total params: 11,680 Trainable params: 11,680 Non-trainable params: 0 _________________________________________________________________ Model: "sequential_6" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 123, 123, 32) 2432 _________________________________________________________________ conv2d_1 (Conv2D) (None, 121, 121, 32) 9248 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 40, 40, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 38, 38, 32) 9248 _________________________________________________________________ conv2d_3 (Conv2D) (None, 36, 36, 32) 9248 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32) 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 10, 10, 32) 9248 _________________________________________________________________ conv2d_5 (Conv2D) (None, 8, 8, 32) 9248 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 4, 4, 32) 0 ================================================================= Total params: 48,672 Trainable params: 48,672 Non-trainable params: 0
Very practical, right?
ひとたびモデルを得たら何をするべきか
ひとたび貴方のモデル・アーキテクチャが準備できれば、以下を望むでしょう :
- 貴方のモデルを訓練し、評価し、そして推論を実行します。training & evaluation with the built-in loops へのガイド を見てください。
- 貴方のモデルをディスクにセーブしてそれをリストアします。serialization & saving へのガイド を見てください。
- マルチ GPU を活用することによりモデル訓練を高速化します。multi-GPU and distributed training へのガイド を見てください。
シーケンシャル・モデルによる特徴抽出
ひとたびシーケンシャル・モデルが構築されたならば、それは Functional 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 = tf.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 = tf.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 つのパターンを頻繁に使用することを多分気付くでしょう。
That’s about all you need to know about Sequential models!
以上