第2章
ニューラルネットワークで衣服の画像を分類する
Fashion-MNISTを使って畳み込みニューラルネットワークを学習し、未知の画像の分類と誤分類の分析を行います。
この章で学ぶこと
- 画像を数値の配列として扱う
- 学習用・検証用・テスト用データの役割を区別する
- 畳み込みニューラルネットワーク(CNN)を構築する
- 正解率だけでなく、誤分類された画像と確信度を確認する
- 画像認識モデルの限界と、安全な利用方法を考える
作るもの
28×28ピクセルの衣服画像を、Tシャツ、ズボン、スニーカーなど10種類に分類するモデルを作ります。データにはFashion-MNISTを使います。60,000枚が学習用、10,000枚がテスト用として用意されており、各画像はグレースケールです。TensorFlowのFashion-MNISTチュートリアル
28×28の画像 → CNN → 10クラスそれぞれの確率 → 最も高いクラス
この章では、画像の一部に共通して現れる模様や形を学習しやすい**畳み込みニューラルネットワーク(CNN)**を使います。
1. 実行環境を準備する
前章とは別の作業用フォルダーと仮想環境を作ると、依存関係を分けて管理できます。Windows PowerShellでは次のように実行します。
mkdir ml-images
cd ml-images
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install tensorflow matplotlib
macOS・Linuxでは、仮想環境を有効にする行を次のように変更します。
source .venv/bin/activate
TensorFlowが対応するPythonやOSの条件は更新されるため、インストールできない場合はTensorFlow公式のインストール手順を確認してください。GPUの設定は環境によって異なりますが、この演習はCPUでも実行できます。
2. データを読み込んで確認する
完成コードをダウンロードし、作業用フォルダーへ保存します。
完成コード:fashion_mnist_cnn.pyをダウンロード
データはKerasから読み込みます。初回だけインターネットからダウンロードされ、以後はローカルのキャッシュが使われます。
(train_images, train_labels), (test_images, test_labels) = (
tf.keras.datasets.fashion_mnist.load_data()
)
読み込まれる配列の意味は次の通りです。
| 配列 | 内容 | 形状 |
|---|---|---|
train_images |
学習に使う画像 | (60000, 28, 28) |
train_labels |
学習画像の正解ラベル | (60000,) |
test_images |
最後の評価だけに使う画像 | (10000, 28, 28) |
test_labels |
テスト画像の正解ラベル | (10000,) |
ラベルは0〜9の整数で、それぞれ次の種類を表します。
| ラベル | 種類 | ラベル | 種類 |
|---|---|---|---|
| 0 | T-shirt/top | 5 | Sandal |
| 1 | Trouser | 6 | Shirt |
| 2 | Pullover | 7 | Sneaker |
| 3 | Dress | 8 | Bag |
| 4 | Coat | 9 | Ankle boot |
学習用データの一部は validation_split=0.1 によって検証用になります。検証用データは学習中の変化を確認するため、テスト用データは完成したモデルを最後に評価するために使います。
3. 画素を前処理する
各画素は0〜255の整数です。0〜1の小数へ変換し、CNNが受け取るチャンネル方向の次元を追加します。
train_images = train_images.astype("float32") / 255.0
test_images = test_images.astype("float32") / 255.0
train_images = train_images[..., np.newaxis]
test_images = test_images[..., np.newaxis]
これで画像1枚の形状は (28, 28, 1) になります。最後の 1 はグレースケールの1チャンネルを表します。カラー画像の場合は一般に赤・緑・青の3チャンネルです。
前処理の方法は学習用とテスト用でそろえます。ただし、テスト画像や正解ラベルを学習に混ぜてはいけません。
4. CNNを組み立てる
完成コードでは、次のモデルを作ります。
model = tf.keras.Sequential([
tf.keras.layers.Input(shape=(28, 28, 1)),
tf.keras.layers.Conv2D(32, 3, activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Conv2D(64, 3, activation="relu"),
tf.keras.layers.MaxPooling2D(),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation="relu"),
tf.keras.layers.Dropout(0.3),
tf.keras.layers.Dense(10, activation="softmax"),
])
| 層 | 役割 |
|---|---|
Conv2D |
小さなフィルターを動かし、輪郭や模様などの特徴を取り出す |
MaxPooling2D |
特徴を残しながら縦横のサイズを小さくする |
Flatten |
2次元の特徴を1列へ並べる |
Dense |
取り出した特徴を組み合わせて分類する |
Dropout |
学習中に一部の出力を無効にし、学習データへの過度な適合を抑える |
softmax |
10クラスの出力を、合計が1になる確率として表す |
正解ラベルが整数なので、損失関数には sparse_categorical_crossentropy を使います。最適化手法はAdam、確認する指標は正解率です。
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
5. 学習して評価する
プログラムを実行します。
python fashion_mnist_cnn.py
学習は5エポック行います。1エポックは、学習用データ全体を一巡することです。
model.fit(
train_images,
train_labels,
epochs=5,
batch_size=64,
validation_split=0.1,
)
実行中は accuracy と val_accuracy が表示されます。前者は実際に重みの更新へ使う画像、後者は分けておいた検証画像に対する正解率です。学習側だけが上がり、検証側が下がり始める場合は、学習データへ過度に適合する過学習が疑われます。
学習後は、最後まで取っておいたテストデータで評価します。
test_loss, test_accuracy = model.evaluate(
test_images, test_labels, verbose=0
)
正解率は全画像のうち正しく分類した割合です。毎回の実行環境によって結果は多少変わります。値だけを目標にせず、学習用とは別のデータで測定していることを確認してください。
6. 間違い方を観察する
完成コードは、誤分類した画像を最初の12枚まで fashion_mnist_errors.png に保存します。各画像には正解、予測、予測したクラスの確信度が表示されます。
probabilities = model.predict(test_images, verbose=0)
predicted_labels = probabilities.argmax(axis=1)
wrong_indices = np.flatnonzero(predicted_labels != test_labels)[:12]
画像を開き、次を観察してください。
Shirt、T-shirt/top、Pulloverなど形が似たクラスで間違えていないか- 人間にも判別しにくい画像ではないか
- 間違っているのに確信度が高い例がないか
- 28×28ピクセルやグレースケールという条件で失われた情報は何か
softmaxの出力が90%でも、「現実世界で90%正しい」と保証されるわけではありません。確信度の調整には別の検証が必要です。
プログラムは学習済みモデルも fashion_mnist_model.keras に保存します。これはモデルの構造と重みを再利用するためのファイルです。出所が不明な学習済みモデルは、信頼できないプログラムと同様に扱い、むやみに読み込まないでください。
現実の画像へ使う前に
Fashion-MNISTは、中央に配置された28×28のグレースケール画像だけで構成されています。スマートフォンで撮影したカラー写真は、背景、角度、明るさ、縮尺が大きく異なるため、このモデルへそのまま入力してもうまく分類できません。
現実の課題では、次の点も検討します。
- 実際の利用環境を反映した学習・評価データを用意する
- 人や地域などのグループごとに性能差がないか調べる
- 誤分類したときの影響を考え、人が確認する仕組みを設ける
- 画像の著作権、個人情報、撮影された人の同意を確認する
- モデルが未学習の種類を無理に10クラスのどれかへ分類する問題を扱う
医療、本人確認、安全に関わる判断へ、この演習モデルを使用してはいけません。
トラブル対処
| 症状 | 確認すること |
|---|---|
| TensorFlowをインストールできない | Python・OS・CPUが対応条件を満たすか公式手順で確認する |
| 初回のデータ取得に失敗する | インターネット接続、プロキシ、空き容量を確認して再実行する |
| 実行に時間がかかる | epochs=1 で流れを確認してから増やす。ほかの重い処理を終了する |
| メモリ不足になる | batch_size を32や16へ下げる |
val_accuracy が改善しない |
前処理、ラベル、学習回数を確認する。層を増やす前に誤分類を見る |
やってみよう
epochsを1、3、10に変え、学習・検証・テストの正解率を表にしてください。Dropout(0.3)を外した場合、過学習の様子がどう変わるか比較してください。- クラスごとの正解数と誤分類数を数え、苦手な種類を調べてください。
- 自分で撮影した服の写真を使うには、どのような前処理と追加データが必要か設計してください。
精度を上げる変更をしたときも、テストデータを何度も見ながら設定を選ぶと、テストデータへ間接的に適合します。比較には検証データを使い、最後の評価だけをテストデータで行いましょう。