MNISTのニューラルネットワークでの学習の教師データ数と精度の関係

MNISTには全部で6万個の訓練用データがありますが、単純なニューラルネットワークで学習させたときの訓練用データの数と学習結果の精度の関係を見てみました。

size process_time train_loss train_accuracy test_loss test_accuracy
60000 76.70 0.0051 0.9988 0.1270 0.9752
15000 23.22 0.0038 0.9999 0.1766 0.9609
3750 10.67 0.0143 0.9997 0.2706 0.9268
950 7.61 0.0296 1.0000 0.4152 0.8790
250 7.28 0.0661 0.9960 0.7151 0.7821

左から、訓練用データサイズ、処理時間(秒)、訓練データでの損失関数値、訓練データでの精度、テストデータでの損失関数値、テストデータでの精度です。

学習推移のグラフ

size=60000

f:id:suzuki-navi:20200928193609p:plain

size=15000

f:id:suzuki-navi:20200928193630p:plain

size=3750

f:id:suzuki-navi:20200928193654p:plain

size=950

f:id:suzuki-navi:20200928193710p:plain

size=250

f:id:suzuki-navi:20200928193723p:plain

Pythonコード

Google Colaboratoryで実行しました。

import time
import numpy as np
from matplotlib import pyplot as plt
import tensorflow as tf
from tensorflow.keras.datasets import mnist

plt.rcParams['figure.figsize'] = (16.0, 7.0)

(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 入力と出力サイズ
in_size = 28 * 28
out_size = 10

# モデル構造を定義
def createModel():
  hidden_size = 64
  model = tf.keras.models.Sequential()
  model.add(tf.keras.layers.Dense(hidden_size, activation='relu', input_shape=(in_size,)))
  model.add(tf.keras.layers.Dense(out_size, activation='softmax'))
  return model

# 学習の様子をグラフへ描画
def plotLearning(result):
  fig = plt.figure()

  xs = range(1, len(result.history['loss']) + 1)

  # ロスの推移をプロット
  ax1 = fig.add_subplot(1, 1, 1)
  ax1.set_ylim(0, 2.5)
  ax1.set_ylabel('Loss')
  ax1.plot(xs, result.history['loss'])
  ax1.plot(xs, result.history['val_loss'])

  # 正解率の推移をプロット
  ax2 = ax1.twinx()
  ax2.set_ylim(0.75, 1.0)
  ax2.set_ylabel('Accuracy')
  ax2.plot(xs, result.history['accuracy'])
  ax2.plot(xs, result.history['val_accuracy'])

  plt.title('Loss & Accuracy')
  plt.legend(['train', 'test'], loc='upper left')
  plt.show()

def calc(train_size, epochs):
  model = createModel()

  # モデルを構築
  model.compile(
      loss = "categorical_crossentropy",
      optimizer = "adam",
      metrics=["accuracy"])

  start = time.time()
  print("train_size: %d, epochs: %d" % (train_size, epochs))
  x_train_reshape = x_train.reshape(-1, in_size).astype('float32') / 255
  x_test_reshape = x_test.reshape(-1, in_size).astype('float32') / 255
  y_train_onehot = tf.keras.backend.one_hot(y_train, out_size)
  y_test_onehot = tf.keras.backend.one_hot(y_test, out_size)

  x_train_reshape = x_train_reshape[:train_size]
  y_train_onehot = y_train_onehot[:train_size]

  # 学習を実行
  result = model.fit(x_train_reshape, y_train_onehot,
      batch_size=50,
      epochs=epochs,
      verbose=1,
      validation_data=(x_test_reshape, y_test_onehot))

  processTime = time.time() - start
  print("train_size: %d, epochs: %d, processTime: %f" % (train_size, epochs, processTime))
  plotLearning(result)

  return "| %d | %5.2f | %6.4f | %6.4f | %6.4f | %6.4f |" % (train_size, processTime,
    result.history['loss'][-1], result.history['accuracy'][-1],
    result.history['val_loss'][-1], result.history['val_accuracy'][-1])

table = []
table.append(calc(60000, 30))
table.append(calc(15000, 30))
table.append(calc(3750, 30))
table.append(calc(950, 30))
table.append(calc(250, 30))
for s in table:
  print(s)

2020/10/12 追記

ニューロン数と精度の関係も見てみました。