2020年10月20日火曜日

Interface10月号のNNCaseネタをやってみる(途中経過)



インターン地獄に巻き込まれた中の人です(これ年明けも続くのつらいな).今回は雑誌記事の検証的なネタです.
Interface10月号のP.55-58に"AIマイコンK210の汎用AIチップとしての可能性を探る"という記事がありまして,BodyPixを変換し実装までやるという内容でした.記事内の結果では,ファームウェアがkmodelv4に対応していないため動かなかったという結論でした.
記事を読んだ感じでは動かせる気がしたので,とりあえずやってみます(ソースコードの公開は,もう少し先になりそうです).



1.モデルの変換


記事内では,PINTOさんのPINTO_model_zooにある.tfliteを使用していたので,同じようにモデルを準備します(量子化などは行わずfloatのままtfliteにする).入力サイズは320x240,出力はいじりません.
tfliteが生成出来たら,NNCaseを使い,kmodelへの変換を行います.NNCaseでの変換では,量子化のためのデータセット(データの分布を見たいから?)を指定する必要があるのですが,BodyPixのデータセットが見当たらなかったので,各ピクセルの値がランダムな320x240の画像を10枚生成し,データセットの代わりにしました(Imgフォルダに突っ込みました).もしかしたらCocoDatasetを使っているかもしれないですね.

.\ncc.exe compile .\035_BodyPix_tflite\bodypix_025_320x240_weight_quant.tflite .\035_BodyPix_tflite\bodypix_025_320x240_weight_quant.kmodel -i tflite -o kmodel --dataset .\Img\ --dataset-format image --inference-type uint8 --input-mean 0 --input-std 1 --dump-ir --input-type uint8 --max-allocator-solve-secs 120 --calibrate-method l2 --dump-weights-range --weights-quantize-threshold 1024 --output-quantize-threshold 4096

参考
中村仁昭,"AIマイコンK210の汎用AIチップとしての可能性を探る",Interface10月号,CQ出版,PP.55-58
Kaz Sato,Google Developers Japan: BodyPix の概要: ブラウザと TensorFlow.js によるリアルタイム人セグメンテーション,https://developers-jp.googleblog.com/2019/04/bodypix-tensorflowjs.html

2.ファームウェアの準備

kmodelv4を使う場合,ファームウェアのバージョン違いではじかれることがあります(SipeedやM5Stackが配布しているファームが古い時がある).今はアップデートされて行けるかも).そこで,手元のLinux環境でM5StickV向けにファームウェアをビルドしました.(MaixHubのサービスで,カスタムファームウェアのビルドをやっているみたいだけど,いろいろあって手元の環境でやった).
ファームウェアのビルドは紅樹 タカオさんの記事を参考にUbuntu20.04マシンで行いました.オプションで,support v4 kmodelというオプションがあるので,そこを有効化しておく必要があります(配布されているファームウェアだと,これが有効になってないかも).

参考
紅樹 タカオ,"M5StickVのファームウェアビルド手順",https://raspberrypi.mongonta.com/howto-build-firmware-of-m5stickv/

3.MaixPyIDE


BodyPixは4つの出力があるモデルなので,KPUを使う際にkpu.set_outputs()を4つ書いておきます.kpu.forward()を実行し推論をしたのち,kpu.get_output()で目的の出力を得ます.取り出したデータをいい感じに整形すれば完成です.

4.出力データを正しく表示したい


出力データが出たところで,4つの出力を確認していきます.まずは形状とデータサイズから.

{"fmap": "data"=0x80330b70, "size"=20400, "index": 41, "w": 17, "h": 20, "ch": 15, "typecode": f}
{"fmap": "data"=0x803382f8, "size"=40800, "index": 41, "w": 34, "h": 20, "ch": 15, "typecode": f}
{"fmap": "data"=0x80342258, "size"=28800, "index": 41, "w": 24, "h": 20, "ch": 15, "typecode": f}
{"fmap": "data"=0x8032f8b0, "size"=1200, "index": 41, "w": 1, "h": 20, "ch": 15, "typecode": f}

"size"のところと"w","h","ch"の計算がを合わせることで,データ型がわかります.

20400 / (17 x 20 x 15) = 4
40800 / (34 x 20 x 15) = 4
28800 / (24 x 20 x 15) = 4
1200 / (1 x 20 x 15) = 4

全部一致したので,4Byte,かつ出力データからFP32と分かります.形状はw*h*chのように見えますが,実際は,ch * w * hの順番らしいです(NNCaseの方の出力がこっち:MaixPyでのKPUのプロパティが違う).

NNCaseの出力.ch,w,hの順番になっている.

ここまではほぼ確定なのですが,ここからがよくわからないところで,この4つの出力モデルの解釈で,ch=24は体の部位ごとのセグメンテーション,ch=1は体とそれ以外のセグメンテーションと読めるのですが,ほかの2つがよくわかりませんでした.とりあえずch=1の奴を使ってみます.





赤い部分が濃いほど,人がそこにいる確率が高いことを表しているのですが,あまりうまくいっていなさそうです.

5.今後やりたいこと


データの解釈があっているかの確認や精度向上,高速化あたりをやっていきたいです.もしかしたらch,w,hの解釈もあっていないかもしれないですね...



©2020 shts All Right Reserved.


2020年9月11日金曜日

Matplotlibで散布図や折れ線グラフの30fps描画を実現したい




相変わらず引きこもり生活な中の人です。今回はMatplotlibで散布図や折れ線グラフを高速描画する話です。 



1.Matplotlibの描画の話


Pythonでグラフ描画を行う際によく使うのがMatplotlibです.Matlab-likeなインターフェースで扱いやすいのですが,リアルタイム描画を行おうとすると非常に遅いことがあります.
これに関してはいろいろな高速化のやり方があるのですが,この中でも手動更新のコードを自分で書くことで高速化を果たすやり方だと,データ数によっては100fps以上を狙うことができるらしいです.

参考:hukkumameo,【Python】matplotlibの手動で描画更新,俺言語。

2.手動更新について


描画の更新方法はいくつかあるのですが,今回は
  1. 描画領域を白く塗る
  2. データを描画する
  3. 描画領域のアップデート
  4. 画面の描画更新
でやってみました.(1.の参考に書いてあるcase4)

3.折れ線グラフ


折れ線グラフはhukkumameo氏がやった通りなのですが,少しいじってクラス化しました.まずは初期化から.

class Line:

    def __init__(self, fig, ax, plot_area=(1000, 1000), len_points=100):
        self.fig = fig
        self.plot_area = plot_area

        # axis setup
        self.line_ax = ax
        self.line_ax.set_xlim(0, plot_area[0])
        self.line_ax.set_ylim(-plot_area[1], plot_area[1])
        self.ydata = [0.0 for x in range(len_points)]
        self.line, = self.line_ax.plot(self.ydata)
        # show figure
        self.fig.canvas.draw()
        self.fig.show()

高速化のために自動での軸レンジの計算を手動に変更し,初期化部分で設定しています.描画するデータに関しては,専用のリスト(FIFO)を作成し,データ更新が走るたびに一番古いデータを破棄し,新しいデータを足していくようにしました.
次は更新周りです.

    def update_data(self, points):
        # draw background with white
        self.line_ax.draw_artist(self.line_ax.patch)

        # plot points
        self.ydata.append(points)
        self.ydata.pop(0)
        self.line.set_ydata(self.ydata)
        self.line_ax.draw_artist(self.line)

        # update this graph
        self.fig.canvas.blit(self.line_ax.bbox)

    def plot(self, ydata):
        self.update_data(ydata)
        self.fig.canvas.flush_events()

