1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

アニメキャラ画像入力してキャラ名出力するAIの作り方

Last updated at Posted at 2023-03-25

Chat GPTへの質問

Pythonにてアニメキャラ画像を入力し、キャラクター名を出力する機械学習を行いたいです
コーディング例を教えてください

(おおざっぱ)

なぜそんな質問をしたか

上記書籍にて、ざっっっくりとPython×機械学習について学び、「機械学習っぽい」ことを実際にやってみたかったから。

回答は

アニメキャラ画像を入力し、キャラクター名を出力する機械学習を行うためには、以下の手順が必要です。

学習用の画像とキャラクター名を用意する
画像から特徴量を抽出する
特徴量を用いて機械学習モデルを学習する
テスト用の画像を用意し、モデルで予測を行いキャラクター名を出力する
以下に、具体的なコード例を示します。

  1. 学習用の画像とキャラクター名を用意する
    学習用の画像とキャラクター名を用意します。
    例えば、「Naruto」というキャラクターの画像を10枚、
    「Luffy」というキャラクターの画像を10枚用意するとします。
    画像は、任意の場所からダウンロードすることができます。

  2. 画像から特徴量を抽出する
    画像から特徴量を抽出するためには、以下の手順が必要です。

Python
import numpy as np
from PIL import Image
from sklearn.feature_extraction.image import extract_patches_2d

# 学習用データの読み込み
naruto_images = []
for i in range(10):
    image = Image.open(f'naruto_{i}.jpg').convert('L')
    naruto_images.append(np.array(image))

luffy_images = []
for i in range(10):
    image = Image.open(f'luffy_{i}.jpg').convert('L')
    luffy_images.append(np.array(image))

# データセットの作成
X = []
y = []
for i, images in enumerate([naruto_images, luffy_images]):
    for image in images:
        patches = extract_patches_2d(image, (32, 32), max_patches=100)
        for patch in patches:
            X.append(patch.flatten())
            y.append(i)

3.特徴量を用いて機械学習モデルを学習する
特徴量を用いて機械学習モデルを学習するためには、以下の手順が必要です。

Python
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

# 学習データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# SVMモデルの作成と学習
clf = SVC(kernel='linear')
clf.fit(X_train, y_train)

# テストデータでの正解率を計算
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")

テスト用の画像を用意し、モデルで予測を行いキャラクター名を出力する
テスト用の画像を用意し、モデルで予測を行いキャラクター名を出力するためには、以下の手順が必要です。

Python
# テスト用画像の読み込み
test_image = Image.open('test.jpg').convert('L')
test_patches = extract_patches_2d(np.array(test_image), (32, 32), max_patches=100)

# 予測
predictions = clf.predict(test_patches.reshape(-1, 1024))

# 出力
print(predictions)

以上の手順で、アニメキャラ画像を入力し、キャラクター名を出力する機械学習が行えます。

とりあえず1スクリプトにまとめてみる

detect_character
import numpy as np
from PIL import Image
from sklearn.feature_extraction.image import extract_patches_2d

# 学習用データの読み込み
naruto_images = []
for i in range(10):
    image = Image.open(f'naruto_faces/naruto_{i}.jpg').convert('L')
    naruto_images.append(np.array(image))

luffy_images = []
for i in range(10):
    image = Image.open(f'luffy_faces/luffy_{i}.jpg').convert('L')
    luffy_images.append(np.array(image))

# データセットの作成
X = []
y = []
for i, images in enumerate([naruto_images, luffy_images]):
    for image in images:
        patches = extract_patches_2d(image, (32, 32), max_patches=100)
        for patch in patches:
            X.append(patch.flatten())
            y.append(i)

from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

# 学習データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# SVMモデルの作成と学習
clf = SVC(kernel='linear')
print("学習中...")
clf.fit(X_train, y_train)

# テストデータでの正解率を計算
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")

# テスト用画像の読み込み
test_image = Image.open('test.jpg').convert('L')
test_patches = extract_patches_2d(np.array(test_image), (32, 32), max_patches=100)

# 予測
predictions = clf.predict(test_patches.reshape(-1, 1024))

# 結果の判定
luffy_count = 0
naruto_count = 0
for prediction in predictions:
    if prediction == 0:
        naruto_count += 1
    else:
        luffy_count += 1

if naruto_count > luffy_count:
    print('結果:ナルト')
else:
    print('結果:ルフィー')

実行結果

ipynbファイルと同階層に「naruto_faces」「luffy_faces」というフォルダを作成。
それぞれに、naruto_1.jpg...、luffy_1.jpg...を10ファイル格納。
※これもChat GPTに聞きつつ別プログラム書きました(別記事)
https://qiita.com/horita_toshiki_r0/items/14229168fc0789e2da54

実行結果
学習中...
Accuracy: 0.5175
結果:ナルト

Accuracy:0.5、ほぼあてにならない?
4回試して3勝1敗
学習量10ずつだとまだ外れることも多そう

