4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JubatusAdvent Calendar 2016

Day 11

Jubatusにcurlでアクセスするインタフェースについて

Posted at

この記事はJubatus Advent Calendar 11日目の記事です。

Jubatusをとあるプロジェクトで使う為に問題になったことを手元で解決するために作った道具の話をします。

問題点1. JubatusにHTTP経由でアクセスしたい

Jubatusとはmsgpack-rpcプロトコルで通信するサーバプロセスである。
msgpack-rpcは高速なバイナリプロトコルで、それをjubatus-proxyで負荷分散することができる。

しかし、JubatusにHTTP経由でアクセスすることができればロードバランサで負荷を散らしたりnginxにhttpsを終端させたりBASIC認証を噛ませたりと様々なHTTPのノウハウを活かす事ができる。

問題点2. Jubatusプロセスを再起動せずにモデルを作り直したい

0.3までのJubatusは実は新しいモデルを set_config rpcで作ることができたが、一度に1プロセスに付き1モデルしか保持できない事から、実質初期化rpcに過ぎなかったので起動時オプションで与える形に変わった。
昔のJubatusの構想としてはrpc経由で複数のモデルを作ったりその出力を組み合わせたり多段にしたりアンサンブルしたりなどといろんなことができる構想が有ったようだが、そのインタフェースをどうしたら良いか確定しなかったのもあって実装されなかった。

Jubatusのrpcは第一引数にnameという引数を取り、クラスタ内にある複数のモデルを呼び分ける事ができる。しかし1プロセス1モデルの構造の上なので複数のモデルを同時に使うためにはそれぞれ別のモデル名を与えたJubatusプロセスを立ち上げる必要がある。そしてZooKeeperとjubatus_proxyが必要となり管理が面倒になる。

http_jubatus

これら2つの問題を同時に解決するために作ったのが、httpエンドポイントを持ち、複数のJubatusプロセスの死活を行い、そいつらとの通信を中継してくれるhttp_jubatusである。
慣れないGo言語でおっかなびっくり書いたのでイケてないコードはちょいちょいあると思う。

$ go run http_jubatus.go

と立ち上げる事ができる。

モデル追加

新たにclassifierプロセスを立ち上げる際には

POST /classifier/

にjubatusのコンフィグファイルとnameを投げつける。幸いにしてjubatusのコンフィグファイルはjsonなのでhttpと親和性が高い。classifier以外のプロセスを立ちあげたい場合はその名前がpathになっているので POST /recommender/ なり何なりできる。

$ curl localhost:3000/classifier \
    -H 'Content-type: application/json' \
    -X POST \
    -d '{
          "name": "sample_classifier",
          "parameter": {
            "converter" : {
                "string_rules" : [
                    { "key" : "*", "type" : "str", "sample_weight" : "bin", "global_weight" : "bin" }
                ],
                "num_rules" : [
                    { "key" : "*", "type" : "num" }
                ]
            },
            "method" : "PA"
          }
        }'

という感じでcurlでPOSTすると、sample_classifierというnameを持ったjubatusプロセスが新たにexecされ、コンフィグとしてJSONファイルの中身が渡される。

機械学習実行

nameはそのままPATHの一部となる、そこの下にjubatusのrpc名をつなげた物が機械学習のHTTPエンドポイントになる。また、msgpackはJSONとおおよそ対応関係があるので、JSON形式でjubatusのパラメータを表現する事で機械学習が実行できる。例えばtrainを行いたい場合は以下のようになる。

curl localhost:3000/classifier/sample_classifier/train \
    -H 'Content-type: application/json' \
    -X POST \
    -d '[
        [
            [
                "bar",
                [
                    [],
                    [
                        ["fuga", 1.0]
                    ],
                    []
                ]
            ]
        ]
      ]'

反省点

良かったことと悪かった事がある。

良かったこと:モデルをRPCで作れるのは便利

ハイパーパラメータの調整のためなどでモデルを調整するにしてもクライアント側のプログラムを調整してリトライすればよいし、複数のハイパーパラメータで精度を比べたい場合でも全部とりあえず立ち上げるというクライアント側のプログラムがとても書きやすかった。サーバに食わせるJSONファイルを個別に編集してプロセスを立ちあげては殺していた日々は何だったのか。

悪かった事:JSONパラメータをcurlで記述するのは地獄

括弧の対応関係を追いかけるのが非常につらい。
HTTPで与えるオブジェクトを1つにしたかったのもあり、引数全体を1つの配列オブジェクトとして受け取るので配列1層、trainは複数の教師データを一度に与える事ができるようにpaired datumの配列を受け取る。paired datumはラベルとdatumによる長さ2の配列としてmsgpackの構造で表現されている。そしてdatumは長さ3の配列となっていて、string_values,num_values,binary_valuesでできている。それぞれのvaluesはキーバリューペアの配列でありキーバリューペアはキーとバリューを含む長さ2の配列である。それらがすべて入れ子構造になっているので、それを表したJSON構造のデバッグは地獄だった。
もっとJSONライクに配列ではなくてオブジェクトでデータ構造を詰め込めばよかったのだけれど、RPC毎にJSON⇔msgpackの変換を手作業で書くのは現実的なコストではなく、いっそのことJubatus-idlから自動生成するようjeneratorに改変を加えたほうが良いと思う。

もう少し使ってみて良さそうであればJubatus本流でも同様のインタフェース経由で使えるようにできたらいいなと思う。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?