複数のEdge TPUで複数のモデルを実行する

Edge TPUには、モデルのパラメーターデータをローカルに保存するために使用される少量のRAMが含まれており、外部メモリからデータを取得する場合と比較して、より高速な推論速度を実現します。 通常、2つ目のモデルを実行するにはRAM内のモデルのパラメーターデータを交換する必要があるため、パイプライン全体が遅くなるため、Edge TPUごとに1つのモデルのみを実行する場合にパフォーマンスが最高になります。 このページで説明するように、1つの解決策は、異なるEdge TPUで各モデルを単純に実行することです。

または、モデルを同時コンパイルすることにより、パラメーターデータのスワップのオーバーヘッドコストを削減できます。 同時コンパイルにより、Edge TPUは複数のモデルのパラメーターデータをRAMに一緒に格納できます。つまり、通常、小さなモデルでのみうまく機能します。 このオプションの詳細については、パラメーターデータのキャッシュと同時コンパイルについてお読みください。 それ以外の場合、複数のEdge TPUに複数のモデルを配布する場合は、ここで読み続けてください。

#### パフォーマンスに関する考慮事項
システムにさらにEdge TPUを追加する前に、次のパフォーマンスの問題を検討してください:

- Pythonは、CPUに制限された操作の実際のマルチスレッドをサポートしていません（Pythonグローバルインタープリターロック（GIL）について読んでください）。 ただし、Edge TPU Python API（TensorFlow Lite Python APIは除く）を最適化し、すべてのEdge TPU操作に対してPythonのマルチスレッド環境内で動作するようにしました。これらはIOに制限されており、パフォーマンスが向上します。 ただし、複数のモデルを実行する場合、これらの操作はPythonでマルチスレッド化できないため、イメージのダウンスケーリングなどのCPUに制限された操作は、おそらくパフォーマンスに影響することに注意してください。

- 複数のUSBアクセラレータを使用する場合、特に大規模モデルを実行している場合、ホストUSBバスの速度によって最終的に推論速度がボトルネックになります。

- USBハブを介して複数のUSBアクセラレータを接続する場合、各USBポートがデフォルトの動作周波数を使用する場合は少なくとも500mA、最大周波数を使用する場合は900mAを提供できることを確認してください（USBアクセラレータのパフォーマンス設定を参照）。 そうしないと、デバイスが適切に機能するのに十分な電力を消費できない可能性があります。

- 外部USBハブを使用する場合は、USBアクセラレーターをプライマリポートのみに接続してください。 一部のUSBハブには、互換性のないセカンダリポートを備えたサブハブが含まれています。APIはこれらのポートでEdge TPUコンテキストを確立できません。 たとえば、`lsusb -t`と入力すると、次のようにポートが印刷されます。 最初の2つのUSBポート（`usbfs`）は正常に機能しますが、最後の1つは機能しません。

```
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/7p, 5000M
| Port 3: Dev 36, If 0, Class=Hub, Driver=hub/4p, 5000M
    | Port 1: Dev 51, If 0, Class=Vendor Specific Class, Driver=usbfs, 5000M  # WORKS
    | Port 2: Dev 40, If 0, Class=Hub, Driver=hub/4p, 5000M
        | Port 1: Dev 41, If 0, Class=Vendor Specific Class, Driver=usbfs, 5000M  # WORKS
        |__ Port 2: Dev 39, If 0, Class=Vendor Specific Class, Driver=usbfs, 5000M  # DOESN'T WORK
```

### TensorFlow Lite Python APIを使用する
TensorFlow Lite Python APIを使用して推論を実行し、複数のEdge TPUがある場合、`load_delegate（）`関数を使用して各 `Interpreter`が使用するEdge TPUを指定できます。

`load_delegate（）`に1つのエントリ``device``を持つ辞書を渡すだけで、使用するEdge TPUデバイスを指定できます。 受け入れられる値は次のいずれかです:

- `usb`：デフォルトのUSB接続Edge TPUを使用します。
- `sb：<index>`：列挙されたデバイスインデックスによって示されるUSB接続のEdge TPUを使用します。
- `pci`：デフォルトのPCIe接続エッジTPUを使用します。
- `pci：<index>`：列挙されたデバイスインデックスによって示されるPCIe接続のEdge TPUを使用します。

```
interpreter_1 = Interpreter(model_1_path,
  experimental_delegates=[load_delegate('libedgetpu.so.1.0', {"device": "usb:0"})])

interpreter_2 = Interpreter(model_2_path,
  experimental_delegates=[load_delegate('libedgetpu.so.1.0', {"device": "usb:1"})])
```
この方法で個別のEdge TPUを指定しない場合、両方のモデルが同じEdge TPUで実行されます。これは、上記の概要で説明したように低速です。

###TensorFlow Lite C ++ APIを使用する

