Google Edge TPU画像分類器

Coralは、開発者がEdge TPUを使用してアプリケーションを構築するためのハードウェアおよびソフトウェアツールを提供します。Googleが設計した小型ASICで、低電力デバイス用の高性能機械学習（ML）推論を提供します。

![微信图片_20190718135827.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/6cff16b1-3b6a-b3ef-c4f2-651d315a726d.jpeg)

> 注：Google Edge TPUは日本で購入できます-代理店Gravitylink: https://store.gravitylink.com/global

TensorFlow™は、データフローグラフを使用した数値計算用のオープンソースソフトウェアライブラリです。 TensorFlowは、機械学習モデルを訓練し、それらのモデルを使用して迅速な意思決定ソフトウェアを必要とする現実世界の問題を解決するための一般的なフレームワークになりました。

##### 構築するもの
このコードラボでは、Edge TPU Python APIを使用して、カメラから画像フレームをストリーミングし、事前に訓練されたInception v2モデルに対してローカルに分類するデバイスを構築します。

##### 何を学ぶでしょう

gstreamerを使ってカメラから画像フレームをキャプチャする
Edge TPU Python APIを使用してML推論を実行する
Edge TPUアクセラレータのパフォーマンスを評価する

##### 必要なもの
コーラル開発ボード
コーラルカメラまたはUSBカメラ
Python 3.5
LinuxまたはmacOSワークステーション

![微信图片_20190404110322_副本.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/cd857f92-cd7c-ad6d-aaad-b3df01f4d371.jpeg)

> **開発ボード** 

##入門

####OSをフラッシュする
ボードが新品の場合は、メンデルシステムイメージを使ってフラッシュする必要があります。

####周辺機器を接続する

USBカメラをUSB-Aホストポートに接続するか、または以下の手順に従ってCSIカメラモジュールを接続します。

####デバイスシェルに接続する

- 2-3A電源ケーブルをPWRというラベルの付いたUSB-Cポートに差し込みます。
- USB-Cケーブルを使用して、ワークステーションをOTGというラベルの付いたUSB-Cデータポートに接続します。
- HDMIポートを外部ディスプレイに接続します
- ワークステーションにMendel開発ツールをインストールします:

```console
$ pip3 install --user mendel-development-tool
```
- 使用しているワークステーションがmdtを使用しているデバイスを認識できることを確認します:

```console
$ mdt devices
device-name                (192.168.100.2)
```
##スタータープロジェクトを入手する

GitHubリポジトリはコマンドラインからクローンできます:

```console
$ git clone https://github.com/googlecodelabs/edgetpu-classifier
```

> codelabの各ステップに対する解決策は、フォルダごとにまとめられています:
  - classifier-start  - 初期プロジェクト
  - classifier-end - 最終解

#### プロジェクトについて
スタータープロジェクトには以下が含まれます:

- カメラフレームをキャプチャして表示するための初期スクリプト（`main.py`）
- 事前学習済みのInception v2画像分類モデルとラベルファイル（`models /` の下）
- カメラから画像をキャプチャして表示するためのコードを含むライブラリモジュール（`lib /`の下）


スタータープロジェクトの`lib.gstreamer`モジュールは、`gstreamer`に基づいて次のパイプラインを作成します:

![微信截图_20190724163918.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/2f001496-822f-6a36-a321-70d539ba10b0.png)

パイプラインの大部分は内部で処理されますが、`Image Processing`ステップはメインスクリプト内で公開されているコールバック関数（`frame_callback`）をトリガーします。

####スタータープロジェクトをデプロイして実行する
`classifier-start`ディレクトリに移動します。 スタータースクリプトとモデルファイルをデバイスにプッシュします:

```console
$ cd classifier-start/
$ mdt exec mkdir /home/mendel/lib
$ mdt push lib/* /home/mendel/lib

$ mdt push models/* /home/mendel
$ mdt push main.py /home/mendel
...
```
2番目の端末ウィンドウを開き、デバイスシェルに接続して、ファイルがすべて存在することを確認します:

```console
$ mdt shell
...
mendel@device-name:~$ ls
imagenet_labels.txt  inception_v2_224_quant.tflite  lib  main.py
```
提供されているモデルとラベルファイルを使用して、デバイスシェルウィンドウでスタータースクリプトを実行します:

```console
mendel@device-name:~$ python3 main.py \
  --model=inception_v2_224_quant.tflite \
  --labels=imagenet_labels.txt
```
####USBカメラを使う
メインスクリプトはデフォルトでCSIを介して接続されたCoralカメラを入力用にします。 USBカメラを使用している場合は、次の手順に従ってカメラに使用する適切な入力ソース、解像度、およびフレームレートを決定してください。 次のようにこれらの値をスクリプトに渡します：

