Skip to content

13. Web アプリへの展開

第 13 回では、これまで学んだ機械学習モデルを Web アプリケーションとして展開する方法を紹介します。

13.1 Web アプリケーションとは

13.1.1 Web アプリケーションの概要

Web アプリケーションとは、Web ブラウザを通じて利用できるアプリケーションのことです。ユーザは特別なソフトウェアをインストールすることなく、ブラウザさえあればどこからでもアプリケーションを利用できます。

Web アプリケーションの利点

  • アクセスの容易さ: ブラウザがあればどこからでもアクセス可能
  • クロスプラットフォーム: Windows、Mac、スマートフォンなど、環境を選ばない
  • 共有が簡単: URL を共有するだけで他の人も利用可能
  • メンテナンスが楽: サーバ側を更新すれば全ユーザに反映

13.1.2 機械学習モデルの Web アプリ化

機械学習モデルを Web アプリとして公開することで、以下のようなことが可能になります。

  • 実用的なサービス: モデルを実際のサービスとして提供
  • デモンストレーション: 研究成果やポートフォリオとして公開
  • フィードバック収集: ユーザからの反応を得て改善
  • API として提供: 他のシステムから利用可能

13.1.3 Python の Web フレームワーク

Python には、Web アプリケーションを構築するためのフレームワークがいくつか存在します。

フレームワーク 特徴 適用場面
Streamlit 簡単、素早くプロトタイプを作成 デモ、社内ツール
Flask 軽量、柔軟性が高い 小〜中規模の Web アプリ、API
FastAPI 高速、API 構築に特化 REST API、本格的なサービス
Django 多機能、大規模開発向け 大規模 Web アプリケーション

本講義では、StreamlitFlask を使った実装例を紹介します。

13.2 Streamlit による簡単な Web アプリ

13.2.1 Streamlit とは

Streamlit は、データサイエンス向けの Web アプリを簡単に作成できる Python ライブラリです。わずか数行のコードで、インタラクティブな Web アプリを構築できます。

Streamlit の特徴

  • 簡単: Python スクリプトを書くだけで Web アプリが作れる
  • 高速: プロトタイプを素早く作成できる
  • インタラクティブ: スライダ、ボタンなどの UI 部品が豊富
  • ホットリロード: コードを編集すると自動的に反映される

13.2.2 Streamlit のインストール

Streamlit がインストールされていない場合は、以下のコマンドでインストールします。

pip install streamlit

Web アプリケーション開発環境について

以降の説明は、ローカル環境での開発を想定しています。

  • Google Colab などのクラウドのノートブック環境では、Web アプリの開発・実行に工夫が必要となります
  • CHIKUWA Editor は現状 Web アプリ開発に対応していません

13.2.3 Streamlit の基本的な使い方

まず、簡単な Hello World アプリを作成してみましょう。

app.py
import streamlit as st

# タイトル
st.title("Hello, Streamlit!")

# テキスト
st.write("これは Streamlit で作った Web アプリです。")

# ボタン
if st.button("クリックしてください"):
    st.write("ボタンがクリックされました!")

# スライダー
value = st.slider("値を選択してください", 0, 100, 50)
st.write(f"選択された値: {value}")

このスクリプトを app.py として保存し、以下のコマンドで実行します。

streamlit run app.py

