今回、システムのプログラム更新をいちいちモノを回収して行うのが面倒なので、PHPサーバにスクリプト(MicroPython)をアップロードし、ESP32(ATOM Lite)からPHPサーバにアクセスして、スクリプトの更新を行うといったことをしました。
オンラインでプログラムを更新することをOver The Airで、OTAと呼ぶらしい。
今回、システムのプログラム更新をいちいちモノを回収して行うのが面倒なので、PHPサーバにスクリプト(MicroPython)をアップロードし、ESP32(ATOM Lite)からPHPサーバにアクセスして、スクリプトの更新を行うといったことをしました。
オンラインでプログラムを更新することをOver The Airで、OTAと呼ぶらしい。
先日、購入しましたM5Stack ATOM Lite(ESP32搭載)でPCとBluetooth通信をするところまでやってみました。
言語は、ATOMLiteはMicroPython、PCはPythonです。
RaspberryPi Zero WとRaspberryPi Picoを、GPIOでシリアル通信(UART)させました。
簡単だろうと思っていたら、ジャストな情報源がなくて、意外と時間がかかりました。終わってみれば、簡単なんですが。どっちもPythonを使いました(PicoはMicroPython)。
<目次>
・RaspberryPi Zeroの設定
・RaspberryPi Zeroの設定の確認
・GPIO配線
・PicoからZeroにテキスト送信
・ZeroからPicoにテキスト送信
PyTorchで作成した手書き数字認識プログラムを手軽に使えるようにライブラリ化できないかなぁっという思いで、以前、PyTorchで作成した全結合のニューラルネットワークの学習したパラメータを、Cythonで作成した自前のニューラルネットワークに読み込ませるといったことをしました。
今回は、それを畳み込みニューラルネットワーク(CNN)でやってみました。
元となるPyTorchのモデル
class MyNet(torch.nn.Module): def __init__(self): super(MyNet, self).__init__() self.conv1 = torch.nn.Conv2d(1, 20, 5, 1) self.conv2 = torch.nn.Conv2d(20, 50, 5, 1) self.fc1 = torch.nn.Linear(4*4*50, 500) self.fc2 = torch.nn.Linear(500, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.max_pool2d(x, 2, 2) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 2, 2) x = x.view(-1, 4*4*50) x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1)
参照元:
PyTorchでシンプルな畳み込みニューラルネットワークを作ろう
https://qiita.com/sudamasahiko/items/fd6a52f958f3f9013f0f
以前、このモデルで、手書き数字の判別をさせてみると正解率95%以上という結果でした。
そこで、前回、勉強がてら、PyTorchで学習したパラメータを利用して、生Pythonで実装した畳み込み演算で画像判別をするということを行いました。今回、これをCython化して高速化しました。
結果、生Pythonでは、1文字1.609秒かかる処理が0.062秒になり、およそ25倍高速化しました。まずまずですが、まだ少し物足りない・・・かな。
過程を書くと、
・1文字もコードを変えずにCython化すると0.929秒(1.7倍)
・クラスをcdef化し、def内整数と実数をcdefで宣言すると0.311秒(5.2倍)
・Cython内のみで使用する配列をポインタ化すると0.062秒(26.0倍)
となり、ポインタ化がすごく効いてきます。
今回のソースは、PyTorchでのモデル定義をなるべくそのまま使えるような形を意識しており、Python側でモデルを定義できます。それゆえ、各関数の出力データは、生Pythonで扱えるlistオブジェクトで返してます。そのlistの生成に時間がかかっている気がします。
ちなみにlistの代わりにnumpyの配列(メモリービュー)も試しましたが、あまり速くならず、というかlistより遅くなりました。listと違い、要素の型を指定するので高速化するはずなのですが、処理ごとに配列を生成する書き方をしているので、生成に時間がかかってしまっているのかなと。モジュールをインポートした際に、必要な配列を用意しておく書き方にすれば、たぶんもうちょっと高速化するのだろうけど、今回はここまでにします。
そもそも、手書き数字認識ライブラリを作ることを目的とするなら、モデルの定義をPython側で柔軟にできるようにする必要もなく、Cython側で固定してしまって、全てのデータを配列なりポインタなりで扱えば、もっと大幅に高速化するはずです。その方向性でのを次回試すことにします。
追記:さらに約6倍高速化しました。