7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

M5Stack COM.X Sigfoxを用いた「人流エッジAI計測」

Last updated at Posted at 2021-02-17

M5Stack COM.X Sgifoxモジュールを用いたエッジAIの組み込み実装と,エッジAIによる画像処理結果をSigfoxでクラウドへ送信する仕組みのユースケース一例として,「人流エッジAI計測」を作ってみました。

【補足】ここで言うエッジAI
ここで言うエッジAIとは,一般にAIモデルがコンピュータリソースの豊富なクラウドサーバーにおいて実行されることが多いのに対して,現場で取得したデータのインプットをその場でタイムリーにAIモデルに与えて推論させ,取得したい特定の情報を得ることを意味しています。

#人流エッジAI計測
画像から人を検出する,ということを断続的に超短周期で実行し続けることで,カメラの前を通り過ぎる人の数をカウントします。
###ソリューションのポイントとメリット
デバイスを設置した現場で,エッジAIを用いて画像から人物の数の情報の取り出しを実行することにより…

  • データ量を削減し、必要なデータのみSigfoxで送信可能になる
  • プライバシーデータを送信することなく、集めたい必要なデータ収集が可能
  • アップロード先のストレージサーバ容量の削減が可能
  • AI推論専用の高価な解析サーバが不要に

これらのメリットが得られます。

#前提
Sigfoxについての前提理解は、下記サイトを確認してください。

#使用デバイス

デバイス 写真
M5Stack Gray image.png
UnitV AI Camera image.png
M5Stack用Sigfoxモジュール image.png

#処理概要
全体処理の流れは下記のようになります。
system.png

  1. UnitVのカメラが映像(画像)を取得する
  2. AIモデルが人を検出し移動人数をカウント,Grayに送る
  3. GrayがSig moduleを通じてカウント数をSig Cloudへ送信.同時に簡易的な画面表示
  4. Sig CloudからIot Agency Platformへ集計結果を送信,ダッシュボードを表示

#開発
AIモデル開発、エッジデバイス開発、デプロイの流れを記載します。
##AIモデル開発
YOLOv2をアーキテクチャとした検出モデルで,人物検出の学習を行います。
学習自体に特別なことはありませんが,最終的にエッジデバイス上で動かすkmodel形式にする必要がある為、

  • 軽量である
  • 変換可能なモデル(レイヤー)である

という制限が加わります。
これらの制限をクリアしてくれる学習環境としてaXeleRateを利用しました。

###AIモデル開発環境
Ubuntu16.04.5 LTS
###データセット
COCOデータセット2017から以下の絞り込みを行っています.

  1. personタグを持つ
  2. 画像の中に写っている人が2人まで

2人までにしている理由は,人数が多い画像に含まれる人物は非常に小さく映っているものが多く,今回の検出対象(カメラの前を通り過ぎる人)として不適当と判断したことによります。
最終的に絞られたトレーニングデータ35562枚,テストデータ1481枚で学習と評価を行っています。

###学習結果
テストデータに対するmAPの学習推移です。
mAPは物体検出タスクにおいて使われる評価指標で大きい程良い事を示します。
mAP.png

また,kmodelへの変換はaXeleRateが学習終了時に行ってくれています。
モデル自体はページ下部の付録にリンクを置いているので,自由に使って頂いて構いません。

変換処理を自分で行う場合の参考リンク
モデルの変換は,基本的にkeras(h5)→tflite→kmodelというステップで行われます。

##エッジデバイス開発
###UnitV
基本的に公式のクイックスタートに則って準備します。

ファームウェア(※後に自作モデルを動かす為に別のパッケージを焼くことになるので,動作確認目的以外では不要です)はEasyLoaderをダウンロードし焼きます。

IDEはMaixyPy IDEを使用しました。
コード全体はページ最下部の付録に載せています。
全体の大まかな流れは以下の通りです。

  1. UART, KPU, sensor系の初期化
  2. 画像の撮影
  3. モデルへの画像入力と検出情報の出力
  4. トラッカーへ検出情報の入力,前フレームとの差異情報の出力
  5. カウンタへ差異情報の入力,条件に応じてカウント情報を更新
  6. Grayへカウント情報と現フレームの検出数を送信,2.へ戻る
  7. kmodelのロード

ベースはaXeleRateのコードです.
####KPU初期化

init_kpu.py
def init_kpu(threshold=0.3):
  classes = ["person"]
  task = kpu.load(0x300000) #change to "/sd/name_of_the_model_file.kmodel" if loading from SD card
  a = kpu.set_outputs(task, 0, 7,7, 30)   #the actual shape needs to match the last layer shape of your model(before Reshape)
  anchor = (0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828)
  a = kpu.init_yolo2(task, threshold, 0.3, 5, anchor) #tweak the second parameter if you're getting too many false positives
  return task
