画像分類 - MNISTで予測精度を試す
AIゆめ
画像分類(image classification)で良く知られた手書き数字を分類する課題MNIST(Mixed National Institute of Standards and Technology database)では、
Image Classification on MNIST のページに予測誤差のランキングとその論文が紹介されている。最近の成功例では、訓練パラメーター(Trainable Parameters)が100万を超えるような大規模なモデルが多いようだが、本ページでは、訓練パラメーターが15万~36万程度の比較的小さなモデルを使用し、機械学習の分野で良く知られた手法の組合せで、どの程度の予測精度が達成できるかを試してみたので報告する。
画像分類は、脳画像から異常を見つけ出したり、商品画像から不良品を見つけ出したり、ネット画像の中から自社商品を見つけ出したりする目的などに活用できるでしょう。本ページで示すように日々AI技術を磨いていますので、製造業・非製造業に拘わらず、画像分類の応用例をご覧になって、「自社の問題解決に応用できるのではないか?」と思われた方は、
ネオラクス・メール送信フォーム からお気軽にご相談ください。AI技術を用いて、世の中にある様々な問題の解決に貢献して行きたいと思います。
本課題では、0~9の手書き数字が、60,000個の訓練データと10,000個の評価データに分かれており、訓練データでモデルのトレーニングを行い、評価データで評価する。テストは、TensorFlow/Kerasを使用して行うが、訓練パラメーターがそれ程多くないため、CPUで十分だという判断から、普段よく使うGoogle ColabのGPUは使用せず、Intel Core i5-9600H(6コア)のCPUを使用して行った。余談だが、前記PCにはGPX1080が搭載されているものの、TensorFlow2.12.0が使用しているCUDA11.8のツールキットに対応するGPX1080ドライバーが見つからないため、現在は稼働していない(TensorFlowがCUDA12.1に対応するようになったら使う予定)。
MNISTで使用したモデル
標準モデル
各層に二個のCNN(Conv2D)を使用した3層のCNNを使用し、この出力を2層の全結合ネットワークで推論するような下記のモデルを出発点とし、 これを標準モデルと呼ぶ。このモデルは、ディープラーニングで良く知られたテキスト「ゼロから作るDeep Learning(オライリー・ジャパン発行)」に掲載されている認識誤差0.62%を達成したというモデルとほぼ同じと考えて良い。ここで、最初から3層のCNNを使用した理由は、層が深くなると過学習を起こしにくくなること以外に、訓練パラメーターの削減が大きな理由である。訓練パラメーターが最も多いのは、CNNの最後の層(この場合は3x3x64=576)と128ノードとの全結合の部分であり、仮に、中間のCNN層を取り除くと、7x7x64=3136と128ノードとの全結合になり、訓練パラメーターは約5倍以上に増えてしまう。
model = tf.keras.models.Sequential([
tf.keras.layers.Input(shape=[MODEL_SIZE,MODEL_SIZE,1]),
tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu'),
tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #14x14
tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu'),
tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #7x7
tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu'),
tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #3x3
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
画像強調(Augmentation)モデル
一般的な
画像分類 や
画像セグメンテーション の分野では、画像の上下左右のフリップ(反転)、回転、平行移動、ズームなどをする画像強調(Augmentation)により誤差が小さくなることが知られているので、ここではこの効果を調べる。ただし、左右のフリップや回転は逆効果であったため、平行移動とズームのみ適用する。通常の画像とは異なり、動物や花のなどの画像は、フリップや回転などを施しても意味は変わらないが、数字は意味が異なる場合があるというのがその理由だと考えている(例えば、180度回転すると'6'と'9'が同じになる)。このモデルは、標準モデルのInput層の下に以下の二行を追加するだけである。
tf.keras.layers.RandomZoom(0.1),
tf.keras.layers.RandomTranslation(0.1,0.1),
Dropoutモデル
学習時に伝達ニューロンを一定の確率で消去するDropoutは、過学習の抑制効果があることで知られているので導入する。なお、当初は、
ENSEMBLE LEARNING IN CNN AUGMENTED WITH FULLY
CONNECTED SUBNETWORKS を参考に、Dropout層の前にBatchNormalization層を入れて学習していたが、学習時の精度は上がるものの、学習したモデルを使用して実際に予測してみると、予測精度が悪かったことを付記しておく。BatchNormalizationは、学習を行うミニバッチごとに、データの平均が0、分散が1になるよう正規化を行う操作であるが、予測時にはバッチの概念そのものがないので、この辺りの不具合かも知れない。このモデルは下記の通り。
model = tf.keras.models.Sequential([
tf.keras.layers.Input(shape=[MODEL_SIZE,MODEL_SIZE,1]),
tf.keras.layers.RandomZoom(0.1),
tf.keras.layers.RandomTranslation(0.1,0.1),
tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu'),
tf.keras.layers.Dropout(0.35),
tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #14x14
tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu'),
tf.keras.layers.Dropout(0.35),
tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #7x7
tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu'),
tf.keras.layers.Dropout(0.35),
tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2), #3x3
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
Encoder-Decoderモデル
上記のモデルは全てシーケンシャルに接続されたモデルだが、ここでは、機械翻訳の分野で良く知られたAttentionモデルや画像セグメンテーションの分野で良く知られたU-Netモデルなどで採用されているEncoder-Decoderモデルに類似した考え方を導入する。基本モデルを上記のDropoutモデルとし、最後のMaxPooling2D(2,2)の出力である(3,3,64)の行列と、その前のMaxPooling2D(2,2)の出力である(7,7,32)の行列をConcatenateして全結合ネットワークDense(128, activation='relu')に入力する。このモデルの流れは図1の通り。
図1 Encoder-Decoderモデル概要
MNISTの評価方法
標準モデル、画像強調モデル、Dropoutモデルでは、最初の70epochは最適化手法としてAdamを用いて60,000個の訓練データで訓練し、その後、評価誤差を安定させるため、30epochは最適化手法としてAdaGradを用いて訓練した。Dropoutモデルの学習状況を図2、図3に示す。Encoder-Decoderモデルも他のモデルと同様の評価を行った結果、評価誤差は0.37%まで改善したが、実際の評価では評価ミスしたMNIST画像は46枚となった。このため70epochの追加計算と、30epochの安定化計算を行い評価した。他のモデルでも追加計算を行ったが、過学習が発生し、必ずしも予測精度は向上しなかったが、本モデルでは過学習が起こりにくかったようである。Encoder-Decoderモデルの学習状況を図4、図5に示す。なお、標準モデル、画像強調モデル、Dropoutモデルの訓練パラメーターは154,554個であり、Encoder-Decoderモデルでは364,282個となった。ただし、計算時間は標準モデル、画像強調モデル、Dropoutモデルが26分/70epochに対して、Encoder-Decoderモデルでは29分/70epochであり、顕著な増加は見られなかった。
図2 Dropoutモデルの学習状況(0~70epoch)
図3 Dropoutモデルの学習状況(残りの30epoch)
図4 Encoder-Decoderモデルの学習状況(70~140epoch)
図5 Encoder-Decoderモデルの学習状況(最後の30epoch)
MNISTの評価結果
各モデルの最終の評価誤差
1万枚の評価画像による評価誤差が安定した時点における最終の評価誤差と、この画像で評価ミスを犯した画像の枚数を表1に示す。大規模なモデルや最新の手法を用いた解析の結果には及ばないけれども、22位くらいには入りそうなデータであり、小規模な既知の層を積み重ねたモデルとしてはまずまずの結果と言える。
表1 各モデルの最終の評価誤差とテスト画像の評価ミス枚数
モデル名称 epoch数 最終の評価誤差 テスト画像の評価ミス枚数(1万枚中)
標準モデル 70+30=100 0.56% 58枚
画像強調モデル 70+30=100 0.52% 53枚
Dropoutモデル 70+30=100 0.41% 45枚
Encoder-Decoderモデル 140+30=170 0.37% 40枚
最初の100枚のテスト画像の評価状況
図6は、最初の100枚のテスト画像の評価状況である。各手書き画像の上にある数字は予測値であり、正解であれば〇(':o')が付けられる。全モデルにおいて最初の100枚のテスト画像は全問正解であった。
図6 最初の100枚のテスト画像の評価状況(全モデル共通)
各モデルが評価ミスしたMNIST画像
図7~図10に各モデルが評価ミスを犯したMNIST画像を示す。各手書き画像の上にある数字は予測値であり、不正解の場合には×印(':x')と正解値が括弧書きで表示される。即ち、7:x(2)という表示は、7と評価されたけれども不正解であり、正解は2という意味である。人が見ても紛らわしい手書き文字が多い中で、まずまずの結果が得られているようである。
図7 標準モデルが評価ミスしたMNIST画像
図8 画像強調モデルが評価ミスしたMNIST画像
図9 Dropoutモデルが評価ミスしたMNIST画像
図10 Encoder-Decoderモデルが評価ミスしたMNIST画像