機械学習モデルもdockerで管理するのが好きな人もいると思うので、
nipsで紹介されてたのを動かして確認してみました。
今回はモデルを登録して、api機能をデプロイするところをやってみました。
http://clipper.ai/tutorials/basic_concepts/
https://github.com/ucbrise/clipper
Clipperクラスタ
Clipperは3つPython,R,PySparkに対応しています。
Clipperクラスタのコアは、クエリフロントエンド、管理フロントエンド、および構成データベースの3つのコンポーネントで構成されています。
-
クエリフロントエンド: 受信した予測リクエストとスケジュールをリッスンし、それらをデプロイされたモデルにルーティングします。ClipperのREST予測インターフェースを照会すると、フロントエンドに要求が送信されます。
-
管理フロントエンド: Clipperの内部構成状態を管理および更新します。新しいアプリケーションの登録や新しいモデルの展開など、Clipperクラスタの設定を変更するときは、管理フロントエンドのadmin RESTインターフェイスに対してコマンドを発行しています。
-
構成データベース: Clipperの内部構成状態を永続的に保存するために使用されるRedisインスタンス。Clipperの内部構成の変更は、管理フロントエンドからRedisに伝えられ、永続的に保存されます。
クエリフロントエンドは、構成データベースへの変更を監視し、変更が検出されたときにその状態を適切に更新します。
自分で試した環境
cat /etc/os-release
>>>NAME="Ubuntu"
>>>VERSION="16.04.1 LTS (Xenial Xerus)"
>>>ID=ubuntu
>>>ID_LIKE=debian
>>>PRETTY_NAME="Ubuntu 16.04.1 LTS"
>>>VERSION_ID="16.04"
>>>...
pyenv versions
>>>* system (set by /home/user1/.pyenv/version)
>>> anaconda2-4.4.0
>>> anaconda2-4.4.0/envs/py27
python -V
>>>Python 2.7.13 :: Continuum Analytics, Inc.
docker -v
>>>Docker version 18.02.0-ce, build fc4de44
Python2.7の環境設定:Ubuntu
python2.7系しかclipperではサポートされていない。
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
bachrcに設定。
# pyenv
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
eval "$(pyenv init -)"
pyenv install anaconda2-4.4.0
bachrcに設定。
export PATH="$PYENV_ROOT/versions/anaconda2-4.4.0/bin:$PATH"
conda環境を作る。
conda create -n py27 python=2.7
環境に入る。
source activate py27
参照
https://qiita.com/miyamotok0105/items/5f26e4ae41f0e35ded16
clipperの環境設定
# clipper
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
pip install git+https://github.com/ucbrise/clipper.git@develop#subdirectory=clipper_admin
clipperの基礎を動かしてみる。
git clone https://github.com/ucbrise/clipper.git
cd examples/basic_query
python example_client.py
from __future__ import print_function
from clipper_admin import ClipperConnection, DockerContainerManager
from clipper_admin.deployers import python as python_deployer
import json
import requests
from datetime import datetime
import time
import numpy as np
import signal
import sys
def predict(addr, x, batch=False):
url = "http://%s/simple-example/predict" % addr
if batch:
req_json = json.dumps({'input_batch': x})
else:
req_json = json.dumps({'input': list(x)})
headers = {'Content-type': 'application/json'}
start = datetime.now()
r = requests.post(url, headers=headers, data=req_json)
end = datetime.now()
latency = (end - start).total_seconds() * 1000.0
print("'%s', %f ms" % (r.text, latency))
def feature_sum(xs):
return [str(sum(x)) for x in xs]
# Stop Clipper on Ctrl-C
def signal_handler(signal, frame):
print("Stopping Clipper...")
clipper_conn = ClipperConnection(DockerContainerManager())
clipper_conn.stop_all()
sys.exit(0)
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
clipper_conn = ClipperConnection(DockerContainerManager())
clipper_conn.start_clipper()
python_deployer.create_endpoint(clipper_conn, "simple-example", "doubles",
feature_sum)
time.sleep(2)
# For batch inputs set this number > 1
batch_size = 1
try:
while True:
if batch_size > 1:
predict(
clipper_conn.get_query_addr(),
[list(np.random.random(200)) for i in range(batch_size)],
batch=True)
else:
predict(clipper_conn.get_query_addr(), np.random.random(200))
time.sleep(0.2)
except Exception as e:
clipper_conn.stop_all()
動いた。
python example_client.py
18-03-21:15:40:06 INFO [docker_container_manager.py:106] Starting managed Redis instance in Docker
18-03-21:15:40:09 INFO [clipper_admin.py:114] Clipper is running
18-03-21:15:40:09 INFO [clipper_admin.py:189] Application simple-example was successfully registered
18-03-21:15:40:09 INFO [deployer_utils.py:49] Saving function to /tmp/clipper/tmpajrwFc
18-03-21:15:40:13 INFO [deployer_utils.py:58] Anaconda environment found. Verifying packages.
18-03-21:15:40:24 INFO [deployer_utils.py:158] Fetching package metadata .........
Solving package specifications: .
18-03-21:15:40:24 INFO [deployer_utils.py:159] Using Anaconda API: https://api.anaconda.org
18-03-21:15:40:24 INFO [deployer_utils.py:67] Supplied environment details
18-03-21:15:40:25 INFO [deployer_utils.py:79] Supplied local modules
18-03-21:15:40:25 INFO [deployer_utils.py:85] Serialized and supplied predict function
18-03-21:15:40:25 INFO [python.py:184] Python closure saved
18-03-21:15:40:25 INFO [clipper_admin.py:391] Building model Docker image with model data from /tmp/clipper/tmpajrwFc
18-03-21:15:40:26 INFO [clipper_admin.py:395] Pushing model Docker image to simple-example:1
18-03-21:15:40:28 INFO [docker_container_manager.py:243] Found 0 replicas for simple-example:1. Adding 1
18-03-21:15:40:29 INFO [clipper_admin.py:569] Successfully registered model simple-example:1
18-03-21:15:40:29 INFO [clipper_admin.py:487] Done deploying model simple-example:1.
18-03-21:15:40:29 INFO [clipper_admin.py:232] Model simple-example is now linked to application simple-example
'{"query_id":0,"output":94.6718686566,"default":false}', 17.186000 ms
'{"query_id":1,"output":97.4406443212,"default":false}', 7.134000 ms
'{"query_id":2,"output":95.5675770539,"default":false}', 6.241000 ms
'{"query_id":3,"output":101.933600191,"default":false}', 6.785000 ms
...
dockerでバアアアっと立ち上がってる。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
81c72516f3aa simple-example:1 "/container/python_c…" 55 seconds ago Exited (137) 26 seconds ago simple-example_1-46743
2e652c31cec7 prom/prometheus:v2.1.0 "/bin/prometheus --c…" About a minute ago Exited (0) 26 seconds ago metric_frontend-35815
a6d0987a6f74 clipper/frontend-exporter:develop "python ./front_end_…" About a minute ago Exited (137) 15 seconds ago query_frontend_exporter-88393
5c1523a4b5ea clipper/query_frontend:develop "/clipper/release/sr…" About a minute ago Exited (137) 5 seconds ago query_frontend-88393
687d4f2e650a clipper/management_frontend:develop "/clipper/release/sr…" About a minute ago Up About a minute 0.0.0.0:1338->1338/tcp mgmt_frontend-10174
81d8ec025f20 redis:alpine "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:6379->6379/tcp redis-75736
いらないのであれば消しておく。
docker system prune
docker rm -f `docker ps -a -q`
アプリケーション
- clipperを動かす。
まだ動いてないなら
clipper_conn.start_clipper()
もう動いてるなら接続する。
clipper_conn.connect()
register_applicationでアプリを登録して、deploy_python_closureでデプロイする。
link_model_to_appでモデル同士を接続できる。
- アプリケーションの登録は ClipperConnection.register_application
Clipperにアプリケーションを登録すると、そのアプリケーションのRESTエンドポイントが作成されます。
URL: /<app_name>/predict
Method: POST
Data Params: {"input": <input>}
- モデルをアプリケーションにリンクするには ClipperConnection.link_model_to_app
モデルを登録したらリンクしてルーティングする。
from clipper_admin import ClipperConnection, DockerContainerManager
clipper_conn = ClipperConnection(DockerContainerManager())
# Start Clipper
clipper_conn.start_clipper()
# Register an application
# a prediction REST endpoint at http://localhost:1337/hello_world/predict
clipper_conn.register_application(name="hello-world", input_type="doubles", default_output="-1.0", slo_micros=100000)
# Inspect Clipper to see the registered apps
print(clipper_conn.get_all_apps())
def feature_sum(xs):
return [str(sum(x)) for x in xs]
from clipper_admin.deployers import python as python_deployer
python_deployer.deploy_python_closure(clipper_conn, name="sum-model", version=1, input_type="doubles", func=feature_sum)
clipper_conn.link_model_to_app(app_name="hello-world", model_name="sum-model")
ローカルから呼び出す。
curl -X POST --header "Content-Type:application/json" -d '{"input": [1.1, 2.2, 3.3]}' 127.0.0.1:1337/hello-world/predict
>>>{"query_id":0,"output":6.6,"default":false}
外部から呼び出す時はipを変えるだけ。
curl -X POST --header "Content-Type:application/json" -d '{"input": [1.1, 2.2, 3.3]}' 150.95.145.xxx:1337/hello-world/predict
{"query_id":1,"output":6.6,"default":false}
pythonで呼び出す。
import requests, json, numpy as np
headers = {"Content-type": "application/json"}
requests.post("http://localhost:1337/hello-world/predict", headers=headers, data=json.dumps({"input": list(np.random.random(10))})).json()
なんとなく動かせたので、
今度は違うサンプルか他のものを動かしたいと思います。
エラー集
AttributeError: 'bool' object has no attribute 'rfind'
→このエラーで何度かハマった。Python3系を使ったり、2系入れてもanacondaのバージョンの問題なのかエラーが出てた。自分のubuntu16環境ではanaconda2-4.4.0を使ったら治った。あとはdockerバージョンも新しくしておいた気がする。
https://github.com/ucbrise/clipper/issues/382