📑

EMNIST Digits で遊んでみたら知見の塊だった

2020/10/02に公開

EMNIST Digits で数字認識をやってみました。数字認識といえば MNIST ですが、 2017 年に EMNIST というデータセットが公開されました。その中の数字認識タスク (EMNIST Digits) が素晴らしい。訓練データ 24 万件、テストデータ 4 万件ものデータ量があります。

そして実際に遊んでみたら知見の塊でした。得られた結論もなかなか面白い内容だったので、Zenn の練習がてら共有したいと思いました。

MNIST に感じる様々な疑問

EMNIST Digits について説明する前に、MNIST の精度の肌感触について説明しておくと、fully-connected で 98%、適当に作った CNN で 99%、良い感じの CNN で死ぬほど Data Augmentation やアンサンブルすると 99.7% と思ってます。最高精度に至っては 99.84% と言われ完全にオワコン扱いされている昨今ですが、最高精度に近いモデル (99.7%) を使って手書きしてみると、どう考えてもそんなに精度が出ません。98% が出ているのかも怪しい。本当にこれで良いのでしょうか?

MNIST については色々思うところがありますが、特に気になるのはデータ量です。0.3% の精度向上は 30 画像ぶんの分類向上しかしていないので、ほんの少し当たりが良かったものを過剰評価していないか気になります。どこかでピコッと精度が上がってしまうと、その変化を過剰評価してしまわないかと心配に思っています。

そして手書きしてみるとすぐに気付くのは、5 と 6 は間違える確率のほうが高いくらいという事実です。学習データを見ればすぐに理由は思い付きます。5 と 6 のデータは他と比較して少ないのです。たぶん Under Sampling や、Focal Loss などの対策がいるのですが、今や MNIST にオワコン感があるため、無視されているのかなあとも思っています。さらにデータセットも小さいため、テストで精度が高くても実利用では問題が生じる可能性も、すぐに想像できます。

…このように MNIST は Deep Learning の基本のキである一方、様々な違和感を感じていたので、EMNIST Digits は一度やってみたかったのです。

検証

ということで実際に検証してみました。どこまでやるかという問題もあるので、今回はデータ量がすべて解決してくれると信じて、あまり深い調査はしていません。例えば、(1) データの不均衡性と精度の関係、(2) データ量や分布と精度の関係に関しては調査しません。単純に MNIST のデータ量が EMNIST Digits で使い物になるのかだけを調査します。

確認のためのデータセットとしては、MNIST と EMNIST Digits のデータを混ぜ、最大量の均衡データにしたものを使います。具体的な量としては、訓練データ 294210、テストデータ 48920 になります。パラメータの探索は主に、学習率とバッチサイズを調整しています。GPU は不要で、メモリは 8GB あれば動きます。コードも公開してますので、気になる方は中を見てください

結果

以下は MNIST で学習したモデルを EMNIST Digits に適用した結果です。b はバッチサイズです。MobileNet と EfficientNet は EarlyStopping (patience=0) を使い、Data Augmentation は行っていません。だいたいの感触を掴むための検証なので、正確な精度は勘弁してください。MobileNet 安定しないんだよなあ。Data Augmentation なしだとやはりデータ不足に見えますね。MNIST だけの学習では精度が足りないという感覚は正しかったようです。

model MNIST MNIST + EMNIST (balanced)
KerasMLP 98.47% 79.12%
KerasCNN 99.12% 91.01%
MobileNet (lr=1e-3, b=128) 95.95% 82.43%
EfficientNet B0 (lr=1e-3, b=128) 97.59% 89.01%

さて、ここからが本番です。まずはデータ不足を Data Augmentation で補ってみましょう。といっても Data Augmentation は最適化のパラメータが多いので、検証は意外と手間です。徹底的に鍛え上げられたつよつよ pre-trained モデルが Curt-Park/handwritten_digit_recognition で公開されているので、利用させてもらいました。結果は以下です。

model MNIST MNIST + EMNIST (balanced)
VGG16 99.68% 83.24%
MobileNet 99.68% 90.38%
RestNet164 99.70% 47.14%
WideRestNet28 99.72% 97.62%

なかなか衝撃的な結果です。 VGG16 や MobileNet は KerasCNN から成長が見られません。ResNet164 は汎化性能が酷いことになっています。WideRestNet28 の汎化性能は素晴らしいですが、推論が遅くモデルサイズも大きいのでフロントエンドには向きません。より良いモデルを模索したいところです。この結果を見ていると、Data Augmentation よりモデルの構造のほうがよほど重要に感じます。

最後に MNIST + EMNIST Digits のデータで学習した結果を見てみましょう。最適化関数はどれも Adam を使い、EarlyStopping (patience=0) で学習を止めています。こちらはだいたい予想通りの結果になりました。やはり EfficientNet だからといって無敵という訳ではないですね。もっと探索すれば良いパラメータが見つかるのかも知れませんが、他の構造のほうが最適化も楽です。

model MNIST MNIST + EMNIST (balanced) size
KerasMLP (lr=1e-3, b=2^13) 98.73% 99.01% 7.7M
KerasCNN (lr=1e-3, b=128) 99.50% 99.56% 14M
MobileNet (lr=1e-3, b=128) 98.96% 99.28% 38M
EfficientNet B0 (lr=1e-3, b=128) 98.05% 98.70% 47M

考察