ブラウザが自動的に開き、Web アプリが表示されます(通常は http://localhost:8501)。

以下に、実際に動作する Web アプリを用意しておきました(講義期間のみアクセス可)。
https://ml-sample.ibadai.com/st1/

13.2.4 主要な Streamlit コンポーネント

Streamlit では、さまざまな UI コンポーネントを簡単に追加できます。

テキスト表示

st.title("タイトル")
st.header("ヘッダー")
st.subheader("サブヘッダー")
st.write("テキスト")
st.markdown("**太字** や *斜体* も使えます")

入力ウィジェット

# テキスト入力
text = st.text_input("テキストを入力してください")

# テキストエリア
long_text = st.text_area("長いテキストを入力してください")

# 数値入力
number = st.number_input("数値を入力してください", min_value=0, max_value=100)

# スライダー
value = st.slider("値を選択してください", 0, 100, 50)

# セレクトボックス
option = st.selectbox("選択してください", ["オプション1", "オプション2", "オプション3"])

# ボタン
if st.button("送信"):
    st.write("送信されました!")

データ表示

import pandas as pd

# DataFrame の表示
df = pd.DataFrame({
    "列1": [1, 2, 3],
    "列2": [4, 5, 6]
})
st.dataframe(df)

# テーブルの表示
st.table(df)

グラフ表示

import matplotlib.pyplot as plt

# Matplotlib のグラフ
fig, ax = plt.subplots()
ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
st.pyplot(fig)

# 簡易グラフ
st.line_chart(df)
st.bar_chart(df)

公式ドキュメント: Streamlit API Reference

以下は、上記コードの実行例です(講義期間のみアクセス可)。
https://ml-sample.ibadai.com/st2/

13.3 Streamlit で感情分析アプリを作る

13.3.1 アプリの概要

第 12 回で学んだ Sentence Transformers を使って、テキストの感情分析ができる Web アプリを作成してみましょう。

機能:

  • ユーザがテキストを入力
  • 「Positive(ポジティブ)」「Negative(ネガティブ)」を分類
  • 予測結果と確率を表示

13.3.2 モデルの準備と保存

まず、感情分析モデルを学習して保存します。

import pandas as pd
from sentence_transformers import SentenceTransformer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
import pickle

# データの読み込み
df = pd.read_csv('movie_reviews.csv')

# モデルの読み込み
model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

# ベクトル化
embeddings = model.encode(df['text'].tolist())

# ラベルを数値に変換
df['label_num'] = (df['label'] == 'positive').astype(int)

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(
    embeddings, df['label_num'],
    test_size=0.2,
    random_state=42
)

# ロジスティック回帰で学習
clf = LogisticRegression(random_state=42, max_iter=1000)
clf.fit(X_train, y_train)

# モデルの保存
with open('sentiment_model.pkl', 'wb') as f:
    pickle.dump(clf, f)

print("モデルを保存しました: sentiment_model.pkl")

13.3.3 Streamlit アプリの実装

次に、保存したモデルを読み込んで使用する Streamlit アプリを作成します。

sentiment_app.py
import streamlit as st
from sentence_transformers import SentenceTransformer
import pickle

# ページの設定
st.set_page_config(page_title="感情分析アプリ", page_icon="😊")

# タイトル
st.title("😊 感情分析アプリ")
st.write("テキストを入力すると、Positive(ポジティブ)か Negative(ネガティブ)かを判定します。")

# モデルの読み込み(キャッシュを使って1回だけ読み込む)
@st.cache_resource
def load_models():
    # Sentence Transformers モデル
    encoder = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

    # 分類モデル
    with open('sentiment_model.pkl', 'rb') as f:
        classifier = pickle.load(f)

    return encoder, classifier

# モデルの読み込み
encoder, classifier = load_models()

# テキスト入力
text_input = st.text_area(
    "テキストを入力してください",
    height=150,
    placeholder="例:この映画は本当に面白かった!"
)

# 予測ボタン
if st.button("感情を分析"):
    if text_input.strip() == "":
        st.warning("テキストを入力してください。")
    else:
        # ベクトル化
        embedding = encoder.encode([text_input])

        # 予測
        prediction = classifier.predict(embedding)[0]
        probability = classifier.predict_proba(embedding)[0]

        # 結果の表示
        st.subheader("分析結果")

        if prediction == 1:
            st.success("😊 Positive(ポジティブ)")
            st.progress(probability[1])
            st.write(f"確率: {probability[1]:.2%}")
        else:
            st.error("😞 Negative(ネガティブ)")
            st.progress(probability[0])
            st.write(f"確率: {probability[0]:.2%}")

        # 詳細情報
        with st.expander("詳細情報を表示"):
            st.write(f"Positive の確率: {probability[1]:.2%}")
            st.write(f"Negative の確率: {probability[0]:.2%}")

# サイドバー
st.sidebar.header("ℹ️ このアプリについて")
st.sidebar.write("""
このアプリは、機械学習を使って日本語テキストの感情を分析します。

**使用技術**
- Sentence Transformers
- Logistic Regression
- Streamlit
""")

13.3.4 アプリの実行

以下のコマンドでアプリを起動します。

streamlit run sentiment_app.py

ブラウザで http://localhost:8501 にアクセスすると、感情分析アプリが表示されます。

以下に、完成版を用意しておきました(講義期間のみアクセス可)。
https://ml-sample.ibadai.com/st3/

13.3.5 キャッシュの活用

@st.cache_resource デコレータを使うことで、モデルの読み込みを 1 回だけ実行し、結果をキャッシュできます。これにより、アプリの起動が高速になります。

@st.cache_resource
def load_models():
    # 時間のかかる処理(モデルの読み込みなど)
    return model

キャッシュの種類:

デコレータ 用途
@st.cache_resource モデル、DB 接続などのグローバルなリソース
@st.cache_data データの読み込みや変換処理

13.4 Flask による Web アプリ

13.4.1 Flask とは

Flask は、Python で Web アプリケーションを構築するための軽量なフレームワークです。Streamlit よりも柔軟性が高く、より本格的な Web アプリや REST API を構築できます。

Flask の特徴

  • 軽量: 必要最小限の機能のみを提供
  • 柔軟: 拡張性が高く、カスタマイズしやすい
  • REST API: API サーバとして利用できる
  • 豊富なエコシステム: 多数の拡張ライブラリが存在

13.4.2 Flask のインストール

pip install flask

13.4.3 Flask の基本的な使い方

最も簡単な Flask アプリの例を見てみましょう。

hello_flask.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, Flask!"

if __name__ == '__main__':
    app.run(debug=True)

このスクリプトを実行します。

python hello_flask.py

ブラウザで http://localhost:5000 にアクセスすると、"Hello, Flask!" と表示されます。

13.4.4 Flask の基本構造

Flask アプリは、ルーティング(URL とハンドラ関数の対応付け)を基本としています。

from flask import Flask, request, render_template

app = Flask(__name__)

# ルート(トップページ)
@app.route('/')
def index():
    return "トップページ"

# 別のページ
@app.route('/about')
def about():
    return "About ページ"

# パラメータを受け取る
@app.route('/user/<name>')
def user(name):
    return f"Hello, {name}!"

# POST リクエストを処理
@app.route('/submit', methods=['POST'])
def submit():
    data = request.form['data']
    return f"受け取ったデータ: {data}"

if __name__ == '__main__':
    app.run(debug=True)

13.4.5 テンプレートエンジン

Flask では、HTML テンプレートを使って動的なページを生成できます。テンプレートには Jinja2 というテンプレートエンジンを使用します。

ディレクトリ構造

project/
├── app.py
└── templates/
    └── index.html

テンプレート(templates/index.html)

<!DOCTYPE html>
<html>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
    <h1>{{ message }}</h1>
  </body>
</html>

Flask アプリ(app.py)

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html',
                           title="My App",
                           message="Hello, Flask!")

if __name__ == '__main__':
    app.run(debug=True)

13.5 Flask で感情分析 API を作る

13.5.1 REST API とは

REST API は、HTTP リクエスト/レスポンスを使ってデータをやり取りする仕組みです。Web アプリや他のプログラムから機械学習モデルを利用できるようになります。

REST API の利点

  • プログラムから利用可能: 他のアプリケーションから呼び出せる
  • 言語非依存: どんなプログラミング言語からでも利用可能
  • スケーラブル: サーバを増やして処理能力を向上できる

13.5.2 感情分析 API の実装

Flask を使って、感情分析の REST API を実装してみましょう。

api.py
from flask import Flask, request, jsonify
from sentence_transformers import SentenceTransformer
import pickle

app = Flask(__name__)

# モデルの読み込み
print("モデルを読み込んでいます...")
encoder = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')

with open('sentiment_model.pkl', 'rb') as f:
    classifier = pickle.load(f)

print("モデルの読み込みが完了しました。")

@app.route('/')
def index():
    return """
    <h1>感情分析 API</h1>
    <p>使い方:POST /predict にテキストを送信してください。</p>
    <p>例:curl -X POST -H "Content-Type: application/json" -d '{"text":"この映画は面白かった"}' http://localhost:5000/predict</p>
    """

@app.route('/predict', methods=['POST'])
def predict():
    # リクエストから JSON データを取得
    data = request.get_json()

    # テキストの取得
    if 'text' not in data:
        return jsonify({'error': 'テキストが指定されていません'}), 400

    text = data['text']

    if not text.strip():
        return jsonify({'error': 'テキストが空です'}), 400

    # ベクトル化
    embedding = encoder.encode([text])

    # 予測
    prediction = classifier.predict(embedding)[0]
    probability = classifier.predict_proba(embedding)[0]

    # 結果を返す
    result = {
        'text': text,
        'sentiment': 'positive' if prediction == 1 else 'negative',
        'confidence': float(probability[prediction]),
        'probabilities': {
            'positive': float(probability[1]),
            'negative': float(probability[0])
        }
    }

    return jsonify(result)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

13.5.3 API の使い方

API の起動:

python api.py

curl コマンドでテスト:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"text":"この映画は本当に素晴らしかった!"}' \
  http://localhost:5000/predict

レスポンス例

{
  "text": "この映画は本当に素晴らしかった!",
  "sentiment": "positive",
  "confidence": 0.92,
  "probabilities": {
    "positive": 0.92,
    "negative": 0.08
  }
}

Python からの利用

import requests

url = 'http://localhost:5000/predict'
data = {'text': 'この映画はつまらなかった'}

response = requests.post(url, json=data)
result = response.json()

print(result)

13.5.4 Flask アプリと HTML フォーム

Flask アプリに HTML フォームを追加して、ブラウザから直接利用できるようにしてみましょう。

ディレクトリ構造

project/
├── app.py
├── sentiment_model.pkl
└── templates/
    ├── index.html
    └── result.html

app.py

from flask import Flask, render_template, request
from sentence_transformers import SentenceTransformer
import pickle

app = Flask(__name__)

# モデルの読み込み
encoder = SentenceTransformer('sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2')
with open('sentiment_model.pkl', 'rb') as f:
    classifier = pickle.load(f)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/analyze', methods=['POST'])
def analyze():
    text = request.form['text']

    if not text.strip():
        return render_template('index.html', error="テキストを入力してください")

    # ベクトル化と予測
    embedding = encoder.encode([text])
    prediction = classifier.predict(embedding)[0]
    probability = classifier.predict_proba(embedding)[0]

    sentiment = 'Positive' if prediction == 1 else 'Negative'
    confidence = probability[prediction]

    return render_template('result.html',
                           text=text,
                           sentiment=sentiment,
                           confidence=confidence,
                           prob_positive=probability[1],
                           prob_negative=probability[0])

if __name__ == '__main__':
    app.run(debug=True)

templates/index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>感情分析アプリ</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        max-width: 600px;
        margin: 50px auto;
        padding: 20px;
      }
      textarea {
        width: 100%;
        height: 150px;
        padding: 10px;
        font-size: 14px;
      }
      button {
        background-color: #4caf50;
        color: white;
        padding: 10px 20px;
        border: none;
        cursor: pointer;
        font-size: 16px;
      }
      button:hover {
        background-color: #45a049;
      }
      .error {
        color: red;
      }
    </style>
  </head>
  <body>
    <h1>😊 感情分析アプリ</h1>
    <p>テキストを入力すると、ポジティブかネガティブかを判定します。</p>

    {% if error %}
    <p class="error">{{ error }}</p>
    {% endif %}

    <form method="POST" action="/analyze">
      <textarea
        name="text"
        placeholder="テキストを入力してください..."
      ></textarea>
      <br /><br />
      <button type="submit">分析する</button>
    </form>
  </body>
</html>

templates/result.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>分析結果</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        max-width: 600px;
        margin: 50px auto;
        padding: 20px;
      }
      .result {
        padding: 20px;
        border-radius: 5px;
        margin: 20px 0;
      }
      .positive {
        background-color: #d4edda;
        border: 1px solid #c3e6cb;
      }
      .negative {
        background-color: #f8d7da;
        border: 1px solid #f5c6cb;
      }
      a {
        color: #007bff;
        text-decoration: none;
      }
    </style>
  </head>
  <body>
    <h1>分析結果</h1>

    <div
      class="result {% if sentiment == 'Positive' %}positive{% else %}negative{% endif %}"
    >
      <h2>{{ sentiment }}</h2>
      <p><strong>入力テキスト:</strong> {{ text }}</p>
      <p><strong>信頼度:</strong> {{ "%.2f"|format(confidence * 100) }}%</p>
      <hr />
      <p>Positive: {{ "%.2f"|format(prob_positive * 100) }}%</p>
      <p>Negative: {{ "%.2f"|format(prob_negative * 100) }}%</p>
    </div>

    <a href="/">← 戻る</a>
  </body>
</html>

13.6 デプロイ(公開)の基礎

13.6.1 デプロイとは

デプロイ(Deploy)とは、作成したアプリケーションをインターネット上のサーバに配置し、誰でもアクセスできるようにすることです。

13.6.2 主要なデプロイ先

サービス 特徴 無料プラン
Streamlit Community Cloud Streamlit 専用、簡単 あり(制限付き)
Render Flask/FastAPI など幅広く対応 あり(制限付き)
Heroku 老舗、多機能 有料のみ
Google Cloud Run コンテナベース、スケーラブル 無料枠あり
AWS (EC2, Lambda) 柔軟性が高い、学習コストも高い 無料枠あり(1 年間)
自宅サーバ 自由度が最も高い サーバ費用が必要

13.6.3 Streamlit Community Cloud へのデプロイ

Streamlit アプリを最も簡単に公開する方法は、Streamlit Community Cloud を使うことです。

手順

  1. GitHub にコードをアップロード

  2. リポジトリを作成

  3. app.pyrequirements.txt(必要なライブラリ)、モデルファイルをアップロード

  4. requirements.txt の作成

requirements.txt
streamlit
sentence-transformers
scikit-learn
  1. Streamlit Community Cloud に登録

  2. Streamlit Community Cloud にアクセス

  3. GitHub アカウントでログイン

  4. アプリをデプロイ

  5. "New app" をクリック
  6. GitHub リポジトリを選択
  7. デプロイするファイル(app.py)を指定
  8. "Deploy!" をクリック

数分でアプリが公開され、URL が発行されます。

13.6.4 注意点

モデルファイルのサイズ

  • 大きなモデルファイルは GitHub にアップロードできません(100MB 制限)
  • 対処法: モデルの軽量化 / Git LFS の使用 / クラウドストレージから読み込む

環境変数

  • API キーなどの秘密情報は、環境変数として設定する
  • Streamlit では st.secrets を使って安全に管理できる

13.7 チャレンジ問題

チャレンジ 13-1: 画像分類 Web アプリの作成

チャレンジ 13-1

Streamlit を使って、画像分類(例: MNIST 手書き数字認識)の Web アプリを作成してください。

タスク:

  1. ユーザが画像をアップロードできるようにする
  2. アップロードされた画像を分類モデルで予測
  3. 予測結果(クラスと確率)を表示

ヒント:

  • st.file_uploader() で画像をアップロード
  • PIL で画像を読み込み
  • st.image() で画像を表示

チャレンジ 13-2: Flask API の拡張

チャレンジ 13-2

13.5 で作成した Flask API を拡張して、複数の文を一度に分析できる機能を追加してください。

タスク:

  1. /predict_batch エンドポイントを作成
  2. リクエストで複数の文を受け取る(JSON 配列)
  3. 各文の感情分析結果をまとめて返す

入力例:

{
  "texts": [
    "この映画は素晴らしかった",
    "退屈な映画だった",
    "普通の映画だった"
  ]
}

出力例:

{
  "results": [
    {"text": "この映画は素晴らしかった", "sentiment": "positive", "confidence": 0.95},
    {"text": "退屈な映画だった", "sentiment": "negative", "confidence": 0.88},
    {"text": "普通の映画だった", "sentiment": "negative", "confidence": 0.62}
  ]
}

13.8 まとめ

本章では、機械学習モデルを Web アプリケーションとして展開する方法について学びました。

第 13 回のまとめ

Web アプリケーション

  • ブラウザで利用できるアプリケーション
  • アクセスしやすく、共有が簡単
  • Python の Web フレームワークを使って構築

Streamlit

  • データサイエンス向けの Web アプリフレームワーク
  • 簡単に素早くプロトタイプを作成できる
  • st.text_input(), st.button(), st.write() などの UI 部品
  • @st.cache_resource でモデルをキャッシュ

Flask

  • 軽量で柔軟な Web フレームワーク
  • ルーティングで URL とハンドラを対応付け
  • テンプレートエンジン(Jinja2)で HTML を生成
  • REST API の構築に適している

REST API

  • HTTP リクエスト/レスポンスでデータをやり取り
  • プログラムから機械学習モデルを利用可能
  • JSON 形式でデータを送受信

デプロイ

  • アプリをインターネット上に公開
  • Streamlit Community Cloud: Streamlit アプリを簡単に公開
  • Render, Heroku, Google Cloud Run など様々な選択肢

実装のポイント

  • モデルを pickle で保存・読み込み
  • キャッシュを活用して高速化
  • エラーハンドリングを適切に行う
  • 環境変数で秘密情報を管理

13.9 講義全体の総括

本講義「機械学習」では、全 13 回を通じて、機械学習の基礎から実践的な応用までを学んできました。

学んできたこと

テーマ 内容
1 ガイダンス 講義の概要、機械学習の全体像
2 Python 入門 プログラミングの基礎
3 データ可視化 Matplotlib によるデータの可視化
4 機械学習の基礎 教師あり学習、訓練とテスト、評価指標
5 回帰モデル 単回帰分析、重回帰分析
6 分類モデル ロジスティック回帰、決定木、ランダムフォレスト
7 画像処理 ① 画像データの基礎、読み込み・表示・変換
8 画像処理 ② 古典的な特徴抽出(エッジ検出、HOG など)
9 画像処理 ③ 画像分類の実践
10 自然言語処理 ① テキストの前処理、形態素解析
11 自然言語処理 ② Bag-of-Words、TF-IDF による文書分類
12 自然言語処理 ③ Sentence Transformers によるテキストのベクトル化
13 Web アプリへの展開 Streamlit、Flask による機械学習モデルの公開

機械学習プロジェクトの流れ

本講義で学んだ内容を組み合わせることで、以下のような機械学習プロジェクトの一連の流れを実践できます。

1. 問題の定義
2. データの収集・整理
3. データの可視化・探索(第 3 回)
4. 特徴量の抽出・前処理(第 7〜12 回)
5. モデルの選択・学習(第 4〜6 回)
6. モデルの評価・改善(第 4〜6 回)
7. デプロイ・公開(第 13 回)

今後の学習に向けて

本講義では機械学習の基礎を学びました。興味のある方は、以下のようなトピックについても学んでみてください。

  • ディープラーニング: ニューラルネットワーク、CNN、RNN、Transformer
  • 大規模言語モデル(LLM): GPT、BERT、LLaMA などの活用
  • 強化学習: ゲーム AI、ロボット制御
  • MLOps: 機械学習モデルの運用・管理
  • 倫理と公平性: AI の社会的影響、バイアスへの対処

機械学習は日々進化している分野です。本講義で学んだ基礎を土台に、引き続き学習を続けてください。