ESP8266で手書き文字を認識してみた

# 概要
ESP8266上に3層ニューラルネットを実装し、手書き文字認識を行いました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ESP8266による手書き文字認識。隠れ層1層のNNでsoftmax出力結果を右グラフに表示。0.4秒以内の予測だが、通信が律速なので推論自体は一瞬。500円でArduinoより圧倒的に高速。ESP8266なら2MBのメモリ領域に重みを格納でき、高価なラズパイ使わずともエッジ処理できる。<br> <a href="https://twitter.com/hashtag/ESP8266?src=hash&amp;ref_src=twsrc%5Etfw">#ESP8266</a> <a href="https://twitter.com/hashtag/mnist?src=hash&amp;ref_src=twsrc%5Etfw">#mnist</a> <a href="https://twitter.com/hashtag/DeepLearning?src=hash&amp;ref_src=twsrc%5Etfw">#DeepLearning</a> <a href="https://t.co/lgVesHpNml">pic.twitter.com/lgVesHpNml</a></p>&mdash; triwave33 (@triwave33) <a href="https://twitter.com/triwave33/status/1015864374920003584?ref_src=twsrc%5Etfw">2018年7月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# はじめに
Deep Learningが大注目されている昨今では、高価なサーバやクラウドサービスを使うだけでなく、データを取得する現場（エッジ）でセンサの生データを処理し、高度化してサーバ上へ集約することで、負荷の分散や遅延の解消などが期待されます。

また、Raspberry piなど安価なコンピューティングボードの発展により、ホビーユースでもCNNを用いた画像認識などが可能になってきました。Movidiusが発売されたことも話題になりましたね。

# もっと安くできない？
ラズパイ（約6000円）とMovidiusで（約15000円）でエンドユーザが深層学習モデルを実行（推論）できることは大きな魅力です。センサを搭載したラズパイをエッジコンピュータとして使う方法は、例えば農業における環境センサなどにおいて非常に有用だと思います。しかし、ラズパイとて基本的にはPCですから、環境の構築方法や電源のオンオフなどに気を使います。

実際、私も不安定な電源状態でラズパイを使い、電源が落ちた後にOSが起動しないという経験をよくしました。環境構築を一からやりなおすのは、SDカードのコピーで済んだとしても面倒です。

そこで目指したいのは、もう少しシンプルで簡単な方法。OSやライブラリなどをあまり考えなくても手軽に実行できて、電源が落ちようがあまり関係なし、壊れてももう一台買ってるからいいや、と思えるようなデバイスです。

# ArduinoはDeep Learningに使えるか
さて、ラズパイよりももう少しシンプルに扱えるものとしてはマイコンボードであるArduinoです。Cライクの言語で実装でき、電源をブチっと抜いても問題なし（多分）。センサとの接続に関しても情報が出回っています。

しかし、さすがにDeep Learningによく用いられるニューラルネットワークをArduinoで実行しようとすると、さすがに処理能力の面でも、メモリ容量の点でも無理があります。

そこで目指したいのは、Arduino以上、ラズパイ未満の解決方法です。できれば

- 学習とまでは言わないが、実時間で推論（forward propagation）を処理できる計算能力
- NNの重みを格納できるメモリ空間
- エッジマシンとしてばらまける安価さ
- ネットワーク機能を搭載
- Arduinoとしてネットに溢れている情報は活用したい

を満たすデバイスがあれば安価にニューラルネットを処理することができそうです。もちろん、SSDやYOLOのような大きな画像処理アルゴリズムは搭載できません。

ですが、近接センサやジャイロセンサなど、低次元のセンサをエッジ処理して異常検知したりノイズ処理するといった動作には十分使えると思います。
そこで、ESP8266を使います。ESP8266なら、上記の要望を満たすことができそうです。


# ESP8266


（ESP8266の詳細は例えばこちらの記事を参照。）
[技適済み格安高性能Wi-FiモジュールESP8266をArduinoIDEを使ってIoT開発する為の環境準備を10分でやる方法] (https://qiita.com/azusa9/items/264165005aefaa3e8d7d)

Arduino開発環境が使える上に、ネットワーク機能も充実、さらにディープスリープ機能を用いれば電池で数ヶ月単位の運用も可能です。


| |  arduino uno         |       ESP8266 |    ESP32    |
|:---------------------|---------------------:|:------------------:|:------------------:|
| クロック周波数             |   16MHz   |        80MHz （最大160MHz）        |160MHz （最大240MHz）
| RAM           |2KB |  32KB   |       520KB       |
| フラッシュメモリ   |    32KB |        2MB（最大16MB）       |4MB(最大64MB)

上手の比較表ではESP8266の後継機種であるESP32の情報も入れています。実は今回の制作物は2年ほどまえ（ESP32が技適をとる前）に作ったもので、当時はESP32を試せる状況ではありませんでした。

今回の記事もESP32を用いれば、より高速に、さらにメモリの制約もさらになくなるのでより大きな構造のネットワークを試せると思います（が、現状試してはいません。）

今回はセンサの代わりにタッチパネル上に書いた数字をESP8266を用いてニューラルネットワークで認識することを試しました。

# 設定

## 使ったデータセット
- mnistの手書き文字タスク　（mnistについては例えば下記）

[TensorFlowチュートリアル - ML初心者のためのMNIST（翻訳）](https://qiita.com/KojiOhki/items/ff6ae04d6cf02f1b6edf)

## 学習
ネットワーク構造
- 入力層28*28=784node
- 隠れ層12node（ReLU関数）
- 出力層10層（Softmax関数）

PC上で学習後、重み係数をバイナリファイルにダンプ。ESP8266のSPIFFSにロード

## タッチパネル
Adafruitの2.8 inchタッチパネルを使用。
https://www.adafruit.com/product/1651
タッチパネルの駆動にはArduino Megaを用い、ESP8266とはSoftwareシリアルで通信。NNの演算はESP8266側で処理。

# 結果

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ESP8266による手書き文字認識。隠れ層1層のNNでsoftmax出力結果を右グラフに表示。0.4秒以内の予測だが、通信が律速なので推論自体は一瞬。500円でArduinoより圧倒的に高速。ESP8266なら2MBのメモリ領域に重みを格納でき、高価なラズパイ使わずともエッジ処理できる。<br> <a href="https://twitter.com/hashtag/ESP8266?src=hash&amp;ref_src=twsrc%5Etfw">#ESP8266</a> <a href="https://twitter.com/hashtag/mnist?src=hash&amp;ref_src=twsrc%5Etfw">#mnist</a> <a href="https://twitter.com/hashtag/DeepLearning?src=hash&amp;ref_src=twsrc%5Etfw">#DeepLearning</a> <a href="https://t.co/lgVesHpNml">pic.twitter.com/lgVesHpNml</a></p>&mdash; triwave33 (@triwave33) <a href="https://twitter.com/triwave33/status/1015864374920003584?ref_src=twsrc%5Etfw">2018年7月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


上記の動画では、文字を書いた後に、赤い四角のTESTボタンを押して文字認識をスタートさせています。右側のバーグラフはソフトマックス関数による予想結果です。

一番もっともらしいと思われる予想結果が一番グラフ上で長く表示されます。
予想にかかる時間は大体0.4秒ですが、これは手書きした文字データをソフトウェアシリアル通信でESP8266に送る時間も含めています。実際はこの通信が処理時間の大半を占めており、ESP8266による手書き文字認識はさらに短いです（未計測）

今回は3層のニューラルネットというお世辞にもディープとは言えないネットワークですが、マイコンを使って現実的な時間内で、入力データ（784ピクセルの画像）から文字を推定することができました。

# まとめ
- ESP8266を用いて3層ニューラルネットワークを実行
- 手書き文字を0.4秒以内で予測
- ESP8266は数百円で購入でき、Arduinoやラズパイと比べるとコストパフォーマンス○
- ESP8266のWifiネットワーク機能と組み合わせることでさらに可能性が広がる
- ESP32を使うともう少し早いかも

今回は分量的にコードの詳細までは書けませんでしたが、時間があればニューラルネット部のコードや、タッチパネル部との連携についても書いてコードを公開しようかと思っています。

# 追記
今回、2年ぶりにESP8266を引っ張り出してきました。ハード的にも、ソフト的にも風化にさらされていたので、当時を思い出しつつ動かすのに骨が折れました。

特に、ESP8266のスケッチ書き込み時の電源周り、SPIFFS周りはトラブルが起きやすく、勘所を思い出すのに難儀しました。
Twitter上で助けていただいたりもして、大変感謝しております。
配線が問題ないのにスケッチ書き込みがうまくいかないときはトラブルは大体電源周りにあるような気がしますね。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ESP8266に供給している電源レギュレーターLDOの最低動作電圧を下回らなければ良いですが、その応答速度もいろいろありますからね。<br>USBハブ側のパワースイッチ能力もいろいろありますし・・・。<br>できるだけハブは使わず、短く太く良質なUSBケーブルを使うことだと思います。</p>&mdash; mgo-tec (@mgo_tec) <a href="https://twitter.com/mgo_tec/status/1014121039247261696?ref_src=twsrc%5Etfw">2018年7月3日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>