- 概要
- スタートアップガイド
- ユーザガイド
-
リファレンス
-
ABEJA Platform CLI
- CONFIG COMMAND
- DATALAKE COMMAND
- DATASET COMMAND
- TRAINING COMMAND
-
MODEL COMMAND
- check-endpoint-image
- check-endpoint-json
- create-deployment
- create-endpoint
- create-model
- create-service
- create-trigger
- create-version
- delete-deployment
- delete-endpoint
- delete-model
- delete-service
- delete-version
- describe-deployments
- describe-endpoints
- describe-models
- describe-service-logs
- describe-services
- describe-versions
- download-versions
- run-local
- run-local-server
- start-service
- stop-service
- submit-run
- update-endpoint
- startapp command
-
ABEJA Platform CLI
- FAQ
- Appendix
モデルハンドラー関数 FOR 18.10
本頁では、 18.10
のイメージで利用できるハンドラー関数について説明します。
19.04
以降のイメージで利用できるハンドラー関数については、こちらを参照ください。
モデルハンドラー関数はモデルを実行する際に呼び出されるコード内の関数です。ハンドラー関数は以下の構文構造を使用します。
def handler(input_iter, context):
for line in input_iter:
...
yield ret_line
- input_iter : 入力データがこのパラメータに格納されます。このパラメータは通常、 Python のイテレータです。
- context : 実行時のメタデータなどがこのパラメータに格納されます。
ハンドラーの引数
入力データ
ハンドラー関数の第一引数には入力データがイテレータとして渡されます。 イテレータに含まれるデータの形式は MIME Type 毎に異なります。
JSON
入力された JSON はイテレータの最初の要素に dict
またはlist
型として渡されます。イテレータの長さは1です。
以下の MIME Type に対応しています。
- application/json
画像
入力された画像はイテレータの最初の要素に numpy.ndarray
型として渡されます。イテレータの長さは1です。
また、 numpy.ndarray
の色の順番は RGB となります。
以下の MIME Type に対応しています。
- image/jpeg
- image/png
動画
現在、動画はトリガー、実行でのみサポートされています。
入力された動画は、フレーム画像を含む以下の dict
を返すイテレータに変換されハンドラー関数に渡されます。
{
"image": `numpy.ndarray`,
"pos_frames": `int`,
"pos_msec": `int`
}
キー | 型 | 説明 |
---|---|---|
image |
numpy.ndarray |
RGB 順の画像の配列 |
pos_frames |
int |
0 から始まる動画のインデックス |
pos_msec |
int |
動画の現在の位置となる秒数 (単位: ミリ秒) |
以下の MIME Type に対応しています。
- video/avi
- video/x-matroska
- video/quicktime
- video/mp4
コンテキストデータ
ハンドラー関数の第二引数には以下のプロパティをコンテキスト情報として持つ変数が渡されます。
プロパティ名 | 説明 |
---|---|
datatypes | ABEJA Platform 上で返却値として処理可能な型を含んだモジュール |
exceptions | ABEJA Platform 上で例外として処理可能な型を含んだモジュール |
http_method | 実行された HTTP メソッド |
http_headers | HTTP リクエスト・ヘッダーを含む辞書。ヘッダー名をキーとし、すべて小文字に変換されています。Authorization ヘッダーを含む一部のヘッダーは削除されます |
parameters | 実行時のメタ情報やその他のパラメータ |
ハンドラーの環境変数
ハンドラー関数では以下の環境変数を使用することが可能です。
環境変数名 | 説明 |
---|---|
ABEJA_ORGANIZATION_ID | オーガニゼーションの ID です |
ABEJA_MODEL_ID | モデルの ID です |
ABEJA_MODEL_VERSION_ID | モデルバージョンの ID です |
ABEJA_DEPLOYMENT_ID | デプロイメントの ID です |
ABEJA_SERVICE_ID | サービスの ID です |
HANDLER | ハンドラーのパスです |
TRAINING_JOB_DEFINITION_NAME | 学習ジョブ定義名です |
TRAINING_JOB_ID | 学習ジョブの ID です |
ABEJA_TRAINING_RESULT_DIR | 学習ジョブの結果が格納されるディレクトリへの相対パスです |
上記のほか、コードバージョン/サービス/トリガー/ Run 作成時に指定出来る環境変数も使用可能です。 ユーザーの指定可能な環境変数についての詳細は、こちらを参照ください。
学習結果のモデルハンドラーでの使用
ABEJA Platform では学習の結果を元にモデルバージョンを作成することができます。
学習時の出力をモデルハンドラー関数で使用するためには、学習時にABEJA_TRAINING_RESULT_DIR
環境変数で指定されるディレクトリに格納する必要があります。
学習時に出力した結果は、モデルハンドラー関数実行時にABEJA_TRAINING_RESULT_DIR
環境変数に格納されたディレクトリに展開されます。
ハンドラーの返り値と例外
返り値
データを出力するためには、コンテキストデータのdatatypes
に含まれるResponse
型のデータをジェネレータとして返却します。
context.datatypes.Response([返却するデータ], metadata=[('Content-Type', 返却するMIME Type)])
Response
の第一引数には返却するデータを配列で渡します。 metadata
はレスポンス時のヘッダーとして使用されます。
以下は返却するデータと MIME Type の例です。
MIME Type | 返却するデータの型 |
---|---|
application/json | dict またはlist |
image/jpeg | bytes |
image/png | bytes |
ABEJA Platform ではapplication/json
をデフォルトの MIME Type として扱うため、JSON をレスポンスとしたい場合はResponse
型を使用せず dict
またはlist
を返却することも可能です。
例外
ABEJA Platform が定義する例外をハンドラー関数内で投げることで例外の種類に対応する処理が行われます。
定義された以下の例外クラスが、コンテキストデータの exceptions
プロパティに含まれます。
context.exceptions.InvalidInput
context.exceptions.ModelError
モデルハンドラー関数の実装例
以下はモデルハンドラー関数の簡単な実装例です。
CLI のrun-localコマンドを使うことで動作を確認することができます。
JSON を入力し JSON を返却する
入力された JSON に対し簡単な計算を行い、JSON のレスポンスを返す例です。
入力データを含む イテレータinput_iter
から入力となるデータを以下のように取得します。
JSON 出力時には、 出力したいdict
またはlist
型のデータを含むcontext.datatypes.Response
型を返却するジェネレータを実装します。その際 metadata
に以下のように Content-Type
が application/json
となるように返却します。
def handler(input_iter, context):
for line in input_iter:
total_without_tax = line['total_without_tax']
total_without_tax = int(total_without_tax)
total = total_without_tax * 1.08
yield context.datatypes.Response([{'total': total}], metadata=[('Content-Type', 'application/json')])
また、 JSON をレスポンスとする場合、Response
型を返却せず以下のように省略して書いた場合も上記と同じレスポンスを返します。
def handler(input_iter, context):
for line in input_iter:
total_without_tax = line['total_without_tax']
total_without_tax = int(total_without_tax)
total = total_without_tax * 1.08
yield {'total': total}
run-local
コマンドの実行結果です。 request.json
を入力とした出力結果が表示されます。
$ abeja model run-local --image abeja/all-cpu:18.10 --handler main:handler --input request.json --quiet
{
"total": 108.0
}
画像を入力とし画像を返却する
入力された画像を左右反転して返す例です。
JSON と同様に入力データを含むイテレータinput_iter
から入力となるデータを以下のように取得します。
反転した入力画像をbytes
型としてcontext.datatypes.Response
型に含め返却するジェネレータを実装しています。この例では 出力が JPEG 画像であるため metadata
に以下のように Content-Type
を image/jpeg
として設定します。
import cv2
def handler(input_iter, context):
for img in input_iter:
flipped_image = cv2.flip(img, 1)
_, encoded_flipped_image = cv2.imencode('.jpeg', cv2.cvtColor(flipped_image, cv2.COLOR_BGR2RGB))
yield context.datatypes.Response(
[encoded_flipped_image.tostring()],
metadata=[('Content-Type', 'image/jpeg')]
)
run-local
コマンドの実行結果です。 入力であるcat.jpeg
を反転した画像が出力されます。
$ abeja model run-local --image abeja/all-cpu:18.10 --handler main:handler --input cat.jpeg --quiet > flipped_cat.jpeg
$ open flipped_cat.jpeg
学習結果を使用し画像から JSON を返却する
学習の結果として出力された HDF5 ファイルを用いたモデルの推論結果を JSON で返却します。
ABEJA_TRAINING_RESULT_DIR
に展開される学習結果から HDF5 ファイルを読み込み推論を行います。
この際、学習時に出力ディレクトリに保存した HDF5 ファイルと同じファイル名を指定する必要があります。
import os
from keras.models import load_model
from PIL import Image
model = load_model(os.path.join(os.environ.get('ABEJA_TRAINING_RESULT_DIR', '.'), 'model.h5'))
def handler(input_iter, ctx):
for img in input_iter:
img = Image.fromarray(img)
# PREPROCESS INPUT HERE
...
result = model.predict(img)
# CONVERT RESULT FOR RESPONSE
...
yield {"result": result}
run-local
コマンドの実行結果です。 入力であるcat.jpeg
を入力とした推論結果が返されます。
$ abeja model run-local --image abeja/all-cpu:18.10 --handler main:handler --input cat.jpeg
{
"result": [
{ "label":"cat", "probability":"0.85" },
{ "label":"dog", "probability":"0.15" }
]
}
不正な JSON 入力を例外として通知する
context.exceptions.InvalidInput
を例外として投げることで不正な入力であることをリクエスト実行者に通知します。
この場合、入力された JSON のtotal_without_tax
にデータが存在しない場合を不正な入力としています。
def handler(iter, context):
for line in iter:
if 'total_without_tax' not in line:
raise context.exceptions.InvalidInput('total_without_tax not in the request')
total_without_tax = line['total_without_tax']
total_without_tax = int(total_without_tax)
total = total_without_tax * 1.08
yield {'total': total}
run-local
コマンドの実行結果です。 不正な入力に対しエラーが出力されていることが確認できます。
$ abeja model run-local --image abeja/all-cpu:18.10 --handler tax:handler --input request.json --quiet
[error] failed to send request : 400 Client Error: BAD REQUEST for url: http://localhost:49873/
------ Local Server Error ------
{"log_id": "de614348-365b-446f-99c2-44f58d57eefd", "log_level": "INFO", "timestamp": "2018-05-10T01:27:15.416427+00:00", "source": "model:run.run.203", "requester_id": "-", "message": "start executing model. version:0.9.7", "exc_info": null}
{"log_id": "ef77beac-5384-442e-b345-fde112a2952b", "log_level": "INFO", "timestamp": "2018-05-10T01:27:15.416955+00:00", "source": "model:run.run.218", "requester_id": "-", "message": "start installing packages from requirements.txt", "exc_info": null}
{"log_id": "8024e5b7-c4da-4298-8e13-7fbace8c986d", "log_level": "INFO", "timestamp": "2018-05-10T01:27:15.417698+00:00", "source": "model:run.run.224", "requester_id": "-", "message": "requirements.txt not found, skipping", "exc_info": null}
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
{"log_id": "1e730acd-4b6b-4f24-98b5-0c874c122a11", "log_level": "INFO", "timestamp": "2018-05-10T01:27:16.031969+00:00", "source": "model:http_view.endpoint.91", "requester_id": "__requester-id__", "message": "start request", "exc_info": null}
{"log_id": "d6d12c55-57e1-4ca1-bf31-9e6a1b7cb34a", "log_level": "INFO", "timestamp": "2018-05-10T01:27:16.032966+00:00", "source": "model:http_view.endpoint.132", "requester_id": "__requester-id__", "message": "UserException::InvalidInput total_without_tax not in the request", "exc_info": null}
172.17.0.1 - - [10/May/2018 01:27:16] "POST / HTTP/1.1" 400 -