みなさんこんにちは。さとうじょうゆです。
最近AIについて学んでいることもあり、実際に自分で犬か猫の写真をアップロードするとそれがどちらか判定してくれるアプリを作ったので、その流れを皆さんに紹介したいと思います。
あくまで今回は流れだけ紹介します。本当に自分で作ってみたいときには、この記事を参考にしながら、ChatGPTとかに聞きながらやってみてください。
これが実際に作ったものになります。
写真に写っているのが、犬か猫かをAIの力で判定してくれているね!
- STEP1データ収集
- STEP2データの前処理
- STEP3モデル設計とトレーニング
- STEP4モデルのエクスポート
- STEP5Webアプリケーションの開発
- STEP6デプロイメント
基本的にはこの様な流れで作業していきます。
データ収集
webスクレイピングで一から犬猫の画像データを集めるのも面倒なので、今回は公開データセットを利用するよ。
今回は、AIコンペを実施しているkaggleのデータセットを利用するにことにしました。
kaggleから、お好みのデータセットをダウンロードしましょう。
import kaggle
# APIコマンドに従ってデータセットをダウンロード
!kaggle competitions download -c dogs-vs-cats
データの前処理
データの前処理には、numpyやpandasが便利です。
今回は次の様な順番でデータの前処理をしました。
- 画像の読み込み: OpenCVやPILを使用して画像データを読み込みます。
- ラベルのエンコーディング: 犬と猫のラベルをエンコーディング(例: 犬=0, 猫=1)します。
- 画像の正規化: 画像データを正規化します(ピクセル値を0~1の範囲にスケーリング)。
- データセットの分割: データを訓練セットと検証セットに分割します。
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: アプリケーションのデプロイ
- Herokuにログイン: ターミナルで
heroku login
コマンドを実行します。 - リポジトリの初期化: アプリケーションのディレクトリでGitを初期化します。
git init
- Herokuアプリの作成: アプリケーションのディレクトリで以下のコマンドを実行します。
heroku create [app-name]
[app-name]
は任意のアプリ名です(省略も可能で、その場合ランダムな名前が割り当てられます)。 - デプロイ: アプリケーションをHerokuにデプロイします。
git add .
git commit -m "Initial commit"
git push heroku
main - 開く:
heroku open
コマンドでアプリケーションをデフォルトのウェブブラウザで開きます。
まとめ
今回は、AIを実装したWebアプリの作り方の一連の流れを見てみました。あくまでこの記事では表面的なことしか書いてないので実際に自分でやってみるときにはChatGPTとかに聞きながらやってみてください。
東京大学工学部B2。AIに興味があり、AI技術を活かした起業を目指して奮闘中。スマホアプリも作ってたりします。
コメント