`kpu.load()`
モデルの書き込まれてるアドレスを指定します(書き込みについては後述)。コメントにある通りSDカードを利用する場合はその保存パスに
`anchor`
モデル生成時に使用したアンカーボックスです。縦・横の繰り返しでボックスが記述されていて、ここには5つのアンカーボックスが書かれています。
`kpu.init_yolo2()`
引数は、kpuオブジェクト・検出の閾値(probability threshold)・絞り込みの閾値(nms threshold)・アンカーボックス数・アンカーボックスです。 第2引数が、コメントにあるように物体を検出したとみなすかどうかの閾値(確率値)になります。例えば0.3であれば,検出した区域の「物体らしさ」が0.3より小さければそれは破棄されます。 第3引数が、Non-Maximum Suprresion(nms)で使用するIoUの閾値(確率値)です。nmsを簡単に言うと、「同じクラスとして検出された候補群があった時、それらが示すものは一つの物体なのか複数の物体なのかをいい感じにまとめてor削ってくれるアルゴリズム」です。この閾が大きい程、一つの物体とみなされやすくなります.詳細はこちらの記事が非常に分かりやすく説明してくれています。
[参考ドキュメント](https://maixpy.sipeed.com/en/libs/Maix/kpu.html#kpu)

####UART制御

init_uart.py
def init_uart():
    fm.register(35, fm.fpioa.UART1_TX, force=True)
    fm.register(34, fm.fpioa.UART1_RX, force=True)
    uart = UART(UART.UART1, 115200,8,0,0, timeout=1000, read_buf_len=4096)
    return uart

参考ドキュメント

`fm.register()`
UnitVのuartで使用するピンは35と34番。
`UART()`
UARTオブジェクトの生成です.
トラッキング及びカウンタ
こちらは長いので,以下に図示しております。 ![algorithm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/b427b428-7713-fb0c-29c7-c98e32d915d3.png)

###M5Stack Gray(+COM.X)
M5 Stack Grayの開発環境としてArudinoがメジャーですが、micropythonを使用する為UIflowを使用します。
こちらもクイックスタートに則って準備します。

同じmicropythonベースですが、UnitVとモジュールが色々異なる点に注意が必要です(UnitV側はMaixpy: micropython to k210)
M5 Stack micropython
全体の大まかな流れは以下の通りです.

  1. UART、アイコン生成部の初期化
  2. UnitVからの信号を待つ
  3. 信号を受信したら,カウント数と検出数を画面に描画し,Sigfox通信
  4. 2に戻る
uart_m5stack.py
## UnitV
VTX, VRX = (22, 21)
## Sig
STX, SRX = (17, 16)

def uart_init():
  # Sigfox
  uart1 = UART(1, tx=STX, rx=SRX)
  uart1.init(9600, bits=8, parity=None, stop=1)
  
  # UnitV
  uart2 = UART(2, tx=VTX, rx=VRX)
  uart2.init(115200, bits=8, parity=None, stop=1)
  return uart1, uart2

##デプロイ
####UnitV
AI開発部分で作ったモデルを動かす為に,kfpkgパッケージを作成し焼いていきます。
参考:https://maixpy.sipeed.com/en/get_started/upgrade_firmware.html

flash_list.json
{
"version": "0.1.0",
"files": [
 {
   "address": 0x00000000,
   "bin": "maixpy_v0.5.0_42_g458ed4e_m5stickv.bin",
   "sha256Prefix": true
 },
 {
   "address": 0x00D00000,
   "bin": "m5stickv_resources.img",
   "sha256Prefix": false
 },
 {
   "address": 0x00300000,
   "bin": "my_model.kmodel",
   "sha256Prefix": false
 }
]
}
  • 4つのファイルをzipにまとめ,拡張子をkfpkgへと戻す

  • パッケージの書き込み
    参考:https://github.com/kendryte/kflash.py
    kflashをインストールしUnitVに書き込みます.筆者はAnaconda環境にインストールしました。

kflash.py
conda create -n kflash python=3.6
conda activate kflash
pip install kflash
kflash my_kfpkg.kfpkg
  • コードの書き込み
    IDE上のコードをブートコードとして書き込みます.

この時点で,電源を接続すると動くようになっています.(Grayに接続しないと動きは見えませんが..)

####M5Stack Gray
UnitV同様,IDEからコードを書きこみます。
※表示がダウンロード(誤訳?)になっていることに注意

この時点で,こちらも電源を接続すると動くようになっています。

#動作確認
####UnitV
検出の様子をIDEのデバッガで表示したものです。
「2人の人物が左からやってきて,立ち止まった後,右に抜けていく」というシナリオです。
image.png
矩形:人物検出領域
赤の数字:トラッカーによって振られたID
緑の数字:カウント
####M5Stack Gray(+COM.X)
動作画面です。
grayDemo.png
画面上部の緑の数字が人数を、それに合わせ人型のアイコンを表示しています。定期的に計測した人数をSigfox通信で送信しています。
####ダッシュボード
人流カウントをダッシュボードで確認する事ができます
sigBoard.png
ある展示会での人流を計測したもので、凡そ、どの時間帯で来場者が多いかが見て取れるかと思います。

#付録
それぞれのデバイスで使用したコードの全体とモデルを置いておきます。
https://github.com/kccsairc/Edge_AIoT

7
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?