1. ksasao

    No comment

    ksasao
Changes in body
Source | HTML | Preview
@@ -1,107 +1,109 @@
# はじめに
 液晶ディスプレイ・カメラ・マイク・深層学習用推論モジュールなどを搭載し、約3000円で入手できるAIカメラである [M5Stack](https://m5stack.com/)社の [M5StickV](https://www.switch-science.com/catalog/5700/) を利用して、デバイス単独で画像のリアルタイム学習・推論を行う拙作アプリ [Brownie](https://github.com/ksasao/brownie) の実装について説明します。
 下記が Brownie の動作の一例です。パー、グー、チョキの順に1回ずつ学習していくと、それぞれがだんだん識別できるように学習されていく様子が分かると思います。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Brownie Learn で、まっさらな状態から少しずつじゃんけんを学習していく様子です。数字が小さいほど自信ありです(登録時の画像の特徴ベクトルとの距離の2乗)。 <a href="https://t.co/GX1jR1mbJ8">https://t.co/GX1jR1mbJ8</a> <a href="https://twitter.com/hashtag/M5StickV?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickV</a> <a href="https://t.co/nrvSSGpyHN">pic.twitter.com/nrvSSGpyHN</a></p>&mdash; ミクミンP/Kazuhiro Sasao (@ksasao) <a href="https://twitter.com/ksasao/status/1161978500091301893?ref_src=twsrc%5Etfw">August 15, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
## M5StickV について
M5StickV の主な特徴は以下の通りです。詳しくは[公式サイト](https://docs.m5stack.com/#/en/core/m5stickv)を参照してください。
### プロセッサ
[Cannan Inc.](https://canaan.io/)の [Kendryte K210](https://kendryte.com/) という SoC (System-on-a-chip)が採用されており、下記のようなもので構成されています。
- 64bit RISC-V プロセッサ × 2 (400MHz動作)
- ハードウェアによるFFT(高速フーリエ変換)
- 深層学習向けプロセッサ Neural Network Processor(KPU) (0.8TOPS)
- 8MiB 64bit幅 SRAM
- 16MB Flash
### 開発環境・言語
[SiPEED](https://www.sipeed.com/)が開発した RISC-V プロセッサ向け micropython 開発環境 [MaixPy](https://maixpy.sipeed.com/)を利用するのが簡単です。組み込み向けであり、NumPyなどは利用できませんが、最小限のコードで tiny YOLO v2 などが利用できるような API が[提供されています](https://bbs.sipeed.com/t/topic/683)。
# 動作のしくみ
 224x224ピクセルの画像に対して、MobileNet v1 を特徴抽出器として利用し、画像から得られた768次元の特徴ベクトルを K近傍法(k-Nearest Neighbor algorithm, k-NN)で分類しています。なお、今回は k=1 (最近傍法)としています。以下で簡単に説明していきます。
## 画像分類の大まかな仕組み
 深層学習を利用して画像に何が映っているかを判別(Classification)する仕組みは、おおむね下図のようになっています。
 入力された画像は特徴抽出層(主に畳み込み層)によって、位置や明るさや形などが多少変化しても近い値となるような低次元の画像特徴量に変換されます。今回の場合は 224x224x3(RGB)=150528次元の画像を768次元の画像特徴量に変換しています。さまざまな画像でうまく動作するような都合の良い特徴抽出層は簡単には作れないように思われますが、非常に大量の画像を利用して学習したものが多く公開されていますので、今回はそれを利用しています。 ![画像認識のしくみ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43450/a126f664-6d93-bb4f-60cb-0bc3bfb566f1.png)
 自分で独自の画像分類を行いたい場合、上記の特徴抽出器の部分は変更せずにそのまま使いまわし、特徴抽出器の出力を何らかの方法で分類することが良く行われています。このようにある領域(ドメイン)で学習したものを他に転用する技術を転移学習と呼びます。
 ニューラルネットワークのみで転移学習を行う場合は、上図のように特徴抽出器の上に全結合層などを追加し、追加した部分のみ学習を行うことが多いです。実際、M5Stackが提供している無料のモデル作成サービス [V-training](http://v-training.m5stack.com/) でも、識別したい種類の数(クラス数)に応じて、全結合層などを適宜追加し、その部分のみ再学習を行っています。この計算は、GPUなどが使えれば比較的短時間で行うことが可能ですが、M5StickV 単体で行うことは困難なので別な手を考えます。
## M5StickV上で転移学習
 左側に一般的に行われている機械学習の模式図を示します。●, ■, ▲が学習時の画像から得た特徴量です。それぞれをうまく分離でき、新しいデータがやってきてもきちんと分類できるようなできるだけもっともらしい境界線を引くことができれば、うまく学習したといえます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43450/457bdfdd-4650-e909-18c0-599945af1f59.png)
 このような境界線を引くのはなかなか大変なので、今回は、右側のようにあらかじめ学習した画像特徴量とカメラ画像から新たに得た画像特徴量との距離を計算し、最も近いものを探すという実装をしています。このような方法は[k近傍法](https://ja.wikipedia.org/wiki/K近傍法)のうち最近傍法と呼ばれています。
2つの特徴量ベクトル $\boldsymbol{a}$, $\boldsymbol{b}$ 間の距離 dist (単純にユークリッド距離を利用しました)を求めるのは簡単で、下記のようなコードになります。
```py
dist = 0
for i in range(768):
dist = dist + (a[i]-b[i])**2
```
 これをあらかじめ取得した画像特徴量の数だけ繰り返し、最も値が小さいものを探せばよいことになります。なお、ユークリッド距離をもとめるには、最後に平方根をとる必要がありますが、今回は距離の大小関係のみわかれば十分なので省略しています。
 さまざまな画像について上記の計算を行ってみると、今回の構成では dist < 200 とするとおおむね良く分類ができているようでした。一方全く異なるような対象を撮影しても dist は 500 程度とそれほど大きくは変化しません。
## 2枚の画像を使って量を求める
 2枚の類似した画像から得た特徴ベクトルもまたそれなりに似たものとなっているはずです。これを利用して、残量のようなものを測ることができます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">転移学習で対象までの距離のようなものが測れるような気がしたので試したらできた <a href="https://twitter.com/hashtag/M5StickV?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickV</a> <a href="https://t.co/Vedtk5gy0b">pic.twitter.com/Vedtk5gy0b</a></p>&mdash; ミクミンP/Kazuhiro Sasao (@ksasao) <a href="https://twitter.com/ksasao/status/1185909464471232512?ref_src=twsrc%5Etfw">October 20, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
-模式図で書くと以下のようになります。線形だと仮定し、図の $t$ を求めれば、$\boldsymbol{a}$ に一致するとき 0, $\boldsymbol{b}$ に一致するとき 1 となるような関数を作ることができます。この $t$ の求め方ですが、
+画像特徴ベクトル$\boldsymbol{a}$ に一致するとき 0, 特徴ベクトル$\boldsymbol{b}$ に一致するとき 1 となるような関数を考えます。カメラで撮影した画像より得た $\boldsymbol{p} $ は $\boldsymbol{a}$ と$\boldsymbol{b}$ を通る直線上にあるとは限らないので、$\boldsymbol{p}$ を含み、$\vec{ab}$ を法線ベクトルとするような平面を考えます。また、$\boldsymbol{a}$, $\boldsymbol{b}$ を通る直線とこの平面の交点を $\boldsymbol{x}$ と置きます。
+
+そうすると、図の $t$ を求めればよいことになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43450/006d3b31-be12-e176-e280-b28ff98e70a9.png)
-法線ベクトルを $\boldsymbol{u} = \boldsymbol{b}-\boldsymbol{a}$ とし、特徴ベクトル $\boldsymbol{p}$ を通る平面の方程式を考えると
+法線ベクトルを $\boldsymbol{u} = \boldsymbol{b}-\boldsymbol{a}$ とし、特徴ベクトル $\boldsymbol{p}$ を通る平面の方程式
```math
\sum_{k=0}^{767} u_k(x_k-p_k)=0 \cdots ①
```
一方、$\boldsymbol{a}$を通り、$\boldsymbol{u}$と平行な直線の方程式は、
```math
\begin{pmatrix}
x_0 \\
x_1 \\
\vdots \\
x_{767}
\end{pmatrix}
= t \begin{pmatrix}
u_0 \\
u_1 \\
\vdots \\
u_{767}
\end{pmatrix}
+
\begin{pmatrix}
a_0 \\
a_1 \\
\vdots \\
a_{767}
\end{pmatrix}
\cdots ②
```
②を①に代入して、$t$について整理すると、
```math
\sum_{k=0}^{767} u_k(t u_k+a_k-p_k)=0 \\
\Leftrightarrow
t\sum_{k=0}^{767} u_k^2 = \sum_{k=0}^{767} u_k(p_k-a_k) \\
\Leftrightarrow
t = \frac{\sum_{k=0}^{767} u_k(p_k-a_k)}{\sum_{k=0}^{767} u_k^2} \\
\Leftrightarrow
t = \frac{\sum_{k=0}^{767} (b_k-a_k)(p_k-a_k)}{\sum_{k=0}^{767} (b_k-a_k)^2} \\
```
となります。上記の動画のスレッドにも記載していますが、この方法で対象物までの距離をもとめたり、左右のどのあたりにいるかを求めたりといったことも可能です。なお、実際には線形とみなせないことも多いので、あくまで目安として使うとよいでしょう。
## 使いどころ
 今回の手法は、汎化性能はそれほど高くないものの、少ない教師画像(1枚から数枚)で動作するため気軽に利用することができます。例えば、[マグロとサーモンを区別](https://twitter.com/ksasao/status/1200707417132003328)したり、[素人を判別したり](https://twitter.com/ksasao/status/1201047666878119936)といったことが可能です。一目で見て簡単に区別できる程度の違いがあればおおむね動作すると期待できます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">マグロとサーモンの違いがわかる Brownie <a href="https://twitter.com/hashtag/NT%E6%9C%AD%E5%B9%8C?src=hash&amp;ref_src=twsrc%5Etfw">#NT札幌</a> <a href="https://twitter.com/hashtag/M5StickV?src=hash&amp;ref_src=twsrc%5Etfw">#M5StickV</a> <a href="https://t.co/F5j1iIgJcc">pic.twitter.com/F5j1iIgJcc</a></p>&mdash; ミクミンP/Kazuhiro Sasao (@ksasao) <a href="https://twitter.com/ksasao/status/1200707417132003328?ref_src=twsrc%5Etfw">November 30, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
現在人間が監視しているようなものを [Brownie](https://github.com/ksasao/brownie) で置き換えてみませんか?
## 関連資料
- <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/ksasao/20190928-m5stickv-tfug" title="20190928 M5StickVではじめる軽量モデルの実世界への応用 #TFUG" target="_blank">20190928 M5StickVではじめる軽量モデルの実世界への応用 #TFUG</a> </strong> from <strong><a href="https://www.slideshare.net/ksasao" target="_blank">Kazuhiro Sasao</a></strong> </div>