KerasでCNNを書くとき、Conv2Dのfilters数をいくつにするか迷ったことはありますか?
「よくある記事が32か64を使っているから」「なんとなく64にしている」という方も多いと思います。
では実際、32・64・128で精度はどれだけ変わるのでしょうか?そして学習時間は?
今回はGoogle ColabとCIFAR-10を使い、filters数だけを変えた3パターンを実験で比較しました。
この記事を読むとわかること:
- filters=32・64・128でval_accuracyはどう変わるか
- 学習時間(秒)とパラメータ数の違い
- 精度と計算コストのトレードオフを踏まえた選び方
filtersとは?増やすと何が起きるか
Conv2Dのfilters(フィルタ数)は、その層が検出できる特徴パターンの数です。
filters=32なら「32種類の特徴」を同時に検出し、filters=64なら「64種類」を検出します。多いほど複雑なパターンを学習できますが、パラメータ数と計算コストは比例して増加します。
直感的にはこのように考えると整理しやすいです。
- filters=32:エッジ・シンプルなテクスチャ程度なら十分
- filters=64:中程度の複雑さのパターンに対応
- filters=128:細かい特徴・複雑なパターンも検出可能
では実際に数値で確認してみましょう。
※特徴マップの可視化で実際に何が検出されているか確認したい方 → 中間層の特徴マップを可視化してみた|Keras × CNN × MNIST
実験設定:3パターンのモデルコード
使用環境はGoogle Colab(GPU:T4)、データセットはCIFAR-10(32×32×3のカラー画像、10クラス)です。
filters数以外の条件(層数・Optimizer・エポック数・バッチサイズ)は全て同一にして、filters数の影響だけを取り出します。学習時間はtime.time()で計測しました。
実験コード
環境準備(最初に一度だけ実行)
# ── 環境準備(最初に一度だけ実行)──────────────────────
!apt-get -y install fonts-ipafont-gothic
!rm -rf /root/.cache/matplotlib
!pip install -q japanize_matplotlib
print("環境準備完了")
実行結果をクリックして内容を開く
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
fonts-ipafont-mincho
The following NEW packages will be installed:
fonts-ipafont-gothic fonts-ipafont-mincho
0 upgraded, 2 newly installed, 0 to remove and 37 not upgraded.
Need to get 8,237 kB of archives.
After this operation, 28.7 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-gothic all 00303-21ubuntu1 [3,513 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy/universe amd64 fonts-ipafont-mincho all 00303-21ubuntu1 [4,724 kB]
Fetched 8,237 kB in 2s (4,623 kB/s)
Selecting previously unselected package fonts-ipafont-gothic.
(Reading database ... 121852 files and directories currently installed.)
Preparing to unpack .../fonts-ipafont-gothic_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-gothic (00303-21ubuntu1) ...
Selecting previously unselected package fonts-ipafont-mincho.
Preparing to unpack .../fonts-ipafont-mincho_00303-21ubuntu1_all.deb ...
Unpacking fonts-ipafont-mincho (00303-21ubuntu1) ...
Setting up fonts-ipafont-mincho (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-mincho/ipam.ttf to provide /usr/share/fonts/truetype/fonts-japanese-mincho.ttf (fonts-japanese-mincho.ttf) in auto mode
Setting up fonts-ipafont-gothic (00303-21ubuntu1) ...
update-alternatives: using /usr/share/fonts/opentype/ipafont-gothic/ipag.ttf to provide /usr/share/fonts/truetype/fonts-japanese-gothic.ttf (fonts-japanese-gothic.ttf) in auto mode
Processing triggers for fontconfig (2.13.1-4.2ubuntu5) ...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.1/4.1 MB 31.0 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Building wheel for japanize_matplotlib (setup.py) ... done
環境準備完了
import・データ準備・共通関数
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import japanize_matplotlib
import time
# CIFAR-10データの読み込み・前処理
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
# モデル構築関数(filtersを引数で切り替え)
def build_cnn(filters, name):
return keras.Sequential([
keras.layers.Input(shape=(32, 32, 3)),
keras.layers.Conv2D(filters, (3, 3), activation='relu', padding='same'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(filters * 2, (3, 3), activation='relu', padding='same'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Flatten(),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dense(10, activation='softmax')
], name=name)
# 共通コンパイル&学習関数(学習時間も計測)
def compile_and_fit(model):
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
start = time.time()
history = model.fit(
x_train, y_train,
epochs=30,
batch_size=64,
validation_split=0.2,
verbose=1
)
elapsed = time.time() - start
return history, elapsed
実行結果をクリックして内容を開く
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 4s 0us/step
3パターンの学習実行
print("\n=== Pattern A:filters=32 ===")
model_A = build_cnn(32, 'A_filters32')
history_A, time_A = compile_and_fit(model_A)
print(f"学習時間:{time_A:.1f}秒 パラメータ数:{model_A.count_params():,}")
print("\n=== Pattern B:filters=64 ===")
model_B = build_cnn(64, 'B_filters64')
history_B, time_B = compile_and_fit(model_B)
print(f"学習時間:{time_B:.1f}秒 パラメータ数:{model_B.count_params():,}")
print("\n=== Pattern C:filters=128 ===")
model_C = build_cnn(128, 'C_filters128')
history_C, time_C = compile_and_fit(model_C)
print(f"学習時間:{time_C:.1f}秒 パラメータ数:{model_C.count_params():,}")
# テストデータで最終精度を評価
test_results = {
'A:filters=32': model_A.evaluate(x_test, y_test, verbose=0),
'B:filters=64': model_B.evaluate(x_test, y_test, verbose=0),
'C:filters=128': model_C.evaluate(x_test, y_test, verbose=0),
}
実行結果をクリックして内容を開く
=== Pattern A:filters=32 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 16s 12ms/step - accuracy: 0.3625 - loss: 1.7537 - val_accuracy: 0.5511 - val_loss: 1.2897 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.5850 - loss: 1.1766 - val_accuracy: 0.6335 - val_loss: 1.0524 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.6487 - loss: 1.0045 - val_accuracy: 0.6507 - val_loss: 1.0107 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.6932 - loss: 0.8887 - val_accuracy: 0.6583 - val_loss: 0.9884 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.7162 - loss: 0.8132 - val_accuracy: 0.6740 - val_loss: 0.9524 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.7485 - loss: 0.7218 - val_accuracy: 0.6980 - val_loss: 0.9009 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.7695 - loss: 0.6715 - val_accuracy: 0.6712 - val_loss: 0.9868 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.7873 - loss: 0.6083 - val_accuracy: 0.6960 - val_loss: 0.9115 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.8138 - loss: 0.5399 - val_accuracy: 0.6925 - val_loss: 0.9418 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.8305 - loss: 0.4865 - val_accuracy: 0.6976 - val_loss: 0.9703 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.8525 - loss: 0.4212 - val_accuracy: 0.6984 - val_loss: 1.0167 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.8712 - loss: 0.3754 - val_accuracy: 0.6931 - val_loss: 1.0332 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.8863 - loss: 0.3267 - val_accuracy: 0.6876 - val_loss: 1.1452 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9073 - loss: 0.2805 - val_accuracy: 0.6877 - val_loss: 1.2071 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.9169 - loss: 0.2407 - val_accuracy: 0.6874 - val_loss: 1.2856 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.9322 - loss: 0.1992 - val_accuracy: 0.6879 - val_loss: 1.3737 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9410 - loss: 0.1747 - val_accuracy: 0.6850 - val_loss: 1.4368 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9494 - loss: 0.1513 - val_accuracy: 0.6843 - val_loss: 1.5439 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9610 - loss: 0.1223 - val_accuracy: 0.6741 - val_loss: 1.7076 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.9629 - loss: 0.1131 - val_accuracy: 0.6837 - val_loss: 1.7454 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9649 - loss: 0.1046 - val_accuracy: 0.6813 - val_loss: 1.8495 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9692 - loss: 0.0897 - val_accuracy: 0.6708 - val_loss: 1.9698 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9668 - loss: 0.0940 - val_accuracy: 0.6768 - val_loss: 2.0167 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.9767 - loss: 0.0708 - val_accuracy: 0.6716 - val_loss: 2.1593 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9788 - loss: 0.0664 - val_accuracy: 0.6704 - val_loss: 2.3555 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9714 - loss: 0.0868 - val_accuracy: 0.6649 - val_loss: 2.2778 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9781 - loss: 0.0709 - val_accuracy: 0.6710 - val_loss: 2.3457 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.9799 - loss: 0.0596 - val_accuracy: 0.6769 - val_loss: 2.4372 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9782 - loss: 0.0635 - val_accuracy: 0.6720 - val_loss: 2.4973 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - accuracy: 0.9836 - loss: 0.0487 - val_accuracy: 0.6775 - val_loss: 2.5907 学習時間:103.6秒 パラメータ数:545,098 === Pattern B:filters=64 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 9ms/step - accuracy: 0.3862 - loss: 1.6852 - val_accuracy: 0.5938 - val_loss: 1.1673 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.6184 - loss: 1.0908 - val_accuracy: 0.6383 - val_loss: 1.0413 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.6817 - loss: 0.9116 - val_accuracy: 0.6779 - val_loss: 0.9395 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7183 - loss: 0.8030 - val_accuracy: 0.6903 - val_loss: 0.9098 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.7531 - loss: 0.7030 - val_accuracy: 0.6893 - val_loss: 0.9225 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.7854 - loss: 0.6167 - val_accuracy: 0.7042 - val_loss: 0.8753 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.8111 - loss: 0.5454 - val_accuracy: 0.7002 - val_loss: 0.9164 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.8383 - loss: 0.4693 - val_accuracy: 0.7085 - val_loss: 0.8816 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.8660 - loss: 0.3888 - val_accuracy: 0.7191 - val_loss: 0.9419 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.8885 - loss: 0.3244 - val_accuracy: 0.7155 - val_loss: 1.0077 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9102 - loss: 0.2634 - val_accuracy: 0.7003 - val_loss: 1.1001 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9230 - loss: 0.2238 - val_accuracy: 0.7041 - val_loss: 1.1758 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9444 - loss: 0.1695 - val_accuracy: 0.7016 - val_loss: 1.2449 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9571 - loss: 0.1348 - val_accuracy: 0.7043 - val_loss: 1.3737 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9633 - loss: 0.1136 - val_accuracy: 0.6952 - val_loss: 1.5601 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9632 - loss: 0.1103 - val_accuracy: 0.6918 - val_loss: 1.5530 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9679 - loss: 0.0962 - val_accuracy: 0.7021 - val_loss: 1.6425 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9768 - loss: 0.0693 - val_accuracy: 0.6998 - val_loss: 1.7488 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9770 - loss: 0.0710 - val_accuracy: 0.6998 - val_loss: 1.8728 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9761 - loss: 0.0712 - val_accuracy: 0.6936 - val_loss: 1.9332 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9793 - loss: 0.0593 - val_accuracy: 0.6957 - val_loss: 1.9568 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9795 - loss: 0.0589 - val_accuracy: 0.6873 - val_loss: 2.1381 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9767 - loss: 0.0705 - val_accuracy: 0.6933 - val_loss: 2.1083 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9761 - loss: 0.0682 - val_accuracy: 0.6873 - val_loss: 2.2367 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9833 - loss: 0.0510 - val_accuracy: 0.6954 - val_loss: 2.3435 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9809 - loss: 0.0529 - val_accuracy: 0.6898 - val_loss: 2.3137 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9833 - loss: 0.0515 - val_accuracy: 0.6896 - val_loss: 2.2306 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 6ms/step - accuracy: 0.9792 - loss: 0.0596 - val_accuracy: 0.6908 - val_loss: 2.6236 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - accuracy: 0.9775 - loss: 0.0680 - val_accuracy: 0.6929 - val_loss: 2.4238 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - accuracy: 0.9858 - loss: 0.0414 - val_accuracy: 0.6917 - val_loss: 2.6809 学習時間:129.3秒 パラメータ数:1,125,642 === Pattern C:filters=128 === Epoch 1/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 12s 14ms/step - accuracy: 0.3838 - loss: 1.6947 - val_accuracy: 0.5943 - val_loss: 1.1492 Epoch 2/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.6297 - loss: 1.0574 - val_accuracy: 0.6610 - val_loss: 0.9736 Epoch 3/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.6973 - loss: 0.8735 - val_accuracy: 0.6782 - val_loss: 0.9280 Epoch 4/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.7350 - loss: 0.7565 - val_accuracy: 0.6952 - val_loss: 0.8848 Epoch 5/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.7762 - loss: 0.6437 - val_accuracy: 0.7054 - val_loss: 0.8593 Epoch 6/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 9s 14ms/step - accuracy: 0.8135 - loss: 0.5388 - val_accuracy: 0.7107 - val_loss: 0.8953 Epoch 7/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 11ms/step - accuracy: 0.8447 - loss: 0.4484 - val_accuracy: 0.7250 - val_loss: 0.8993 Epoch 8/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.8769 - loss: 0.3591 - val_accuracy: 0.7106 - val_loss: 1.0159 Epoch 9/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9021 - loss: 0.2846 - val_accuracy: 0.7016 - val_loss: 1.0348 Epoch 10/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9246 - loss: 0.2213 - val_accuracy: 0.7145 - val_loss: 1.1100 Epoch 11/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9445 - loss: 0.1675 - val_accuracy: 0.7009 - val_loss: 1.2857 Epoch 12/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9494 - loss: 0.1451 - val_accuracy: 0.7088 - val_loss: 1.3051 Epoch 13/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 12ms/step - accuracy: 0.9630 - loss: 0.1096 - val_accuracy: 0.6985 - val_loss: 1.4761 Epoch 14/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 8s 13ms/step - accuracy: 0.9701 - loss: 0.0912 - val_accuracy: 0.7029 - val_loss: 1.6217 Epoch 15/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9726 - loss: 0.0842 - val_accuracy: 0.7097 - val_loss: 1.6592 Epoch 16/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9759 - loss: 0.0716 - val_accuracy: 0.7007 - val_loss: 1.6959 Epoch 17/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9745 - loss: 0.0750 - val_accuracy: 0.7036 - val_loss: 1.8456 Epoch 18/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9782 - loss: 0.0644 - val_accuracy: 0.7007 - val_loss: 1.9264 Epoch 19/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9778 - loss: 0.0625 - val_accuracy: 0.7023 - val_loss: 1.8913 Epoch 20/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9800 - loss: 0.0573 - val_accuracy: 0.6957 - val_loss: 2.0243 Epoch 21/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9759 - loss: 0.0698 - val_accuracy: 0.6911 - val_loss: 2.0259 Epoch 22/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9815 - loss: 0.0579 - val_accuracy: 0.7027 - val_loss: 2.2861 Epoch 23/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9832 - loss: 0.0484 - val_accuracy: 0.6973 - val_loss: 2.1983 Epoch 24/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9801 - loss: 0.0578 - val_accuracy: 0.6868 - val_loss: 2.3369 Epoch 25/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9823 - loss: 0.0511 - val_accuracy: 0.6954 - val_loss: 2.4092 Epoch 26/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9802 - loss: 0.0576 - val_accuracy: 0.6994 - val_loss: 2.5139 Epoch 27/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9849 - loss: 0.0493 - val_accuracy: 0.7012 - val_loss: 2.5416 Epoch 28/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9873 - loss: 0.0375 - val_accuracy: 0.6995 - val_loss: 2.4627 Epoch 29/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9850 - loss: 0.0458 - val_accuracy: 0.6915 - val_loss: 2.5602 Epoch 30/30 625/625 ━━━━━━━━━━━━━━━━━━━━ 7s 11ms/step - accuracy: 0.9859 - loss: 0.0453 - val_accuracy: 0.7005 - val_loss: 2.6231 学習時間:217.9秒 パラメータ数:2,397,322
学習曲線グラフ + 最終結果サマリー
histories = {
'A:filters=32': history_A,
'B:filters=64': history_B,
'C:filters=128': history_C,
}
# ── val_accuracy / val_loss 比較グラフ ───────────────
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
for label, h in histories.items():
axes[0].plot(h.history['val_accuracy'], label=label)
axes[1].plot(h.history['val_loss'], label=label)
axes[0].set_title('val_accuracy の比較(全30エポック)')
axes[1].set_title('val_loss の比較(全30エポック)')
for ax in axes:
ax.set_xlabel('Epoch'); ax.legend(); ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('filters_comparison.png', dpi=150)
plt.show()
# ── 最終結果サマリー ─────────────────────────────────
key_order = ['A:filters=32', 'B:filters=64', 'C:filters=128']
time_list = {'A:filters=32': time_A, 'B:filters=64': time_B, 'C:filters=128': time_C}
params_list = {
'A:filters=32': model_A.count_params(),
'B:filters=64': model_B.count_params(),
'C:filters=128': model_C.count_params(),
}
print("\n===== 最終結果サマリー =====")
print(f"{'Pattern':>16} | {'Val Acc':>8} | {'Test Acc':>9} | {'Time(s)':>8} | {'Params':>10}")
print("-" * 65)
for key in key_order:
val_acc = histories[key].history['val_accuracy'][-1]
test_loss, test_acc = test_results[key]
elapsed = time_list[key]
params = params_list[key]
print(f"{key:>16} | {val_acc:>8.4f} | {test_acc:>9.4f} | {elapsed:>8.1f} | {params:>10,}")
print("-" * 65)
最終結果サマリー
===== 最終結果サマリー =====
Pattern | Val Acc | Test Acc | Time(s) | Params
-----------------------------------------------------------------
A:filters=32 | 0.6775 | 0.6707 | 103.6 | 545,098
B:filters=64 | 0.6917 | 0.6823 | 129.3 | 1,125,642
C:filters=128 | 0.7005 | 0.6969 | 217.9 | 2,397,322
-----------------------------------------------------------------
実験結果①:精度の比較
val_accuracy の比較(全30エポック)
精度グラフ
損失グラフ
グラフから読み取れること:
- filters=128(パターンC)が最も高い最終精度に到達しましたが、差は思ったより小さい結果でした。
- filters=32(パターンA)は序盤の立ち上がりが最も速く、精度への到達効率が良いことが見て取れます。
- val_lossを見ると、filters数が多いモデルほどvalidationとのギャップがやや大きくなる傾向が見られ、過学習の兆候が示唆されます。
| パターン | 最終 val_accuracy | 最終 test_accuracy | 収束の速さ | 過学習の傾向 |
|---|---|---|---|---|
| A:filters=32 | 67.75% | 67.07% | 速い | 少ない |
| B:filters=64 | 69.17% | 68.23% | 普通 | 中程度 |
| C:filters=128 | 70.05% | 69.69% | やや遅い | やや多い |
実験結果②:学習時間とパラメータ数の比較
精度だけ見ると「filters=128が最強」に見えますが、コストを加えると話が変わります。
| パターン | Test Accuracy | 学習時間(秒) | パラメータ数 | 精度/コスト比 |
|---|---|---|---|---|
| A:filters=32 | 67.07% | 103.6秒 | 545,098 | ◎ 最良 |
| B:filters=64 | 68.23% | 129.3秒 | 1,125,642 | ○ バランス |
| C:filters=128 | 69.69% | 217.9秒 | 2,397,322 | △ 高コスト |
学習時間・パラメータ数を見ると、filters=32からfilters=128へ大きく増加することが確認できます。
精度の改善幅と比べたとき、コストの増加が精度向上を上回る場合があるという「トレードオフ」がこの表から読み取れます。
Colabの無料枠(GPU利用時間に制限あり)で実験する場合は特に、このコスト感覚が重要になります。
結論:filters数はどう選ぶべきか
実験結果をもとに、状況別の結論をまとめます。
「まず動かしてみたい・プロトタイプを作りたい」→ filters=32から始める
学習が速く、結果をすぐに確認できます。精度に不満が出てから大きくすれば十分です。
「バランスよく使いたい・迷ったらこれ」→ filters=64
多くの教材やサンプルコードが64を使っているのは理由があります。精度と速度のバランスが良く、CIFAR-10程度の難易度なら十分な表現力があります。
「精度を追求したい・学習時間を気にしない」→ filters=128以上を検討
ただしCIFAR-10レベルでは精度改善幅は限定的です。より複雑なデータセットや深いモデルほど効果が出やすくなります。
また、よくある設計パターンとして「Conv2D(32) → Conv2D(64)」のように層を深くするにつれてfilters数を増やす方法があります。最初の層でシンプルな特徴(エッジ等)を検出し、深い層で複雑な特徴を検出するという考え方です。
補足:filters数の増やし方のパターン
今回の実験では全層で同じfilters数を使いましたが、実際によく見るアーキテクチャでは層が深くなるほどfilters数を増やす設計が一般的です。
例:32 → 64 → 128(徐々に増やす)
これは最初の層では「エッジ・色」などシンプルな特徴を少ないfiltersで検出し、深い層ほど「形・テクスチャの組み合わせ」など複雑な特徴を多くのfiltersで表現するという考え方に基づいています。
全層を128にするより、32→64→128と徐々に増やす方がパラメータ数を抑えながら表現力を確保できます。
まとめ
今回はKerasとCIFAR-10を使い、Conv2Dのfilters数を32・64・128の3パターンで比較しました。
- プロトタイプ・速さ優先なら → filters=32
- バランス重視・迷ったら → filters=64
- 精度追求・コスト許容できるなら → filters=128以上
「大きければ良い」ではなく、精度とコストのトレードオフを意識して選ぶことが重要です。
関連記事もあわせてどうぞ:
- CNNの層数を変えると何が変わるか → CNNの層数で精度はどう変わる?1層・2層・3層モデルをKerasで比較検証
- CIFAR-10での過学習対策 → CIFAR-10で学ぶ:過学習(オーバーフィッティング)の判定方法と実践的対策
- CIFAR-10のCNNモデル詳細 → CIFAR-10の応用例と実装方法|Pythonコード付き実践ガイド



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