月別アーカイブ: 2019年3月

決定木アンサンブルモデルのデプロイを容易にするライブラリtreeliteの紹介(2)

技術開発部の安井です。前回に引き続き、treeliteの紹介をしたいと思います。今回はtreeliteの予測速度について検証しようと思います。ドキュメント上では2~6倍のスループットが出ると書かれています。この点に関して実際にpython上とgolang上の2つの言語環境で検証しようと思います。

使用データと学習について

今回予測速度を検証する際に使用するデータはAvazuのclick予測のデータセットを使用します。全データ使用すると学習に時間がかかるので、300万件のデータのみを使用して学習を行います。Avazuのデータセットは変数がすべてカテゴリカル変数になっています。今回はこれらの変数をFeeatureHasherを使用して特徴量に変換します。今回FeatureHasherを使用する理由は後述します。FeatureHasherの次元数として今回は16、64、256次元でそれぞれ検証を行います。学習には前回に引き続きLightGBMを使用し、num_boost_roundを100で設定します。これで弱学習器として決定木が100本生成されることになります。学習するときに使用したコードを以下に記述します。

pythonでの予測速度比較

まずはじめにpythonでの予測速度の比較を行います。 予測速度は以下の3パターンのデータ量で比較を行います。

  • instance: 1件
  • batch: 1,000件
  • big batch: 1,000,000件

予測速度は複数回予測したときの平均時間を記載しています。

16次元の場合

16次元の場合、treeliteの方がおおよそ1/2~1/3の時間で予測ができており、概ねドキュメントの記載の通りであることが見受けられます。

64次元の場合

64次元の場合、バッチ予測の場合は16次元と同様にtreeliteの方がおおよそ1/2~1/3の時間で予測ができています。 しかし、instance予測の場合lightgbmとtreeliteの予測速度はそこまで差がないように見受けられます。

256次元の場合

256次元の場合、バッチ予測の場合はtreeliteの方が1/3~1/4の時間で予測ができており、treeliteの効果が最も出ていると考えられます。 対象的に、instance予測の場合はtreeliteの方が予測に3倍の時間がかがっていることがわかります。

まとめ

バッチ予測の場合は概ね期待している効果が出ていますが、インスタンス予測の場合は予測する特徴量のサイズが増えるほどの効果が出ないばかりか、 悪化する場合も存在します。これに関してはtreelite側のメソッドがバッチ予測の場合とインスタンス予測の場合で異なることが原因として考えられます。

  • バッチ予測: treelite.Predictor.predict(batch, verbose=False, pred_margin=False)
  • インスタンス予測: treelite.Predictor.predict_instance(inst, missing=None, pred_margin=False)

この2つの違いに関してですが、batchの方はtreelite側で処理をしやすいようなデータ型を期待していますが、instの方ではnumpy.ndarrayやscipy.sparse.csr_matrix等のarray objectを期待しています。この差により予測速度に差が出ているのではないかと想像していますが、詳しくは引き続き調査を続けていきたいと思います。

golangでの予測速度比較

golangでの予測速度比較にはtreeliteで生成したモデルコードの予測と以下のGBDT予測ライブラリの予測での速度比較を行います。

このライブラリはXGBboost/LightGBm/scikit-learnで学習したGBDTのモデルをロードしてgolang上で予測を行えるようにしたライブラリです。 こちらはインスタンス予測のみを比較することとします。 以下がgolanで測定したベンチマークの結果です。

BenchmarkPredictTreelite-8がtreeliteで予測した場合のベンチマークで、BenchmarkPredictLeaves-8がleavesで予測した場合のベンチマークです。 treeliteの予測モデルのほうが1/4~1/6の時間で予測が行えれていることがわかります。 これを見ると動的にロードしたleavesの予測モデルより、はじめに実行バイナリに組みこんでおいたtreeliteの予測モデルのほうがパフォーマンスが良いことが わかります。

treelite使用上の注意

冒頭でも述べましたが今回はカテゴリカル変数をFeatureHasherを使用して学習するときに使用する特徴量を作成しました。 しかし、LightGBMではカテゴリカル変数をそのまま特徴量として入力することができるようになっています。(厳密にはint型のidへの変換は必要) 今回カテゴリカル変数をそのまま学習に用いなかった理由としてはLightGBMでカテゴリカル変数を使用して学習を行うとtreeliteの予測結果と異なってしまうという事象が発生したためです。 しかし、現在では以下のissueによってこの問題も解決されたようです。

https://github.com/dmlc/treelite/issues/77

実際手元の環境でカテゴリカル変数を用いた場合でもLightGBMの予測モデルとtreeliteの予測モデルの結果が一致することを確認しました。 古いバージョンのtreeliteを使用する場合はご注意ください。

さいごに

今回はtreeliteの予測速度性能に関してpython, golang上で比較を行いました。 golangでの予測、pythonでのバッチ予測に関してはスピードアップしていることが確認できました。 最近は予測に特化したライブラリが他にも出てきているので実環境に組み込むといった観点でこういった予測に特化したライブラリもチェックしていきたいと思います。

ClassicLinkを使用してVPCとEC2-Classic間の相互通信を行う

こんにちは。技術開発部部長の川住です。

弊社DSP「Bypass」はシステムをAWSに移行してから5年以上が経過しました。近年ではEC2インスタンスをVPC (Virtual Private Cloud) 内に作成し運用していますが、AWSへの移行当初にVPC外(EC2-Classic)に作成したサーバがいくつか現在も稼働しており、「VPC内で稼働しているインスタンス」と、「VPC外で稼働しているインスタンス」が混在している環境となっています。今回はこのような環境で使用すると便利な「ClassicLink」という機能を紹介します。

ClassicLinkを使うとできること

  • VPC外のインスタンスと特定のVPCの相互接続

ClassicLinkを使用すると、VPC内(外)のサーバがあたかも同一のLAN上に存在するかのように、VPC外(内)のインスタンスからアクセスできるようになります。これによって、VPC外インスタンスのVPC内への移行を段階的に行えますし、移行の際のダウンタイムを減らせます。

ClassicLinkではできないこと

  • 異なるVPC間の相互接続

ClassicLinkでは、「VPC外 (EC2-Classic) 」のインスタンスと特定のVPCとの相互接続を行う機能であり、VPC間の相互接続には使用できません。このような場合には、「VPC peering」機能を使用して相互接続の設定を行う必要があります。

  • VPC外のインスタンスと、複数のVPCとの相互接続

ClassicLinkはサーバごとに相互接続を行うVPCを設定できますが、ClassicLinkで接続できるVPCは1インスタンスに対して1つだけです。複数のVPCへのアクセスを実現にするには「VPC peering」機能と、VPCのルーティング設定を組み合わせる必要があります。

ClassicLinkの使い方

ClassicLinkの設定はAWSのコンソール画面上、またはaws-cliで行えます。設定したいインスタンスを選択し、接続したいVPC名と、VPC外からの通信の際にVPC側で適用するセキュリティグループを選択します。VPC内のセキュリティグループからはVPC外のセキュリティグループは参照できないので、EC2-ClassicのIP帯などを指定したインバウンドルールを設定したセキュリティグループを作成しておく必要があります。

ClassicLink使用時の注意点

ClassicLinkは起動中のインスタンス対してのみ設定でき、停止すると設定が失われてしまうので注意が必要です。

まとめ

使用できる場面は少ないですが、ClassicLinkを使用することで、VPC内外の相互接続を簡単に行えて、それによってVPC内への移行作業の手間やダウンタイムの削減が可能です。

今回は以上となります。