PredictionIOはSparkを中心としたJVMベースの機械学習アプリケーションを開発・運用するために必要なミドルウェアやフレームワークなどを統合的に提供するもので、開発者はPredictionIOのフレームワークに従ってエンジンを作成することで、機械学習を使用したアプリケーションをWebサービスとしてデプロイすることができます。
まずはPredictionIOのWebサイトに掲載されているレコメンデーションのテンプレートを動かしてみます。
PredictionIOのインストール
ドキュメントを見るとソースからビルドするべしとなっており中々スパルタンな感じです。Dockerで動かすこともできるようですが、折角なのでソースからビルドしてみることにします(Javaは予めインストールしておく必要があります)。
まずはこちらから現時点で最新版の0.11.0-incubatingの配布物をダウンロードし、適当なディレクトリに展開します。ルートディレクトリがないようなのでディレクトリを掘ってから展開するのが良いです。
$ wget http://ftp.riken.jp/net/apache/incubator/predictionio/0.11.0-incubating/apache-predictionio-0.11.0-incubating.tar.gz
$ mkdir apache-predictionio-0.11.0-incubating
$ tar xvzfC apache-predictionio-0.11.0-incubating.tar.gz apache-predictionio-0.11.0-incubating
展開したディレクトリ内にあるmake-distribution.sh
でおもむろにビルドします。
$ cd apache-predictionio-0.11.0-incubating
$ ./make-distribution.sh
ビルドが成功するとPredictionIO-0.11.0-incubating.tar.gz
というファイルができるので、これを適当な場所に展開します。
Sparkのインストール
PredictionIO-0.11.0-incubating/vendors
にSparkのディストリビューションを展開しておきます。が、PredictionIOがデフォルトでサポートしているのはSpark 1.6.3という古いのバージョンのようです。オプションでSpark 2系を使用するようビルドすることもできるのですが、デフォルトで最新のものが使われるようになって欲しいところです。
$ wget http://d3kbcqa49mib13.cloudfront.net/spark-1.6.3-bin-hadoop2.6.tgz
$ mkdir PredictionIO-0.11.0-incubating/vendors
$ tar zxvfC spark-1.6.3-bin-hadoop2.6.tgz PredictionIO-0.11.0-incubating/vendors
ストレージのインストール
PredictionIOの動作に必要なデータや、学習に使用するデータなどを格納するためのストレージを別途インストールする必要があります。PredictionIOは以下のストレージをサポートしています(ストレージに保存するデータにはメタデータ、イベントデータ、モデルデータの3種類があり、ストレージごとに保存できるデータが異なります)。
- PostgreSQL(メタデータ、イベントデータ、モデルデータ)
- Elasticsearch(メタデータ、Elasticsearch 5ならイベントデータも保存可能)
- HBase(イベントデータ)
- HDFS(モデルデータ)
- ローカルファイルシステム(モデルデータ)
デフォルトではPostgreSQLを使用するようになっているのでこれを使ってみます。MacであればHomebrewでPostgreSQLをインストールできます。
$ brew install postgresql
ついでにbrew servicesで自動起動するようにしておきます(brew services stop postgresql
すると自動起動をやめることができます)。
$ brew services start postgresql
PredictionIOで使用するデータベースやユーザを作成します。
$ createdb pio $ psql pio -c "create user pio with password 'pio'"
PostgreSQLのJDBCドライバをダウンロードしてPredictionIO-0.11.0-incubating/lib
に配置します。
$ cd PredictionIO-0.11.0-incubating/lib
$ wget https://jdbc.postgresql.org/download/postgresql-42.0.0.jar
PredictionIOを起動する
ここまでできたらPredictionIOを起動してみます。
$ cd PredictionIO-0.11.0-incubating/bin
$ ./pio eventserver &
すると、7070ポートでイベントサーバが起動します。この後の操作ではPredictionIO-0.11.0-incubating/bin
にあるpio
コマンドを多用することになるのでこのディレクトリにPATH
を通しておくとよいです。
学習データを登録する
PredictionIOのイベントサーバにアクセスするためのアクセスキーを発行します。
$ pio app new MyApp1
こんな感じでアクセスキーが発行されます。
... [INFO] [App$] Initialized Event Store for this app ID: 1. [INFO] [Pio$] Created a new app: [INFO] [Pio$] Name: MyApp1 [INFO] [Pio$] ID: 1 [INFO] [Pio$] Access Key: i-zc4EleEM577EJhx3CzQhZZ0NnjBKKdSbp3MiR5JDb2zdTKKzH9nF6KLqjlMnvl
このアクセスキーを毎回指定するのは面倒なので以下のように環境変数に設定しておきます。
$ ACCESS_KEY=i-zc4EleEM577EJhx3CzQhZZ0NnjBKKdSbp3MiR5JDb2zdTKKzH9nF6KLqjlMnvl
学習データとして使用するデータをイベントサーバに登録してみます。
$ curl -i -X POST http://localhost:7070/events.json?accessKey=$ACCESS_KEY \ -H "Content-Type: application/json" \ -d '{ "event" : "rate", "entityType" : "user", "entityId" : "u0", "targetEntityType" : "item", "targetEntityId" : "i0", "properties" : { "rating" : 5 } "eventTime" : "2014-11-02T09:39:45.618-08:00" }'
$ curl -i -X POST http://localhost:7070/events.json?accessKey=$ACCESS_KEY \ -H "Content-Type: application/json" \ -d '{ "event" : "buy", "entityType" : "user", "entityId" : "u1", "targetEntityType" : "item", "targetEntityId" : "i2", "eventTime" : "2014-11-10T12:34:56.123-08:00" }'
登録したイベントを検索してみます。
$ curl "http://localhost:7070/events.json?accessKey=$ACCESS_KEY"
以下のように、2つのイベントが登録されていることが確認できます。
[ { "eventId":"774fdb3a572f48479e76e34681c7371b", "event":"rate", "entityType":"user", "entityId":"u0", "targetEntityType":"item", "targetEntityId":"i0", "properties": { "rating":5 }, "eventTime":"2014-11-02T09:39:45.618-08:00", "creationTime":"2017-05-05T09:35:54.604Z" }, { "eventId":"c1182fe0451d4744a0b695770c8098e9", "event":"buy", "entityType":"user", "entityId":"u1", "targetEntityType":"item", "targetEntityId":"i2", "properties":{}, "eventTime":"2014-11-10T12:34:56.123-08:00", "creationTime":"2017-05-05T09:36:05.372Z" } ]
レコメンデーションエンジンを動かしてみる
本題のレコメンデーションエンジンです。PredictionIOのオフィシャルで提供されているエンジンテンプレートを使用してみます。まずはgit
コマンドでテンプレートのリポジトリを適当な場所にクローンします。
$ git clone https://github.com/apache/incubator-predictionio-template-recommender.git MyRecommendation
$ cd MyRecommendation
準備として予め用意されているデータをまとめてインポートします。まずはPredictionIOのPython用SDKをインストールします。
$ pip install predictionio
以下のようにするとサンプルデータをまとめてイベントサーバにインポートできます。
$ curl https://raw.githubusercontent.com/apache/spark/master/data/mllib/sample_movielens_data.txt --create-dirs -o data/sample_movielens_data.txt $ python data/import_eventserver.py --access_key $ACCESS_KEY
次にMyRecommendation/engine.json
を編集してappName
に先ほどアクセスキーを発行したしたアプリケーション名を設定します。
... "datasource": { "params" : { "appName": "MyApp1" } }, ...
レコメンデーションエンジンをビルドします。
$ pio build --verbose
登録したイベントデータを使用して学習を行います。
$ pio train
ここでスタックオーバーフローが発生してしまうことがあります。その場合はMyRecommender/src/main/scala/ALSAlgorithm.scala
の以下の行のコメントアウトを外してチェックポイントを有効にします。
sc.setCheckpointDir("checkpoint")
ここまででようやく準備完了です。レコメンデーションエンジンをWebサービスとしてデプロイします。
$ pio deploy
8000ポートでレコメンデーションエンジンのWebサービスが起動します。ブラウザでアクセスすると以下のような画面が表示されるはずです。
実際にレコメンデーションエンジンを呼び出してみます。
$ curl -H "Content-Type: application/json" \ -d '{ "user": "1", "num": 4 }' http://localhost:8000/queries.json
すると以下のような結果が返ってくるはずです。指定したユーザに対してスコアが高い順に4つのアイテムが返却されていることがわかります。
{ "itemScores":[ {"item":"22","score":4.072304374729956}, {"item":"62","score":4.058482414005789}, {"item":"75","score":4.046063009943821}, {"item":"68","score":3.8153661512945325} ] }
まとめ
だいぶ手順が長くなってしまいましたが、PredictionIOは機械学習を使用したアプリケーションを開発・運用するために以下のような機能を提供していることがおわかりいただけたのではないかと思います。
今回は実際にPredictionIOでどのようにエンジンを開発するのかについては触れませんでしたが、興味のある方はエンジンテンプレートのソースコードを参照していただければと思います。また、PredictionIOのWebサイトには他にもいくつかのエンジンテンプレートが紹介されており、同様の手順で動かすことができますのでこちらも試してみていただければと思います。