CIFAR-10を使ったCNNモデル実験!MNISTとの違いは?【Google Colab&TensorFlow】

2025年9月2日火曜日

CIFAR-10 CNN Google Colab Keras MNIST

X f B! P L
アイキャッチ画像 CIFAR-10を使ったCNNモデル実験!MNISTとの違いは?【Google Colab&TensorFlow】

CIFAR-10を使ったCNNモデル実験!MNISTとの違いは?【Google Colab&TensorFlow】

本記事では、CIFAR-10 データセットで畳み込みニューラルネットワーク(CNN)を学習し、MNIST との違いを実験で確かめます。すべて Google Colab で動くコードを掲載。データ前処理・データ拡張・学習・評価まで一気通貫で解説します。

CIFAR-10とは?

CIFAR-10(Canadian Institute For Advanced Research 10) とは、画像認識の分野で広く利用されるベンチマークデータセットです。 32×32ピクセルのカラー画像が60,000枚収録されており、10種類のクラス(飛行機、自動車、鳥、猫、鹿、犬、カエル、馬、船、トラック)に分類されています。

機械学習や深層学習の研究者・エンジニアが、CNN(畳み込みニューラルネットワーク)の性能を比較する際の基準として利用することが多く、 初学者が「画像分類モデルの練習」に使うのにも最適なデータセットです。

🔽 Tensorflowを学ぶならこの入門書がオススメ 🔽

CIFAR-10の特徴は、小さなカラー画像であることです。 これにより、MNIST(手書き数字データセット)と比較して、色や背景の情報が分類の難しさを増しています。 つまり「より実世界に近い画像分類の課題」に挑戦できるというわけです。

このためCIFAR-10は、ディープラーニングを使った画像認識モデルを学ぶ上で非常に重要なステップとなります。

CIFAR-10 と MNIST の違い(表で理解)

項目 MNIST CIFAR-10
画像サイズ / チャンネル 28×28 / 1(グレースケール) 32×32 / 3(RGBカラー)
クラス数 10(手書き数字) 10(飛行機・犬・猫等)
難易度 比較的やさしい 背景や色の多様性で難しい
有効な手法 簡単なCNNでも高精度 データ拡張・BatchNorm・Dropout

Colab での準備

ランタイムは「GPU」を推奨(ランタイム → ランタイムのタイプを変更 → ハードウェア アクセラレータ: GPU)。CUDAやcuDNNはColabにプリインストールされています。

実験コード(コピーしてColabへ)

以下のコードは、データ読み込み→前処理→モデル構築→学習→評価→予測までを一気通貫で実行します。

# CIFAR-10 × CNN 実験(TensorFlow/Keras)
import tensorflow as tf
from tensorflow.keras import layers, models
import numpy as np

print(tf.__version__)

# 1) データ読み込み
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
y_train = y_train.reshape(-1)
y_test  = y_test.reshape(-1)

# 2) 前処理:0-255 → 0-1 正規化
x_train = x_train.astype("float32") / 255.0
x_test  = x_test.astype("float32") / 255.0

# 3) データ拡張(CIFAR-10では効果大)
data_augmentation = tf.keras.Sequential([
    layers.RandomFlip("horizontal"),
    layers.RandomRotation(0.05),
    layers.RandomTranslation(0.05, 0.05),
    layers.RandomZoom(0.1, 0.1)
])

# 4) モデル構築(シンプルだがCIFAR向けに少し深め)
num_classes = 10
inputs = layers.Input(shape=(32, 32, 3))
x = data_augmentation(inputs)
x = layers.Conv2D(32, (3,3), padding="same", activation="relu")(x)
x = layers.BatchNormalization()(x)
x = layers.Conv2D(32, (3,3), padding="same", activation="relu")(x)
x = layers.MaxPooling2D()(x)
x = layers.Dropout(0.25)(x)

x = layers.Conv2D(64, (3,3), padding="same", activation="relu")(x)
x = layers.BatchNormalization()(x)
x = layers.Conv2D(64, (3,3), padding="same", activation="relu")(x)
x = layers.MaxPooling2D()(x)
x = layers.Dropout(0.25)(x)

x = layers.Conv2D(128, (3,3), padding="same", activation="relu")(x)
x = layers.BatchNormalization()(x)
x = layers.Conv2D(128, (3,3), padding="same", activation="relu")(x)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.3)(x)

