はじめに
機械学習モデルを作ったらそのまま放置することは私も経験があります。 ただそのままだとWebサイト上で活用(例:レコメンドシステム)として使うことはできなかったり、 定期的に動かすためにAPIを呼び出すなどができません。
そのため、Web API化して、サーバーとして起動できるようにしておくと システムに組み込んだりしやすくなりますので、 この記事ではできるだけ最小構成でFastAPIにMLモデルを組み込んでWebAPIとして呼び出せるWebサーバーを作りたいと思います。
FastAPIについて
APIを作るために特化しており高パフォーマンス(Fast)、実装時間がFastなOSSです。 FastAPI
2022/6/28時点でPythonの軽量webフレームワークとして有名なFlaskと比較すると、
watch | folk | star | 初回リリース | |
---|---|---|---|---|
Flask | 2,154 | 15,127 | 59,378 | 2010/4/16 |
FastAPI | 589 | 3,647 | 46,651 | 2018/4/17 |
でした。 Flaskは2010年に最初のリリースがGithub上にあり、FastAPIは2018年にGithub上にリリースされました。 FastAPIは後発ということもありますので全体的にメトリックは小さいですが、それを鑑みてもStar数などは後発にも関わらず増えていることがわかります。
インストールや簡単な使い方は公式サイトに詳しく載っておりますのでそちらで実施していただければと思います 参考。
今回使う機械学習モデル
Kaggleで有名なTitanicの機械学習モデルを使います。Codeは公開されているupuruさんのこちらのCodeを参考に使わせていただきます code:upura-kaggle-tutorial-03-feature-engineering
今回は最低限の構築にしたく、使わない特徴量はコード中で削除しています。 FastAPIで構築するときも使わない特徴量の削除は必要になりますので忘れなく削除する必要があります。
こちらのコードを参考にWebサーバーにモデルを取り込むため、pickleファイルを用意します。 下記はpickleファイルを作成するためのjupyterのコードです。
import numpy as np
import pandas as pd
import pickle
from sklearn.linear_model import LogisticRegression
train = pd.read_csv('./train.csv')
test = pd.read_csv('./test.csv')
combine = [train_df, test_df]
data = pd.concat([train, test], sort=False)
data['Sex'].replace(['male','female'], [0, 1], inplace=True)
data['Embarked'].fillna(('S'), inplace=True)
data['Embarked'] = data['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}).astype(int)
data['Age'].fillna(999, inplace=True)
delete_columns = ['Name', 'PassengerId', 'SibSp', 'Parch', 'Ticket', 'Cabin', 'Fare']
data.drop(delete_columns, axis=1, inplace=True)
train = data[:len(train)]
test = data[len(train):]
y_train = train['Survived']
X_train = train.drop('Survived', axis=1)
X_test = test.drop('Survived', axis=1)
clf = LogisticRegression(penalty='l2', solver="sag", random_state=0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
with open('model.pickle', mode='wb') as fp:
pickle.dump(clf, fp)
model.pickleでモデルを出力をしています。
FastAPIで機械学習モデルをWeb API化
この作ったモデルを用いて、FastAPIでWebAPIのコードは下記になります。
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
import pandas as pd
import pickle
app = FastAPI()
clf = pickle.load(open("model.pickle", "rb"))
class Predict(BaseModel):
PassengerId: int
Pclass: int
Name: str
Sex: str
Age: int
SibSp: int
Parch: int
Ticket: str
Fare: float
Cabin: str
Embarked: str
def _titanic_predict(df):
df['Sex'].replace(['male', 'female'], [0, 1], inplace=True)
df['Age'].fillna(999, inplace=True)
df['Embarked'].fillna(('S'), inplace=True)
df['Embarked'] = df['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}).astype(int)
delete_columns = ['Name', 'PassengerId', 'SibSp',
'Parch', 'Ticket', 'Cabin', 'Fare']
df.drop(delete_columns, axis=1, inplace=True)
return clf.predict_proba(df)
@app.post("/titanic/")
def titanic(req: Predict):
df = pd.DataFrame([req.dict()])
prediction = _titanic_predict(df)
return {"res": "ok", "proba of survive": prediction[0][1]}
clf = pickle.load(open("model.pickle", "rb"))
でモデルをロードしています。 さきほど実施した特徴量の削除も忘れなく実施しています(delete_columns = …)。
uvicorn main:app --reload
上記コマンドで実行します。 テストとしてcurlでもリクエストを遅れますし、FastAPIのweb ui上からrequestのテストができます。 web ui上からテストする場合は下記のような図でテストできます。 URLは環境によって異なりますが、私が実施した環境では下記のlocalhostを指定して参照することができました。
http://127.0.0.1:8000/docs
おわりに
最小構成でFastAPIを使って機械学習モデルをWeb API化をしてみました。 もちろん実際の検証ではサーバーにデプロイして、Public IPを付与して外部公開したり、 もしきはバックエンドサーバーからしかアクセスできないように認証を設けたり、 外部からアクセスできないネットワークでのサーバーをデプロイしたりと 本番環境で実施するためには他にもやることはありますが上記だけでモデルをサービングする機能が対応しております。 Flaskなどで同様な機能をつくるとコード量が増えたり、Web UIの機能がなかったりしますので FastAPIはWeb APIを作る際に使いやすいツールかと思いますので良かったら試してみてはいかがでしょうか。