ちなみに、実行結果出るまでは5分程度かかりました。
clf.fit(X_train, y_train)(学習)のところで結構かかるらしい。

プログラムをざっくりとひも解く

☆第一ステップ:学習用の画像を配列に

Python
naruto_images = []
for i in range(10):
    image = Image.open(f'naruto_faces/naruto_{i}.jpg').convert('L')
    naruto_images.append(np.array(image))

ざっくり:

1.画像を読み込む

2.グレースケールに変換

3.NumPy配列に変換

極限までざっくり

⇒画像ファイルを数字に変換して配列に格納する

☆第二ステップ:データセット作成

Python
X = []
y = []
for i, images in enumerate([naruto_images, luffy_images]):
    for image in images:
        patches = extract_patches_2d(image, (32, 32), max_patches=100)
        for patch in patches:
            X.append(patch.flatten())
            y.append(i)

ざっくり:

0.配列X,yを準備
⇒Xには「パッチ」のデータが格納。
 yには各パッチのラベル、つまりナルトは「0」、ルフィーは「1」

1.第一ステップで配列化した各画像について、「パッチ」として100個に分割
※1パッチのサイズは32px*32px

2.それぞれの「パッチ」化した配列について一次元配列に変換

もっとざっくり:

「ナルト」と「ルフィー」のそれぞれ10枚の学習素材をそれぞれさらに100に細分化して、学習用データにする。

疑問:

●なんでわざわざパッチ化するの?画像をそのまま学習すればいいじゃない
⇒画像全体を1枚のデータとして扱うと、画像全体の特徴が把握しにくくなるためです。パッチに分割することで、小さな領域に特徴が集中し、学習が容易になります。

●どうして一次元配列化したの?
⇒SVMなどの機械学習アルゴリズムは、入力として1次元配列を受け取るためです

☆第三ステップ:パッチを「学習用」「テスト用」に分ける

Python
# 学習データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

ざっくり:

第二ステップで作ったパッチ全部を学習用に使うわけではない

パッチのうち80%だけを学習用に使い、残り20%で学習による予測精度の確認に使う

☆第四ステップ:学習!

Python
clf = SVC(kernel='linear')
print("学習中...")
clf.fit(X_train, y_train)

ざっくり:

SVM(Support Vector Machine)モデルの学習をします
時間がかかります

X_trainが入力データ、y_trainが教師データです。
つまり、「こんな感じ」のやつは、「ルフィー」だよ!を詰め込んでいくイメージでしょうか

☆第五ステップ:精度確認

Python
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")

ざっくり

1.20%分取っておいたパッチについて、学習成果をもとに、予測

2.y_test(教師データ、つまり正答)と↑の予測を比較

☆第六ステップ:「本番」の予測

Python
test_image = Image.open('test.jpg').convert('L')
test_patches = extract_patches_2d(np.array(test_image), (32, 32), max_patches=100)

# 予測
predictions = clf.predict(test_patches.reshape(-1, 1024))

ざっくり

1.「ナルト」か「ルフィー」か判定したい画像を入力⇒グレースケールに

2.↑をパッチ化(100個に分割)

3.予測
⇒predictionsには、100個に分割されたパッチについて、「ルフィー!」「ルフィー!」「ナルト!」「ルフィー!」「ルフィー!」「ナルト!」と判定結果が格納される

☆最終ステップ:結果出力

Python
luffy_count = 0
naruto_count = 0
for prediction in predictions:
    if prediction == 0:
        naruto_count += 1
    else:
        luffy_count += 1

if naruto_count > luffy_count:
    print('結果:ナルト')
else:
    print('結果:ルフィー')

ざっくり:

配列predictionsの要素のうち、「ルフィー」が多ければ「ルフィー」、「ナルト」が多ければ「ナルト」が答えと出力

最後に

今後機械学習を勉強するうえで頻出しそうなメソッド

●convert('L')

・・・ライブラリpillowのメソッドで、引数が'L'の時はグレースケールに変換してくれる
※引数を'1'にすると、1ビットの白黒画像にするらしい

●extract_patches_2d(image, (32, 32), max_patches=100)

・・・2次元の配列(画像)を小さなブロックに分割

引数は以下の通りです。

●image: パッチを抽出したい画像(2次元のNumPy配列)。
●patch_size: 抽出するパッチのサイズを指定するタプル。(n, m)の形式で指定します。
●max_patches: 抽出するパッチの最大数。デフォルトはNoneで、全パッチを抽出します。

●train_test_split(X, y, test_size=0.2)

・・・、機械学習のデータセットを訓練用データセットとテスト用データセットに分割

引数は以下の通りです。

●特徴量データ配列
●正解データ配列
●テストデータに割り当てる割合

clf.fit(X_train, y_train)

・・・学習

入力データと正解データを引数として、両者の関連性をインプット。

clf.predict(X_test)

・・・予測

一次元配列化したパッチを、学習結果をもとに予測
それぞれのパッチについて、結果を配列に格納する。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?