自分で書いておいてなんですが,update_dataとplotの分割はあんまり意味は無さそうです...

4.散布図


折れ線ができたら散布図もやりたいということで,実際にやってみました.描画の基本方針は折れ線グラフとは変わらないのですが,やり方が少し変わってきます.このあたりの話に関しては,差分更新によるmatplotlibのアニメーションの高速化の記事によく書かれています.

class Scatter:

    def __init__(self, fig, ax, plot_area=(1000, 1000), len_points=100, show_icon=False, icon_radius=100):
        self.fig = fig
        self.plot_area = plot_area
        self.icon_radius = icon_radius if show_icon is True else None

        # axis setup
        self.pos_ax = ax
        self.pos_ax.set_xlim(-plot_area[0], plot_area[0])
        self.pos_ax.set_ylim(-plot_area[1], plot_area[1])
        self.pos_points = self.pos_ax.scatter([], [])
        self.xy = [[0.0, 0.0] for x in range(len_points)]
        if show_icon is True:
            self.agent_icon = mpatches.RegularPolygon(xy=(0, 0), numVertices=4, radius=self.icon_radius, orientation=0.0, ec="r", fill=False)
            self.pos_ax.add_patch(self.agent_icon)

        # show figure
        self.fig.canvas.draw()
        self.fig.show()


折れ線グラフと同じく,軸のレンジを決めFIFOの準備をしています.これに加え,最新のデータを示すためのポリゴン描画のコードが入っています.差分更新の記事ではmpatches.Circleの例が挙げられていますが,今回はポリゴンの方を使用し,描画に関してもdraw_artistを使用します.mpatchesに関しては公式が詳しいです.

    def update_data(self, points, orientation=0.0):
        # draw background with white
        self.pos_ax.draw_artist(self.pos_ax.patch)

        # plot points
        self.xy.append(points)
        self.xy.pop(0)
        self.pos_points.set_offsets(self.xy)
        self.pos_ax.draw_artist(self.pos_points)

        # plot the icon
        if self.icon_radius is not None:
            self.agent_icon.xy = points
            self.agent_icon.orientation = orientation
            self.pos_ax.draw_artist(self.agent_icon)

        # update this graph
        self.fig.canvas.blit(self.pos_ax.bbox)

    def plot(self, points, orientation=0.0):
        self.update_data(points, orientation)
        self.fig.canvas.flush_events()

基本的には折れ線グラフと一緒です.こっちもupdate_dataとplotはひとまとめにした方がよかったかもしれません.

   matplotlib公式,matplotlib.patches — Matplotlib 3.3.1 documentation,Matplotlib 3.3.1 documentation

5.動かす


とりあえず,[-1000, 1000]の範囲でランダムな点の組(X,Y)を生成し,グラフに打っていくことにしました.これを5000回繰り返して,平均フレームレートを計算します.実行コードはこちらから.


平均フレームレートは22.9[fps]で,目標の30[fps]には届きませんでした....
試しに一度に表示する点数を,折れ線グラフと散布図の両方で5000 -> 2500にしてみます.


平均フレームレートは31.0[fps]で,目標は達成したようです.一度の表示する点数を2500 -> 1250とさらに減らしてみます.


平均フレームレートは52.2[fps]とそこそこ速くなりました.どうやら表示するデータ数に応じてフレームレートが変動するようです.

6.結局どうなのよ


これは目標の30fps描画というべきかについてはいろいろ考える必要があると思いますは,とりあえず部分的には目標達成ということにしましょう.もやもやするけど.散布図のみだったり,グラフの更新を並列で走らせるとか,更新を隠蔽するとかすればもっとフレームレートは上がるはずなので,まだまだといったところでしょうか.

7.参考


matplotlib公式,matplotlib.patches — Matplotlib 3.3.1 documentation,Matplotlib 3.3.1 documentation




©2020 shts All Right Reserved.

2020年9月10日木曜日

このブログを参照するときに気を付けてほしいこと


インターン準備が大変すぎて,おめめぐるぐる中の人です.さて,今回はブログの利用に関しての話です.弊ブログも来月で7年目に突入し,だんだんとほかのブログなどから参照されること増えてきました. 今のところ目立ったトラブルもないのですが,もしかしたら今後何か起きるかもしれないので,その前に手を打っていくのがこの記事の趣旨です.



1.このブログの趣旨


このブログは,中の人が試してみてうまくいった・うまくいかなかった事例をまとめたものです.

2.情報の内容と免責


当然,開発環境・アップデートなどにより,このブログ内で紹介した方法も動かなくなることがあります.うまくいかない場合にはほかの方法を試してください.また,ブログ内で紹介した方法で何か起こっても(物損など)責任は負えないのでご了承ください.

3.ほかの媒体での利用


基本的に他の媒体(ブログ・Twitter・同人誌など)での使用に関して,商用・非商用問わず,基本的にNGはないのですが,元にしたブログ記事のリンクを貼ってほしいです.許可は取らなくてもいいです.
諸事情により元記事が消えることもあるのでご了承ください.


4.その他


この記事は状況に合わせてアップデートします.そのため途中で内容が変わるかもしれません.




©2020 shts All Right Reserved.

2020年7月30日木曜日

M5StickVでSemantic Segmentationやってみた(3)(失敗編)




最近忙しすぎて目がぐるぐるな中の人です.前回はモデルをNNCaseで変換したと思うのですが,今回はそれを実装していきます.



1.早速本体で動かす


kflash_guiでファームウェアとともに書き込む.


NNCaseでコンパイルすると".kmodel"が生成されるので,本体のフラッシュに焼いていきます.このバイナリファイルを書き込んだのち,MaixPy IDEから

2.あれ,画像が...


実行結果.虚無が広がる.

さて,実行してみました...が,虚無虚無な出力ですね.左にカメラからの画像,右には変換結果を表示しています.フレームレートは2fpsぐらいです.

 

3.敗因分析


validは動いたんだけど...

何となく予想できたのでやっぱりかって感じですね.実は,id:shintarofさんが既に動かしていたようで,その様子から考えると,

1. 背景とターゲットとなる物体は,色などで容易に分離できる
2. 背景にあまり多くの色が混ざっていない(単色に近い)
3. データセットとよく似た状況で運用する(<-超重要)

あたりを改善する必要があるようです.あとは,入力画像のサイズを大きくするとかですかね.


©2020 shts All Right Reserved.

2020年6月10日水曜日

M5StickVでSemantic Segmentationやってみた(2)





久しぶりに研究室に顔を出しに行ったら,次の日筋肉痛になった中の人です.前回に引き続き,M5StickV(K210)にSemantic Segmentationを入れる話です.



1.使えそうで使えないレイヤ



前回示したように,使えるレイヤを守ればKeras->TFLite->NNCaseの変換は可能です.しかし,Softmaxレイヤ(Activation("softmax")も同様)に関しては動作しませんでした.
公式がBBS等で配布しているデータだと,Softmaxを使っているモデルもあるのでそこから類推するに,画像のような2D(実際はチャンネル方向があるので3D)データは動かず,全結合層の出力のように1Dのデータのみ動くようになっていると考えられます.この問題はBeta3, Beta4で確認したのですが,そのうちだれかがIssue上げてくれないかなって思っています(そこまで手が回らない).

2.Softmaxを回避する


こうなるとSoftmaxを使わずにモデルを構築したいわけですが,トレーニング時にはこのレイヤがないと正しく収束しないことがほとんどだったので,結局必要になります.
回避方法としてはいくつか存在して,

  1. tensorflowの損失関数でSoftmaxが含まれているものを使う
  2. Softmaxありで学習したモデルからSoftmaxを取り除く

あたりが主な方法になりそうです.1のやり方は,Tensorflow 1.x系だと存在したのですが,2.x系で廃止されたようです(tf.compat.v1には残されているので,厳密には存在している).
2.xの書き方になるべくしたいと考えているので,今回は2のやり方で回避しました.

モデル分割のやり方はここを見てほしいです.元のモデルをロードして,分割したものを新しいモデルとして生成しなおす方式をとっています.

3.モデルのトレーニング  


今回はVOC2012をベースに,人,椅子+ソファー,テーブル,人,TVの5分類としました.画像サイズも入力が32x32x3,出力が32x32x5となるように変更し,データ生成時には左右を反転した画像も追加するようにしました(実際はじょうげ反転も入れたほうが良い).
誤差関数はCategorogicalCrossentropyの結果にピクセルの出現回数に合わせた係数を掛け合わせています.

4.トレーニング結果

input
Ground Truth

Output(Before Pruning)
Output(After Pruning)
こんな感じになりました(この入力画像はトレーニングに使用していない).
枝刈りをやってみたのですが,ファイルサイズなどはそこまで変わった気がしていません.クラス分類でArgmaxを取って結果を出すので,Softmaxは取り除いても影響は全くありません.
そこそこ動きそうだったのでNNCaseでコンパイルしました.NNCaseでのコンパイルの際はtfliteの量子化されていない版を使用しましょう.量子化はNNCaseで勝手にやります.

5.NNCase


NNCaseではここを参考にしてコンパイルをしました.オプション等が変わっているので,注意が必要です.


.\ncc.exe compile Model_V0_1.tflite Model_V0_1.kmodel -i tflite -o kmodel --dataset ./data/JPEGImages_Sample/ --dataset-format image --inference-type uint8 --input-mean 0 --input-std 1 --dump-ir --input-type uint8 --max-allocator-solve-secs 120 --calibrate-method l2 --dump-weights-range --weights-quantize-threshold 128 --output-quantize-threshold 256


パラメータの量子化のためにデータセットのサンプルを準備することや,quantizeのためのオプションの値の設定があります.この辺はモデルと出力結果を眺めつつ変えていけばいいと思います.
このコンパイル作業は非常に長いので(3-40min, XPS 9360 i5モデル),気長に待ちます.この時の出力結果にモデルのサイズが出るので,KPUのメモリに載るかを確認しておきましょう.大きい場合は,元モデルの構造を変えることなどで修正しましょう.

6.次回予告


NNCaseでのコンパイルが終わったので,実機確認編です.





©2020 shts All Right Reserved.

2020年6月1日月曜日

M5StickVでSemantic Segmentationやってみた(1)



インターンの日程と授業日程がことごとく合わない中の人です.
今回はやるやる詐欺で延期していたM5StickV(K210)でSemantic Segmentationの話です.
メモリサイズとか、ネットワークが実行できないとか色々あったのでその辺の話もしていけたらと思います.



1.Semantic Segmenationとは


こんな感じのヤツ.https://mc.ai/semantic-segmentation-for-dummies/より

Semantic Segmentationはピクセル単位でクラス分類を行うタスクで,自動運転などの例でよく出てくるあれです.普通のクラス分類と比べ出力のサイズが大きくなりやすい傾向があります.Instance Segmentationはこれの親戚にあたる.

2.モデルの構築


Semantic Segmentationのモデルはいろいろ提案されています.速度重視のものだとENet,ICNet,ESPNetなどがあります。とはいえ論文中だと速度計測用のデバイスがRTX2080やTitanといった普通のGPUになっていることが多く,そのままでは到底K210では使えません。
そこで今回は泣く泣く独自にモデルを設計することから始めます。

3.KPUのメモリとモデルの制約


K210のKPUを使う場合,メモリの制約を気にする必要があります.

参考:kmodel v4 tips

特に入出力用のメモリは2MBなので、画像サイズを気にしないとサイズオーバーで動かなくなります。(NNCaseでのコンパイルはサイズオーバーでも通ってしまい、実機に突っ込んで初めて気がつくなんてことがありました)
今回は32x32x3の入力で32x32x5の出力にしました。もう少し大きくても動きそうな
印象です。
パラメータの方はまだ余裕がありそうなので、もう少し深いモデルでも動きそうです.(今回の場合では50%程度しか使っていない)

4.NNCaseが対応するレイヤ


NNCaseで使えるTFLiteのレイヤには制限があり,kerasで作ったモデルが使えないなんてこともあります.

参考:tflite_ops.md

netronなどで,TFLiteに変換したモデルを確認するといいでしょう.
実はTFLite以外にもONNXとCaffeにも対応しています.こちらも対応表があるので,使う場合には参考にしましょう.

5.自作したモデル


モデル全体図.サイズ違いの同じ画像の入力を渡すようにしている.

今回作成したモデルはサイズ違いの入力を持つ構成にしました.各ブロックの中身はこんな感じ.

ブロック部分.フィルタサイズを変えている.

MixConvもどきです.高速化の観点からだとKPUがダイレクトに走らせられるようにカーネルサイズを3x3にしたいのですが,無理やり3x3を2回走らせるよりはマシってことで5x5カーネルを使用しています.
元の入力が32x32の時点でここまで小さくする必要はないのですが,何となくやってます.実は,KPUの仕様的にはあと1回ぐらいはサイズを落とせる(4x4)ようなのですが,そこまで落としても意味が無さそうなのでやっていません.

6.次回予告


次回もモデルの解説をうだうだやりつつ,NNCase v0.2.0 Beta4を使った実装の方もやっていきたいと思います.



©2020 shts All Right Reserved.

2020年5月30日土曜日

iPad Pro買ってみた




在宅作業が始まる前よりも、忙しくなっている中の人です。在宅作業であったら便利かなと思いタブレットを買ったのですが、使い始めてから1週間ぐらい使ってみたのでそのレビューをしてみようと思います。



1.購入までの経緯


こんな感じの奴を見たかった

そもそもなんで買ったのかって話ですが,
  • 在宅でバイト・授業を受けるので,資料がPDFなどの電子データで来る
  • 家のPCにつないでる画面は1枚だけなので,PDF+ビデオ会議見たいのなことはしにくい
  • PDFに書き込みたい
ってあたりを前々から考えており,実験TAのレポート確認がPDFになることが確定したことがダメ押しになった感じです.

2.機種選定


お値段約12万円(学割適応済み)

今回はiPad Pro 11inch 128GB Wi-fiのみを選びました.いわゆる最安の奴なんですが,
  • iPhone XRの運用経験から,容量は64GBあれば足りそう
  • 出先ではiPhoneのテザリングを使うので,cellularはいらない
  • 画面サイズはPDF読む程度なら11inchで足りる
  • ぬるぬる動いてほしい
  • ビデオ通話もやりたい
ってあたりを判断した結果,iPad Proの最安モデルになりました.

3.使ってみた感想  


汚い画面だ.

買って2週間ぐらいたったわけなんですが,そこそこ好印象でした.
画面が大きくなった恩恵が想像以上に大きく,
  • PCでサイトを読むよりも一度に見れる情報量が多い上,スマホより文字が大きく出来る.
  • ペンでかける範囲が大きいのでメモとかが取りやすい.
ってあたりが良かったです.縦置きディスプレーの印象に近い感じです.

4.その他


扉にくっつく.

元々iPhone XRを使っていたのですが,初期設定の際にアカウントデータとかをbluetoothで勝手に引き継いでくれる機能が良かったです.
バッテリーもそこそこ持ち,Zoom8h耐久とかやっても100%->20%と耐えてくれました.
ケースは純正の奴を買ったのですが,磁力があまりにも強いので鉄の扉とかにiPadごと貼り付けられます.結構便利です.