x = layers.Dense(128, activation="relu")(x)
x = layers.Dropout(0.3)(x)
outputs = layers.Dense(num_classes, activation="softmax")(x)
model = models.Model(inputs, outputs)

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
    loss="sparse_categorical_crossentropy",
    metrics=["accuracy"]
)

model.summary()

# 5) 学習
history = model.fit(
    x_train, y_train,
    validation_split=0.1,
    epochs=20,
    batch_size=128,
    verbose=1
)

# 6) テスト評価
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(f"Test Accuracy: {test_acc:.4f}")

# 7) 予測例(最初の10枚)
class_names = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]
pred = model.predict(x_test[:10])
pred_labels = pred.argmax(axis=1)
for i, (pl, gt) in enumerate(zip(pred_labels, y_test[:10])):
    print(f"{i:02d} pred={class_names[pl]:>10s}  /  true={class_names[gt]:>10s}")

実行結果

2.19.0
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170498071/170498071 ━━━━━━━━━━━━━━━━━━━━ 4s 0us/step
Model: "functional_1"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ input_layer (InputLayer)        │ (None, 32, 32, 3)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ sequential (Sequential)         │ (None, 32, 32, 3)      │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d (Conv2D)                 │ (None, 32, 32, 32)     │           896 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization             │ (None, 32, 32, 32)     │           128 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 32, 32, 32)     │         9,248 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 16, 16, 32)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 16, 16, 32)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_2 (Conv2D)               │ (None, 16, 16, 64)     │        18,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization_1           │ (None, 16, 16, 64)     │           256 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_3 (Conv2D)               │ (None, 16, 16, 64)     │        36,928 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 8, 8, 64)       │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_1 (Dropout)             │ (None, 8, 8, 64)       │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_4 (Conv2D)               │ (None, 8, 8, 128)      │        73,856 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ batch_normalization_2           │ (None, 8, 8, 128)      │           512 │
│ (BatchNormalization)            │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_5 (Conv2D)               │ (None, 8, 8, 128)      │       147,584 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 128)            │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_2 (Dropout)             │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │        16,512 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout_3 (Dropout)             │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 10)             │         1,290 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 305,706 (1.17 MB)
 Trainable params: 305,258 (1.16 MB)
 Non-trainable params: 448 (1.75 KB)
Epoch 1/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 18s 27ms/step - accuracy: 0.3113 - loss: 1.8386 - val_accuracy: 0.2086 - val_loss: 2.7651
Epoch 2/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 9s 25ms/step - accuracy: 0.5142 - loss: 1.3566 - val_accuracy: 0.4902 - val_loss: 1.3944
Epoch 3/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.5720 - loss: 1.1993 - val_accuracy: 0.6060 - val_loss: 1.1458
Epoch 4/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 8s 24ms/step - accuracy: 0.6134 - loss: 1.0921 - val_accuracy: 0.5686 - val_loss: 1.3412
Epoch 5/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 11s 25ms/step - accuracy: 0.6467 - loss: 1.0138 - val_accuracy: 0.6276 - val_loss: 1.1525
Epoch 6/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.6655 - loss: 0.9598 - val_accuracy: 0.5962 - val_loss: 1.2402
Epoch 7/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.6861 - loss: 0.9034 - val_accuracy: 0.6720 - val_loss: 0.9580
Epoch 8/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.7023 - loss: 0.8578 - val_accuracy: 0.6692 - val_loss: 1.0548
Epoch 9/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 11s 27ms/step - accuracy: 0.7157 - loss: 0.8234 - val_accuracy: 0.7062 - val_loss: 0.9024
Epoch 10/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 9s 24ms/step - accuracy: 0.7251 - loss: 0.7962 - val_accuracy: 0.6978 - val_loss: 0.9246
Epoch 11/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 24ms/step - accuracy: 0.7318 - loss: 0.7731 - val_accuracy: 0.7152 - val_loss: 0.8704
Epoch 12/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.7432 - loss: 0.7491 - val_accuracy: 0.7428 - val_loss: 0.7529
Epoch 13/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.7539 - loss: 0.7208 - val_accuracy: 0.7106 - val_loss: 0.9263
Epoch 14/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.7526 - loss: 0.7231 - val_accuracy: 0.7464 - val_loss: 0.7552
Epoch 15/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 25ms/step - accuracy: 0.7552 - loss: 0.7050 - val_accuracy: 0.6942 - val_loss: 0.9692
Epoch 16/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 8s 24ms/step - accuracy: 0.7680 - loss: 0.6821 - val_accuracy: 0.6954 - val_loss: 0.9317
Epoch 17/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 10s 24ms/step - accuracy: 0.7680 - loss: 0.6773 - val_accuracy: 0.7404 - val_loss: 0.8171
Epoch 18/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 11s 25ms/step - accuracy: 0.7739 - loss: 0.6611 - val_accuracy: 0.7688 - val_loss: 0.6931
Epoch 19/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 9s 25ms/step - accuracy: 0.7781 - loss: 0.6451 - val_accuracy: 0.7738 - val_loss: 0.6947
Epoch 20/20
352/352 ━━━━━━━━━━━━━━━━━━━━ 9s 27ms/step - accuracy: 0.7804 - loss: 0.6402 - val_accuracy: 0.7388 - val_loss: 0.8267
Test Accuracy: 0.7248
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 248ms/step
00 pred=       cat  /  true=       cat
01 pred=      ship  /  true=      ship
02 pred=      ship  /  true=      ship
03 pred=  airplane  /  true=  airplane
04 pred=      frog  /  true=      frog
05 pred=      frog  /  true=      frog
06 pred=automobile  /  true=automobile
07 pred=      frog  /  true=      frog
08 pred=       cat  /  true=       cat
09 pred=     truck  /  true=automobile

