Kerasでモデルを作ると、こんな出力を必ず目にします。
model.summary()
でも最初のうちは、「Output ShapeのNoneって何?」「Param # はどうやって計算されてるの?」と疑問に思いながら読み飛ばしてしまいがちです。
この記事では、model.summary()の各列の意味とパラメータ数の計算方法を、CNNモデルを例に使ってひとつずつ丁寧に解説します。一度理解してしまえば、モデルの設計ミスやパラメータ数の膨らみにもすぐ気づけるようになります。
📘 この記事でわかること
- model.summary()の3つの列(Layer / Output Shape / Param #)の読み方
- Conv2D・Dense・Pooling・Flatten層それぞれのパラメータ数の計算方法
- パラメータ数を確認するべき理由(過学習との関係)
model.summary()を表示するコード
まず確認用のシンプルなCNNモデルをKerasで作り、summary()を表示してみます。データセットはMNIST(28×28のグレースケール画像)を想定しています。
from tensorflow import keras
from tensorflow.keras import layers
model = keras.Sequential([
keras.Input(shape=(28, 28, 1)),
layers.Conv2D(32, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax'),
])
model.summary()
ここでDense層を2層(64次元 → 10次元)にしているのには理由があります。5,408次元をいきなり10次元に落とすより、一度中間層で特徴を整理してからクラス分類する方が、モデルが複雑なパターンを学習しやすいためです。ただしMNISTのようなシンプルなデータでは、Dense層を1層にしても精度はほとんど変わりません。今回はパラメータ計算のパターンを2種類紹介するという教育的な目的もあって2層にしています。
実行すると、以下のような出力が得られます。
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃ Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D) │ (None, 26, 26, 32) │ 320 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D) │ (None, 13, 13, 32) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten (Flatten) │ (None, 5408) │ 0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense) │ (None, 64) │ 346,176 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense) │ (None, 10) │ 650 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 347,146 (1.32 MB)
Trainable params: 347,146 (1.32 MB)
Non-trainable params: 0 (0.00 B)
では、この表をひとつずつ読み解いていきましょう。
3つの列の意味
① Layer (type):層の名前と種類
そのままの意味で、モデルに追加した層の名前と種類が表示されます。Sequential APIで作ると自動で conv2d dense などと命名されます。Functional APIや name= 引数で任意の名前をつけることもできます。
② Output Shape:その層が出力するテンソルの形
各層を通過したあとのデータの「形(shape)」が表示されます。たとえば (None, 26, 26, 32) は「バッチサイズ × 縦26 × 横26 × チャンネル32」を意味します。
先頭の None はバッチサイズです。バッチサイズはコンパイル時には未確定なので、Kerasは None として表示します。実際の学習時には 32 や 64 などの値が入ります。
③ Param #:その層が持つ学習パラメータの数
その層が持つ「重み(weight)」と「バイアス(bias)」の合計数です。学習の際に調整される値の数です。多いほどモデルが複雑になり、過学習のリスクも上がります。
Pooling層とFlatten層は常に 0 です。これらはデータを変換するだけで、学習可能なパラメータを持ちません。
Output Shape の変化を追う
入力から出力まで、データの形がどう変わるかを順番に見てみましょう。
入力:(None, 28, 28, 1)
MNISTの入力画像。28×28ピクセル、チャンネル数1(グレースケール)。
Conv2D(32, (3,3)) → (None, 26, 26, 32)
3×3のカーネルを padding='valid'(デフォルト)で適用すると、縦横それぞれ (28 - 3 + 1) = 26 になります。フィルター数32なので、チャンネルが32になります。
MaxPooling2D((2,2)) → (None, 13, 13, 32)
2×2の領域で最大値をとり、サイズが半分になります。26 ÷ 2 = 13。チャンネル数は変わりません。
Flatten() → (None, 5408)
多次元テンソルを1次元ベクトルに展開します。13 × 13 × 32 = 5,408。
Dense(64) → (None, 64)
全結合層。5,408次元の入力を64次元に変換します。
Dense(10) → (None, 10)
出力層。MNIST(0〜9)の10クラス分類なので10次元。Softmaxで確率に変換します。
Param # の計算方法
Param # がどのように計算されているかを、各層ごとに確認します。一度理解すると、モデル設計のときにパラメータ数を頭の中で見積もれるようになります。
Conv2D:320パラメータ
計算式はこうなります:
(カーネルH × カーネルW × 入力チャンネル数 + 1) × フィルター数
今回の場合:
(3 × 3 × 1 + 1) × 32 = 10 × 32 = 320
+1 はバイアス(bias)の分です。バイアスはフィルターごとに1つ存在します。use_bias=False を指定するとバイアスなしにもできます。
MaxPooling2D:0パラメータ
Pooling層は「領域内の最大値を取る」という固定の演算を行うだけで、学習可能なパラメータを持ちません。
Flatten:0パラメータ
データの形を変えるだけで、演算や学習はありません。
Dense(64):346,176パラメータ
計算式:
(入力ユニット数 + 1) × 出力ユニット数
(5408 + 1) × 64 = 5409 × 64 = 346,176
Flattenで5,408次元になった入力を、64次元に変換します。各入力ユニットから各出力ユニットへの重みが全部で 5,408 × 64 本、それにバイアスが64個で 346,176 になります。
Denseのパラメータ数が膨らむ原因はここです。 Flattenの出力次元(5,408)が大きければ大きいほど、その後のDense層のパラメータ数が爆発的に増えます。
Dense(10):650パラメータ
(64 + 1) × 10 = 65 × 10 = 650
64次元を10次元(クラス数)に変換します。
Total params の内訳
Total params: 347,146
Trainable params: 347,146
Non-trainable params: 0
Trainable params:学習中に更新されるパラメータの数。
Non-trainable params:固定されて更新されないパラメータ。BatchNormalizationを使うときや、転移学習でベースモデルをフリーズしたときにここに数が出ます。
今回はシンプルなモデルなのでNon-trainable paramsは0ですが、たとえばMobileNetV2を使って特定の層を layer.trainable = False で固定すると、その分がNon-trainableに移ります。
パラメータ数と過学習の関係
パラメータ数はモデルの「表現力の大きさ」を表します。パラメータが多いほど複雑なパターンを学習できますが、一方で訓練データへの過学習が起きやすくなります。
今回のモデルでは Dense(64) の1層だけで346,176パラメータを占めています。これはConv2DやMaxPoolingなど残りの全層を合わせたパラメータの約1,000倍です。
このように、Flatten → Dense の組み合わせがパラメータ数を一気に増やす原因になりがちです。これを防ぐ手法のひとつが GlobalAveragePooling2D(GAP)です。FlattenをGAPに置き換えると、Denseへの入力次元を大幅に小さくできます。
※FlattenとGAPの比較実験はこちらの記事で詳しく解説しています:
→ Global Average Pooling vs Flatten|CNNの最終層、どっちが精度・速度で有利か?【Keras実験】
補足:count_params() でパラメータ数を数値で取得する
summary()の表示だけでなく、パラメータ数をコードの中で数値として取得したいときは count_params() が使えます。
print(model.count_params())
# → 347146
複数モデルを比較するスクリプトや、実験ログに記録したいときに便利です。
まとめ
model.summary()の各列をまとめると次のようになります。
| 列名 | 意味 | 注意点 |
|---|---|---|
| Layer (type) | 層の名前と種類 | nameで任意の名前をつけられる |
| Output Shape | その層の出力テンソルの形 | 先頭のNoneはバッチサイズ(未確定) |
| Param # | 学習パラメータ(重み+バイアス)の数 | Pooling・Flattenは常に0 |
パラメータ数の計算式まとめ:
- Conv2D:(カーネルH × カーネルW × 入力ch + 1) × フィルター数
- Dense:(入力ユニット数 + 1) × 出力ユニット数
- MaxPooling / AveragePooling / Flatten:常に 0
model.summary()を読む習慣をつけると、「パラメータが多すぎないか」「特徴マップのサイズが想定通りか」を毎回確認できます。モデルの設計ミスを早期に発見するためにも、summary()をこまめに確認するようにしましょう。
関連記事もあわせてどうぞ:
- FlattenとGAPの比較実験 → Global Average Pooling vs Flatten|CNNの最終層、どっちが精度・速度で有利か?【Keras実験】
- Conv2Dのフィルター数の選び方 → Conv2DのFilters数(32 vs 64 vs 128)を変えると精度はどう変わる?【CIFAR-10実験】
- 重みの初期化の違い → 【Keras】glorot_uniformとhe_normalの違いをCNNで比較|ReLUならどれを選ぶ?

0 件のコメント:
コメントを投稿