©2020 shts All Right Reserved.

2020年5月12日火曜日

VSCodeでDraw.ioが使えるExtensionが出たので試してみた


 就活が始まり、慌ててRustやり始めた中の人です。さて今回はVSCode向けにDraw.ioのExtensionが出たのでを使ってみた話です。中の人は結構Draw.ioとVSCodeを使うこともあり、非常にありがたい話です。

開発者(@hediet_dev)の元ツイート https://twitter.com/hediet_dev/status/1259214515683590144?s=20


2020/5/17追記:v0.4.0におけるExport機能についてを追記


1.インストール

"draw"まで打ち込んだら、出てきた

ExtensionsでDraw.ioって打つと"Draw.io Integration"が一番上に出てくるので、それをインストールするだけ。超絶簡単。

マーケットプレイス
https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio

2.使ってみる


使ってみた様子。数式も使えれば、矢印もオートでつながる。

使い勝手は、Draw.ioのオフラインエディタに近い感じです。PNGなどの画像出力とか、数式組版とかもそのまま使えます。(数式組版使ったやつをPNGとかJPGとかで吐き出すと、組版の表示が元に戻るみたい)

先ほどのやつをPNGで吐き出した。数式組版が戻る。

今のところ(2020/05/12現在)、PNGなどできれいな数式を入れたい場合は、VSCodeで編集した.drawioファイルをオンラインのDraw.ioに上げてエクスポートしてあげる必要があるみたいです。

2020/5/17追記:

v0.4.0のChange Log.

バージョン0.4.0がリリースされ,Export機能が削除されたようです.
(Removes export options as they did not work.)
もしExportを使いたい場合は,0.3.0にダウングレードして使うか,Draw.ioに編集した.drawioファイルを上げて,Exportしましょう.

3.その他


GitHubにリポジトリが転がってたよ。PDF吐き出せないとかがissueに上がってるみたいです。(2020/05/12現在)



©2020 shts All Right Reserved.

2020年5月10日日曜日

素人でもわかる!"回 路 設 計"におけるリスケジューリング



今まで作った基板たち。圧倒的な青率

 家籠り生活1か月目、ついに手が滑ってiPad Pro 11inchを買ってしまった中の人です。
約1か月振りの投稿です。
 回路設計におけるリスケジューリングって題名ですが、予定通りに進まず、締め切り駆動開発になった話です。




1.回路設計の始まり


作った回路。ふぇぇぇぇ

メカの開発に四苦八苦していたのは前回話しましたが、実はこの裏で回路設計を始めていました。使ってみたいセンサやマイコンのテストを2019/12-2020/01初頭にかけてやりつつ卒論を書きつつ卒研発表準備みたいなことをしていたので、夜の研究室で一人発狂していました(メタなことを話せば、この時期のブログ投稿はすべてこのための準備)。
 なんだかんだコノ辺までは計画通りで、旧正月前には基板が届くようなスケジュールで動くことができていました。

2.発注期限は旧正月前


別基板にして配線するので、未配線の部分が残っている

 とりあえず仕様が決まったので、回路設計を始めました。いろいろな機能を載せようとた結果、再設計を何回もする羽目に...。想像以上にESP32のアンテナ周りの制約がきつく、メカ側の設計にも影響が出ました。この一件で進捗が大幅に遅れました。
 こんな感じで設計を進めていたところ、TLにコロナの話題がちらほらと流れてきました。旧正月は織り込み済みだったのですが、想定外だったのがコロナです。しかも深センあたりも封鎖するみたいな話が流れてきたので、急ピッチで設計を進めました。
 結果、メールを受け取ってくれる最終日に何とか発注を終え一安心...と思ったのですが、結局業者の方が旧正月後も動けず(当たり前ですが)、基板発注から1か月後に到着しました。当初の予定から1か月遅れです。

3.遅れた原因を振り返る


当時のツイート。

 今振り返ってみると、"同時に走らせるタスクが多すぎてキャパオーバーした"ことと、"どこかで詰まることは予想していたが、バッファの見積もりも甘く、時間が足りなかった"のが原因だったと思います。まあ趣味でやってるものなので学業優先が基本なのですが。



©2020 shts All Right Reserved.

2020年4月14日火曜日

0からごみを生み出す!素人機械設計 入門




 サークルの新歓っていつなのかわからない中の人です。今回はメカ設計未経験のド素人が、トイラジコンの設計をする話です。



1.サイズを決めよう!


作りたいサイズは道路が基準。
Jet何某が2車線使っているので、対抗して1車線分で作成。

 何を作るかは決めたので、最初はメカの設計から始めました。手元にあったレゴの道路プレート(廃盤、代替品が出てる)の1車線分を基準にサイズを決めました(50mmx95mm、車軸間62.5mm)。このサイズが後々悲劇を生むわけなのですが。

2.大まかに設計しよう!


設計の参考にしたMINI-Z AWD MA-010。
4輪駆動、ギヤデフ、4輪独立サスなどロマンもりもり。
これの最新版がMA-030で、FF版のMA-03Fがベース。

盛り込みたい機能は決まっているので、実際のラジコンを参考に設計をはじめました。参考にしたラジコンは目標サイズより一回り大きいので、各部分をスケールダウンしながら、違う設計に変えていく必要がありました(丸パクリはできないからね)。
 うだうだ設計を進めつつ(実は基板と並行して設計)、2月中頃には最初の設計が終了しました。

3.条件をよく見よう...


DMMのAgiristaは初めて使った。
最小厚み等で3Dプリント担当者には相当ご迷惑をおかけしました。

 今回はAgiristaやMJFの精度を見極めたかったので、アクリルUltraの使用は最小限にして、AgiristaやMJFを多用することにしました。(Agiristaは単価の安いアクリルだと思っていた)
 実際にDMMの3Dプリントサービスに自分で設計したデータを投げつけたところ、Agiristaで作ろうとしていたデータに厚みが足らない部分があるために作成できないとの連絡が届き、結局設計変更を行い事なきを得ました。

4.足らない強度と精度


できた部品。
届いた部品を嬉々として組み立てたが...

 数日後、部品が届いたので試しに組んでみることにしたのですが、届いた部品を見て絶句しました。あまりにも小さすぎたのです。
 これは決してDMMのせいではなく(むしろほぼ設計通り)、完全に設計段階で本当のサイズを確認していなかった私のせいでした。
 実際に組んでみたのですが、当然思ったとおりには動作しませんでした(小さく作りすぎたため、強度も精度も足らない)。

数万円のお小遣いがゴミに変わった瞬間でした。

5.再設計


再設計は辛いよ...

 ガラクタを作った事実に直面した次の日から、再設計を始めました。この時には、いろいろ妥協して既製品を使うことにしたのですが、またいろいろありました(その辺は再設計編で)。

6.次回予告

 URLのまとめは初回投稿にあるので、よかったらどうぞ。また、テクニカルな面の解説は別にしようと思っています。こちらは少々お待ちください...





©2020 shts All Right Reserved.

2020年4月13日月曜日

卒業制作(改め入学制作)(現在進行形)




 大学院に進学したものの授業開始が5月になり、就活がリアルに終活になりそうな中の人です。今回はかねてからやってはいたものの、あまり表に出してこなかった、卒業制作(改め入学制作)の話です。



1.卒業(入学)制作までの経緯


現状の"名称未設定"君。いい名前を考えてほしい。

 大学に入ってから、あまり"自分の作りたいものを作る"ことができていなかったのと、卒業研究からの逃避場所を設ける観点から、何となくCADをいじり始めたのが最初です。作るものに関しても完全に何となくで自動運転の車に決めました。

2.仕様について


ユニットごとにばらしたところ。

 仕様を固め始めたあたりにM5StickVを塩漬けにしていたことを思い出し、これを使うことに決めました。せっかくなのでいくつか試すことにしました。
  • サスペンション、デフ、ステアリングを盛り込む
  • 昇圧IC、モータの電流検知、LiPo充放電回路の搭載
  • テレメトリシステム、DeepLearningによる画像処理(Semantic Segmentation)
 ざっと書くとこの辺でしょうか。(本当はFPGAの小さいヤツを積んで、デジタルセンサのハブを作るとかも考えていました。)
 すべてにおいて専門外の中の人がやるにはとてつもなく酷野心的ではありますが、とりあえずやってみました。

3.ページまとめと次回予告


  1. 作り始めた経緯(今回)
  2. 0からごみを生み出す!素人機械設計 入門
  3. 素人でもわかる!"回 路 設 計"におけるリスケジューリング
  4. 0からごみを生み出す!素人機械設計 あげいん
  5. 基 板 が 届 か な い
  6. M5StickV触ってみた
  7. (M5StickVでセマンティックセグメンテーション)
  8. (基 板 実 装)
  9. (回路設計あげいんにならないといいな)
  10. (ESP32でテレメトリ)
  11. (動け、"名称未設定"君)
()の中身は現在進行中or予定です。おそらくうまくいかないので、あてにしないでください。

次回は、"0からごみを生み出す!素人機械設計 入門"です。次の更新はいつになるのか...


©2020 shts All Right Reserved.

2020年3月26日木曜日

kmodel v4 tips




 ここ最近はFPGAに全く触れていない中の人です。kmodel v4の実装で詰まったところがあったので、まとめておきます。


1.KPUのメモリとモデル圧縮


推定されるKPUのメモリ空間の割り当て(中の人の想像)。
コンパイル時にWeightsとDataの境界を決定しているらしい。

NNCaseでは、KPUのメモリ空間を6MBのメインメモリと2MBの入出力データ用メモリに分けており、重みやバイアス、中間生成データはメインメモリに載せているようです。
 このため、大きなモデルを載せるためにはメインメモリ側と入出力専用メモリ側の両方でモデルを圧縮する必要があります。今回作成したモデルの場合、入出力専用メモリは足りるのですが、メインメモリ側でサイズ超過が発生しました。

1-1.カーネルサイズ、チャンネル数


 CNN系のレイヤでは、カーネルサイズと入出力のチャンネル数が重みパラメータ数を決めるのですが、大半のモデルでは チャンネル数 >> カーネルサイズなので、チャンネル数削減の方がよりモデルの圧縮に効いてくるようです。

1-2.レイヤ数


レイヤ数の削減は、パラメータ数の削減以外にもネットワーク全体の高速化に効いてきます。ですが精度を落ちてしまうのでそこのバランスはしっかり見ておく必要があります(チャンネル数の削減も同じ)。

1-3.入力データサイズ


 中間生成データの削減には、入力データのサイズを落とすことも有効です。入力のサイズを落とすことで、レイヤ通過後の中間生成データも小さくしようというわけです。


 NNCaseの仕様的にパラメータを載せる領域と中間生成データを載せる領域も分けているようです。中間生成データ領域の量は、モデル内で最も中間データが大きくなった時の値で固定なので、ここを小さくするのが最も効果的でした。

2.アクセラレーション


 完全な形でKPUのアクセラレーションをしようとした場合、いくつかの制限があります。
  • 各レイヤの入力フィーチャーマップが320x240以下かつ出力フィーチャーマップが4x4
  • どの辺も同じパディング幅であること
  • Conv2DやDepthwiseConv2Dのカーネルサイズは1x1または3x3、かつストライド幅が1または2
  • MaxpoolとAveragepoolは2x2または4x4
  • 要素ごとの活性化関数がReLU, ReLU6, LeakyRelu, Sigmoidで、PReLUは未対応(FAQ上だと使える関数に...ってなってたけど、実際はよくわからん)
 部分的なアクセラレーションになるのは

  • 畳み込み系のレイヤで非対称なパディング、パディングされていない場合
  • ストライドが1、2以外(KPUConv2D+StrideSliceに置き換え)
  • MatMul(Pad(to 4x4)+KPUConv2D(1x1kernel)+Crop(to 1x1)に置き換え)->Beta 3でKPU matmulが追加されたので、もしかしたら専用の命令に置き換わってるかも。
  • TransposeConv2D(SpaceToBatch+KPUConv2D+BatchToSpaceに置き換え)
らしいです。これ以外にも置き換えはあるかもしれないのですが、公開はされていないです(NNCaseのオプションに--dump-irをつければレイヤの変換過程が見られる)。
意外とFakeKPUConv2DとかIgnoreが多かったです。

参考:https://github.com/kendryte/nncase/blob/master/docs/FAQ_EN.md

3.入出力データの扱い


この辺は情報が特に出回っていないので、苦労しました。

3-1.データの正規化


 トレーニング時に入力データの正規化を行いますが、M5StickV上で動かすことを考えると[0, 1]に正規化したほうが扱いやすかったです。どうやらNNCaseが勝手に、画像データの入力の場合は[0, 1]に正規化しているようです。[0, 255]とかでもやったのですが、うまくいかなかったです。

3-2.出力データフォーマット


 入力が画像の場合、image.Image()にすればいいので問題ないのですが、出力は画像出力でも1次元のtupleなので変換する必要があります。いろいろ探した結果、NCHWだったことが判明し、実際に変換してみても同じだったので安心しました。
 ただ、tuple->Imageの変換の際には、画素ごとに色を割り当てたいのでNCHWよりもNHWCの方がより便利です。NNCaseのオプションで変えられればいいのですが。

4.その他

4-1.Maix_Toolbox


 Maix_Toolboxにはtflite2kmodel.shという変換用のshellスクリプトが用意されています。中身はNNCaseでコンパイルを実行しているだけなのですが、コンパイルオプションから推定するとNNCase V0.1.0向けであることがわかります。
 なので、NNCase V0.2.0系を入れてしまうと動かなくなります。また、V0.1.0は対応するレイヤが少ないので、個人的にはV0.2.0をお勧めします。

参考:

4-2.Beta2とBeta3


 いつの間にやらNNCase v0.2.0 Beta3がリリースされたようなので、そちらのテストをしました。
 コンパイルのオプションは、Beta 2で使えたものはすべて使えました。Beta 3で追加されたオプションはあるかどうかがわかりませんでした。
 コンパイル結果を見ると、同じモデルでもBeta3の方がメインメモリの使用量が増えているようです。また、"Optimize Pass 3"という工程が増えていました。実行速度はあまり変わっていませんでした。もう少しコンパイラの気持ちになってモデルを作れば、速くなるかもしれません。

4-2(2020/5/21追記).Beta4


 Beta3が出たと思ったら,NNCase v0.2.0 Beta4がリリースされたようなので、そちらのテストをしました。
 リリースの内容を見ると,オプションとして,--weights-quantize-threshold,--output-quantize-threshold,--no-quantized-binaryが追加されているようです.(実は,--dump-weights-rangeなんていうオプションも追加されてる)
量子化周りの設定のようで,しきい値の設定をできるようです.(後でいろいろ書きます.)
 出力されるモデルサイズはBeta3とBeta4で違いはないようです.オプション次第で変わるかもしれないです.

4-3.ファームウェア


