【犬猫判定】AIを実装したWebアプリをデプロイするまでの流れ

AI・プログラミング

みなさんこんにちは。さとうじょうゆです。

最近AIについて学んでいることもあり、実際に自分で犬か猫の写真をアップロードするとそれがどちらか判定してくれるアプリを作ったので、その流れを皆さんに紹介したいと思います。

あくまで今回は流れだけ紹介します。本当に自分で作ってみたいときには、この記事を参考にしながら、ChatGPTとかに聞きながらやってみてください。

これが実際に作ったものになります。

さとじょくん
さとじょくん

写真に写っているのが、犬か猫かをAIの力で判定してくれているね!

AI実装Webアプリ開発手順
  • STEP1
    データ収集
  • STEP2
    データの前処理
  • STEP3
    モデル設計とトレーニング
  • STEP4
    モデルのエクスポート
  • STEP5
    Webアプリケーションの開発
  • STEP6
    デプロイメント

基本的にはこの様な流れで作業していきます。

データ収集

データ収集の方法
  • webスクレイピング
  • 公開データセットの利用
さとじょくん
さとじょくん

webスクレイピングで一から犬猫の画像データを集めるのも面倒なので、今回は公開データセットを利用するよ。

今回は、AIコンペを実施しているkaggleのデータセットを利用するにことにしました。

kaggleから、お好みのデータセットをダウンロードしましょう。

import kaggle

# APIコマンドに従ってデータセットをダウンロード
!kaggle competitions download -c dogs-vs-cats

データの前処理

データの前処理には、numpyやpandasが便利です。

今回は次の様な順番でデータの前処理をしました。

  1. 画像の読み込み: OpenCVやPILを使用して画像データを読み込みます。
  2. ラベルのエンコーディング: 犬と猫のラベルをエンコーディング(例: 犬=0, 猫=1)します。
  3. 画像の正規化: 画像データを正規化します(ピクセル値を0~1の範囲にスケーリング)。
  4. データセットの分割: データを訓練セットと検証セットに分割します。
import cv2
import numpy as np
import os
from sklearn.model_selection import train_test_split
from tensorflow.keras.utils import to_categorical

# 画像データとラベルを格納するリスト
data = []
labels = []

# 画像のサイズ
img_size = 128

# 画像データのパス
data_dir = "/Users/yourname/dogs-vs-cats/train"

# 画像データの読み込みとラベルの作成
for img_name in os.listdir(data_dir):
    try:
        img_path = os.path.join(data_dir, img_name)
        img = cv2.imread(img_path)
        
        # 画像のリサイズと正規化
        img = cv2.resize(img, (img_size, img_size))
        img = img / 255.0
        
        data.append(img)
        
        # ラベルのエンコーディング
        if "dog" in img_name:
            labels.append(0)
        else:
            labels.append(1)
    except Exception as e:
        print(e)

# NumPy配列に変換
data = np.array(data)
labels = np.array(labels)

# ラベルをone-hotエンコーディング
labels = to_categorical(labels)

# データを訓練セットと検証セットに分割
X_train, X_val, y_train, y_val = train_test_split(data, labels, test_size=0.2, random_state=42)

モデル設計とトレーニング

ここからは、ここまでで集めて整理した写真データを使って犬と猫を判定するモデルを作成していきます。

今回は、Keras(TensorFlowの一部)を使用してシンプルな畳み込みニューラルネットワーク(CNN)モデルを設計することにします。

さとじょくん
さとじょくん

詳しくは深層学習を勉強してみよう!

import tensorflow as tf
from tensorflow.keras import layers, models

model = models.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(128, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(512, activation='relu'),
    layers.Dense(1, activation='sigmoid')  # 2クラス分類なのでsigmoidを使用
])

# ここでオプティマイザーを指定する部分を修正します
model.compile(loss='binary_crossentropy',
              optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=1e-4),
              metrics=['accuracy'])

次に、モデルのトレーニングに使用する写真を保持しておくディレクトリを作りましょう。

import os
import shutil
import random

# 基本ディレクトリのパス
base_dir = '/Users/yourname/dogs-vs-cats/train'

# トレーニングデータとバリデーションデータを保存するディレクトリを作成
train_dir = os.path.join(base_dir, 'train2')
validation_dir = os.path.join(base_dir, 'validation')

# 猫と犬の画像を保存するディレクトリをそれぞれ作成
os.makedirs(os.path.join(train_dir, 'cats'))
os.makedirs(os.path.join(train_dir, 'dogs'))
os.makedirs(os.path.join(validation_dir, 'cats'))
os.makedirs(os.path.join(validation_dir, 'dogs'))