学習のコツ(CIFAR-10)

  • データ拡張(水平反転、平行移動、回転、ズーム)はほぼ必須
  • Batch NormalizationDropout の併用で安定&汎化。
  • エポック数は 20–50 程度で様子見。EarlyStopping で自動停止も◎。
  • 学習率スケジューラ(CosineDecay, ExponentialDecay など)で微改善。

PR: 現場で使える!TensorFlow開発入門 Kerasによる深層学習モデル構築手法

MNISTでのベースラインと比べてみる

同じ構成のCNNをMNISTに適用すると、5エポック前後で精度99%近くに到達することが多いです。一方CIFAR-10はデータの多様性が高く、80〜90%台に乗せるには拡張・正則化・学習率調整・層の深さなどの工夫が必要になります。この違いこそが、CIFAR-10が良い練習台とされる理由です。

よくあるつまずきと対処

  • 過学習:訓練精度だけ上がる → Dropout強化、データ拡張を増やす、EarlyStopping。
  • 精度が頭打ち:学習率を下げる/スケジューラ導入、層を1–2ブロック追加、バッチサイズ変更。
  • 学習が不安定:BatchNormの位置を確認(Conv→BN→ReLUの順が無難)。

発展:より高精度を狙うには?

  • 転移学習:ImageNetで学習済みの軽量モデル(MobileNetV2, EfficientNet)を32×32に合わせて微調整。
  • CutMix/MixUp:画像とラベルを混ぜる正則化で汎化性能UP。
  • 学習率ファインチューニング:OneCycleやCosineAnnealingで最終精度を押し上げ。

まとめ

  • CIFAR-10はMNISTより難易度が高く、実践的なチューニングを学ぶのに最適。
  • データ拡張・BatchNorm・Dropoutを組み合わせるだけでも大きく改善します。
  • Colabで完結するので、誰でもすぐに再現可能。まずは本記事のコードから試してみてください。

FAQ

Q. 学習が遅いと感じます。高速化のコツは?

GPUランタイムを使用し、バッチサイズを128や256に増やします。データ拡張をオンザフライで行うため、入出力で詰まる場合はtf.dataprefetch等も検討。

Q. どれくらいの精度が出れば合格ライン?

シンプルなCNNで80%前後が目安。発展テクニックを積むと90%台を狙えます。

Q. 転移学習はCIFAR-10でも有効?

はい。小型の事前学習モデルを使うと学習が安定しやすく、少ないエポックで高精度に到達しやすいです。

この記事が役立ったら、ブックマークシェアをお願いします。
※一部リンクはアフィリエイトを含みます。コンテンツの独立性を損なわないよう配慮しています。

このブログを検索

おすすめツール(PR)

このブログのまとめページ

自己紹介

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

お問い合わせフォーム

名前

メール *

メッセージ *

プライバシーポリシー

QooQ