R&Dセンター 技術開発部 古林 隆宏

TensorFlow+Keras入門 ~ ウチでもできた⁉ ディープラーニング ~

第4回 Java WebアプリでTensorFlow(検討編)

第4回はTensorFlowで作成した学習済みモデルの実際のシステムでの動かし方、もっと具体的にはJavaで書いたWebアプリからの利用方法について検討します。

TensorFlow, the TensorFlow logo and any related marks are trademarks of Google Inc.
この記事のTensorFlowロゴ画像を含む図は、CC-BY 3.0ライセンスのもと利用許諾されたTensorFlowロゴ画像の派生物です。

1) それ、Javaで動く?

第3回までの内容で、ディープラーニングをTensorFlowで実装することができました。
それを報告すると、あなたのボスは何と言うでしょうか?
あなたのボスがノリノリな人物であれば「よし、では早速それを例のシステムに取り込もう!」と言うかもしれません。
喜んで次の打ち合わせ日時を決めたあと、ボスは自席に戻るあなたを呼び止めてこう言います。

そうでした。「例のシステム」はJavaによるWebシステム。手元にあるのはPythonスクリプトです。
さて、どうしたものか・・・。

ディープラーニングを始めとする機械学習を行うときに最もよく使われる言語としては、2017年現在で言えばPythonということになるかと思います。
ひるがえって、学習済みモデルを利用する側はどうでしょう?これは一概には言えませんが、筆者が自席から周りを見渡すと、GUIならWebシステム、WebシステムならとりあえずJavaという雰囲気を感じます。

そこで今回は、Javaで書かれている既存アプリケーションに「AI機能」を組み込む、というなんだか他人事でなさそうな状況を想定し、ディープラーニングとアプリケーションの環境の違いを乗り越える方法について検討していきたいと思います。

選択肢1:JavaからPythonプロセスを起動する

もし既にディープラーニングをPythonで実装してしまっている場合、この選択肢を勧める悪魔のささやきが聞こえてくるでしょう。

実際考え方としては単純で、JavaからPythonプロセスを起動し、標準入出力やパイプを用いてデータをやりとりすれば良いわけです。
手元のPythonプログラムも最小限の改修で利用できますし、どのライブラリを利用していても使える方法ですから、試験的に動かしてみるぶんには悪くないかもしれません。

しかし本番環境への適用を視野に入れると、Pythonプロセスの管理のわずらわしさ(起動完了確認、異常終了時の対応等)、処理のスケーラビリティなど、一筋縄ではいかないことが多くなってきます。
先々苦労しそうな雰囲気を感じて突貫するか撤退するかはそれぞれの判断ですが、私であればこの方法を押し通したいとはあまり思いません。

選択肢2:あきらめてJavaで再実装する

アプリケーションにあわせてディープラーニング用ライブラリを再選定し、処理を再実装するというパターンです。
はじめから本番への適用を見据えたプロジェクトであれば、そもそもディープラーニングをはじめる前に、アプリケーションにあわせてライブラリを選定することもあるでしょう。

既にPythonで作ってしまっている場合、新たなライブラリの習得と今あるモデル再実装というコストはかかってしまいますが、アプリケーションと同じ環境で動くという利点は見過ごせないものがあります。
アプリケーションとの連携がとりやすくなりますし、ソースコードの管理と保守において、1つの言語だけを見ればよいので人員確保や育成が容易になることが期待できます。
(もちろん、その言語ができることとディープラーニングの保守ができることは別の問題ですが……まあ容易になることは間違いないということでこの場はご容赦願います)。

また新たなライブラリの習得コストについても、別のディープラーニングライブラリでの実装経験からある程度勘が働く可能性もあり、やってみたら案外簡単にできてしまうかも、という希望的観測もできます。
というのも、言語やライブラリが違うといえどディープラーニングで実装する内容は同じわけで、特にKerasやTensorFlowのLayes APIのような高レベルAPIでは、その実装方法もおのずと類似したものになる傾向があるからです。

ただし、やはり勇気がいる選択肢であることには間違いありません。
特に、現状でディープラーニング実装に有利なPython環境をあえて捨てることに大きな未練が残る方法です。

選択肢3:TensorFlow Java APIを併用する

復数の言語から利用できるライブラリの場合は、モデルの構築と学習はやりやすい言語で行い、利用はアプリケーションに合わせた言語で行うということが可能な場合があります。

TensorFlowはPythonのほかにJavaとC++からも利用できますので、Pythonで学習してJavaで利用するということが可能です。
TensorFlow以外には、AWSが肩入れしているMXNetはPythonやScalaをはじめとする6つの言語から、またMicrosoftによるCNTKはPythonとC#およびC++から利用できます。

