事前学習済みCNNモデル(MobileNetV2)を使った画像分類入門(Keras+Python)

2025年5月27日火曜日

Google Colab Keras MobileNetV2 画像分類 転移学習

X f B! P L
アイキャッチ画像 事前学習済みCNNモデルを使った画像分類入門(Keras+Python)

はじめに

こんにちは、SHOUです。

「画像認識を始めたいけど、何から手をつければいいのか分からない…」そんな悩みを持つ方も多いのではないでしょうか。

この記事では、画像認識の代表的な手法である 畳み込みニューラルネットワーク(CNN) と、既に学習済みの強力なモデルを再利用する 事前学習(転移学習) を組み合わせて、手軽に高精度な画像分類を行う方法を紹介します。

Python と Keras を使って実際に動かしながら学べる内容になっており、初めて画像分類に挑戦する方にもおすすめです。

CNNとは何か?

CNN(Convolutional Neural Network) は、画像や映像のような空間的な情報を効率よく処理できる、ディープラーニングでよく使われるモデルです。

画像分類や物体検出といったタスクにおいて高い性能を発揮するCNNは、次のような層で構成されています:

  • 畳み込み層:画像からエッジや形状などの特徴を抽出
  • プーリング層:特徴量を圧縮し、計算効率を向上
  • 全結合層:抽出した特徴を使って分類や予測を行う

これらの層が組み合わさることで、画像内のパターンを認識することが可能になります。

事前学習(転移学習)とは?

事前学習とは、すでに大規模なデータで学習されたモデルを活用し、自分の課題に合わせて再利用する方法です。これにより、ゼロから学習を行うよりも効率よく、かつ高精度なモデルを作成することができます。

主なメリット:

  • 大量のデータを用意しなくても良い
  • 学習時間を大幅に短縮できる
  • 精度の高いモデルを素早く構築できる

代表的な事前学習済みモデルには、以下のようなものがあります:

  • VGG16 / VGG19:シンプルで理解しやすい構造
  • ResNet50:深いネットワーク構造でも学習が安定
  • InceptionV3:計算効率と精度のバランスが良い
  • MobileNetV2:軽量でモバイルデバイスでも動作可能

今回は、数字(0〜9)の画像分類というタスクに対して、軽量で高性能な MobileNetV2 を利用してみます。

Kerasで事前学習済みモデルを使った画像分類

ここからは実際に、KerasとGoogle Colabを使って、事前学習済みの MobileNetV2 を用いた画像分類の実装を行います。

分類対象は、手書きの数字画像(0〜9)です。分類には自作の画像データを使いますが、枚数が少なくても高精度を狙えるのが転移学習の強みです。

まずは、Google DriveをColabに接続して、画像データを読み込めるようにしましょう。

事前準備:Google DriveをColabにマウント

まず、Google Drive を Colab に接続します👇
from google.colab import drive
drive.mount('/content/drive')
すると、認証リンクが出るので、指示に従って認証してください。
マウントが完了すると、Drive のファイルが /content/drive/MyDrive/ 以下に見えるようになります。

転移学習

ここでは、Kerasに内蔵されているMobileNetV2という事前学習済みのモデルを使って、手書き数字の分類を行います。 MobileNetV2は、軽量で高速に動作するため、Colabやモバイル環境での使用にも適しています。

ただし、MobileNetV2は元々、一般的な物体画像(犬・猫・車など)を対象に学習されており、入力画像サイズも96×96以上のRGB画像を想定しています。 そのため、手書き数字画像(28×28・白黒)を分類に使うには、以下のような前処理が必要になります。

  • 画像サイズの拡大:MNISTの28×28画像を96×96にリサイズ
  • RGB化:グレースケール画像を3チャンネルに変換
  • 白黒反転:MNISTは「黒地に白文字」ですが、事前学習済みモデルは通常「白地に黒い物体」を想定しているため、明暗を反転
  • データ拡張:回転や拡大・平行移動を加えて、少ない画像でも学習効果を高める

