SageMakerのBuilt-inアルゴリズムを使ったエッジ推論

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、小澤です。

先日のDevlopers.IO 2018にて、無人店舗 横田deGoの横でひっそりと商品の物体認識(無人レジなどの仕組みとして想定)のデモを行なっていました。

どんなことができるかについてはすでにいくつか記事が上がっているので、そちらをご参照ください。

エッジ推論とエンドポイント

さて、このデモでは推論を行う際にJetson TX2を利用してエッジ推論を行なっています。 そのため、従来通りエンドポイントへREST APIでアクセスしてといった使い方ができません。

SageMakerでは、学習結果のモデルはS3に出力されます。 MXNet, Tesorflow, Chainerなどのオープソースライブラリを使ったり独自の学習ロジックを組み込んだライブラリを利用したりといったことが可能です。 この仕組みを利用すると、S3のモデルのみを利用してエンドポイントに相当するものは独自に実装するという使い方も可能です。

Built-inアルゴリズムをエッジ推論で使うには

上記のような仕組みであれば、どのようなライブラリを使って読み込むことが可能なモデルが生成されるかまで制御することが可能です。 しかし、今回の商品検出ではBuilt-inアルゴリズムのObject Detectionを利用しています。

この場合、どうやって出力されたモデルを使ってエッジ推論を行えばいいのでしょうか? 実は答えは簡単です。 出力されたモデルはtar.gzで固められてS3上に置かれてます。 これを展開すると以下のような3つのファルが含まれていることがわかります。

  • hyperparams.json
  • model_algo_1-0000.params
  • model_algo_1-symbol.json

これはMXNetが出力するモデルのファイルと同じ形式になっているようです。 そのため、MXNetがインストールされた環境であればPythonのプログラムなどを使って推論部分を記述してやればいいことになります。

※ Built-inアルゴリズムの実装に関しては公開されていません。そのため、出力されるモデルはMXNetで読み込み可能ですが、学習の処理がMXNetで実装されているとは限りませんのでご注意ください。

実装内容について

実装に関しては、MXNetのモデルを読み込んで推論するのみです。 簡単なサンプルとしては、以下のようになります。 なお、私があまりMXNetについて詳しくないので正確にはそうじゃない!とかもっと効率いい方法がある!とかのご意見はあるかもしれません(^^;)

import mxnet as mx
import numpy as np

# Built-inアルゴリズムで利用している画像サイズ
size_x = 512 
size_y = 512 

category_size = <検出対象となる物体の数>

model_path = '</path/to/mxnet/model>'

data_shapes = [('data', (1, 3, size_x, size_y))]
label_shapes = [('label', (1, category_size, category_size))]

# モデルの読み込み
sym, args, auxs = mx.model.load_checkpoint(model_path, 0)
mod = mx.mod.Module(sym, label_names=['label'], context=mx.gpu()) # Jetson TX2ではGPUが利用可能なのでcontextにmx.gpu()を指定
mod.bind(data_shapes=data_shapes, label_shapes=label_shapes, for_training=False)
mod.set_params(args, auxs)

# 検出対象となる物体のラベルリストを所定の形に合わせて作成
label = np.arange(category_size, dtype=np.float32)
label = np.resize(label, (1, category_size, category_size))

img = ... # 推論対象となる画像を読み込み

# MXNetのDataBatch型で推論対象となるデータを指定して推論処理を実行
batch = mx.io.DataBatch([mx.nd.array(img, mx.gpu())], label=[mx.nd.array(label, mx.gpu())])
mod.forward(batch)
result = mod.get_outputs()[3].asnumpy()

# 画像中で検出された物体の以下の値が取得される
#  - 検出された物体に対応するラベル
#  - 確信度
#  - 矩形領域のそれぞれ左上、右下のx,y座標
# 
# これらが検出された物体の数だけ取得できるのでループで順に処理していく
for i in result[0]:
        class_label = i[0] 
        score = i[1]
        # 領域は0-1で返ってくるので画像のサイズに合わせる
        x_min = int(i[2] * size_x)
        y_min = int(i[3] * size_y)
        x_max = int(i[4] * size_x) 
        y_max = int(i[5] * size_x)
        
        ... # ここで必要な処理を行う

画像の取得や検出された物体のラベル名、矩形領域を画像に重ねると言った処理は別途OpenCVなどを使って行う必要がありますが、推論部分に関してこういった感じになります。

おわりに

今回は、エッジ推論をユースケースとして、Built-inアルゴリズムをエンドポントを使わずに推論に使う方法を紹介しました。 SageMakerとGreengrassを使ってエッジ推論させるドキュメントを見るとMXNetやTensorflowに対応しているって書いてあるけどBuilt-inアルゴリズムはどうするんだ?とか、MXNet使ったことないからわからねぇ!とか、泣きそうになる場面も何度かありましたが、当日デモを見ていただいた方はわかる通りなんとか動くところまで持っていくことができましたw

MXNetの知識さえあれば比較的難しいことなくできる仕組みになっているので気になった方はぜひお試しください。