```console
mendel@device-name:~$ python3 main.py \
  --source=/dev/video1 \
  --resolution=1280x720 \
  --frames=30 \
  --model=inception_v2_224_quant.tflite \
  --labels=imagenet_labels.txt
```

####スタータープロジェクトを確認する
接続されているHDMIディスプレイにライブカメラのプレビューが表示され、カメラのパイプラインが正しく設定されていることを示しますが、TensorFlow Liteモデルは実際にはまだ実行されていません。 次のステップでは、Edge TPU Python APIを使用してカメラからの各画像を分類するためのコードを追加します。

##実行画像分類
私たちの現在のスタータープロジェクトは、画像が表示される前に画像を処理していません（`classify_image（）`関数は現在何もしません。 このセクションでは、`Edge TPU Python API`を使用して`ClassificationEngine`をインスタンス化し、それを使用して各フレームで推論を実行します。

#### 推論エンジンを作成する
`main.py`スクリプトは、引数として提供されたモデルファイルを`init_engine（）`関数に渡します。 この関数を見つけて、そのモデルに基づいて`ClassificationEngine`を返します。

```main.py
from edgetpu.classification.engine import ClassificationEngine

def init_engine(model):
    """Returns an Edge TPU classifier for the model"""
    return ClassificationEngine(model)
```

入力テンソル形状を決定する
`gstreamer`パイプラインの`Image Resize`ステージは、与えられたイメージを分類モデルで必要とされる入力寸法と一致するようにスケーリングします。 あなたは単にそれらの必要な寸法が何であるかを指定する必要があります。

`get_input_tensor_shape（）`メソッドは、モデルの予想されるテンソル形状を`[dimensions、height、width、channels]`の形式で返します。 これを使用して`input_size（）`関数を実装し、必要な画像サイズを返します。 次に、この`input_size（）`関数がメインスクリプトによって呼び出されて、必要な画像の拡大縮小寸法をgstreamerパイプラインに渡します。

```main.py
def input_size(engine):
    """Returns the required input size for the model"""
    _, h, w, _ = engine.get_input_tensor_shape()
    return w, h
```
####推論をプロファイルする
パフォーマンスを評価するためには、各フレームの処理にかかる時間を知る必要があります。 最後の推論実行についてこの値を報告するには、`inference_time`関数を実装します。 `ClassificationEngine` は、`get_inference_time（）`メソッドによる最後の推論に要した時間を提供します。

```main.py
def inference_time(engine):
    """Returns the time taken to run inference"""
    return engine.get_inference_time()
```
#### 画像を分類する
これで`classify_image`を実装することができます。 `gstreamer`パイプラインは、このコールバックを（`frame_callback`メソッドを介して）呼び出して、サイズ変更された各画像フレームを平坦化された1-Dテンソルとして配信します。 `ClassificationEngine`の`ClassifyWithInputTensor（）`メソッドを使用して画像フレームを処理します。 入力テンソルに加えて、次のパラメータが必要です。

- threshold→結果にラベルを返すための最小信頼スコア
- top_k→最高スコアに基づく、返される結果の最大数

エンジンは結果のリストを返します。それぞれが2つの値（ラベルインデックスと信頼性スコア（画像が各ラベルにどれだけ一致したか））を持つタプルとして返されます。 モデルに付属のテキストファイルを使用して、インデックスを実際のラベルに再マップします。

```main.py
def classify_image(tensor, engine, labels):
    """Runs inference on the provided input tensor and
    returns an overlay to display the inference results
    """
    results = engine.ClassifyWithInputTensor(
        tensor, threshold=0.1, top_k=3)
    return [(labels[i], score) for i, score in results]
```
>分類ラベル
画像分類モデルのトレーニングプロセス中に、付随するテキストファイルが、使用されるデータセットの画像ラベル（クラスまたはカテゴリ）に対して生成されます。 各ラベルにはインデックスが付けられています。インデックスは、分類中にモデルによって報告された値です（文字列ではありません）。
以下は、このコードラボで使用されているImageNetラベルファイルの抜粋です:
0 background
1 tench, Tinca tinca
2 goldfish, Carassius auratus
3 great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias
4 tiger shark, Galeocerdo cuvieri
5 hammerhead, hammerhead shark


#### 結果を確認する
更新したスクリプトをデバイスに展開します:

```console
$ mdt push main.py /home/mendel
```
デバイスシェル端末ウィンドウからスクリプトをもう一度実行します:

```console
mendel@device-name:~$ python3 main.py \
  --model=inception_v2_224_quant.tflite \
  --labels=imagenet_labels.txt
```
>重要：USBカメラを使用している場合は、カメラパラメータをコマンドラインに追加することを忘れないでください。

カメラのプレビューの上に推論結果が重ねて表示されます。 デバイスのカメラをさまざまなオブジェクトに向けて、推論結果が自動的に更新されるのを確認してください。

![3852a24c3ec52538.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/b5f4e11e-721c-12c9-ceca-178115c63645.jpeg)

>ヒント：写真を拡大してキャプチャしやすくするには、新しいタブで画像を開きます。 カメラを画像に十分近づけて、フレーム全体を埋めます。

次のような予想される出力結果が表示されることを確認します:

```
Inference time: 655.08 ms (1.53 fps)                goldfish, Carassius auratus (0.96)
```

#### パフォーマンスを向上させる
現時点では、モデル推論は現在デバイスのCPU上で完全に実行されています。これは、これらの推論操作に最適化されておらず、ワークロードをシステムの他の部分と共有しています。 次のセクションでは、Edge TPUがパフォーマンスの向上にどのように役立つかを説明します。

### Edge TPUで加速する
それでは、モデル推論を加速するために専用のEdge TPUチップを使用してパフォーマンスを向上させる方法を見てみましょう。 必要なのは、Tensorflow Liteモデルを再コンパイルすることだけです。 このプロセスは、CPUに限定された推論操作をEdge TPUでサポートされているものと置き換えます。

>重要：Edge TPUコンパイラは、すべてのモデルアーキテクチャと推論タイプをサポートするわけではありません。

#### Edge TPU用にモデルをコンパイルする
Coralサイトの`Edge TPU Model Compiler`に移動し、条件に同意して、プロジェクトから`models / inception_v2_224_quant.tflite`ファイルをアップロードします。


プロセスが完了したら、コンパイル結果を確認してください。 このレポートは、Edge TPU用にモデルのどれだけが正常にコンパイルされたか、および操作がCPUにフォールバックするかどうかを示します。 私たちのモデルはEdge TPUで100％動作するはずです。

![微信截图_20190725111912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/ef634263-a87e-1846-58cb-aed9afaba341.png)

「モデルのダウンロード」をクリックして、結果のファイルをプロジェクトディレクトリに`inception_v2_224_quant_edgetpu.tflite`として保存します。

#### 新しいモデルをテストする
新しいモデルファイルをデバイスに展開します:

```console
$ mdt push inception_v2_224_quant_edgetpu.tflite /home/mendel
```
デバイスシェルのターミナルウィンドウから`main.py`をもう一度実行します。ただし、Edge TPUファイルを`--model`引数として使用します:

```console
mendel@device-name:~$ python3 main.py \
  --model=inception_v2_224_quant_edgetpu.tflite \
  --labels=imagenet_labels.txt
```
>重要：USBカメラを使用している場合は、カメラパラメータをコマンドラインに追加することを忘れないでください。

推論時間が以前の10倍以上に減少したことに注目してください。 モデル推論はパフォーマンスのボトルネックではなくなり、カメラのフレームレートに簡単についていくことができます。

>注：この時点で、オーバーレイによって報告されたFPS値は、カメラが実際にフレームを報告しているよりも速くなりました。 この値は、推論時間に基づくモデルの理論上の処理能力を表します。

#### 使い方
Edge TPUアクセラレーションを有効にするためにコードを変更していないことに注意してください - このプロセスは、使用するモデルによって管理されています。 `Edge TPU Model Compiler`はモデルグラフ内のノードを処理し、サポートされている操作をEdge TPUランタイムによって認識される新しいカスタム操作に変換します。 推論中に、ランタイムは個々の操作がEdge TPUまたはCPUのどちらで実行されるかを決定します。

アクセラレーションを活用するために、モデルがEdge TPUでサポートされている操作で完全に構成されている必要はありません。 サポートされていない操作が発生するモデルグラフの最初の点で、コンパイラはグラフを2つの部分に分割します。 サポートされている操作のみを含むグラフの最初の部分はEdge TPU上で実行され、その他の部分はすべてCPU上で実行されます。

分類結果がまだ有効であることを確認するために、前の手順で使用したのと同じオブジェクトにデバイスカメラを向けます。

おめでとうございます。 これで、Inception v2モデルとEdge TPUアクセラレータを使用して、リアルタイムで画像を分類するアプリケーションを構築できました。