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 Normalization と Dropout の併用で安定&汎化。
- エポック数は 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.data
のprefetch
等も検討。
Q. どれくらいの精度が出れば合格ライン?
シンプルなCNNで80%前後が目安。発展テクニックを積むと90%台を狙えます。
Q. 転移学習はCIFAR-10でも有効?
はい。小型の事前学習モデルを使うと学習が安定しやすく、少ないエポックで高精度に到達しやすいです。
この記事が役立ったら、ブックマークやシェアをお願いします。
※一部リンクはアフィリエイトを含みます。コンテンツの独立性を損なわないよう配慮しています。
0 件のコメント:
コメントを投稿