# トレーニング用画像の移動
for i in range(1000):  # ここでは例として1000枚をトレーニングデータとしていますが、数を調整してください
    shutil.move(os.path.join(base_dir, f'cat.{i}.jpg'), os.path.join(train_dir, 'cats'))
    shutil.move(os.path.join(base_dir, f'dog.{i}.jpg'), os.path.join(train_dir, 'dogs'))

# バリデーション用画像の移動
for i in range(1000, 1200):  # ここでは例として200枚をバリデーションデータとしていますが、数を調整してください
    shutil.move(os.path.join(base_dir, f'cat.{i}.jpg'), os.path.join(validation_dir, 'cats'))
    shutil.move(os.path.join(base_dir, f'dog.{i}.jpg'), os.path.join(validation_dir, 'dogs'))

画像データをモデルにフィードする前に、前処理およびデータオーギュメンテーションを行います。

データオーギュメンテーションとは、簡単にいうとすでにあるデータを拡大縮小したり並行移動させたりしたりしてさらにデータ数を増やすことです。

さとじょくん
さとじょくん

大量の学習データが必要なAIモデルの作成に必要なノウハウだね!

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 画像のオーギュメンテーション
train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
)

# テストデータはオーギュメンテーションしない(ただし、正規化は行う)
test_datagen = ImageDataGenerator(rescale=1./255)

train_dir = '/Users/yourname/dogs-vs-cats/train/train2'

train_generator = train_datagen.flow_from_directory(
    train_dir,  # トレーニングデータのディレクトリ
    target_size=(150, 150),  # すべての画像を150x150にリサイズ
    batch_size=32,
    class_mode='binary'  # binary_crossentropyを使用しているため、binaryラベルが必要
)

validation_dir = '/Users/yourname/dogs-vs-cats/train/validation'

validation_generator = test_datagen.flow_from_directory(
    validation_dir,
    target_size=(150, 150),
    batch_size=32,
    class_mode='binary'
)

モデルをトレーニングしましょう!(DeepLearningを勉強しましょう)

import os

train_cats_dir = '/Users/yourname/dogs-vs-cats/train/train2/cats'
train_dogs_dir = '/Users/yourname/dogs-vs-cats/train/train2/dogs'
validation_cats_dir = '/Users/yourname/dogs-vs-cats/train/validation/cats'
validation_dogs_dir = '/Users/yourname/dogs-vs-cats/train/validation/dogs'

train_cat_fnames = os.listdir(train_cats_dir)
train_dog_fnames = os.listdir(train_dogs_dir)
validation_cat_fnames = os.listdir(validation_cats_dir)
validation_dog_fnames = os.listdir(validation_dogs_dir)

total_train = len(train_cat_fnames) + len(train_dog_fnames)
total_val = len(validation_cat_fnames) + len(validation_dog_fnames)

batch_size = 32  # あるいはお使いのバッチサイズに設定してください
epochs = 100

steps_per_epoch = total_train // batch_size
validation_steps = total_val // batch_size

# モデルトレーニング
history = model.fit(
    train_generator,
    steps_per_epoch=steps_per_epoch,  # 以前の値の代わりにこれを使用
    epochs=epochs,
    validation_data=validation_generator,
    validation_steps=validation_steps  # 以前の値の代わりにこれを使用
)

モデルのエクスポート

モデルがトレーニングされたら、ファイルとしてエクスポートし、後で使用またはデプロイメントできるようにします。

# モデルをHDF5ファイルとして保存
model.save('cats_vs_dogs.h5')

また、TensorFlow ServingやTFLiteなどで使用するためにSavedModelフォーマットで保存することも可能です。

# SavedModelフォーマットでモデルを保存
model.save('cats_vs_dogs_saved_model')

Webアプリケーションの開発

ここからは、Webアプリケーションのフロントエンドとバックエンドを作っていきましょう!

まずは、バックエンドです。

バックエンドはFlaskを使用して作成します。FlaskはPythonで書かれた軽量なWebフレームワークで、APIエンドポイントを作成するのに適しています。

モデルをロードし、APIエンドポイントを作成します。

このコードは、ローカルホストのポート5000でバックエンドAPIサーバーを起動し、フロントエンドHTMLページから画像を受け取って分類結果を返すものです。

from flask import Flask, request, jsonify, render_template
import tensorflow as tf
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
import numpy as np
import io
from PIL import Image
from flask_cors import CORS
from flask_cors import cross_origin

app = Flask(__name__)
CORS(app)



# モデルのロード部分を変更
model = load_model('/Users/yourname/DogvsCatAPP/cats_vs_dogs.h5')  # <-- パスを変更




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

@app.route('/predict', methods=['POST'])
@cross_origin()
def predict():
    if 'file' not in request.files:
        return jsonify({'error': 'no file'}), 400
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'no filename'}), 400
    
    # 画像の読み込みと前処理
    img = image.load_img(io.BytesIO(file.read()), target_size=(150, 150))
    img_array = image.img_to_array(img)
    img_array_expanded_dims = np.expand_dims(img_array, axis=0)
    preprocessed_img = img_array_expanded_dims / 255.  # モデルのトレーニング時と同じスケーリング
    
    # 予測
    prediction = model.predict(preprocessed_img)
    
    # レスポンスの作成
    if prediction >= 0.5:
        predicted_class = 'dog'
    else:
        predicted_class = 'cat'
    
    response = {'class': predicted_class}
    return jsonify(response), 200, {'Access-Control-Allow-Origin': '*'}

# ローカルでAPIサーバーを実行
if __name__ == '__main__':
    app.run(port=5000, debug=True)

次に、フロントエンドです。

フロントエンドでは、ユーザーがアップロードする画像を受け入れ、結果を表示するインターフェースを作成します。HTML, CSS, JavaScriptが基本的な技術スタックとなります。

HTMLファイルには、画像をアップロードするためのインプットフィールドと結果を表示するエリアを作成します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cat or Dog Classifier</title>
</head>
<body>
    <h1>Is it a cat or a dog?</h1>
    <input type="file" id="fileInput" accept="image/*">
    <button onclick="classifyImage()">Classify</button>
    <p id="result"></p>

    <script>
        async function classifyImage() {
            const fileInput = document.getElementById('fileInput');
            const resultParagraph = document.getElementById('result');
            const file = fileInput.files[0];
            const formData = new FormData();
            formData.append('file', file);
    
            resultParagraph.textContent = 'Classifying...';
    
            try {
                const response = await fetch('http://127.0.0.1:5000/predict', {
                    method: 'POST',
                    body: formData
                });
    
                if (!response.ok) {
                    console.error('Network response was not ok:', response);
                    resultParagraph.textContent = 'Network response was not ok';
                    return;
                }
    
                const result = await response.json();
                resultParagraph.textContent = `It's a ${result.class}!`;
            } catch (error) {
                console.error('Error during fetch operation:', error);
                resultParagraph.textContent = 'Error during classification';
            }
        }
    </script>    
</body>
</html>

実際に手元でこのアプリを動かしてみる

あなたのWebアプリのファイルを作った上で、ターミナルなどのコマンドプロンプトで次のコードを実施します。

cd 'your app path'
python app.py

そうすると、初めの動画のように、http://127.0.0.1:5000でアプリを動かすことができる様になっています。

デプロイメント

Herokuは、小規模なアプリケーションを無料でホスティングするのに非常に人気があります。

ただ、今回私は色々試してみたのですが、slug sizeを小さくすることができずに諦めました。。。

また挑戦します。

手順だけ書いておきますね。

ステップ1: Herokuアカウントの作成

Herokuにはサインアップが必要です。Herokuの公式サイトから無料アカウントを作成してください。

ステップ2: Heroku CLIのインストール

Herokuコマンドラインツール(CLI)を公式サイトからダウンロード・インストールし、セットアップを完了します。

ステップ3: アプリケーションのデプロイ

  1. Herokuにログイン: ターミナルでheroku loginコマンドを実行します。
  2. リポジトリの初期化: アプリケーションのディレクトリでGitを初期化します。
    git init
  3. Herokuアプリの作成: アプリケーションのディレクトリで以下のコマンドを実行します。
    heroku create [app-name]
    [app-name]は任意のアプリ名です(省略も可能で、その場合ランダムな名前が割り当てられます)。
  4. デプロイ: アプリケーションをHerokuにデプロイします。
    git add .
    git commit -m "Initial commit" 
    git push heroku main
  5. 開く: heroku openコマンドでアプリケーションをデフォルトのウェブブラウザで開きます。

まとめ

今回は、AIを実装したWebアプリの作り方の一連の流れを見てみました。あくまでこの記事では表面的なことしか書いてないので実際に自分でやってみるときにはChatGPTとかに聞きながらやってみてください。

コメント

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