はじめに
機械学習で作成したモデルを実用化するには、システムが必要になる。もっともシンプルなシステム実装としては、学習済みモデルが API リクエストに対して推論結果をレスポンスで返す簡単な Web API が考えられる。具体的には、推論対象の CSV データをもたせた POST リクエストに対して推論結果を返すような Web API を想定している。機械学習モデルは大半が Python で構築されているため、API も Python ベースで作成することが望ましいと考え、FastAPI を用いた Web API を段階を踏んで作成していく。
まずはじめにシンプルな Web API を FastAPI で作成では、FastAPI に触れ簡単な Web API を作成した。続いて、推論器へのデータ入力部分を構築していく。推論時には DataFrame 形式でデータを扱いたいが、学習時のように保存されている CSV データを読み込む方法を想定すると、入力データを一度保存する必要が出てくるため、ストリームデータに対して準リアルタイムに推論を行うには時間がかかり効率が悪い。私が最終的に作成したい Web API は、ストリームデータに対して準リアルタイムに推論をするようなものを見据えているため、本記事では、POST リクエストで取得したデータを保存することなく直接 DataFrame に入れることを試みた。Request Files - FastAPI を参考にした。
実行環境は以下。
- Python 3.7.12
- fastapi 0.70.0
ファイルを受け取る Web API の作成
Request Files - FastAPI を参考に、ファイルを受け取るところまでを作成して確認する。
まず pip install python-multipart
でファイルを受け取るために必要なパッケージをインストールし、参考記事のコード例(以下掲載)を作成し、$ uvicorn main:app --reload
で実行する。
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
return {"filename": file.filename}
ここでは、受け取ったファイルに対してそれぞれ bytes, UploadFile の2つの型が使われている。参考記事には、UploadFile が bytes に対して以下のような優位性があるとのこと。(詳細は参考記事を参照されたい。)
- 容量の大きなファイルに適している
- 非同期インターフェイスを持っている
推論対象のデータは容量が大きいことが想定されるため、UploadFile という型を用いるのが適切だと考える。
受け取ったデータを直接 DataFrame に入力する Web API を作成
ファイルの受け取りまでは上記で確認できたため、続いてそのファイルデータの処理を検討する。以下では、受け取ったファイルを DataFrame で読み込んでサイズを返すような API を作成している。
from fastapi import FastAPI, File, UploadFile
from io import StringIO
app = FastAPI()
@app.post("/uploadfile/read")
async def dataframe_file(file: UploadFile = File(...)):
_csvdata = StringIO(str(file.file.read(), 'utf-8'))
csvdata = pd.read_csv(_csvdata)
return {"DataFrame": csvdata.shape}
pandas.read_csv ドキュメントによると、pd.read_csv()
は file-like object も読み込むことができることがわかる。
filepath_or_buffer : str, path object or file-like object
Any valid string path is acceptable. The string could be a URL. Valid URL schemes include http, ftp, s3, gs, and file. For file URLs, a host is expected. A local file could be: file://localhost/path/to/table.csv.
If you want to pass in a path object, pandas accepts any os.PathLike.
By file-like object, we refer to objects with a read() method, such as a file handle (e.g. via builtin open function) or StringIO.
また Request Files - FastAPI によると、UploadFile オブジェクトには file-like な file
アトリビュートがあるので、これに対して _csvdata = StringIO(str(file.file.read(), 'utf-8'))
のように処理することで、pd.read_csv()
で読み込むことができるようになる。
おわりに
POST リクエストで入力された CSV データをファイルとして保存することなく、DataFrame に直接入力し扱うことができる Web API を作成した。今後、実際に入力したデータで準リアルタイムに推論を行い、結果を返すような Web API の作成を試していきたい。