Skip to content

Instantly share code, notes, and snippets.

@kumagi
Last active December 31, 2015 14:29
Show Gist options
  • Save kumagi/8000306 to your computer and use it in GitHub Desktop.
Save kumagi/8000306 to your computer and use it in GitHub Desktop.
JubatusのMixアルゴリズム改善について

解決したい問題

  • put_diffを取り漏らした時などに学習モデルがズレる
  • 新規マシンを追加する機能がない

解決方針

  • モデルにバージョン番号を埋め込む事で一番多くmixを受け取ったモデルを識別可能にする
  • get_diff時にバージョン番号を埋め込む事でそのdiffをmixに利用するかを判断する
  • put_diff時にバージョン番号を埋め込む事で受け取った側が今持っているモデルが最新かどうかを判断する
  • 今持っているモデルが最新でないと判断したら他のプロセスからモデルを受け取る

変更に伴う外部/内部IFの非互換な変更

  • /jubatus/actors/classifier/[NAME]/activeを追加
    • これはnodesと異なり「ProxyがRPCを投げても良いプロセス」を意味するEphemeralノード
    • これに伴いnodesは「ZKから生きていると認識されているプロセスとなるよう意味を変更
  • save/load時のデータ非互換
    • バージョン番号のメンバを加えた分、save/load時に型が合わない
      • masterとして公開する際にコンバータを用意するなどで対処予定(別のパッチ)
  • put_diffの戻り値をvoidからboolへ変更
    • これまでput_diffは成功シナリオのみしか想定していなかったが、バージョン番号埋め込みと共に失敗するパターンを考慮する必要がある
    • フレームワークとしてのJubatusは個々のアルゴリズム内部に踏み込まない為、アルゴリズム側から「put_diffに失敗した」と教えてもらう必要がある
    • classifier以外のすべてのアルゴリズムは暫定的にput_diffはすべてtrueを返す。これはこれまでの挙動を全く変更しない。
      • それらのアルゴリズムでモデルの最新バージョン獲得機能を使いたい場合にはput_diffにfalseを返せば良い(regressionもできるがやるとしたら別のパッチ)

linear_mix.cpp

外観

  • 他のプロセスにモデル全部を要求するget_modelの送信側と受信側を実装
  • mixer_loopは、「mix」のみの無限ループだったがこの処理を「mix」及び「必要なら他のプロセスからモデルを全部もらってくる」の2つの処理を行うループへと変更。それに伴って名前をstabilizer_loopに変更
  • put_diff適用時にfalseが帰ってきたら、自身のモデルが世代遅れになっていることを意味するので、is_obsolete_フラグを立て、activeとして保存したZKのエントリを消去
  • stabilizer_loop内で、is_obsolete_フラグが立っている事を検知したら他のプロセスからモデルを獲得しにいく
    • モデル獲得時(get_model)は自分以外のプロセスからランダムに一つ選んでget_model RPCを投げる。獲得したら即Mixして最新であるか試す。
  • 晴れてモデルが最新になっていればis_obsolete_フラグを折り、put_diffの成功時にactiveとしてZooKeeperに保存。
    • これによりproxy経由でリクエストが来るようになる。

議論

  • 1プロセスのみしか居ない場合、get_modelは諦めて即座にactiveとして昇格する。
  • どこかのタイミングで最新のモデルを持つプロセスがすべて死んだ場合、古いモデル同士のmix時に採用するバージョン番号は必ずその古いモデルに合成可能なものとなるため、いずれ何らかの形で可能な限り最新なモデルが共有されるはず − get_modelをリクエストする先をランダムで決定しているが、性能的にはランダムではなくバージョン確認RPCを別で用意するなどの最適化が考えられるが、その場合いくつか問題がある
    • RPCコマンドが更に増えてしまう
    • フレームワークがバージョン番号というアルゴリズム固有のデータに踏み込んだ情報を管理する必要がある
  • なぜモデル側に番号を持たせるのか。フレームワーク側ではダメなのか
    • linear_mixerの用例によっては古いものをput_diffしても問題なく動いて欲しいタイプの物もあると想定し、フレームワーク側ですべてを吸収するのは避けた。将来的にはフレームワーク側で吸収するモードのlinear_mixerを作り分けても良いかもしれない
@suma
Copy link

suma commented Jan 6, 2014

  • put_diffに関して:返り値をbool(成功・失敗)としたとき、put_diffの失敗原因が複数あるとき対応しづらそうだが、いまのJubatus想定で大丈夫そうか(失敗原因が増えることはないだろうか?)
  • 議論> フレームワーク側 というのはコードでいえばjubatus/server以下のサーバ・mixer周辺部分のことをいっていると捉えて良いか?

@unnonouno
Copy link

  • put_diffの失敗ケースは何種類かに分類できないか? @sumaさんの議論のつづき
  • フレームワークとしてバージョンを持ってもいいと思う。「問題なく動く」ものもあるが、簡単に同期がちゃんと取れてくれる方が嬉しそう
  • activeとnodesは、「activeかつnode」「nodeのみ」「いずれにもない」の3通りだけで、「activeのみ」というのは異常ということであってる?

@unnonouno
Copy link

・「get_diff時にバージョン番号を埋め込む事で」→どっちのバージョンを? 取得側、送信側両方?

@kumagi
Copy link
Author

kumagi commented Jan 9, 2014

  • put_diffの失敗原因が複数考えられたとして、フレームワーク側から行える操作というのはそう多くないため、boolで問題ないと考えている。
    • 強いて言えば例外を投げた方がすっきり書けるけれど他の失敗パターンが思いつかなかったのでそこまで一般化を急ぐ必要性を感じなかった
    • 任意のアルゴリズムの任意の失敗ハンドリングをフレームワーク側で行わせたいなら、コールバック関数登録などで記述することになるけれどむしろ複雑さを増しているのではないか
  • activeとnodesは「activeのみ」という状態には陥らない(万一陥った場合、nodesが削除されたら受動的に自殺するのでactiveのephemeralも揮発する
  • get_diff時に埋め込むバージョンは、diff情報を送信する側のバージョン。get_diffそのもののパラメータは利用されていない

@kumagi
Copy link
Author

kumagi commented Jan 9, 2014

フレームワーク側 というのはコードでいえばjubatus/server以下のサーバ・mixer周辺部分のことをいっていると捉えて良いか?

その通り。jubatus/core側はささない。

@suma
Copy link

suma commented Jan 10, 2014

返信ありがとうございます。put_diff原因の追跡性を今は詳細まで頑張らないとして、今後修正/参照するにも必要な情報がまとまっていると思います。
どうでしょう?> @unnonouno

@unnonouno
Copy link

はい、あとは清書すればOKだとおもいます

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment