Panel応用編 第9回: Panelと機械学習モデルの連携 (後半)

Python
この記事は約16分で読めます。

こんにちは、JS2IIUです。機械学習の結果を表示するためにPanelを使う事例紹介その2です。よろしくお願いします。

TensorFlowを使った機械学習モデルの統合

前回の前半に続いて今回はTensorFlowを使ってディープラーニングモデルを訓練し、Panelアプリに統合する方法を紹介します。ここでは、手書き数字の画像を分類するMNISTデータセットを使用して、画像分類モデルを作成し、それをPanelアプリケーションで使います。

TensorFlowでのモデル訓練

まず、TensorFlowを使ってMNISTデータセットを読み込み、シンプルなニューラルネットワークモデルを訓練します。最初にTensorFlowとKerasをインストールします。これは少し時間がかかります。

pip install tensorflow
pip install keras

こちらのプログラムの実行も少し時間がかかります。

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

# MNISTデータセットの読み込み
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# データの正規化
X_train, X_test = X_train / 255.0, X_test / 255.0

# シンプルなニューラルネットワークモデルの構築
model = Sequential([
    Flatten(input_shape=(28, 28)),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')
])

# モデルのコンパイルと訓練
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=5)
  • mnist.load_data() を使って、手書き数字のデータセットを読み込みます。画像は28×28ピクセルのグレースケール画像で、それぞれ0から9の数字が含まれています。
  • データは255.0で割って正規化し、ニューラルネットワークに適した形式に変換しています。
  • Sequential モデルを構築し、Flatten レイヤーで画像データを一次元化し、Dense レイヤーを使用して分類タスクを実行するシンプルなニューラルネットワークを定義しています。

TensorFlowモデルのPanel統合

次に、手書き数字の画像を入力として予測を行うPanelアプリを作成します。ユーザーがアップロードした画像を使い、モデルがその画像を分類します。

import numpy as np
import panel as pn
from PIL import Image

pn.extension()

# 画像の入力フィールド
image_input = pn.widgets.FileInput(name='Upload an Image')

# 予測結果の表示
result_pane = pn.pane.Markdown("## Prediction: ")

# 画像を処理して予測を行う関数
def predict_image(event):
    if image_input.value is not None:
        image = Image.open(image_input.file).convert('L').resize((28, 28))
        image_data = np.array(image) / 255.0
        image_data = image_data.reshape(1, 28, 28)
        prediction = np.argmax(model.predict(image_data), axis=1)[0]
        result_pane.object = f"## Prediction: {prediction}"

# ボタンクリックで予測実行
predict_button = pn.widgets.Button(name='Predict')
predict_button.on_click(predict_image)

# レイアウトの作成
layout = pn.Column(
    "## MNIST Image Classification",
    image_input,
    predict_button,
    result_pane
)

layout.servable()
pn.serve(layout)
  • FileInput ウィジェットを使用して、ユーザーがアップロードした画像を受け取ります。
  • 画像がアップロードされると、predict_image() 関数で画像を28×28ピクセルにリサイズし、モデルに入力します。
  • 予測結果はMarkdown パネルに表示され、数字がリアルタイムで分類されます。

このアプリケーションでは、ユーザーがアップロードした手書き数字の画像に対してリアルタイムで分類を行うことができます。

あれ、ちょっと変ですね・・・

PyTorchを使った機械学習モデルの統合

最後に、PyTorchを使って機械学習モデルをPanelアプリに統合する方法を紹介します。ここでは、PyTorchを使った線形回帰モデルの訓練と、そのモデルを使って予測を行うPanelアプリを作成します。

PyTorchでのモデル訓練

まず、PyTorchでシンプルな線形回帰モデルを作成し、訓練します。

import torch
import torch.nn as nn
import torch.optim as optim

# ダミーデータの作成
X_train = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y_train = torch.tensor([[2.0], [4.0], [6.0], [8.0]])

# シンプルな線形モデルの定義
class LinearRegressionModel(nn.Module):
    def __init__(self):
        super(LinearRegressionModel, self).__init__()
        self.linear = nn.Linear(1, 1)

    def forward(self, x):
        return self.linear(x)

model = LinearRegressionModel()

