【Python】kerasの可視化されたモデルのパラメータの数の計算方法

8月 1, 2020

KerasのSequentialモデルのサンプル1

Kerasのパラメータの計算方法として次のWebのサンプルを使って計算します。回答で、明確な計算方法が書かれていなかったので記事にしてみました。
https://teratail.com/questions/165439
この例でのKerasのSequentialモデルは以下の通りです。

from keras.models import Sequential
from keras.layers import Dense, Dropout,     Flatten, Conv2D, MaxPool2D

model = Sequential()

model.add(Conv2D(filters=32, kernel_size=(5, 5), padding="same", activation="relu", input_shape=(28, 28, 1)))
model.add(Conv2D(filters=32, kernel_size=(5, 5), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same", activation="relu"))
model.add(Conv2D(filters=64, kernel_size=(3, 3), padding="same", activation="relu"))
model.add(MaxPool2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(256, activation="relu"))
model.add(Dropout(0.25))
model.add(Dense(10, activation="softmax"))

モデルの深層構造を可視化する

このSequentialモデルを可視化すると以下の通りになります。

print(model.summary())

出力結果
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)        832       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 32)        25632     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 14, 14, 64)        18496     
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 14, 14, 64)        36928     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 7, 7, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 3136)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 256)               803072    
_________________________________________________________________
dropout_3 (Dropout)          (None, 256)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                2570      
=================================================================
Total params: 887,530
Trainable params: 887,530
Non-trainable params: 0
_________________________________________________________________

サイト上の回答で計算方法が書かれていますが、丁寧ではありません。Paramの計算方法は以下の通りです。

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 28, 28, 32)        832       ← conv_size(5*5)*filter_num(32)*rgb_num(1)+bias_num(32)=832    
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 32)        25632     ← conv_size(5*5)*filter_num(32*32)+bias_num(32)=25632
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 14, 14, 64)        18496     ← conv_size(3*3)*filter_num(64*32)+bias_num(64)=18496
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 14, 14, 64)        36928     ← conv_size(3*3)*filter_num(64*32)+bias_num(64)=18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 7, 7, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 3136)              0         ← 畳み込み後の画像の幅(7)*畳み込み後の画像の高さ(7)*filter_num(64)
_________________________________________________________________
dense_1 (Dense)              (None, 256)               803072    ← 入力層の数(3136)*中間層の数(256)+bias_num(256)=803072
_________________________________________________________________
dropout_3 (Dropout)          (None, 256)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                2570      ← 中間層の数(256)*出力層の数10+bias_num(10)=2570
=================================================================
Total params: 887,530
Trainable params: 887,530
Non-trainable params: 0
_________________________________________________________________

解説

バイアスというのは、切片のことです。学校で習ったy=ax+bにおけるbの部分です。ニューラルネットワークの場合、y=wx+w’x’+w"’x"’+w""x""+bという形で線形結合しますので(曖昧)、このbがbias(=切片)となります。Paramでこの切片を合計した方がよいのか分かりませんが、model.summary()で表示するとこのように表示されて、計算はこのようにやればParamの数値と合致するというだけです。

なぜ、バイアス(切片)を足すのか?

中間層のニューロンの数だけバイアスがあるからです。ちなみに出力層のニューロンにもバイアスがあります。Paramは単に変化するパラメータを合計しているだけです。およその数がわかればいいのです。

paramの数値は大きくした方がよいのか?

わかりません。しかし、大きすぎると、GPUサーバのメモリが足りなくて、計算できずにエラーとなります。複雑でない画像の場合や、画像が小さいのに必要以上にParamが大きくなるのは意味がありません。

Paramの使い所

自分がParamの数値を参考にしているのは、畳込み処理をやると、パラメータが少なくなりますので、畳み込みをしすぎて、その後Flatten()で一次元の配列にしたときに、要素数が少なすぎると良い結果がでないと思うので、畳み込みの層や中間層の各層で、今どのくらいの次元数(≒ノード数≒パラメーター数)なのかを確認するときにParamの数値が参考になります。

画像を単なるニューラルネットワークで計算した場合

画像を単なるニューラルネットワークで機械学習するとします。KerasのSequentialモデルのコードです。畳み込み処理を利用していない簡単な例です。

model = Sequential()

# 横640縦480のカラー画像を一次元の配列に変換するという意味。
# 一直線にすることでニューラルネットワークの計算が可能となる
model.add(Flatten(input_shape=(640, 480, 3)))

# 中間層
model.add(Dense(128, activation = "relu"))
# 中間層
model.add(Dense(8, activation = "relu"))
# 出力層
model.add(Dense(50, activation = "softmax"))

KerasのSequentialモデルを可視化すると以下のようになります。

print(model.summary())

# 出力結果

Layer (type)                 Output Shape              Param #   
=================================================================
flatten_1 (Flatten)          (None, 921600)            0         
_________________________________________________________________
dense_1 (Dense)              (None, 128)               117964928 ← 入力層の数(921600)*中間層の数(128)+bias(128)
_________________________________________________________________
dense_2 (Dense)              (None, 8)                 1032      ← 中間層の数(128)*中間層の数(8)+biasの数(8)=1032
_________________________________________________________________
dense_3 (Dense)              (None, 50)                450       ← 中間層の数(8)*出力層の数(50)+biasの数(50)=450(50)=450
=================================================================
Total params: 117,966,410
Trainable params: 117,966,410
Non-trainable params: 0
_________________________________________________________________

囲碁のAIの層の仕組み

http://home.q00.itscom.net/otsuki/20160415AlphaGopublic.pdf
この記事の通りにKerasでSequentialを作成すると以下の通りになる。(Pooling層とかDropout層とか省略していると思うので、分かり次第修正しますが…)

model = Sequential()

model.add(Conv2D(192, (5, 5), padding='same', activation="relu", input_shape=(19, 19, 48)))
for i in range(0,10):
    model.add(Conv2D(192, (3, 3), padding='same', activation="relu", input_shape=(19, 19, 48)))

model.add(Flatten())

# 出力層
model.add(Dense(19*19, activation="softmax"))

print(model.summary())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 19, 19, 192)       230592    ← conv_size(5*5)*filter_num(192)*channel_num(48)+bias_num(192)=230592    
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 19, 19, 192)       331968    ← conv_size(3*3)*filter_num(192*192)+bias_num(192)=331968
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 19, 19, 192)       331968    
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 19, 19, 192)       331968    
_________________________________________________________________
flatten_1 (Flatten)          (None, 69312)             0         ← 畳み込み後の画像の幅(19)*畳み込み後の画像の高さ(19)*filter_num(192)=69312
_________________________________________________________________
dense_1 (Dense)              (None, 361)               25021993  ← 入力層の数(69312)*出力層の数(19*19)+biasの数(361)=25021993
=================================================================
Total params: 28,572,265
Trainable params: 28,572,265
Non-trainable params: 0
_________________________________________________________________

このKerasのSequentialが他の画像処理でも利用できるのか、いつか確認してみたい。