手書き数字識別タスクにおいて、従来の統計的機械学習手法と近年のディープラーニング手法の性能差を明らかにすることは、モデル選定における重要な指針となります。本記事では、標準的なMNISTデータセットを用い、ディープニューラルネットワーク(DNN)、畳み込みニューラルネットワーク(CNN)、およびサポートベクターマシン(SVM)などの代表的なアルゴリズムを同一条件下で比較した実験結果を報告します。
実験設定
各モデルの評価は以下の共通設定に基づいて行われました。
- 学習エポック数: 10
- 訓練データ数: 60,000件
- テストデータ数: 10,000件
- 入力画像サイズ: 28x28ピクセル(グレースケール)
実験結果の比較
1. 予測精度の比較
テストデータに対する正解率(Accuracy)およびパラメータ数の比較は以下の通りです。
| 手法 | 訓練データ正解率 | テストデータ正解率 | パラメータ数 |
|---|---|---|---|
| ディープニューラルネットワーク (DNN) | 0.9950 | 0.9808 | 1,238,730 |
| CNN + MaxPooling | 0.9906 | 0.9742 | 1,332,810 |
| SVC (RBFカーネル) | 0.9899 | 0.9792 | N/A |
| カーネル近似 + LinearSVC | 0.9378 | 0.9371 | N/A |
2. 実行効率の比較
CPU環境(80スレッド、128GBメモリ)における学習および推論の合計時間は以下の通りです。
| 手法 | 実行時間(学習 + 推論) |
|---|---|
| DNN | 約38.8秒 |
| CNN + MaxPooling | 約11分20秒 |
| SVC (RBFカーネル) | 約10分54秒 |
| カーネル近似 + LinearSVC | 約20.9秒 |
分析と考察
- ディープラーニングの優位性: 十分な訓練データが存在する場合、DNNは統計的学習手法(SVM)を上回る精度を達成しました。今回の実験ではDNNが最高精度の98.08%を記録しています。
- 過学習の傾向: 現在のパラメータ構成では、CNN+MaxPoolingモデルに若干の過学習が見られました。ネットワーク構造の最適化により改善の余地があります。
- SVMのトレードオフ: カーネル関数を直接利用するSVCは高い精度を誇りますが、計算コストが非常に高く、DNNの約17倍の時間を要しました。一方で、カーネル近似を用いたLinearSVCは、精度は低下するものの、圧倒的な高速処理が可能です。
実装コード
ディープニューラルネットワーク (DNN)
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical
# データの読み込みと前処理
(train_img, train_lbl), (test_img, test_lbl) = tf.keras.datasets.mnist.load_data()
train_data = train_img.reshape((-1, 28 * 28)).astype('float32') / 255.0
test_data = test_img.reshape((-1, 28 * 28)).astype('float32') / 255.0
train_labels = to_categorical(train_lbl)
test_labels = to_categorical(test_lbl)
# モデルの構築
dnn_model = models.Sequential([
layers.Input(shape=(784,)),
layers.Dense(784, activation='relu'),
layers.Dense(784, activation='sigmoid'),
layers.Dense(10, activation='softmax')
])
dnn_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
dnn_model.fit(train_data, train_labels, batch_size=128, epochs=10)
test_loss, test_acc = dnn_model.evaluate(test_data, test_labels)
print(f"Test Accuracy: {test_acc:.4f}")
畳み込みニューラルネットワーク (CNN)
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.utils import to_categorical
(train_img, train_lbl), (test_img, test_lbl) = tf.keras.datasets.mnist.load_data()
train_data = train_img.reshape((-1, 28, 28, 1)).astype('float32') / 255.0
test_data = test_img.reshape((-1, 28, 28, 1)).astype('float32') / 255.0
train_labels = to_categorical(train_lbl)
test_labels = to_categorical(test_lbl)
# CNNモデルの構築
cnn_model = models.Sequential([
layers.Input(shape=(28, 28, 1)),
layers.Conv2D(784, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Flatten(),
layers.Dense(10, activation='softmax')
])
cnn_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
cnn_model.fit(train_data, train_labels, batch_size=128, epochs=10)
_, test_acc = cnn_model.evaluate(test_data, test_labels)
print(f"CNN Test Accuracy: {test_acc:.4f}")
統計的学習手法 (SVM)
import numpy as np
from sklearn import svm
from sklearn.kernel_approximation import Nystroem
from sklearn.metrics import accuracy_score
import tensorflow as tf
# データ準備
(x_raw, y_raw), (x_val, y_val) = tf.keras.datasets.mnist.load_data()
train_x = x_raw.reshape((-1, 784)) / 255.0
test_x = x_val.reshape((-1, 784)) / 255.0
# 1. 通常のSVC (RBFカーネル)
standard_svc = svm.SVC(kernel='rbf')
standard_svc.fit(train_x, y_raw)
svc_pred = standard_svc.predict(test_x)
print(f"SVC Accuracy: {accuracy_score(y_val, svc_pred):.4f}")
# 2. カーネル近似 + LinearSVC
nystroem_feat = Nystroem(n_components=784)
combined_data = np.vstack((train_x, test_x))
nystroem_feat.fit(combined_data)
train_transformed = nystroem_feat.transform(train_x)
test_transformed = nystroem_feat.transform(test_x)
fast_svc = svm.LinearSVC(max_iter=1000)
fast_svc.fit(train_transformed, y_raw)
fast_pred = fast_svc.predict(test_transformed)
print(f"LinearSVC with Nystroem Accuracy: {accuracy_score(y_val, fast_pred):.4f}")