カスタムファームウェアの_boot.pyをいじった。
中央右の得体のしれないものは猫。

 フラッシュに焼く際に、モデルが大きすぎると載せられない問題が発生します。その対策として、自分でファームウェアをビルドする方法があります。


 やり方は、上のURLを参考にしてもらうとして、私の場合は_threadとulab、MaixPy IDEのみを有効化し、あとは無効化しました。


©2020 shts All Right Reserved.

2020年3月21日土曜日

NNCase on Windows 10



 NNCaseのV0.2.0がWindows 10に対応しているとのことなので、使ってみました。
"tf.kerasの自作モデルをNNCase  v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(2)" のWindows 10版だと思ってください。





2-1.NNCaseのダウンロード


 今回使用する kmodel V4に対応するNNCaseはV0.2.0以降なので、最新版(2020/3/16現在)であるNNCase v0.2.0 から各OS版の圧縮ファイルをダウンロードします。Windows 10の場合は、ncc_win_x86_64.zip を選択しましょう、

2-2.NNCaseのインストール(?)

 落としてきたファイルをどこでもいいので解凍します。解凍した中にncc.exeが存在するはずです。
 このexeファイルをトレーニング済みの.tfliteがあるフォルダに投げ込みましょう。これでインストール(?)は終わりです。

2-3.コンパイルオプション

2-4.コンパイルの例

 コンパイル例です。


.\ncc.exe compile Model.tflite Model.kmodel -i tflite -o kmodel --dataset ./Img/ -- dataset-format image --inference-type uint8 --input-mean 0 --input-std 1 --dump-ir --input-type uint8 --max-allocator-solve-secs 120 --calibrate-method l2

 中の人は、PowerShellで動作確認しました。

2-5.その他

 一応動いたので、よし。
 (Macを持っていないので、そちらの動作確認はほかの方に投げたい所存です。)


©2020 shts All Right Reserved.

NNCase 記事まとめ




 NNCase V0.2.0の記事のまとめです。


tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす


kmodelを作るときのtips


セマンティックセグメンテーションやってみた




©2020 shts All Right Reserved.

2020年3月18日水曜日

tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(3)



 この前研究室に行ったら、学位記って書かれた紙を受け取った中の人です。概略(0)モデル構築(1)kmodelの生成(2)に引き続きkmodel v4をM5StickVで動かす話です。


3-1.MaixPyのファームウェア

 M5StickV向けのプログラミングにはいくつかの方法がありますが、今回はkmodel v4(NNCase v0.2.0)対応のMaixPyを使います。MaixPyを使う場合は、Sipeedが配布しているファームウェアを焼く必要があります。最新版はv0.5.0_31のようです(2020/3/18現在)。M5StickV向けのファームウェアは、maixpy_v0.5.0_31_gd3e71c0_m5stickv.bin です。


3-2.ファームウェアを焼く

ファームウェアの書き込み。中の人は独自ビルドのファームウェアを使用するため、
ファイル名が異なっている
 先ほど紹介したファームウェアと、前回生成したkmodelをKflash GUIを用いて焼きました。ファームウェアは0x00000番地(デフォルト)、kmodelは0x500000番地を先頭に設定しました。

3-3.KPUライブラリ

 MaixPyはMicroPythonをベースにK210向けにライブラリを追加・改変したもので、Python-likeな書き方ができます。K210に搭載されているKPU向けのライブラリも追加されており、比較的容易に扱うことができます、

3-4.関数解説

 Kmodel V4からマルチアウトプットに対応した関係で、V3(NNCase v0.1.0)のころとは書き方が変わっています。

3-4-1. KPU.load(addr)

引数
  • addr : kmodelの先頭アドレス
戻り値
  • task : kpu_netオブジェクト
 最初に実行するのが KPU.load(addr) です。addrはkmodelを焼いた際に指定した先頭アドレス(今回なら0x500000)を指定します。task = KPU.load(0x500000) のようにし、kpu_netオブジェクトを保持しておきましょう。

3-4-2. KPU.set_outputs(task, index, width, height, depth)

引数
  • task : kpu_netオブジェクト
  • index : 何番目のモデル出力かを指定
  • width、height、depth : 出力の横、縦、深さ形状
戻り値
 いまいちわかっていません。どなたか情報をください。
 2020/3/26追記:ただのboolでした。確保できればTrueが返ってきます。

 Kmodel V4になってから必要になった関数です。V4からは複数出力に対応したので、このようなものが必要になったようです。タプル等を使って複数同時指定皆体なことはできないので、各モデル出力に対して実行する必要があるようです。

