👻

Streamlitを使った機械学習サンプルアプリの作成

2023/06/07に公開

はじめに

こんにちは。株式会社アイデミーのエンジニアの和泉です。普段は、クライアント様のDXを推進するためのアプリケーションの開発業務に携わっています。

本稿では、データサイエンティストの方でも、比較的簡単にWEBアプリケーションを作成できるPythonのフレームワークであるStreamlitを利用した機械学習サンプルアプリの作成方法についてお伝えしたいと思っております。
これから、機械学習アプリを作りたいと思っている方の手助けになれば、私としても本望です。

概要

今回、ご紹介するWEBアプリケーションの概要は下記の通りです。

  • 作成機能
    • アヤメの品種予測機能
    • 予測機能に用いるモデル作成機能
      環境構築はDockerを用いて作成し、機械学習ライブラリはscikit-learnを用いました。(今回作成したソースコードは全てこちらで公開しています。)

今回は、サンプルアプリのため、機械学習を行う際に、交差検証によるアルゴリズムの最適化やグリットサーチを用いたパラメーターチューニングなどは行っておりませんので、必要な場合は、適時、scikit-learnの公式サイトなどを参照して下さい。

Streamlitとは

機械学習やデータサイエンスのためのWebアプリを簡単に作成・共有できるオープンソースのPythonライブラリです。
公式サイトはこちらになります。
機械学習エンジニアやデータサイエンティストの場合、エンジニアのようにWEBアプリケーションを作成して、アイデアを共有するのが難しいという課題がありました。
そこで、今回ご紹介するStreamlitを用いることで、フロントエンドの技術(HTML, CSS,JS)がなくとも、WEBアプリケーションを作成することが可能になります。

フォルダ構成

.
├── Dockerfile
├── LICENSE
├── README.md
├── requirements.txt
└── src
    ├── app.py
    ├── models
    │   └── test.pkl
    └── pages
        └── train.py

アプリの構成について

  • app.py

    • アヤメの品種予測画面
      • 作成したモデルを用いて、アヤメの品種を予測する。
  • train.py

    • モデル作成画面
      • アヤメの品種分類データセットを読み込んで、機械学習モデルを作成する。

開発環境

  • Docker(version: 23.0.5)
  • Python(version: 3.10.11)
  • Pythonライブラリ
    • Streamlit(version: 1.22.0)
    • pandas(version: 2.0.2)
    • scikit-learn(version: 1.2.2)

開発環境構築について

Dockerfile

Dockerfileは、以下になっています。

# ベースとなるイメージを指定
FROM python:3.10.11-slim-buster

# ディレクトリを作成し、作業用ディレクトリに指定する。
RUN mkdir /opt/app
WORKDIR /opt/app

# requirements.txtをコピーする。
COPY ./requirements.txt /opt/app/requirements.txt

# 環境変数に、アプリケーションのルートディレクトリを設定する。
ENV PYTHONPATH=/opt/app

# ライブラリをインストールする。
RUN pip install --upgrade pip && pip install -r requirements.txt && rm requirements.txt

# コンテナ起動時のコマンドを指定する。
CMD ["streamlit", "run", "./src/app.py"]

環境構築手順

開発環境方法は、以下の通りです。

  1. Dockerを起動する。
  2. GitHubからソースコードダウンロードする。
cd [アプリを保存するディレクトリ]
git clone git@github.com:ToshinoriIzumi/streamlit_sample.git
  1. Dockerイメージを作成するため、以下のコマンドを実行する。
docker build . -t streamlit_sample_app_env
  1. Dockerコンテナを作成・起動させるため、以下コマンドを実行する。
docker run -p 8501:8501 -v $(pwd)/src:/opt/app/src --rm  --name streamlit_sample_app_env -it streamlit_sample_app_env
  1. アプリを停止する場合は、キーボードで[Ctr+c]を押下する。

データセット

アプリのソースコードについて

  • app.py
import os
import pickle

import pandas as pd
import streamlit as st

st.title('アヤメの品種分類')

# モデルのファイル一覧を取得
model_list_dir = os.path.join(os.path.dirname(__file__), 'models')
model_list = os.listdir(model_list_dir)

if len(model_list) == 1:
    st.write('No model file')
else:
    model_list.remove('.keep')
    # モデルファイルの選択
    model_file_name = st.selectbox('select model file', model_list)

    # モデルの読み込み
    model_file_path = os.path.join(model_list_dir, model_file_name)
    model = pickle.load(open(model_file_path, 'rb'))

    # 予測するデータの入力
    with st.form('input_data'):
        sepal_length = st.number_input(
            label='sepal length(cm)', step=0.1, format='%.1f')
        sepal_width = st.number_input(
            label='sepal width(cm)', step=0.1, format='%.1f')
        petal_length = st.number_input(
            label='petal length(cm)', step=0.1, format='%.1f')
        petal_width = st.number_input(
            label='petal width(cm)', step=0.1, format='%.1f')
        input_data = [[sepal_length, sepal_width, petal_length, petal_width]]
        submit_button = st.form_submit_button(label='predict')

    # 予測結果の表示
    if submit_button:
        pred = model.predict(pd.DataFrame(input_data))
        if pred[0] == 0:
            st.write('pridict: setosa')
        elif pred[0] == 1:
            st.write('pridict: versicolor')
        else:
            st.write('pridict: virginica')
  • train.py
import os
import pickle

import streamlit as st

from sklearn import datasets
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler


def load_data():
    '''あやめのデータを読み込む'''
    df = datasets.load_iris()
    return df.data, df.target


def train_model(x, y):
    '''モデルの学習と評価を行う'''
    X_train, X_test, y_train, y_test = train_test_split(
        x, y, test_size=0.2, random_state=1)
    model = Pipeline([('scaler', StandardScaler()),
                     ('clf', GradientBoostingClassifier())])
    model.fit(X_train, y_train)
    st.write(
        f'f1 score: {f1_score(y_test, model.predict(X_test), average="macro")}')
    return model


st.header('モデルの作成')

# モデルファイル名の入力フォーム
with st.form('train_model'):
    file_name = st.text_input('保存するファイル名')
    submit_button = st.form_submit_button(label='train')

# モデルの学習と保存
if submit_button:
    # データの読み込み
    X, y = load_data()

    # モデルの学習と評価
    model = train_model(X, y)

    # モデルの保存
    model_file_dir = os.path.join(
        os.path.dirname(os.path.dirname(__file__)),
        'models'
    )
    model_file_path = os.path.join(model_file_dir, file_name)
    pickle.dump(model, open(model_file_path, 'wb'))

参考情報

最後に

今回、Streamlitを用いて、短時間で機械学習アプリを作成することができました。

Streamlitを用いたメリットとデメリットは以下の通りです。

  • メリット
    • Pythonのみで開発ができ、プロトタイプの作成には非常に有効である。
    • Pythonの性質やデータの可視化が簡単にでき、機械学習やデータ解析のアプリケーションと相性が良い。
  • デメリット
    • 基本的には、フロントエンドは既存のフォーマットになるため、画面のチューニング等を行う場合は、フロントエンドを始めとした技術が必要になる。

以上のメリット・デメリットより、データサイエンティストやAIエンジニアが、アイデアをユーザーに届けるために、非常に有用な技術だと思いました。
ご興味がある方は、参考にして頂けると幸いです。

Aidemy Tech Blog

Discussion