TensorFlow Lite C ++ APIを使用して推論を実行し、複数のEdge TPUがある場合、`EdgeTpuManager :: OpenDevice（）` を介して`EdgeTpuContext`を作成するときに各`Interpreter` が使用するEdge TPUを指定できます。

`OpenDevice（）`メソッドには`device_type`のパラメーターが含まれており、次の2つの値のいずれかを受け入れます。

- `DeviceType.kApexUsb`：デフォルトのUSB接続Edge TPUを使用します。

- `DeviceType.kApexPci`：デフォルトのPCIe接続Edge TPUを使用します。

たとえば、2つのUSBアクセラレータが接続されている場合、次のようにそれぞれがUSBアクセラレータの1つを使用する2つのインタープリターを指定する必要があります。

同じタイプの複数のEdge TPUがある場合、2番目のパラメーター `device_path` を指定する必要があります。 使用可能な各Edge TPUの特定のデバイスパスを取得するには、`EdgeTpuManager.EnumerateEdgeTpu（）`を呼び出します。

この方法で個別のEdge TPUを指定しない場合、両方のモデルが同じEdge TPUで実行されます。これは、上記の概要で説明したように低速です。

例については、`two_models_two_tpus_threaded.cc` を参照してください。

`edgetpu.h` のAPIの詳細も参照してください。

### Edge TPU Python APIを使用する
Edge TPU Python APIを使用して推論を実行しており、複数のEdge TPUがある場合、Edge TPU APIは各推論エンジン（`ClassificationEngineやDetectionEngine`など）を異なるEdge TPUに自動的に割り当てます。 したがって、上記のTensorFlow Lite APIとは異なり、同じ数の推論エンジンとEdge TPUがあれば、余分なコードを書く必要はありません。

たとえば、2つのEdge TPUと2つのモデルがある場合、通常どおり推論エンジンを作成するだけで、別々のEdge TPUで各モデルを実行できます:

```
# Each engine is automatically assigned to a different Edge TPU
engine_a = ClassificationEngine(classification_model)
engine_b = DetectionEngine(detection_model)
```

その後、それらは別々のEdge TPUで自動的に実行されます。

Edge TPUが1つだけの場合、このコードは引き続き機能し、両方が同じEdge TPUを使用します。

ただし、複数のEdge TPU（N）があり、N + 1（またはそれ以上）モデルがある場合は、追加の推論エンジンごとに使用するEdge TPUを指定する必要があります。 そうしないと、エンジンがEdge TPUデバイスにマップされないというエラーが表示されます。

たとえば、2つのEdge TPUと3つのモデルがある場合、3番目のエンジンを他の1つと同じEdge TPUで実行するように設定する必要があります（どちらを決定するか）。 次のコードは、`device_path` 引数を`engine_b` で使用されるものと同じデバイスに指定することにより、`engine_c`でこれを行う方法を示しています。

```
# The second engine is purposely assigned to the same Edge TPU as the first
engine_a = ClassificationEngine(classification_model)
engine_b = DetectionEngine(detection_model)
engine_c = DetectionEngine(other_detection_model, engine_b.device_path())
```
`ListEdgeTpuPaths（）`から利用可能なEdge TPUデバイスパスのリストを取得することもできます。

サンプルコードについては、`two_models_inference.py` を参照してください。

> 注：USBで接続されたすべてのEdge TPUは同等に扱われます。 モデルを配布する際に優先順位付けはありません。 ただし、USBアクセラレータを開発ボードに接続すると、システムは常にUSBデバイスを使用する前にオンボード（PCIe）エッジTPUを優先します。

#####続きを読む

**[Coral Dev Board](https://store.gravitylink.com/global/product/DevBoard)** は、小さなフォームファクターで高速機械学習（ML）推論を実行する必要がある場合に理想的なシングルボードコンピューターです。 Dev Boardを使用して組み込みシステムのプロトタイプを作成し、オンボードCoral System-on-Module（SoM）をカスタムPCBハードウェアと組み合わせて実稼働環境に拡張できます。

**[Coral USB Accelerator](https://store.gravitylink.com/global/product/UsbAccelerator)** は、システムにEdge TPUコプロセッサーを追加するUSBデバイスです。 USBソケットが含まれているため、任意のLinuxベースのシステムに接続して、加速ML推論を実行できます。

![微信截图_20190904150555.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448511/cd6cd914-8a8c-a24c-be60-0ac44b828b82.png)

- Google Coral Edge TPU代理店Gravitylink! https://store.gravitylink.com/global

オンボードのEdge TPUは、Googleが設計した小さなASICであり、低電力コストで高性能なML推論を提供します。 たとえば、MobileNet v2などの最先端のモバイルビジョンモデルを400 FPSで電力効率の高い方法で実行できます。