# 損失関数とオプティマイザの定義
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# モデルの訓練
for epoch in range(100):
    optimizer.zero_grad()
    outputs = model(X_train)
    loss = criterion(outputs, y_train)
    loss.backward()
    optimizer.step()
  • torch.tensor() を使って、訓練用データとターゲットデータを定義します。
  • LinearRegressionModel クラスでシンプルな線形回帰モデルを定義し、1つの入力に対して1つの出力を予測するモデルを作成します。
  • MSELoss() を使用して損失関数を定義し、勾配降下法 (SGD) を使ってモデルを訓練します。

PyTorchモデルのPanel統合

次に、訓練済みの線形回帰モデルを使って予測を行うPanelアプリを作成します。

import panel as pn

pn.extension()

# 入力ウィジェットの作成
x_input = pn.widgets.FloatSlider(name='Input Value', start=0.0, end=5.0, step=0.1, value=1.0)

# 予測結果を表示するためのパネル
prediction_result = pn.pane.Markdown("## Prediction: ")

# 予測を実行する関数
def update_prediction(event):
    input_value = torch.tensor([[x_input.value]])
    prediction = model(input_value).item()
    prediction_result.object = f"## Prediction: {prediction:.2f}"

# 予測ボタンの作成
predict_button = pn.widgets.Button(name='Predict')

# ボタンクリック時に予測を実行
predict_button.on_click(update_prediction)

# レイアウトの作成
layout = pn.Column(
    "## PyTorch Linear Regression",
    x_input,
    predict_button,
    prediction_result
)

layout.servable()
pn.serve(layout)
  • FloatSlider ウィジェットを使って、ユーザーが入力値を指定できるインターフェースを作成します。
  • update_prediction() 関数で、スライダーからの入力値をPyTorchモデルに渡し、予測結果を計算して表示します。

このアプリでは、PyTorchの線形回帰モデルを使って、リアルタイムで予測を行うことができます。

まとめ

後半では、TensorFlowとPyTorchを使った機械学習モデルをPanelアプリケーションに統合する方法を学びました。TensorFlowでは手書き数字の画像を分類し、PyTorchでは線形回帰モデルを使ってリアルタイムで予測を行うインターフェースを構築しました。これにより、Panelアプリケーションでの機械学習モデルの応用範囲が大幅に広がります。

次回は、Panelを活用したデータサイエンスパイプラインの構築について解説します。お楽しみに!

補足(1) TensorFlowのサンプルプログラム解説

# import os
# os.environ["KERAS_BACKEND"] = "jax"

import tensorflow as tf

from keras._tf_keras.keras.datasets import mnist
from keras._tf_keras.keras.models import Sequential
from keras._tf_keras.keras.layers import Dense, Flatten

# from tensorflow.keras.datasets import mnist
# from keras.models import Sequential
# from keras.layers import Dense, Flatten
from io import BytesIO


# MNISTデータセットの読み込み
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# データの正規化
X_train, X_test = X_train / 255.0, X_test / 255.0

# シンプルなニューラルネットワークモデルの構築
model = Sequential([
    Flatten(input_shape=(28, 28)),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')
])

# モデルのコンパイルと訓練
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=5)


import numpy as np
import panel as pn
from PIL import Image

pn.extension()

# 画像の入力フィールド
image_input = pn.widgets.FileInput(name='Upload an Image')

# 予測結果の表示
result_pane = pn.pane.Markdown("## Prediction: ")

# 画像を処理して予測を行う関数
def predict_image(event):
    if image_input.value is not None:
        # 修正部分: バイナリデータをBytesIOで処理
        image = Image.open(BytesIO(image_input.value)).convert('L').resize((28, 28))
        image_data = np.array(image) / 255.0
        image_data = image_data.reshape(1, 28, 28)
        prediction = np.argmax(model.predict(image_data), axis=1)[0]
        result_pane.object = f"## Prediction: {prediction}"

# ボタンクリックで予測実行
predict_button = pn.widgets.Button(name='Predict')
predict_button.on_click(predict_image)

# レイアウトの作成
layout = pn.Column(
    "## MNIST Image Classification",
    image_input,
    predict_button,
    result_pane
)

layout.servable()
pn.serve(layout)

このプログラムは、Keras(TensorFlowバックエンドを使用)で構築されたシンプルなニューラルネットワークモデルを利用し、MNISTデータセットの手書き数字認識を行います。また、Panelを使ってWebアプリケーションを作成し、ユーザーがアップロードした画像に対して手書き数字の分類予測を行う仕組みになっています。以下に各部分の詳細を説明します。