こうした前処理をまとめて行うために、Kerasの ImageDataGenerator を使います。以下のコードで、データの読み込みと前処理を行い、学習用・検証用に分割します。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# MobileNetV2は最低96x96の入力が必要 → 画像サイズを拡大
IMG_SIZE = 96
BATCH_SIZE = 32

# 白黒反転 + 正規化 + 拡張
datagen = ImageDataGenerator(
    rescale=1./255,
    preprocessing_function=lambda x: 1.0 - x,  # 白地黒文字に対応
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.1,
    zoom_range=0.1,
    validation_split=0.2
)

train_generator = datagen.flow_from_directory(
    '/content/drive/MyDrive/Colab/digits',
    target_size=(IMG_SIZE, IMG_SIZE),
    color_mode='rgb',  # MobileNetV2はRGBを期待
    batch_size=BATCH_SIZE,
    class_mode='sparse',
    subset='training'
)

val_generator = datagen.flow_from_directory(
    '/content/drive/MyDrive/Colab/digits',
    target_size=(IMG_SIZE, IMG_SIZE),
    color_mode='rgb',
    batch_size=BATCH_SIZE,
    class_mode='sparse',
    subset='validation'
)

モデルの構築

続いて、事前学習済みの MobileNetV2 をベースにした分類モデルを構築します。

  • base_model:MobileNetV2の特徴抽出部のみを利用します。分類部分(出力層)は除外します(include_top=False)。
  • trainable=False:ベースモデルの重みは固定(凍結)して使います。これは、学習済みの知識を活かす「転移学習」の基本戦略です。
  • 分類ヘッド:MobileNetV2の出力を受け取り、手書き数字(0〜9)を分類する小さなネットワーク(全結合層)を追加します。

モデル全体は以下のような構成になります:

  1. MobileNetV2(特徴抽出)
  2. GlobalAveragePooling(特徴マップを1次元に変換)
  3. Dense層(隠れ層)+Dropoutで過学習を防止
  4. 最終的な10クラスの出力層(softmax)

モデルが完成したら、model.fit() を使って学習を開始します。 このとき、画像データは train_generatorval_generator から読み込まれ、1エポックごとにパラメータが更新されていきます。

# モデル構築(ベースモデル + 分類ヘッド)
base_model = keras.applications.MobileNetV2(
    input_shape=(IMG_SIZE, IMG_SIZE, 3),
    include_top=False,
    weights='imagenet'
)
base_model.trainable = False  # 転移学習の基本:特徴抽出器は凍結