Data Augmentation は EMNIST Digits には効果がないように見えます。単純な Data Augmentation で対処できることは、Data Augmentation なしでも CNN がうまく学習してくれているのかも知れません。データ分布の検証をしてみないとわからないところが多いですが、EMNIST Digits は Data Augmentation では対応しきれないケースが多いのかも知れません。データを見ても、日本人からすると不思議な書き方の数字がたくさんあります。今後さらにデータ量が増えた場合は、分布を見た上で対応できていない部分をどのように生成・学習するかが大事になると思います。

モデルに関して言えば、2層くらいの単純な CNN か WideRestNet のような広くて浅い CNN が良さそうです。WideResNet28 は特に汎化性能が高いです。とはいえ EMNIST Digits に適用すると 2% 以上の分類ミスが発生しています。現状の技術をベースに数字認識タスクを解くことを考えると、MNIST だけでは Zenn Zenn データ量が足りないという結論になるのではないでしょうか。ResNet164 の結果を見ると、層が深すぎる学習は危険と感じざるを得ません。

今回の結果からわかることは、現状はデータ量が正義ということです。モデル探索に時間を掛けたり小手先の手法改善をしたりするよりは、データを集めたほうが良さそうです。データ量さえ十分にあれば単純な MLP や CNN でも十分な精度が出ています。

とはいえ、タスクが高度化している昨今ではデータを集めるのも大変です。どのようなモデルなら汎化性能が高いか、どのようなデータを用意すればデータ量が少なくて済むか事前に推定する技術が欲しいところです。EfficientNet や AutoML はその解に近いアルゴリズムではありますが、事前により多くの情報が手に入ればさらに効率的な学習ができるのではないでしょうか。特に EfficientNet はMNIST より複雑なタスクを解くことを想定して作られたモデルです。MNIST でも同じようなことをやってみると、面白い結果が得られるかも知れませんね。EMNIST Digits でデータ量が増えたことで、色々な調査がしやすくなったように思います。

Demo

ちょっとした宣伝ですが、実験の成果は以下の 2 つのゲームに適用しています。追試が面倒な方もすぐに試せるので、ぜひ識別精度の高さを体感してみてください。

https://marmooo.github.io/tegaki-de-anzan/
https://marmooo.github.io/tegaki-100masu/

どれくらい進化したかを、私の印象で伝えるとこうなります。昔「ぼくは99.7% のスパーモデル! この字は 5!…やっぱ 6 でした。実は見せかけなんです。すみませんすみません。」今「人間が私に勝てるとでも? 読み取れないのは君の字が汚いだけだぞ。」

実際、人間に対してこれくらいは強気に出られる精度があります。

精度が完璧になってわかったこと

精度が完璧になると、見える景色も変わります。次の問題はレイテンシやユーザビリティだということです。まずレイテンシの問題についてですが、スペックが低めのタブレットは数字の描画にさえ時間が掛かってしまいます。フロントエンド (JavaScript) は非同期処理が基本となっているので注意が必要です。最初に作ったときは数字を描画する前に認識してしまい、誤認識することがありました。先ほどのアプリでは文字の描画遅延をなるべく減らすことで、違和感を減らしました。

次にユーザビリティについてですが、何も考えずに作ると、少し点を打っただけでも認識処理が走ってしまいます。これによって文字が汚くても許されてしまう問題が出てきます。また線を書き過ぎている場合にも対処しないと、TASさんの休日 のように無双されてしまいます。

一番簡単な対処は線の長さと画数を見る方法です。先ほどのアプリにはもちろん組み込んでいますが、数字の書き順や書き方は世界共通ではない ことに注意する必要があります。すべてを考慮すると一筆書きの対処が問題で、4 と 5 の誤爆を防ぐのは難しかったです。

今回は判定が楽なこともあって、日本人の書き方に則った判定をしています。より良い判定処理を模索していて気付いたのですが、日本人の数字の書き方は綺麗に書けて、とても良いです。漢字を綺麗に書くためには書き順はとても大切ですが、数字も馬鹿にできない気がします。一筆書きで 4 や 5 を書こうとすると & や S と混ざりやすいですし、線が曲がって読みにくくなります。

まとめ

MNIST で 99.84% が出たからといって数字認識が完璧だった訳ではありません。安心感のある手書き数字認識には Zenn Zenn データ量が足りませんでした。オープンデータだけで実用レベルになったのは、EMNIST Digits が登場した 2017 年からではないでしょうか。MNIST のタスク自体もまだまだオワコンではなく、EMNIST Digits の登場でより面白くなったように思います。

今回は (1) データの不均衡性と精度の関係、(2) データ量や分布と精度の関係に関しては調査しませんでした。やる気が出れば別稿でまとめる………かも?

追記

結論に関しては、最近いい感じの論文が出てきたので紹介だけしておきます。MNIST のシンプルな実験でもわかってしまうことですが、深い深層学習は過剰適合しやすく正しい保証はないようです。既存のデータセットにはラベルミスが一定量あるため、そこに過剰適合しているようです。

https://twitter.com/stateofai_ja/status/1448043093198999555

また MNIST のデータはラベルミスが多くデータ量も少ないので、QMNIST というデータセットが 2019 年にできていたようです。やはり MNIST の精度は当てにならなかったみたいですね。

facebookresearch/qmnist: The QMNIST dataset

Discussion