フレクトのクラウドblog re:newal

http://blog.flect.co.jp/cloud/からさらに引っ越しています

HerokuでTensorFlowのAPIをホストした話

この記事は、Heroku Advent Calendar 201920日目の記事です。

19日目は@mttrsさんさんによる「Heroku Changelog 2019」でした。 21日目は@sizukutamagoさんです。

こんにちは、技術開発室の藤野です。 今回はHeroku上でTensorFlowの推論を行うWeb APIを作った話についてです。

はじめに

今回の話のあらましは、TensorFlowでディープラーニングのモデルを作ったので、Web APIとして使えるようにしたい、というものです。 APIはリクエストに対して推論結果を返すシンプルなもので、なるべく早く構築しデプロイや運用の手間は省きたいと思っていました。

これに対して、Herokuは下記の利点があります。

  • インフラ、ミドルウェアが用意されており、デプロイが容易
  • 運用のための仕組みがあらかじめ提供されている
  • CI/CDの機能を利用できる

一方で、ディープラーニングアルゴリズムGPU等を使って高速化することが一般的だと思います。 Herokuではこのようなアクセラレータは利用できず、CPUのみで推論処理を行うことになります。

そこで、今回はこのような推論処理を含むAPIをHeroku上で動かしたときのパフォーマンスはどのくらいなのか?を主眼に見ていきたいと思います。

作り物の構成

タスクとモデル

タスクは数十クラスの画像分類、フレームワークはTensorFlow1.14です。

モデルはMobileNet v1のPre-trained Modelから転移学習を行ったものです。 MobileNet V1はベンチマークによると、Desktop CPUで53ms/inferenceの速度が出ています。ひとまずこのくらい出ればOKとします。

(転移学習については、弊社の岡田が記事を書いているのでご覧ください。 Mobilenet v2とInception v4の転移学習

Bucketeerでのモデルファイルの保持

Herokuのアプリケーションはビルド時にSlugというパッケージにまとめられます。 これには500MBの上限があり、諸々のリソースを含めてこの中に収める必要があります。

devcenter.heroku.com

これに対して、TensorFlowで使用するモデルファイルのサイズはMB以上のオーダーになるため、直接Slug内に入れるのは望ましくありません。 また、一つのアプリケーションから複数モデルを使い分けたり、モデルのバージョニングを行うこともしばしばあります。

そのため、今回はAmazon S3バケットを利用できるHerokuアドオンのBucketeerでモデルファイルを保持するようにしました。

Web API

アプリケーションはPython+Gunicorn+Flaskで構築しました。

システム及びAPI構成は下図のとおりです。

API構成
API構成

リクエスト、レスポンスの流れは下記のとおりです。

  1. 推論対象画像のURLと、推論に使うモデルファイルをパラメータとしてリクエストする
  2. 推論対象画像および、モデルファイルを取得する
  3. 画像を推論する
  4. 推論結果を返す

(本筋から外れますが、画像ダウンロードのGET Request高速化のためにurllib3を使っています。)

要求されるDyno

Dynoの選定ですが、TensorFlowライブラリ+モデルをロードするため、かなりのメモリが必要になります。

今回のMobileNet V1の場合、メモリ使用量が少なくとも500MB以上必要だったため、Standard-2Xを使用しました。

下図はアプリケーション動作中の、メモリ使用量のメトリクスです。

動作中のメモリ使用量
動作中のメモリ使用量

パフォーマンス計測

下記の条件で計測を行いました。

  • Gunicornはワーカー1、スレッド2で動作
  • Herokuアプリケーションのリージョンはus
  • DynoはStandard-2X、2dynos
  • リクエスト元はEC2インスタンス(us-west-2)
  • 推論対象の画像はS3バケット(us-west-2)から取得

計測にはsiegeを使いました。

github.com

実行設定は下記のような感じで、クライアントを1から100まで増やしつつ60秒間送り続けるようにしました。

for i in `seq 1 100`; do
    siege -c $i -t 60s "https://xxxxxx.herokuapp.com/predict POST"
done

結果

計測結果は下図のとおりです。各値は平均値を取っています。

計測結果
計測結果

推論に関してはGPUなどが無いHeroku Dynoでも十分な速度が出ています。 先に書いたベンチマークの2倍の時間がかかっていますが、これはリクエストが集中した場合も合わせて平均しているためで、1クライアントの場合は60ms前後で推論できます。

まとめ

Heroku上でディープラーニングによる推論APIを構築し、パフォーマンスを計測しました。 推論結果を1s未満で返せるので、アプリケーション上で静止画を分類するなどの目的には十分足りていると思います。

一方で以下のような場合は、別途検証が必要になるかと思います。

  • より複雑なモデルを使いたい
  • 複数モデルを同時に使いたい
  • 動画のリアルタイム判定のような高頻度の推論を行いたい

複数モデルを使いたい場合は、恐らくメモリ使用量が大きくなるため、Dynoのアップグレードで対応できるかなと思います。

それでは。