3-4-3.  KPU.forward(task, data, [layer)

引数
  • task : kpu_netオブジェクト
  • data : モデル入力。imageオブジェクトのみかも。
  • layer : 実行するレイヤ番号。
戻り値
  • fmap : フィーチャーマップ 
 KPUで実際にモデルを実行する関数です。layerは省略すると、モデル全体の計算を行います。fmapはNCHWフォーマットで、単一出力の場合は、1次元化されたタプルが返ってきます。

3-4-4. KPU.memtest()

 メモリの確保状況を取得します。

3-4-5. KPU.deinit(task)

引数
  • task : kpu_netオブジェクト
 メモリの開放などを行います。

3-5.動作

動作の様子。もっさりしている。


とりあえず動作しました。画面描画を含め3FPSを少し超える程度ですが、動いているのでよしとしましょう(KPU単体なら7FPS程度)。より高速に動作させる場合は、モデルのレイヤ数の低減や入出力サイズの縮小を行うべきです。

 ソースコードはこちら:https://github.com/shtsno24/DAE_for_M5StickV/blob/master/M5StickV/KPU_Test.py

3-6. まとめ

 全4回でM5StickV上でKmodel V4を動かす話をしてきました。日本語情報がほぼない中で完全手探りでしたが、簡易的に動かすことができました。まだ試していない関数があるので、今後の課題にしておきます。
 今後はセマンティックセグメンテーションなどの応用にチャレンジしていきたいと思います。

参考:KPU - MaixPy DOC https://maixpy.sipeed.com/en/libs/Maix/kpu.html
   MaixPy support new nncase &amp; Kmodel V4 Now~ - MAIX - Sipeed bbs
   https://en.bbs.sipeed.com/t/topic/1790


©2020 shts All Right Reserved.

2020年3月16日月曜日

唐突に学部4年間を振り返る



 あまりにも唐突に始まりました、学部4年間の振り返りです。おそらく地球上でこの記事を 黒歴史認定して消し去ろうとする 熱心に読むのは未来の私一人なのですが、まあやっていきましょう。



0.高校時代

 高校時代はLEGO(特にTechnic)が大好きで、WROに友人とともに出てました。最初は機械系を志望していたのですが、途中で電気電子系の学科に変更しました。
 アキバでRaspberry Pi Model Bが発売された当時、Make:とかを読んでいた当時の中の人は、"回路系も面白そうだな"という単純な思考で変更していた気がします。

暇なときに作ったロボットアーム。プログラムを書いてくれた友人には圧倒的感謝。

 Raspberry Piとの出会いは結構衝撃的で、まともにPC(?)でプログラミングしたのはこれが最初でした。なんだかんだ縁あって、最初のラズパイコンテストで学生賞になりました。

当時作成した動画。スマホでいいじゃんとかは言っちゃダメ

 当時は金工木工室をほとんど貸し切りで使っており、動画中のアクリルケースはここで加工しました。モノづくりの環境としては木の切りくずに悩まされた以外、非常に良いものでした。

 大学進学に当たり、もともとは国立の大学を狙っていたのですが、おもに本人の実力不足と努力不足により、滑り止めで受けた東京にある私大に進むことになりました。
 DNNを組込み分野に応用したいって話を考え始めたのが高校を卒業したあたりで、今考えれば、今の研究をやり始める遠因だったかもしれません。

当時の投稿はこの辺:https://www.shtsno24.tokyo/2014/10/

1年生

 期待に胸膨らませ入学式に来たわけですが、式の第一部が終わるころには北の大地に島流しされました。寮生活ではクラスターのメンバーに恵まれ、さらにうまいこと機材とかを持ち込めたので、趣味の開発を続けることができました。ラズパイコンテスト用のHW作成は5-6月ごろからはじめていました。

 このころは、授業の成績が 控えめに言ってクソ 目を覆うほどひどいもので、力学でC、実験でBが付いていました。2Qの試験が終わり、実家に帰省するときには気分がどんよりしていたことを覚えています。
 実家に帰省した後は、ラズパイコンテストのSW開発をずっとしていました。当時は20年物のクーラーを動かす勇気がなく、27℃の部屋でGPU付きのノートを全開にしてサウナ状態でAIのトレーニングをしていました(2016年当時Donkey Carなんて知らず、SWもほとんど自前で作成していました)。

2度目の学生賞。動画作るの難しい。


 苦労した甲斐あって学生賞をいただきました(2度目)。授賞式的なものには授業の関係で参加できず、そこが心残りでした。

 3Q開始後は授業終了後から22:00まで図書館に残って勉強・レポート作成をするような生活で、土日も図書館にこもっていました。大学に入って最初につらかったのがこの時期でした。しかも成績は少ししか上がらず、絶望感に襲われていた記憶があります。

 いまのバイト先に拾われたのが、4Q終わってこちらに帰ってきた直後でした。高校時代にWROに出ていた友人の紹介で入りました。ロボット教室だったのですが、個人経営の小さいところだったので、入って1か月たたずして教材開発に参加するなど、相当ハードでした。

当時の投稿はこの辺:https://www.shtsno24.tokyo/2016/09/

2・3年生

 北の大地での刑期も終わり、東京でのキャンパスライフスタートです。ですが期待に胸膨らませることはあまりなかった気がします。それもそのはずで、実家から片道2h以上かかるため、1限の授業に出るためには6:00前に家を出るのが確定していたからです。別に電車通学にはさほど抵抗感はありませんでしたが、この通学時間(帯)は健康面で相当なハンディになりました(今もだけど)。

 とはいえ、授業にはほとんど出席し成績も少しは良くなったので、精神的には少し良くなった...と言いいたいところですが、絶望感から焦りに変わっただけでした。所属しているどのコミュニティ(大学・サークル・バイト)にも、私よりできる人が多かったので、取り残されまいと必死こいてその場でじたばたしてました。(結局何も進まない)

 このころ、毎週出される実験レポートが結構な重荷になっていました。2年次は手書き、3年次がPCだったのですが、要領よくやることが相当苦手だったので、毎日図書館にこもり、どのレポートも期限ぎりぎりまで作成していました。

初代Camellia。モータが両面テープで止まってる。

 サークルではマウスを2年がかりで作り、公式大会での完走にこぎつけました。この時期趣味は通学時間以外でのプログラミング以外ほとんどやっていなかった気がします。

 キャンパスの近くで一人暮らしをするためのお金が欲しかったので給付型の奨学金に応募しましたが、学内選考でことごとく落とされました。(親が無職になりかけ、金銭的な不安が増してきたのもこのころ)

とあるインターンに行って、無能感に打ちひしがれたこともあったっけ?

4年生

研究室配属ガチャに当選し、第一希望の研究室に入ることができました。研究テーマは組込み向けFPGAにCNNのアクセラレータを載せて高速化するものを考えており、9月ぐらいの進捗報告会で初めて研究室向けに話してOKをもらいました。
 10月から本格的な開発が始まり、HLSツールのバグに悩まされながらも12月末には開発が終了、1月末の発表までには論文もほぼ仕上げられました。このころには13:00ラボ着->23:00ラボ発->25:30自宅着の健康を害する以外何もないルーティンが出来上がっていました。

 バイトの方は2月からのコース再編の関係で、ほぼゼロからコースの立ち上げを行いました。数人のチームを組み、その中のリーダー的な役回りをしていました。このころに他人にタスクを振ることを覚え始めました。(その流れで、3月の対応や5月以降のコース再再編のPMをやる羽目に)

 サークルにはほとんど顔を出していないので、非常に申し訳なく思っていますが、肝心のマウス(もどき)の進捗は虚無なので、これからもガラクタ作ってる影の薄いおじさんになりそうです。

 趣味の方は、いわゆる勉強会的なものに顔を出すようになりました。誰からの紹介もなく一人で行ったのですが、大きい勉強会になればなるほどいろいろなバックグラウンドの方がいるので結構刺激的です(自分の知らない分野の情報が入ってくるのが一番大きい)。

 

4年間で得たこと

  • 体重
  • 焦り
  • 処分に困るガラクタ、ごみ屋敷と化した自分の部屋
  • 両親からの心配
  • 将来の心配
  • 学位
  • 大学院進学


4年間で失ったもの

  • 健康
  • やる気
  • 記憶力
  • アイデア
  • 自尊心
  • 精神の安定感(小中の頃に失ってたかも)
  • 両親からの信頼
  • 将来への希望

4年間で学んだこと

  • 全力で取り組んでも、ほとんど上手くいかない。ごく稀に上手くいく。
  • カネは余裕。あったらあった分だけよい。
  • 長距離通学は、健康で金を買っている。
  • 予備を買うと予備がいらなくなる。
  • 進捗には実軸と虚軸があり、虚軸上で単振動していることがわかると非常に虚しい。
  • 大体のコミュニティには自分の上位互換がいる。
  • 要領の悪さは一生もの。
  • みんなすごい! 自分?無能。

まとめ

 4年間で精神と健康、金を使って、学位を錬成しました。両親や関係者の皆様には頭が上がりません。これから先も無能らしく皆様に媚びて生きるので、何卒よろしくお願いします。



©2020 shts All Right Reserved.

tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(2)



 卒業式が吹き飛んだ中の人です。今回も前回前々回に引き続き、NNCaseの話です。前回まででモデルの作成が終了し、変換の話になります。
2020/3/21 追記:Windows 10でもNNCaseが動きました!





2-1.NNCaseのダウンロード


 前回作成した.tfliteのモデルの変換には、kendryte提供のNNCaseを使用します。というわけでまずはダウンロードしましょう。
 今回使用する kmodel V4に対応するNNCaseはV0.2.0以降なので、最新版(2020/3/26現在)であるNNCase v0.2.0から各OS版の圧縮ファイルをダウンロードします。中の人はUbuntuを使用しているので、ncc_linux_x86_64.tar.xzを落としてきました。

2-2.NNCaseのインストール(?)

 落としてきたファイルをどこでもいいので解凍します。解凍した中にnccという名前のフォルダnccという名前のファイルが存在するはずです(おそらく./ncc/nccという形)。
 このフォルダごとトレーニング済みの.tfliteがあるフォルダに投げ込みましょう。これでインストール(?)は終わりです。

2-2-1.(補足)

 実はフォルダを移動させることなく、tfliteのパスと出力先のパスをファイル名とともにに指定してあげれば問題なく動きます(Linuxなら相対パスでも動作確認済み)。

2-3.コンパイルオプション

 モデルを変換する際のオプションは、以下のようになっています。(2020/5/31更新)

DESCRIPTION
NNCASE model compiler and inference tool.

SYNOPSIS
    ncc compile <input file> <output file> -i <input format> [-o <output
        format>] [-t <target>] [--dataset <dataset path>] [--dataset-format
        <dataset format>] [--inference-type <inference type>] [--input-mean
        <input mean>] [--input-std <input std>] [--dump-ir] [--input-type <input
        type>] [--max-allocator-solve-secs <max allocator solve secs>]
        [--calibrate-method <calibrate method>] [-v]

    ncc infer <input file> <output path> --dataset <dataset path>
        [--dataset-format <dataset format>] [--input-mean <input mean>]
        [--input-std <input std>] [-v]

OPTIONS
    ncc compile <input file> <output file> -i <input format> [-o <output
        format>] [-t <target>] [--dataset <dataset path>] [--dataset-format
        <dataset format>] [--inference-type <inference type>] [--input-mean
        <input mean>] [--input-std <input std>] [--dump-ir]
        [--dump-weights-range] [--input-type <input type>]
        [--max-allocator-solve-secs <max allocator solve secs>]
        [--calibrate-method <calibrate method>] [--weights-quantize-threshold
        <weights quantize threshold>] [--no-quantized-binary] [-v]

    ncc infer <input file> <output path> --dataset <dataset path>
        [--dataset-format <dataset format>] [--input-mean <input mean>]
        [--input-std <input std>] [-v]

    ncc -h [-v]

OPTIONS
    compile
        <input file>        input file
        <output file>       output file
        -i, --input-format  input file format: e.g. tflite, caffe, onnx
        -o, --output-format output file format: e.g. kmodel, default is kmodel
        -t, --target        target arch: e.g. cpu, k210, default is k210
        --dataset           calibration dataset, used in post quantization
        --dataset-format    datset format: e.g. image, raw default is image
        --inference-type    inference type: e.g. float, uint8 default is uint8
        --input-mean        input mean, default is 0.000000
        --input-std         input std, default is 1.000000
        --dump-ir           dump nncase ir to .dot files
        --dump-weights-range
                            dump weights range

        --input-type        input type: e.g. default, float, uint8, default
                            means equal to inference type

        --max-allocator-solve-secs
                            max optimal layout solve time in secs used by
                            allocators, 0 means don't use solver, default is 60

        --calibrate-method  calibrate method: e.g. no_clip, l2, default is
                            no_clip

        --weights-quantize-threshold
                            the threshold to control quantizing op or not
                            according to it's weigths range, default is
                            32.000000

        --output-quantize-threshold
                            the threshold to control quantizing op or not
                            according to it's output size, default is 1024

        --no-quantized-binary
                            don't quantize binary ops

    infer
        <input file>        input kmodel
        <output path>       inference result output directory
        --dataset           input dataset to inference
        --dataset-format    datset format: e.g. image, raw default is image
        --input-mean        input mean, default is 0.000000
        --input-std         input std, default is 1.000000

    -h, --help              show help
    -v, --version           show version
(https://github.com/kendryte/nncase/blob/master/docs/USAGE_EN.mdより引用)

 V0.1.0の頃とは異なり、compileとinferを指定する必要があります。inferはコンパイル済みのkmodelを実行するモードなので今回はパス。

2-3-1.ファイル・ファイルフォーマット・ターゲット

コンパイルオプションの<input flie>は入力ファイルなので、(入力ファイル名).tflite、<output file>は出力ファイルなので、(出力ファイル名).kmodelと入れておきます。
 同様に、-i(--input-format)には tflite、-o(--output-format)には kmodel としておきます。V0.1.0では-oには k210model と指定していたので注意してください。
 -t(--target)は指定しなくても大丈夫です。勝手にK210向けになります。(cpuに指定したときの挙動は未確認)

2-3-2.データセット・データセットフォーマット

--datasetは、データセット内の画像の入ったフォルダを指定しておきます。特には解説していなかったのですが、モデルのテスト用コードとtfliteへの変換用コード内で、テスト画像と出力画像を指定のフォルダ(./Img)に吐き出すようにしていました。今回はここを指定しておきます。これはパラメータの量子化で使っているようです。データ数が増えるほどよい性能になるかもしれませんが、コンパイルに時間がかかります。
 --dataset-formatは入力データがどのようなデータなのかを指定します。といっても、画像orその他の選択肢しかないです。今回は画像が入力なので image を選択しました。音声などの信号データや、2dデータだけどチャンネル数が3(もしかしたらor 1)ではないデータを使う際は raw にしてください。

2-3-3.インターフェース・入力データ

 --interface-typeは内部処理のデータ型を指定します。精度重視の場合には float を選択しますが、メモリの使用率が上がりKPUのアクセラレーションが受けられなくなります。
KPUを使用する場合は、uint8 一択になります。
 --input-meanと--input-stdは入力データの範囲調整に使われます。トレーニング時の入力データと同じ範囲になるようにしましょう。変換式は
y = (x - mean) / std
となっています。
(参考:https://github.com/kendryte/nncase/blob/master/docs/USAGE_EN.md)
NNCaseでは、最初に入力データを[0, 1]に変換してから上記の変換式を使うそうです。
0~1、-1~1、0~255の場合については、上記の参考URL内に値が出ています。

2-3-4.中間生成データ

 --dump-irはNNCase IRが生成する中間生成データを.dot形式でファイルにするかどうかのオプションです。

2-3-5.入力データ型

 --input-typeは入力データのデータ型を指定します。MaixPyで画像データを使う場合は、デフォルトの uint8 にしておきましょう。もし浮動小数点型の場合は float を指定しましょう。

2-3-6.その他

--max-allocator-solve-secsは最適な量子化のレンジの探索にかかる時間を指定します。デフォルトは60sですが、個人的に120sにしています(特に意味はない)。
 --calibrate-methodは最適な量子化のレンジの探索方法を指定します。デフォルトだと全レンジを使う no_clip になっていますが、 l2 を指定すると、時間はかかりますがよい量子化レンジを得られるようです。

2-3-7.2020/05/31追記

NNCase V0.2.0 Beta4の登場により,オプションが追加されています.
--dump-weights-rangeは,conv2dの重みパラメータの範囲を表示します.
--weights-quantize-thresholdは,conv2dとmatmulの重みパラメータの量子化をするための重みパラメータのしきい値を指定します.デフォルトは32です.これよりも大きい場合は,量子化しません.
--output-quantize-thresholdは,conv2dとmatmulの重みパラメータの量子化をするための出力要素数の閾値を指定します.デフォルトは1024です.これより小さい場合量子化しません.
--no-quantize-binaryは,すべての計算を量子化せずにfloatで行うオプションです.

2-4.コンパイルの例

 コンパイル例です(解説文書くの疲れた)。


./ncc/ncc compile Model.tflite Model.kmodel -i tflite -o kmodel --dataset ./Img/ -- dataset-format image --inference-type uint8 --input-mean 0 --input-std 1 --dump-ir --input-type uint8 --max-allocator-solve-secs 120 --calibrate-method l2

 Tensorflowでトレーニング・変換したModel.tfliteをModel.kmodelに変換しています。
 --dataset用のデータを./Imgに入れて置きました。.jpgや.pngのファイルをそのまま./Imgに入れるだけでよく、データセットの画像は0-1に正規化する必要はないです。
 トレーニング時には0-1に正規化していたので、--input-meanと--input-stdを合わせておきます。

2-5.次回予告

 次回は本編最終回で、M5StickVに実装していきます。
 MaixPyやKflashGUIのインストール・使い方は飛ばすので、ほかのところで探しておいてください。
ついに手に入れた、精密ナットドライバー
アキバとかではお目にかかれず、新宿のハンズで購入


©2020 shts All Right Reserved.