CNNモデルを構築する際、Dense層のユニット数をどの程度に設定すべきかで悩むことは少なくありません。 ユニット数はモデルの表現力や過学習のしやすさに直結する一方で、 明確な正解が示されにくいハイパーパラメータのひとつです。
本記事では、畳み込み層(Conv層)の構成を固定したまま、 Dense層のユニット数のみを変更し、 分類精度や学習挙動にどのような違いが生じるのかを 実験的に検証します。
なぜDense層のユニット数が重要なのか
Dense層は、CNNによって抽出された特徴量を入力として、 最終的な分類判断を行う層です。 そのため、Dense層の設計はモデル全体の性能や汎化能力に大きな影響を与えます。
- ユニット数が少なすぎる → 表現力が不足し、精度が伸びにくい
- ユニット数が多すぎる → 過学習を招きやすく、計算コストも増大する
適切なユニット数はデータセットの規模や複雑さ、 およびモデル構造に依存するため、 実際に学習させて挙動を確認することが不可欠です。
実験条件
データセット
- MNIST(手書き数字分類)
モデル構成(Dense層以外は固定)
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3,3), activation="relu", input_shape=(28,28,1)),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Conv2D(64, (3,3), activation="relu"),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(units, activation="relu"),
tf.keras.layers.Dense(10, activation="softmax")
])
比較したDense層のユニット数
- 64
- 128
- 256
- 512
学習条件
- Optimizer:Adam
- Epoch:20
- Batch size:32
実験コード
以下は、本記事で使用した実験用コードです。 TensorFlow(Keras)を用いて、Dense層のユニット数を変更したCNNモデルを構築・学習し、 分類精度への影響を比較します。 以降のコードでは、モデル定義・学習ループ・結果の集計までを順に示します。
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
# =========================
# Data preparation
# =========================
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
x_train = x_train[..., None]
x_test = x_test[..., None]
# =========================
# Model construction function
# =========================
def build_model(dense_units):
model = models.Sequential([
layers.Input(shape=(28,28,1)),
layers.Conv2D(32, (3,3), activation="relu"),
layers.MaxPooling2D((2,2)),
layers.Conv2D(64, (3,3), activation="relu"),
layers.MaxPooling2D((2,2)),
layers.Flatten(),
layers.Dense(dense_units, activation="relu"),
layers.Dense(10, activation="softmax")
])
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
return model
# =========================
# Experiment configuration
# =========================
dense_units_list = [64, 128, 256, 512]
histories = {}
test_results = {}
# =========================
# Training loop
# =========================
for units in dense_units_list:
print(f"\n=== Dense units: {units} ===")
model = build_model(units)
history = model.fit(
x_train, y_train,
validation_split=0.2,
epochs=20,
batch_size=32,
verbose=1
)
histories[units] = history
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
test_results[units] = (test_loss, test_acc)
実行結果
学習結果をクリックして内容を開く
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11490434/11490434 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step === Dense units: 64 === Epoch 1/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 18s 8ms/step - accuracy: 0.8890 - loss: 0.3589 - val_accuracy: 0.9800 - val_loss: 0.0697 Epoch 2/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 7ms/step - accuracy: 0.9832 - loss: 0.0546 - val_accuracy: 0.9833 - val_loss: 0.0555 Epoch 3/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 12s 8ms/step - accuracy: 0.9889 - loss: 0.0363 - val_accuracy: 0.9868 - val_loss: 0.0468 Epoch 4/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 7ms/step - accuracy: 0.9921 - loss: 0.0254 - val_accuracy: 0.9875 - val_loss: 0.0429 Epoch 5/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 6ms/step - accuracy: 0.9943 - loss: 0.0185 - val_accuracy: 0.9877 - val_loss: 0.0471 Epoch 6/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 12s 8ms/step - accuracy: 0.9948 - loss: 0.0155 - val_accuracy: 0.9864 - val_loss: 0.0513 Epoch 7/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 7ms/step - accuracy: 0.9963 - loss: 0.0115 - val_accuracy: 0.9882 - val_loss: 0.0509 Epoch 8/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 6ms/step - accuracy: 0.9968 - loss: 0.0102 - val_accuracy: 0.9888 - val_loss: 0.0440 Epoch 9/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 11s 7ms/step - accuracy: 0.9977 - loss: 0.0074 - val_accuracy: 0.9900 - val_loss: 0.0471 Epoch 10/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 18s 5ms/step - accuracy: 0.9981 - loss: 0.0058 - val_accuracy: 0.9881 - val_loss: 0.0565 Epoch 11/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 7s 3ms/step - accuracy: 0.9989 - loss: 0.0039 - val_accuracy: 0.9877 - val_loss: 0.0591 Epoch 12/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9981 - loss: 0.0060 - val_accuracy: 0.9897 - val_loss: 0.0480 Epoch 13/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9985 - loss: 0.0043 - val_accuracy: 0.9883 - val_loss: 0.0616 Epoch 14/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9981 - loss: 0.0051 - val_accuracy: 0.9871 - val_loss: 0.0617 Epoch 15/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9990 - loss: 0.0031 - val_accuracy: 0.9908 - val_loss: 0.0565 Epoch 16/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9988 - loss: 0.0033 - val_accuracy: 0.9893 - val_loss: 0.0690 Epoch 17/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9984 - loss: 0.0046 - val_accuracy: 0.9902 - val_loss: 0.0590 Epoch 18/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9985 - loss: 0.0039 - val_accuracy: 0.9900 - val_loss: 0.0670 Epoch 19/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9988 - loss: 0.0036 - val_accuracy: 0.9874 - val_loss: 0.0774 Epoch 20/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9988 - loss: 0.0039 - val_accuracy: 0.9896 - val_loss: 0.0693 === Dense units: 128 === Epoch 1/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 13s 7ms/step - accuracy: 0.8997 - loss: 0.3250 - val_accuracy: 0.9835 - val_loss: 0.0528 Epoch 2/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9858 - loss: 0.0478 - val_accuracy: 0.9887 - val_loss: 0.0405 Epoch 3/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9908 - loss: 0.0291 - val_accuracy: 0.9893 - val_loss: 0.0355 Epoch 4/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9931 - loss: 0.0222 - val_accuracy: 0.9883 - val_loss: 0.0426 Epoch 5/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9956 - loss: 0.0137 - val_accuracy: 0.9897 - val_loss: 0.0370 Epoch 6/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9956 - loss: 0.0125 - val_accuracy: 0.9921 - val_loss: 0.0351 Epoch 7/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9965 - loss: 0.0106 - val_accuracy: 0.9905 - val_loss: 0.0370 Epoch 8/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9974 - loss: 0.0070 - val_accuracy: 0.9883 - val_loss: 0.0531 Epoch 9/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9977 - loss: 0.0067 - val_accuracy: 0.9916 - val_loss: 0.0351 Epoch 10/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9990 - loss: 0.0036 - val_accuracy: 0.9892 - val_loss: 0.0486 Epoch 11/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9981 - loss: 0.0053 - val_accuracy: 0.9909 - val_loss: 0.0535 Epoch 12/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9986 - loss: 0.0048 - val_accuracy: 0.9906 - val_loss: 0.0544 Epoch 13/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9987 - loss: 0.0037 - val_accuracy: 0.9886 - val_loss: 0.0599 Epoch 14/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9987 - loss: 0.0049 - val_accuracy: 0.9881 - val_loss: 0.0597 Epoch 15/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9988 - loss: 0.0038 - val_accuracy: 0.9914 - val_loss: 0.0479 Epoch 16/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9984 - loss: 0.0054 - val_accuracy: 0.9891 - val_loss: 0.0587 Epoch 17/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9995 - loss: 0.0015 - val_accuracy: 0.9895 - val_loss: 0.0646 Epoch 18/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9972 - loss: 0.0079 - val_accuracy: 0.9907 - val_loss: 0.0576 Epoch 19/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9991 - loss: 0.0023 - val_accuracy: 0.9893 - val_loss: 0.0735 Epoch 20/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9991 - loss: 0.0028 - val_accuracy: 0.9916 - val_loss: 0.0562 === Dense units: 256 === Epoch 1/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 8s 4ms/step - accuracy: 0.9093 - loss: 0.2855 - val_accuracy: 0.9824 - val_loss: 0.0568 Epoch 2/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9862 - loss: 0.0425 - val_accuracy: 0.9890 - val_loss: 0.0391 Epoch 3/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9914 - loss: 0.0268 - val_accuracy: 0.9843 - val_loss: 0.0626 Epoch 4/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9929 - loss: 0.0220 - val_accuracy: 0.9902 - val_loss: 0.0380 Epoch 5/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9959 - loss: 0.0122 - val_accuracy: 0.9898 - val_loss: 0.0371 Epoch 6/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9967 - loss: 0.0090 - val_accuracy: 0.9898 - val_loss: 0.0403 Epoch 7/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9977 - loss: 0.0070 - val_accuracy: 0.9898 - val_loss: 0.0418 Epoch 8/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9978 - loss: 0.0065 - val_accuracy: 0.9908 - val_loss: 0.0452 Epoch 9/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9974 - loss: 0.0082 - val_accuracy: 0.9908 - val_loss: 0.0464 Epoch 10/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9982 - loss: 0.0049 - val_accuracy: 0.9916 - val_loss: 0.0539 Epoch 11/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9976 - loss: 0.0081 - val_accuracy: 0.9889 - val_loss: 0.0551 Epoch 12/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9986 - loss: 0.0043 - val_accuracy: 0.9898 - val_loss: 0.0589 Epoch 13/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9985 - loss: 0.0048 - val_accuracy: 0.9911 - val_loss: 0.0526 Epoch 14/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9991 - loss: 0.0030 - val_accuracy: 0.9904 - val_loss: 0.0650 Epoch 15/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9984 - loss: 0.0059 - val_accuracy: 0.9908 - val_loss: 0.0576 Epoch 16/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9989 - loss: 0.0038 - val_accuracy: 0.9899 - val_loss: 0.0630 Epoch 17/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9985 - loss: 0.0053 - val_accuracy: 0.9918 - val_loss: 0.0512 Epoch 18/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9991 - loss: 0.0028 - val_accuracy: 0.9913 - val_loss: 0.0668 Epoch 19/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9994 - loss: 0.0018 - val_accuracy: 0.9911 - val_loss: 0.0616 Epoch 20/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 3ms/step - accuracy: 0.9987 - loss: 0.0036 - val_accuracy: 0.9911 - val_loss: 0.0673 === Dense units: 512 === Epoch 1/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 9s 4ms/step - accuracy: 0.9121 - loss: 0.2877 - val_accuracy: 0.9830 - val_loss: 0.0554 Epoch 2/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9871 - loss: 0.0419 - val_accuracy: 0.9877 - val_loss: 0.0409 Epoch 3/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9928 - loss: 0.0241 - val_accuracy: 0.9895 - val_loss: 0.0369 Epoch 4/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9942 - loss: 0.0170 - val_accuracy: 0.9878 - val_loss: 0.0422 Epoch 5/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9955 - loss: 0.0142 - val_accuracy: 0.9902 - val_loss: 0.0382 Epoch 6/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9960 - loss: 0.0117 - val_accuracy: 0.9855 - val_loss: 0.0604 Epoch 7/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9967 - loss: 0.0096 - val_accuracy: 0.9912 - val_loss: 0.0348 Epoch 8/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9985 - loss: 0.0043 - val_accuracy: 0.9893 - val_loss: 0.0462 Epoch 9/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9985 - loss: 0.0048 - val_accuracy: 0.9905 - val_loss: 0.0478 Epoch 10/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9985 - loss: 0.0044 - val_accuracy: 0.9906 - val_loss: 0.0474 Epoch 11/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9985 - loss: 0.0041 - val_accuracy: 0.9905 - val_loss: 0.0583 Epoch 12/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 10s 4ms/step - accuracy: 0.9980 - loss: 0.0051 - val_accuracy: 0.9882 - val_loss: 0.0807 Epoch 13/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9986 - loss: 0.0042 - val_accuracy: 0.9906 - val_loss: 0.0508 Epoch 14/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9982 - loss: 0.0052 - val_accuracy: 0.9896 - val_loss: 0.0559 Epoch 15/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9996 - loss: 0.0012 - val_accuracy: 0.9873 - val_loss: 0.0695 Epoch 16/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9984 - loss: 0.0057 - val_accuracy: 0.9878 - val_loss: 0.0839 Epoch 17/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9990 - loss: 0.0033 - val_accuracy: 0.9925 - val_loss: 0.0662 Epoch 18/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9986 - loss: 0.0038 - val_accuracy: 0.9906 - val_loss: 0.0597 Epoch 19/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 6s 4ms/step - accuracy: 0.9991 - loss: 0.0034 - val_accuracy: 0.9912 - val_loss: 0.0592 Epoch 20/20 1500/1500 ━━━━━━━━━━━━━━━━━━━━ 5s 4ms/step - accuracy: 0.9999 - loss: 5.1035e-04 - val_accuracy: 0.9904 - val_loss: 0.0811
ユニット数別の学習結果
以下のコードにて学習結果を可視化します。
# ====== 最終結果出力 ======
print("\n===== 最終結果サマリー =====")
print(f"{'Dense units':>12} | {'Train Acc':>10} | {'Val Acc':>8} | {'Test Acc':>9}")
print("-" * 60)
for units in sorted(histories.keys()):
history = histories[units]
test_loss, test_acc = test_results[units]
train_acc = history.history["accuracy"][-1]
val_acc = history.history["val_accuracy"][-1]
print(f"{units:>12} | {train_acc:>10.4f} | {val_acc:>8.4f} | {test_acc:>9.4f}")
print("-" * 60)
plt.figure(figsize=(12,5))
# Accuracy
plt.subplot(1,2,1)
for units, history in histories.items():
plt.plot(history.history["val_accuracy"], label=f"{units}")
plt.title("Validation Accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend(title="Dense units")
# Loss
plt.subplot(1,2,2)
for units, history in histories.items():
plt.plot(history.history["val_loss"], label=f"{units}")
plt.title("Validation Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend(title="Dense units")
plt.tight_layout()
plt.show()
実行結果
===== 最終結果サマリー =====
Dense units | Train Acc | Val Acc | Test Acc
------------------------------------------------------------
64 | 0.9988 | 0.9896 | 0.9906
128 | 0.9988 | 0.9916 | 0.9912
256 | 0.9987 | 0.9911 | 0.9919
512 | 0.9996 | 0.9904 | 0.9890
------------------------------------------------------------
精度グラフ
損失グラフ
Denseユニット数ごとの最終結果まとめ
| Dense units | Train Accuracy | Validation Accuracy | Test Accuracy |
|---|---|---|---|
| 64 | 0.9988 | 0.9896 | 0.9906 |
| 128 | 0.9988 | 0.9916 | 0.9912 |
| 256 | 0.9987 | 0.9911 | 0.9919 |
| 512 | 0.9996 | 0.9904 | 0.9890 |
なぜ Dense=256 付近で性能が頭打ちになるのか?
今回の実験では、Denseユニット数を増やすにつれて 訓練精度(train accuracy)は一貫して向上しました。 これは、ユニット数の増加によりモデルの表現力が高まったためです。
一方で、検証精度およびテスト精度に注目すると、 128〜256ユニット付近で性能が頭打ちとなり、 512ユニットではテスト精度がわずかに低下する結果となりました。
CNNにおいて画像の特徴抽出を担うのは主に畳み込み層(Conv層)であり、 Dense層はそれらの特徴を用いて最終的な分類を行う役割を持ちます。
Dense層のユニット数を過剰に増やすと、 必要以上に複雑な決定境界を学習してしまい、 訓練データにはよく適合する一方で、 未知データに対する汎化性能が低下しやすくなります。
今回の結果から、MNISTのような比較的単純な画像分類タスクでは、 Dense層は「大きくしすぎない」ことが重要であり、 128〜256ユニット程度が精度と汎化性能のバランスが取れた構成であることが分かります。
過学習の出方の違い
Dense層のユニット数を増やすほど、以下の傾向が見られました。
- train accuracy は速く向上する
- val loss が途中から上昇しやすい
Flatten直後のDense層はパラメータ数が急増するため、 過学習の影響が特に顕著になります。
実務での目安と注意点
- MNIST程度の小規模画像分類では Dense 128〜256 が目安
- ユニット数を増やす前に以下を検討する
- Dropoutの導入
- データ拡張
Dense層は「多ければ良い」わけではなく、 精度と過学習のバランスが重要です。
まとめ
本記事では、CNNにおけるDense層のユニット数を変更した場合の影響について、 MNISTデータセットを用いた実験結果をもとに比較・検証しました。
実験から、以下の点が確認できました。
- Denseユニット数を増やすと、学習の収束はやや速くなる
- 一方で、検証精度(val_accuracy)の向上は限定的
- ユニット数が多いほど、検証損失が不安定になり、過学習の兆候が現れやすい
- MNIST規模のタスクでは、Dense 64〜128ユニットでも十分な性能が得られる
これらの結果から、
CNNにおいては、特徴抽出の主役は畳み込み層であり、
Dense層は必要最小限の分類器として設計するのが合理的です。
Dense層を大きくすれば精度が必ず向上するわけではなく、 モデル容量の増加は過学習リスクとのトレードオフになる点に注意が必要です。
次の検証としては、
- Dense層にDropoutを追加した場合の比較
- CIFAR-10など、より複雑なデータセットでの再実験
を行うことで、Dense層設計に対する理解をさらに深めることができます。



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