ただし、TensorFlowのJava版はまた試験段階であり、今後もAPIに後方互換性のない変更が入る場合がある旨警告がなされています。
また最新の機能が常にJava APIに取り込まれるわけではなく、第3回のコードで使用しているEstimatorをはじめとする多くの機能がJavaからは利用できません。

これらの障壁をくぐり抜けてJavaから利用できるようにした場合、最後にメモリ消費の問題が残ります。
大規模な学習済みモデルは利用時にけっこうな量のメモリを消費するため、アプリケーションのメモリを圧迫してしまうことになりがちです。
そうなると、学習済みモデルとアプリケーションを分離して管理したい気持ちが高まってきて、次の選択肢が浮かびます。

選択肢4:学習済みモデルをサービス化して分離する

学習済みモデルを動かす部分をRESTやSOAP等を経由して呼び出せるサービスとして実装することで、アプリケーションから分離して管理できるようにするというアプローチです。

この方法の長所は以下の3点です:

  • ディープラーニングとアプリケーションをそれぞれ最適な言語環境で実装できる
  • 追加コストもそれほど多くない
    • 学習済みモデルの利用をサービス化する分のコスト
  • サービスの管理をアプリケーション部と分離できる
    • ソースコード管理、死活管理、メモリ管理など
    • アプリケーションと学習済みモデルを別のマシンで動かすことも可能

つまり、選択肢1~3それぞれの欠点を緩和した、バランスのとれた方式ということができます。

2) TensorFlow Servingを使おう!

TensorFlowを使っている場合は、選択肢4を実現するプロダクトとしてTensorFlow Servingというものが利用できます。
TensorFlow Servingは、TensorFlowの学習済みモデルを配置するとそれを動かすサーバとして動作してくれる製品です。ちょうどWebアプリにおけるTomcatのようなものといえばイメージしやすいかもしれません。

以下はTensorFlow Servingを用いてWebアプリから学習済みモデルを利用する場合の概念図です。

まずPython環境で学習を行い、それをTensorFlowのSavedModelという形式で書き出します。
そしてSavedModelを書き出したディレクトリを読み込むように指定してTensorFlow Servingのサーバを起動します。
SavedModelに変更があれば自動的に追従するので、先に起動しておいてあとは起動しっぱなしでも最新の学習済みモデルが動作します。
アプリケーションからTensorFlow Servingの呼び出しにはgRPCを用います。gRPCはその名の通りGoogleが開発したRPCの仕組みで、PythonやJavaをはじめ9つの言語に対応しています。

このように、ディープラーニングを組む部分、学習済みモデルを動かす部分、そしてそれを呼び出す部分をきれいに分離することができ、言語環境の違いやサービスのライフサイクルの違いを吸収することができます。

3) 学習済みモデル部分のスケーラビリティ

学習済みモデルを本番で動かすにあたり、言語の違い以外で気になるのがそのスケーラビリティです。
選択肢4の方法では学習済みモデルを動かす部分が疎結合となっているため、負荷が当初の想定より大きくなってきた場合にも、少ない手間で学習済みモデル部分のみをスケールアウトさせることが期待できます。

TensorFlow Servingはサーバのクラスタ化に対応していますので、このような状況にも対応がしやすいでしょう。
自前でクラスタを管理したくない場合は、Google Cloud Platformのサービスのひとつ、Cloud Machine Learning Engineを利用する手もあります。TensorFlowから書き出したSavedModel形式の学習済みモデルをアップロードすることで、Googleのクラウド上で動作させることができます。
またTensorFlow以外のライブラリを使っている場合にも、学習済みモデル部分がサービスとして切り出されていれば、アプリケーション部分の変更なしで(あるいは最小限の変更で)スケールアウトに対応できることが期待できます。

おわりに

既存のアプリケーションにディープラーニングを利用した「AI機能」を取り込む、というようなケースでは以下のような要求が存在します。

  • 学習済みモデルを利用する側のアプリケーションは、言語や環境を変更したくない
  • ディープラーニングはディープラーニングがやりやすい言語環境で組みたい
  • 本番利用のために必要な作業量はなるべくおさえたい
  • 将来的なスケールアウトの余地を確保したい
  • メモリや再起動のタイミング、動作させるマシンなど、アプリケーションとディープラーニングは分離して管理したい

これらの要求を満たす方式として、学習済みモデルを動かす部分をサービス化してアプリケーションと分離するというものがあります。
問題はどのようにサービス化するかということなのですが、TensorFlowを使っている場合にはTensorFlow Servingという製品が利用できるため、少ない作業量でサービス化が実現できるというメリットがあります。

次回は実際にTensorFlow Servingを利用して、連載第3回で作成した犬猫画像の分類モデルをJavaから利用できることを確認していきます。

1 2 3

4

5
PAGE TOP