# 新しい分類ヘッドを追加
model = keras.Sequential([
    base_model,
    keras.layers.GlobalAveragePooling2D(),
    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=20, validation_data=val_generator)

学習結果

学習の途中では、訓練精度(accuracy)検証精度(val_accuracy)がログとして表示されます。訓練精度だけでなく、検証精度も重要です。検証精度が高いほど、未知のデータに対しても正しく分類できる可能性が高くなります。

学習中のログは以下のようになります:

Found 80 images belonging to 10 classes.
Found 20 images belonging to 10 classes.
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_96_no_top.h5
9406464/9406464 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
/usr/local/lib/python3.11/dist-packages/keras/src/trainers/data_adapters/py_dataset_adapter.py:121: UserWarning: Your `PyDataset` class should call `super().__init__(**kwargs)` in its constructor. `**kwargs` can include `workers`, `use_multiprocessing`, `max_queue_size`. Do not pass these arguments to `fit()`, as they will be ignored.
  self._warn_if_super_not_called()
Epoch 1/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 19s 6s/step - accuracy: 0.1120 - loss: 2.7394 - val_accuracy: 0.3000 - val_loss: 1.8545
Epoch 2/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 444ms/step - accuracy: 0.3615 - loss: 1.9677 - val_accuracy: 0.5000 - val_loss: 1.5880
Epoch 3/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 362ms/step - accuracy: 0.5229 - loss: 1.4203 - val_accuracy: 0.7000 - val_loss: 1.2281
・・・
Epoch 15/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 354ms/step - accuracy: 0.8927 - loss: 0.3191 - val_accuracy: 0.9000 - val_loss: 0.3266
Epoch 16/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 2s 829ms/step - accuracy: 0.9510 - loss: 0.1885 - val_accuracy: 0.9000 - val_loss: 0.6225
Epoch 17/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 2s 436ms/step - accuracy: 0.8656 - loss: 0.3272 - val_accuracy: 0.9500 - val_loss: 0.3617
Epoch 18/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 332ms/step - accuracy: 0.9617 - loss: 0.1494 - val_accuracy: 0.7500 - val_loss: 0.5225
Epoch 19/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 2s 399ms/step - accuracy: 0.9182 - loss: 0.1808 - val_accuracy: 0.9000 - val_loss: 0.4033
Epoch 20/20
3/3 ━━━━━━━━━━━━━━━━━━━━ 1s 438ms/step - accuracy: 1.0000 - loss: 0.1406 - val_accuracy: 0.8500 - val_loss: 0.3530

このように、エポックが進むにつれて精度が向上していく様子が確認できます。

画像の分類(推論)

学習が終わったら、モデルを使って新しい画像を分類してみましょう。 ここでは、自分で用意した手書き数字の画像を使って、モデルがどの数字だと判断するかを試します。

ポイント:

  • 画像サイズ:MobileNetV2に合わせて、96×96にリサイズ
  • RGB:カラー画像(3チャンネル)として読み込み
  • 白黒反転:MNISTとの整合性を保つために必要
  • 前処理:preprocess_input() でMobileNetV2向けの標準化を実施

推論は、model.predict() を使って行い、np.argmax() で最もスコアの高いクラス(0~9のどれか)を取り出します。

from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
import numpy as np

# 画像パス
img_path = '/content/drive/MyDrive/Colab/handwritten_digit.png'

# MobileNetV2用の入力に合わせてサイズとカラーを指定
img = image.load_img(img_path, target_size=(96, 96), color_mode='rgb')

# 配列に変換
img_array = image.img_to_array(img)

# 白黒反転(白地に黒文字 → 黒地に白文字)
img_array = 255.0 - img_array

# バッチ次元を追加 + 前処理
img_array = np.expand_dims(img_array, axis=0)
img_array = preprocess_input(img_array)

# 予測
prediction = model.predict(img_array)
predicted_label = np.argmax(prediction)

print('予測ラベル:', predicted_label)

実行結果は以下です:

1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 1s/step
予測ラベル: 1

今回、実際の推論結果では「4」と書かれた画像が「1」と誤認識されていました。

実践でのポイント

より高い精度を目指す場合、以下の点にも注目してみてください:

  • データ拡張:学習時に画像をランダムに変形(回転・ズームなど)させることで、モデルの汎化性能を高めます。
  • Fine-tuning:凍結していたベースモデルの一部層を再学習させることで、よりタスクに最適化されたモデルに仕上げられます。
  • GPU活用:Google ColabのGPUを使うことで、学習を高速に行えます(CPUより圧倒的に速いです)。

まとめ

本記事では、KerasとMobileNetV2を使って、事前学習済みモデルによる画像分類に取り組みました。 自分の画像を使って分類を行うことで、ディープラーニングの仕組みを体感しながら学べたのではないでしょうか。

転移学習を活用すれば、少ないデータや短い時間でも、高精度な分類モデルを作成できます。 KerasのAPIはシンプルなので、ぜひこの記事をベースに、自分だけの画像分類プロジェクトに挑戦してみてください!


参考リンク:
Keras Applications公式ドキュメント

このブログを検索

自己紹介

はじめまして、機械学習を独学中のSHOU TAKEと申します。本ブログでは、Python・Keras・Google Colabを活用した画像分類やニューラルネットワークの実験記事を中心に発信しています。初学者の方にも分かりやすく、学んだことをそのまま実験形式でまとめるスタイルです。これまで取り組んだテーマには、学習率やOptimizerの比較、Batch Sizeの検証、事前学習の活用などがあります。ご質問やご感想は、お問い合わせフォームからお気軽にどうぞ。

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