はじめに
こんにちは、SHOUです!
今回は「各クラス10枚の画像だけで機械学習モデルを訓練した場合、どこまで分類精度が出せるのか?」というテーマで実験を行いました。
画像分類モデルを作る際に最も課題となるのが、「学習データの少なさ」です。
ラベル付き画像を大量に用意するのは難しく、現実のプロジェクトでは「数十枚しかない」という場面も珍しくありません。
今回はあえて、1クラスあたり10枚、全体で100枚の手書き数字画像を使い、Kerasの多層パーセプトロン(MLP)でどこまで分類可能かを検証しました。
実験の条件
今回の実験の条件は以下の通りです。
- クラス数:10(0〜9の手書き数字)
- 1クラスあたりの画像数:10枚(合計100枚)
- モデル:Kerasによる多層パーセプトロン
- 学習環境:Google Colab + GPU
- データ拡張:あり(回転・ズーム・シフトなど)
画像はすべて28×28ピクセルのグレースケール画像に統一しました。
学習の様子
100枚の画像だけでは学習に必要な多様性が足りないため、ImageDataGeneratorを使って様々なバリエーションを自動生成しました。
この技術を「データ拡張」と呼び、少ないデータで学習を成立させるためにとても有効な手段です。
Google DriveをColabにマウント
まず、Google Drive を Colab に接続します👇from google.colab import drive drive.mount('/content/drive')すると、認証リンクが出るので、指示に従って認証してください。
マウントが完了すると、Drive のファイルが /content/drive/MyDrive/ 以下に見えるようになります。
データ拡張
1枚の画像から10通り以上のパターンが生成されます。
これにより、実際には100枚でも「1000枚分」の情報を学習させることが可能になります。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# データ拡張の設定
datagen = ImageDataGenerator(
rescale=1./255, # 正規化
preprocessing_function=lambda x: 1.0 - x, # 白黒反転
rotation_range=30, # 回転
width_shift_range=10, # 横移動
height_shift_range=10, # 縦移動
zoom_range=0.1, # ズーム
shear_range=0.1, # 傾き
validation_split=0.2 # 検証データ分割
)
train_generator = datagen.flow_from_directory(
'/content/drive/MyDrive/Colab/digits',
target_size=(28, 28),
color_mode='grayscale',
batch_size=32,
class_mode='sparse',
subset='training',
shuffle=True
)
val_generator = datagen.flow_from_directory(
'/content/drive/MyDrive/Colab/digits',
target_size=(28, 28),
color_mode='grayscale',
batch_size=32,
class_mode='sparse',
subset='validation'
)
学習
モデルはKerasのSequential APIでシンプルに構築しました。
入力画像を1次元に変換(Flatten)し、128ユニットの全結合層とDropout層を通じて過学習を防止、最後に10クラスのsoftmaxで分類する構成です。
import tensorflow as tf
from tensorflow import keras
model = keras.models.Sequential([
keras.layers.Input(shape=(28, 28, 1)),
keras.layers.Flatten(),
keras.layers.Dense(128, activation='relu'),
keras.layers.Dropout(0.3),
keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 学習
history = model.fit(train_generator,epochs=30,validation_data=val_generator)
簡素な構成ですが、過学習対策や損失関数の工夫も取り入れています。
それでも、データが少なすぎると限界があります。
学習結果と限界
30エポックにわたって学習を行ったものの、精度の向上はほとんど見られませんでした。
以下はログの一部です。
Epoch 1/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 2s 273ms/step - accuracy: 0.0432 - loss: 2.9863 - val_accuracy: 0.1500 - val_loss: 2.4238
Epoch 2/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 190ms/step - accuracy: 0.0625 - loss: 2.7927 - val_accuracy: 0.0500 - val_loss: 2.3816
Epoch 3/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 149ms/step - accuracy: 0.0688 - loss: 2.5960 - val_accuracy: 0.1500 - val_loss: 2.3417
Epoch 4/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 156ms/step - accuracy: 0.1023 - loss: 2.4672 - val_accuracy: 0.1000 - val_loss: 2.3062
Epoch 5/30
・・・
Epoch 26/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 175ms/step - accuracy: 0.0646 - loss: 2.3042 - val_accuracy: 0.1000 - val_loss: 2.3020
Epoch 27/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 194ms/step - accuracy: 0.1177 - loss: 2.3022 - val_accuracy: 0.0500 - val_loss: 2.3025
Epoch 28/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 146ms/step - accuracy: 0.1203 - loss: 2.3023 - val_accuracy: 0.1000 - val_loss: 2.3026
Epoch 29/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 160ms/step - accuracy: 0.0932 - loss: 2.3028 - val_accuracy: 0.1000 - val_loss: 2.3026
Epoch 30/30
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 153ms/step - accuracy: 0.0818 - loss: 2.3028 - val_accuracy: 0.1000 - val_loss: 2.3026
学習ログを見ると、「学習しているように見えて、実はほぼ何も学習していない」という状態となっています。
- accuracy: ~0.08 〜 0.15
- val_accuracy: 0.05 〜 0.15
- loss: ≈ 2.30
まとめ:極端に少ない画像では、機械学習はほとんど学習できない
今回の実験では、1クラス10枚、合計100枚の画像データでKerasモデルを訓練しましたが、精度は向上せず、「ほぼ学習していない状態」と なりました。
このように、画像分類においてはある程度のデータ量が必要であることがわかりました。次回は、「事前学習済みCNNモデル」や「転移学習」を用いた手法で、 少量データでも精度を高める方法を検証していきます。
原因の本質
- 学習画像が極端に少ない(各クラス8枚)
- 検証データも各クラス2枚では評価できない
有効な対策
-
事前学習モデルを活用する
例えば、MNISTで学習済みのCNNをベースに、自作データでファインチューニングを行う。 -
Conv2Dを使ったCNNモデルに変更する
空間構造を活かす畳み込み層は、画像の特徴抽出に特に効果的です。model = keras.models.Sequential([ keras.layers.Input(shape=(28, 28, 1)), keras.layers.Conv2D(32, (3, 3), activation='relu'), keras.layers.MaxPooling2D((2, 2)), keras.layers.Conv2D(64, (3, 3), activation='relu'), keras.layers.MaxPooling2D((2, 2)), keras.layers.Flatten(), keras.layers.Dense(64, activation='relu'), keras.layers.Dense(10, activation='softmax') ])
-
データ拡張をさらに強化する
より強いノイズや変形を加えて、モデルの汎化能力を高める。datagen = ImageDataGenerator( rescale=1./255, preprocessing_function=lambda x: 1.0 - x, rotation_range=40, width_shift_range=0.3, height_shift_range=0.3, zoom_range=0.2, shear_range=0.2, validation_split=0.2 )
0 件のコメント:
コメントを投稿