Act 35. Sequentialクラスについて
はじめに
当たり前のようにSequential
クラスを使ってLSTMのモデルを構築しているが、そもそもSequentialクラスで何が出来るのか気になったためこの記事を作ることに決定。
Sequential
Sequential
クラスには以下のプロパティとメソッドが存在する。
プロパティ
-
layers
- 現在のモデルに追加されたレイヤーのリスト。
- 入力レイヤーは含まれない。
-
add()
とpop()
で変更可能。 - 読み取り専用。
from keras.models import Sequential from keras.layers import LSTM # モデルの構築 model = Sequential() # レイヤーの確認 print(model.layers) # レイヤーの追加 model.add(LSTM(units=10)) # 再度レイヤーの確認 print(model.layers)
出力は以下の通り。
[] [<LSTM name=lstm_2, built=False>]
-
input_shape
- モデルの入力の形状。
- 入力形状が定義されていない場合は例外がスローされる。
from keras.models import Sequential from keras.layers import LSTM # モデルの構築 model = Sequential() # 入力形状を確認 print(model.input_shape)
入力形状が定義されていない場合の出力は以下。
AttributeError Traceback (most recent call last) Cell In[28], line 5 2 model = Sequential() 4 # 入力形状を確認 ----> 5 print(model.input_shape) File ~/venv/py312/lib/python3.12/site-packages/keras/src/models/sequential.py:276, in Sequential.input_shape(self) 274 if self._functional: 275 return self._functional.input_shape --> 276 raise AttributeError( 277 f"Sequential model '{self.name}' has no defined input shape yet." 278 ) AttributeError: Sequential model 'sequential_14' has no defined input shape yet.
エラーが発生しないパターンは以下のように入力形状を指定した場合。
from keras.models import Sequential from keras.layers import LSTM # Sequentialモデルの構築 model = Sequential() # レイヤーを追加 model.add(LSTM(units=10, input_shape=(10, 1))) # 入力形状を確認 print(model.input_shape)
出力は以下の通り。
(None, 10, 1) /home/onishi/venv/py312/lib/python3.12/site-packages/keras/src/layers/rnn/rnn.py:200: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead. super().__init__(**kwargs)
kerasのバージョンによっては上記のようにメッセージが出力される。
LSTMレイヤーのinput_shape
を使うのではなく、Inputレイヤーを追加するようにとのこと。from keras.models import Sequential from keras.layers import LSTM, input # Sequentialモデルの構築 model = Sequential() # レイヤーを追加 model.add(Input(shape=(10, 1))) model.add(LSTM(units=10)) # 入力形状を確認 print(model.input_shape)
出力は以下の通り。
(None, 10, 1)
-
output_shape
- モデルの出力の形状。
- 出力形状が定義されていない場合は例外がスローされる。
from keras.models import Sequential from keras.layers import LSTM, Input # Sequentialモデルの構築 model = Sequential() # レイヤーを追加 model.add(Input(shape=(10, 1))) # 入力形状を確認 print(model.output_shape)
出力形状が定義されていない場合は以下のエラーが出力される。
AttributeError Traceback (most recent call last) Cell In[46], line 8 5 model.add(Input(shape=(10, 1))) 6 7 # 入力形状を確認 ---> 8 print(model.output_shape) File ~/venv/py312/lib/python3.12/site-packages/keras/src/models/sequential.py:284, in Sequential.output_shape(self) 282 if self._functional: 283 return self._functional.output_shape --> 284 raise AttributeError( 285 f"Sequential model '{self.name}' has no defined output shape yet." 286 ) AttributeError: Sequential model 'sequential_31' has no defined output shape yet.
正常なパターンは以下の通り。
from keras.models import Sequential from keras.layers import LSTM, Input, Dense # Sequentialモデルの構築 model = Sequential() # レイヤーを追加 model.add(Input(shape=(10, 1))) model.add(LSTM(units=30)) model.add(Dense(units=1)) # 入力形状を確認 print(model.output_shape)
出力は以下の通り。
Dense
で出力形状を指定している。(None, 1)
-
inputs
- モデルの入力テンソル。
- 入力がまだ定義されていない場合は例外がスローされる。
input_shape
とinputs
は似たようなもの。プロパティ input_shape
inputs
目的 入力データの形状を確認 入力テンソルを確認、操作 型 タプル(例: (None, 10, 1)
)TensorFlowのテンソル( tf.Tensor
)主な用途 モデルの概要や構造を確認する 入力テンソルを直接利用、Functional APIと連携 定義される条件 最初のレイヤーで形状を指定する モデルが構築されている( Input
が追加されている)from keras.models import Sequential from keras.layers import LSTM, Input # Sequentialモデルの構築 model = Sequential() # レイヤーを追加 model.add(Input(shape=(10, 1))) model.add(LSTM(units=30)) # 入力形状を確認 print(model.inputs)
出力は以下の通り。
[<KerasTensor shape=(None, 10, 1), dtype=float32, sparse=False, name=keras_tensor_64>]
-
outputs
- モデルの出力テンソル。
- 出力がまだ定義されていない場合は例外がスローされる。
inputs
の出力版。
-
input_dtype
- 入力データのデータ型。
from keras.models import Sequential from keras.layers import Input # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(2, 1))) # 入力データの型を確認 print(model.input_dtype)
出力は以下の通り。
float32
-
built
- モデルが構築済みかどうかを示すフラグ。
from keras.models import Sequential from keras.layers import Input # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(2, 1))) # モデルが構築済みか確認 print(model.built)
出力は以下の通り。
False
Input以外のレイヤーを追加した状態で確認するとモデルが構築されているとみなされる。
# モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(2, 1))) model.add(LSTM(units=10)) model.add(Dense(units=1)) # モデルが構築済みか確認 print(model.built)
出力は以下の通り。
※1つ目のメッセージは表示されない場合もあるかもI0000 00:00:1735950832.512166 213 gpu_device.cc:2022] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 5558 MB memory: -> device: 0, name: NVIDIA GeForce RTX 3070 Ti, pci bus id: 0000:01:00.0, compute capability: 8.6 True
メソッド
-
add(self, layer, rebuild=True)
- モデルに新しいレイヤーを追加する。
- 最初のレイヤーとして
Input
レイヤーを追加することも可能。
レイヤーの追加はいつも使っているメソッド。
from keras.models import Sequential from keras.layers import Input, LSTM, Dense, Dropout # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(10, 2))) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30)) model.add(Dropout(0.1)) model.add(Dense(units=1)) # レイヤーの確認 for idx, layer in enumerate(model.layers): print(f"Layer {idx} is {layer}")
出力は以下の通り。
Layer 0 is <LSTM name=lstm_8, built=True> Layer 1 is <Dropout name=dropout_4, built=True> Layer 2 is <LSTM name=lstm_9, built=True> Layer 3 is <Dropout name=dropout_5, built=True> Layer 4 is <LSTM name=lstm_10, built=True> Layer 5 is <Dropout name=dropout_6, built=True> Layer 6 is <LSTM name=lstm_11, built=True> Layer 7 is <Dropout name=dropout_7, built=True> Layer 8 is <Dense name=dense_3, built=True>
-
pop(self, rebuild=True)
- 最後に追加されたレイヤーを削除する。
- 削除したレイヤーを返す。
from keras.models import Sequential from keras.layers import Input, LSTM, Dense, Dropout # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(10, 2))) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30)) model.add(Dropout(0.1)) model.add(Dense(units=1)) # レイヤーの確認 for idx, layer in enumerate(model.layers): print(f"Layer {idx} is {layer}") print("="*30) # レイヤーの削除 pop = model.pop() print(f"{pop} was deleted") print("="*30) # 削除後のレイヤーの確認 for idx, layer in enumerate(model.layers): print(f"Layer {idx} is {layer}")
出力は以下の通り。
レイヤーが一つ削除されているのが分かる。Layer 0 is <LSTM name=lstm_32, built=True> Layer 1 is <Dropout name=dropout_28, built=True> Layer 2 is <LSTM name=lstm_33, built=True> Layer 3 is <Dropout name=dropout_29, built=True> Layer 4 is <LSTM name=lstm_34, built=True> Layer 5 is <Dropout name=dropout_30, built=True> Layer 6 is <LSTM name=lstm_35, built=True> Layer 7 is <Dropout name=dropout_31, built=True> Layer 8 is <Dense name=dense_9, built=True> ============================== <Dense name=dense_9, built=True> was deleted ============================== Layer 0 is <LSTM name=lstm_32, built=True> Layer 1 is <Dropout name=dropout_28, built=True> Layer 2 is <LSTM name=lstm_33, built=True> Layer 3 is <Dropout name=dropout_29, built=True> Layer 4 is <LSTM name=lstm_34, built=True> Layer 5 is <Dropout name=dropout_30, built=True> Layer 6 is <LSTM name=lstm_35, built=True> Layer 7 is <Dropout name=dropout_31, built=True>
-
build(self, input_shape=None)
- モデルを構築する。
- 入力形状を指定することで手動で構築可能。
from keras.models import Sequential from keras.layers import Dense, LSTM # モデルの定義 model = Sequential() model.add(LSTM(64, return_sequences=True)) model.add(Dense(1)) # モデルのビルド model.build(input_shape=(None, 10, 5)) # モデルの概要を確認 model.summary()
出力は以下の通り。
Model: "sequential" ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ lstm (LSTM) │ (None, 10, 64) │ 17,920 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 10, 1) │ 65 │ └─────────────────────────────────┴────────────────────────┴───────────────┘ Total params: 17,985 (70.25 KB) Trainable params: 17,985 (70.25 KB) Non-trainable params: 0 (0.00 B)
通常は
fit
やpredict
を呼び出す際に内部的にビルドが行われるため、手動で実行する必要はないらしい。fit
やbuild
を行う前にsummary
を確認したい場合などは便利そう。ちなみに
model.build(input_shape=(None, 10, 5))
のinput_shape
は、左から(サンプル数, 期間, 特徴量)
となる。 -
compute_output_shape(self, input_shape)
- 入力形状から出力形状を計算する。
from keras.models import Sequential from keras.layers import Dense, LSTM, Input, Dropout # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(10, 2))) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30)) model.add(Dropout(0.1)) model.add(Dense(units=1)) # 入力形状を指定して出力形状を計算 output_shape = model.compute_output_shape((None, 10, 2)) print(output_shape)
出力は以下の通り。
Dense(units=1)
としているため、出力される値は1つとなる。(None, 1)
-
compute_output_spec(self, inputs, training=None, mask=None)
- 入力仕様に基づいて出力仕様を計算する。
from keras.models import Sequential from keras.layers import Dense, LSTM, Input, Dropout import tensorflow as tf # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(10, 2))) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30, return_sequences=True)) model.add(Dropout(0.1)) model.add(LSTM(units=30)) model.add(Dropout(0.1)) model.add(Dense(units=1)) # 入力スペックを定義 input_spec = tf.TensorSpec(shape=(None, 10, 2), dtype=tf.float32) # 出力スペックを計算 output_spec = model.compute_output_spec(input_spec) print(output_spec)
出力は以下の通り。
<KerasTensor shape=(None, 1), dtype=float32, sparse=False, name=keras_tensor_392>
-
get_config(self)
- モデルの設定を辞書形式で返す。
- 再構築に使用可能。
from keras.models import Sequential from keras.layers import Dense, LSTM, Input # モデルの構築 model = Sequential() # レイヤーの追加 model.add(Input(shape=(10, 2))) model.add(LSTM(units=30)) model.add(Dense(units=1)) # モデルの設定 print(model.get_config())
出力は以下の通り。
{'name': 'sequential_19', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None}, 'layers': [{'module': 'keras.layers', 'class_name': 'InputLayer', 'config': {'batch_shape': (None, 10, 2), 'dtype': 'float32', 'sparse': False, 'name': 'input_layer_16'}, 'registered_name': None}, {'module': 'keras.layers', 'class_name': 'LSTM', 'config': {'name': 'lstm_55', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None}, 'return_sequences': False, 'return_state': False, 'go_backwards': False, 'stateful': False, 'unroll': False, 'zero_output_for_mask': False, 'units': 30, 'activation': 'tanh', 'recurrent_activation': 'sigmoid', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'recurrent_initializer': {'module': 'keras.initializers', 'class_name': 'Orthogonal', 'config': {'seed': None, 'gain': 1.0}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'unit_forget_bias': True, 'kernel_regularizer': None, 'recurrent_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'recurrent_constraint': None, 'bias_constraint': None, 'dropout': 0.0, 'recurrent_dropout': 0.0, 'seed': None}, 'registered_name': None, 'build_config': {'input_shape': (None, 10, 2)}}, {'module': 'keras.layers', 'class_name': 'Dense', 'config': {'name': 'dense_15', 'trainable': True, 'dtype': {'module': 'keras', 'class_name': 'DTypePolicy', 'config': {'name': 'float32'}, 'registered_name': None}, 'units': 1, 'activation': 'linear', 'use_bias': True, 'kernel_initializer': {'module': 'keras.initializers', 'class_name': 'GlorotUniform', 'config': {'seed': None}, 'registered_name': None}, 'bias_initializer': {'module': 'keras.initializers', 'class_name': 'Zeros', 'config': {}, 'registered_name': None}, 'kernel_regularizer': None, 'bias_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}, 'registered_name': None, 'build_config': {'input_shape': (None, 30)}}], 'build_input_shape': (None, 10, 2)}
-
from_config(cls, config, custom_objects=None)
- 設定からモデルを再構築する。
from keras.models import Sequential from keras.layers import Dense, LSTM, Input # モデルの構築 model_1 = Sequential() # レイヤーの追加 model_1.add(Input(shape=(10, 2))) model_1.add(LSTM(units=30)) model_1.add(Dense(units=1)) print(model.layers) print("="*30) # モデルの取得 config = model_1.get_config() model_2 = Sequential.from_config(config, custom_objects=False) print(model_2.layers)
出力は以下の通り。
[<LSTM name=lstm_55, built=True>, <Dense name=dense_15, built=True>] ============================== [<LSTM name=lstm_57, built=True>, <Dense name=dense_17, built=True>]
さいごに
Sequential
クラスについてなんとなく理解できた。
結局、基本的にはadd
メソッドを使用するだけで済みそうな気がした。
一応それ以外にも色々なメソッドやプロパティがあることは覚えておこうと思う。
ではまた
Discussion