きっかけ
昨今話題の生成系AIのコア技術となるニューラルネットワークやディープラーニングの概念を理解したものの、実際に触ってみないと理解できない部分があるなと思い、今更ながらTensorFlowで画像分類モデルを作り、分析させてみました。
やってみる
今回はさくっと試すだけなのでGoogle Colaboratoryで実装していきます。
まずは学習対象とするデータをDLする。
なお、今回は、cifar10のデータを使います。
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
# データセットをロードする(10クラスの画像セット)
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
# データの正規化(0~1の範囲に変換)
x_train, x_test = x_train / 255.0, x_test / 255.0
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 2s 0us/step
DLした中身を確認してみます。
import numpy as np
# データセットの中身を確認
#######################################
# x_train(数値化された画像データ)
#######################################
# データタイプ
print("x_train type : ", type(x_train))
# サンプルデータ(数値化された画像データ)
print("x_train sample : ", x_train[0])
# 形
print("x_train shape:", x_train.shape)
#######################################
# y_train(数値化されたラベル)
#######################################
# データタイプ
print("y_train type : ", type(y_train))
# サンプル
print("y_train sample : ", y_train[0])
# 形
print("y_train shape:", y_train.shape)
# ラベルのはんい
print("y_train unique : ", np.unique(y_train))
50000枚の画像ファイルが数値配列としてデータ化され、0~9までのラベルが付与されていることがわかります。
0~9のラベルの意味は、cifar10の説明を参照ください。
x_train type : <class 'numpy.ndarray'>
x_train sample : [[[0.23137255 0.24313725 0.24705882]
[0.16862745 0.18039216 0.17647059]
...
[0.48235294 0.36078431 0.28235294]]]
x_train shape: (50000, 32, 32, 3)
y_train type : <class 'numpy.ndarray'>
y_train sample : [6]
y_train shape: (50000, 1)
y_train unique : [0 1 2 3 4 5 6 7 8 9]
モデルを定義して、コンパイルします。
コンパイルしたモデルに先ほどの画像データを食わせて今回は学習回数を10として、学習させます。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Input
# モデル定義(ハイパーパラメータ調整)
model = Sequential([
Input(shape=(32, 32, 3)),
Conv2D(32, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
Conv2D(64, (3, 3), activation='relu'),
Flatten(),
Dense(64, activation='relu'),
Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 学習開始(epochsはトレーニングデータセットに対する学習回数)
model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test))
回数を重ねるうちに、accuracyは上がり、lossは下がっているため、精度向上していることがわかります。
Epoch 1/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 73s 45ms/step - accuracy: 0.3594 - loss: 1.7277 - val_accuracy: 0.5505 - val_loss: 1.2381
Epoch 2/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 69s 44ms/step - accuracy: 0.5748 - loss: 1.2031 - val_accuracy: 0.6137 - val_loss: 1.0965
Epoch 3/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 82s 44ms/step - accuracy: 0.6431 - loss: 1.0152 - val_accuracy: 0.6683 - val_loss: 0.9622
Epoch 4/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 82s 44ms/step - accuracy: 0.6858 - loss: 0.9056 - val_accuracy: 0.6748 - val_loss: 0.9317
Epoch 5/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 69s 44ms/step - accuracy: 0.7156 - loss: 0.8135 - val_accuracy: 0.6782 - val_loss: 0.9206
Epoch 6/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 85s 46ms/step - accuracy: 0.7324 - loss: 0.7630 - val_accuracy: 0.6896 - val_loss: 0.8914
Epoch 7/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 83s 47ms/step - accuracy: 0.7534 - loss: 0.7036 - val_accuracy: 0.6996 - val_loss: 0.8631
Epoch 8/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 77s 44ms/step - accuracy: 0.7710 - loss: 0.6543 - val_accuracy: 0.7051 - val_loss: 0.8716
Epoch 9/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 82s 44ms/step - accuracy: 0.7836 - loss: 0.6162 - val_accuracy: 0.6952 - val_loss: 0.9014
Epoch 10/10
1563/1563 ━━━━━━━━━━━━━━━━━━━━ 81s 44ms/step - accuracy: 0.7961 - loss: 0.5739 - val_accuracy: 0.7039 - val_loss: 0.8824
モデルができたので、cifar10内のテストデータを使って、モデルを評価してみます。
# テストデータ(事前に用意された10カテゴリのテストファイル)を使ってモデルを評価
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
# テストデータに対しての正答率を出力する
print("\nTest accuracy:", test_acc)
正答率7割と、まぁまぁの結果になりました。
313/313 - 4s - 11ms/step - accuracy: 0.7039 - loss: 0.8824
Test accuracy: 0.7038999795913696
今度は自前で用意したファイルを使って分析させてみます。
ファイルはGDrive上に配置したものを使うので、認証を通してドライブをマウントします。
from google.colab import drive
# あくまでも自身のドライブへのアクセス権しか持たない
drive.mount('/content/drive')
画像を出力してみます。
(確認のために出力してるだけなので分析とは関係ないです)
from PIL import Image
import matplotlib.pyplot as plt
# 画像を読み込む
image_path = '/content/drive/My Drive/etc/TensorFlow/airplane_test.jpg'
test_img = Image.open(image_path)
# 画像を表示する
plt.imshow(test_img)
plt.axis('off')
plt.show()
実際に分析させてみます。
# 画像を32x32にリサイズ
image = test_img.convert('RGB')
image = image.resize((32, 32))
# 画像をnumpy配列に変換し、正規化
image_array = np.array(image) / 255.0
image_array = image_array.reshape((1, 32, 32, 3))
# モデルによる予測
predictions = model.predict(image_array)
# 予測結果の確認
predicted_class = np.argmax(predictions, axis=1)
# CIFAR-10のクラスラベル
class_labels = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog', 'horse', 'ship', 'truck']
# 出力結果のrawデータ(各カテゴリの確率を配列にしたもの)
print(predictions)
# 一番可能性の高い配列index
print(predicted_class)
# 配列indexに応じたラベル
print("Predicted class name:", class_labels[predicted_class[0]])
出力としては、10分類の各指標が得られており、そのうち、最も高い数値は1つ目(index:0)という結果になりました。
1つ目のラベルはairplane
なので、正しい分類が行われたことがわかります。
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 126ms/step
[[9.7352397e-01 5.4320579e-05 7.3415530e-03 4.5001831e-05 2.6936505e-03
9.7711506e-07 2.2104199e-05 1.9527099e-07 1.6267302e-02 5.0913233e-05]]
[0]
Predicted class name: airplane
感想
こんなにも簡単にモデルができるとは思ってませんでしたが、データが事前に用意されてたからなんですよね。
本当に有用なモデルを作ろうとすると、学習データも大量に必要だし、そこにラベルも付与しないといけないし、学習も相当な時間がかかる(無料のGPUだったのもあるが、今回の学習だけでも数分かかってる)し、ハイパーパラメータの調整もいるし、、、と大変な作業だなというのが想像できます。
また、今まではAIは未知のものって感覚だったんですが、実際に触ってみることで、生の数値データを確認で、処理イメージがなんとなくですが、湧きました。
おまけ
Geminiに「ネコっぽいイヌのイラスト」を描かせて分析してみる。
結果。
イヌとネコの数値も高いが、馬が一番...w
調整って難しそうですね。
[[3.8005831e-04 6.1818724e-07 2.7024343e-03 1.8570235e-02 6.6630021e-03
6.2341474e-02 1.8024031e-06 9.0927386e-01 4.4260210e-06 6.2017134e-05]]
[7]
Predicted class name: horse