1. Kerasバックエンドの設定

os.environ["KERAS_BACKEND"] = "jax"
  • Kerasのバックエンドとしてjaxを設定しています。これは、Kerasが内部的に使用する計算エンジンをTensorFlowからjaxに切り替えるための設定です。jaxはGoogleが開発した自動微分と高速な数値計算ライブラリです。ただし、現在のコードではTensorFlowベースで進めています。

2. 必要なライブラリのインポート

import tensorflow as tf
from keras._tf_keras.keras.datasets import mnist
from keras._tf_keras.keras.models import Sequential
from keras._tf_keras.keras.layers import Dense, Flatten
  • tensorflowkerasTensorFlowの一部)を使用してニューラルネットワークを構築し、データの前処理やモデルの訓練を行います。

3. MNISTデータセットの読み込みと前処理

(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train, X_test = X_train / 255.0, X_test / 255.0
  • mnist.load_data()を使用して、MNISTデータセットをロードします。MNISTは0から9までの手書き数字の画像(28×28ピクセル)と対応するラベルが含まれたデータセットです。
  • ピクセル値は0から255の範囲ですが、ニューラルネットワークの訓練効率を上げるために、これを0から1の範囲に正規化しています。

4. ニューラルネットワークの構築

model = Sequential([
    Flatten(input_shape=(28, 28)),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')
])
  • Sequentialモデルを使用して、層を順番に積み重ねています。
  • Flatten: 28×28の画像を1次元のベクトルに変換します(784個の入力ノードに相当)。
  • Dense(128): 128ユニットの全結合層で、活性化関数にrelu(Rectified Linear Unit)を使用。これは非線形性を導入します。
  • Dense(10): 出力層で、10クラス(数字0-9)を分類します。softmax活性化関数を使用して、各クラスに対する確率を出力します。

5. モデルのコンパイルと訓練

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=5)
  • モデルをコンパイルします。adamオプティマイザと損失関数(sparse_categorical_crossentropy)を使用し、評価指標はaccuracyを指定しています。
  • 訓練データを5エポックにわたってモデルにフィットさせ、モデルが学習します。

6. PanelによるWebインターフェースの構築

import panel as pn
from PIL import Image
pn.extension()
  • panelを使ってWebインターフェースを構築しています。pn.extension()でPanelの拡張機能を有効にします。
  • PIL(Python Imaging Library)を使用して、ユーザーがアップロードした画像を処理します。

7. 画像のアップロードと予測

image_input = pn.widgets.FileInput(name='Upload an Image')
result_pane = pn.pane.Markdown("## Prediction: ")
  • FileInputウィジェットで画像ファイルのアップロードを受け付けます。
  • Markdownパネルで予測結果を表示するためのスペースを確保します。

8. 予測関数

def predict_image(event):
    if image_input.value is not None:
        image = Image.open(BytesIO(image_input.value)).convert('L').resize((28, 28))
        image_data = np.array(image) / 255.0
        image_data = image_data.reshape(1, 28, 28)
        prediction = np.argmax(model.predict(image_data), axis=1)[0]
        result_pane.object = f"## Prediction: {prediction}"
  • ユーザーがアップロードした画像を受け取り、MNISTモデルと同様に28×28のグレースケール画像に変換します。
  • 正規化(255.0で割る)を行い、ニューラルネットワークに入力できる形式に整形します(1×28×28)。
  • model.predict()を使って画像の予測を行い、その結果(0から9の数字)をresult_paneに表示します。

9. 予測ボタンの設定

predict_button = pn.widgets.Button(name='Predict')
predict_button.on_click(predict_image)
  • Buttonウィジェットを作成し、ユーザーがクリックするとpredict_image関数が実行されます。

10. レイアウトの構築とアプリの起動

layout = pn.Column(
    "## MNIST Image Classification",
    image_input,
    predict_button,
    result_pane
)

layout.servable()
pn.serve(layout)
  • pn.Columnを使って、インターフェースのレイアウトを構築しています。
  • pn.serve()でこのレイアウトをWebアプリケーションとして起動します。

全体の流れ

  1. モデルがMNISTデータセットで訓練されます。
  2. ユーザーが手書き数字の画像をアップロードします。
  3. 画像は前処理され、訓練済みモデルで予測が行われます。
  4. 結果がWebインターフェースに表示されます。

コメント

タイトルとURLをコピーしました