STEP 18:CNNアーキテクチャの構築

🏗️ STEP 18: CNNアーキテクチャの構築

CIFAR-10でカラー画像分類に挑戦!実践的なCNNを作ろう

📋 このステップで学ぶこと

  • CIFAR-10データセットの理解
  • 典型的なCNNアーキテクチャ
  • Conv → BatchNorm → ReLU → Poolの構造
  • カラー画像(3チャンネル)の扱い方
  • 実践:CIFAR-10画像分類モデルの構築
  • モデルの評価と改善

📦 1. CIFAR-10データセット

1-1. CIFAR-10とは?

CIFAR-10は、10クラスのカラー画像を含む有名なベンチマークデータセットです。
MNISTの次のステップとして、画像認識の練習に最適です。

項目 MNIST CIFAR-10
画像サイズ 28×28 32×32
カラー グレースケール(1ch) カラー(3ch: RGB)
クラス数 10(数字) 10(物体)
訓練データ 60,000枚 50,000枚
テストデータ 10,000枚 10,000枚
難易度 ★☆☆ 簡単 ★★★ 難しい

1-2. CIFAR-10の10クラス

【CIFAR-10の10クラス】 0: 飛行機(airplane) 5: 犬(dog) 1: 自動車(automobile) 6: カエル(frog) 2: 鳥(bird) 7: 馬(horse) 3: 猫(cat) 8: 船(ship) 4: 鹿(deer) 9: トラック(truck) → 動物と乗り物が混在しており、MNISTより難しい

1-3. データの読み込み

from tensorflow.keras.datasets import cifar10 from tensorflow.keras.utils import to_categorical # データ読み込み (X_train, y_train), (X_test, y_test) = cifar10.load_data() print(f”訓練データ: {X_train.shape}”) # (50000, 32, 32, 3) print(f”テストデータ: {X_test.shape}”) # (10000, 32, 32, 3) print(f”ラベル: {y_train.shape}”) # (50000, 1) # 正規化(0-255 → 0-1) X_train = X_train.astype(‘float32’) / 255.0 X_test = X_test.astype(‘float32’) / 255.0 # ラベルをOne-Hot形式に y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10)

🏛️ 2. 典型的なCNNアーキテクチャ

2-1. CNNの基本構造

以下の図は横スクロールできます。

【典型的なCNNの構造】 入力画像 ↓ ┌─────────────────────────────────────────────────┐ │ 特徴抽出部(Feature Extraction) │ │ │ │ ┌──────────────────────────────────┐ │ │ │ Conv Block 1 │ │ │ │ Conv2D → BatchNorm → ReLU → Pool │ │ │ └──────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────┐ │ │ │ Conv Block 2 │ │ │ │ Conv2D → BatchNorm → ReLU → Pool │ │ │ └──────────────────────────────────┘ │ │ ↓ │ │ ┌──────────────────────────────────┐ │ │ │ Conv Block 3 │ │ │ │ Conv2D → BatchNorm → ReLU → Pool │ │ │ └──────────────────────────────────┘ │ └─────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────┐ │ 分類部(Classifier) │ │ │ │ Flatten または GlobalAveragePooling │ │ ↓ │ │ Dense → Dropout → Dense(softmax) │ └─────────────────────────────────────────────────┘ ↓ 出力(クラス確率)

2-2. 設計のポイント

✅ CNNアーキテクチャ設計のポイント
  • フィルター数は徐々に増やす:32 → 64 → 128のように
  • 画像サイズは徐々に小さく:Poolingで縮小
  • BatchNormalizationを使う:学習の安定化
  • Dropoutで過学習防止:特に全結合層で
  • 最後はsoftmax:多クラス分類の場合

💻 3. CIFAR-10モデルの構築

3-1. シンプルなCNNモデル

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten from tensorflow.keras.layers import Dropout, BatchNormalization # シンプルなCNNモデル model = Sequential([ # === Conv Block 1 === Conv2D(32, (3, 3), padding=’same’, activation=’relu’, input_shape=(32, 32, 3)), BatchNormalization(), Conv2D(32, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D(pool_size=(2, 2)), Dropout(0.25), # === Conv Block 2 === Conv2D(64, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), Conv2D(64, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D(pool_size=(2, 2)), Dropout(0.25), # === Conv Block 3 === Conv2D(128, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), Conv2D(128, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D(pool_size=(2, 2)), Dropout(0.25), # === 分類部 === Flatten(), Dense(512, activation=’relu’), BatchNormalization(), Dropout(0.5), Dense(10, activation=’softmax’) ]) model.summary()
モデル構造:
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 32, 32, 32)        896       
batch_normalization          (None, 32, 32, 32)        128       
conv2d_1 (Conv2D)            (None, 32, 32, 32)        9248      
batch_normalization_1        (None, 32, 32, 32)        128       
max_pooling2d                (None, 16, 16, 32)        0         
dropout                      (None, 16, 16, 32)        0         
...
dense_1 (Dense)              (None, 10)                5130      
=================================================================
Total params: 1,250,698

3-2. コンパイルと学習

from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau # コンパイル model.compile( optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’] ) # コールバック callbacks = [ EarlyStopping(monitor=’val_loss’, patience=10, restore_best_weights=True), ReduceLROnPlateau(monitor=’val_loss’, factor=0.5, patience=5, min_lr=1e-6) ] # 学習 history = model.fit( X_train, y_train, epochs=50, batch_size=64, validation_split=0.1, callbacks=callbacks )
学習経過:
Epoch 1/50
703/703 - accuracy: 0.4523 - val_accuracy: 0.5812
Epoch 10/50
703/703 - accuracy: 0.7856 - val_accuracy: 0.7623
Epoch 20/50
703/703 - accuracy: 0.8534 - val_accuracy: 0.8012
...
Epoch 35/50
Epoch 35: ReduceLROnPlateau reducing learning rate to 0.0005
...
Epoch 45/50
703/703 - accuracy: 0.9123 - val_accuracy: 0.8456

※ CIFAR-10は難しいので、80%台で良好な結果

3-3. 評価

# テストデータで評価 test_loss, test_acc = model.evaluate(X_test, y_test) print(f”\nテスト精度: {test_acc:.4f}”) # 予測 import numpy as np predictions = model.predict(X_test[:10]) predicted_classes = np.argmax(predictions, axis=1) actual_classes = np.argmax(y_test[:10], axis=1) class_names = [‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’] print(“\n予測結果:”) for i in range(10): print(f” 実際: {class_names[actual_classes[i]]}, 予測: {class_names[predicted_classes[i]]}”)
評価結果:
テスト精度: 0.8234

予測結果:
  実際: cat, 予測: cat ✓
  実際: ship, 予測: ship ✓
  実際: ship, 予測: airplane ✗
  実際: airplane, 予測: airplane ✓
  実際: frog, 予測: frog ✓
  ...

📊 4. 学習曲線の可視化

import matplotlib.pyplot as plt # 学習曲線のプロット fig, axes = plt.subplots(1, 2, figsize=(12, 4)) # 精度 axes[0].plot(history.history[‘accuracy’], label=’Train’) axes[0].plot(history.history[‘val_accuracy’], label=’Validation’) axes[0].set_title(‘Model Accuracy’) axes[0].set_xlabel(‘Epoch’) axes[0].set_ylabel(‘Accuracy’) axes[0].legend() # 損失 axes[1].plot(history.history[‘loss’], label=’Train’) axes[1].plot(history.history[‘val_loss’], label=’Validation’) axes[1].set_title(‘Model Loss’) axes[1].set_xlabel(‘Epoch’) axes[1].set_ylabel(‘Loss’) axes[1].legend() plt.tight_layout() plt.show()
📌 学習曲線の見方
  • 両方下がっている:学習が順調 ✓
  • 訓練のみ下がる:過学習の兆候 → Dropoutを増やす
  • 両方停滞:学習率が低い可能性 → 学習率を調整
  • 激しく振動:学習率が高すぎる → 学習率を下げる

📝 5. 完成コード(Google Colab対応)

“”” CIFAR-10画像分類 – 完成コード Google Colabで実行可能 “”” import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.datasets import cifar10 from tensorflow.keras.utils import to_categorical from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dense, Flatten from tensorflow.keras.layers import Dropout, BatchNormalization from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint # ===== 1. データ準備 ===== (X_train, y_train), (X_test, y_test) = cifar10.load_data() X_train = X_train.astype(‘float32’) / 255.0 X_test = X_test.astype(‘float32′) / 255.0 y_train = to_categorical(y_train, 10) y_test = to_categorical(y_test, 10) print(f”訓練データ: {X_train.shape}”) print(f”テストデータ: {X_test.shape}”) # ===== 2. モデル構築 ===== model = Sequential([ # Block 1 Conv2D(32, (3, 3), padding=’same’, activation=’relu’, input_shape=(32, 32, 3)), BatchNormalization(), Conv2D(32, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D((2, 2)), Dropout(0.25), # Block 2 Conv2D(64, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), Conv2D(64, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D((2, 2)), Dropout(0.25), # Block 3 Conv2D(128, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), Conv2D(128, (3, 3), padding=’same’, activation=’relu’), BatchNormalization(), MaxPooling2D((2, 2)), Dropout(0.25), # Classifier Flatten(), Dense(512, activation=’relu’), BatchNormalization(), Dropout(0.5), Dense(10, activation=’softmax’) ]) model.compile(optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’]) # ===== 3. コールバック ===== callbacks = [ EarlyStopping(monitor=’val_loss’, patience=10, restore_best_weights=True), ReduceLROnPlateau(monitor=’val_loss’, factor=0.5, patience=5), ModelCheckpoint(‘best_cifar10_model.keras’, monitor=’val_accuracy’, save_best_only=True) ] # ===== 4. 学習 ===== history = model.fit( X_train, y_train, epochs=50, batch_size=64, validation_split=0.1, callbacks=callbacks ) # ===== 5. 評価 ===== test_loss, test_acc = model.evaluate(X_test, y_test) print(f”\n🎯 テスト精度: {test_acc:.4f}”) print(f”🎯 テスト損失: {test_loss:.4f}”)

📝 STEP 18 のまとめ

✅ このステップで学んだこと
  • CIFAR-10:32×32のカラー画像、10クラス分類
  • CNNの典型構造:Conv→BN→ReLU→Poolのブロック
  • フィルター数:32→64→128と徐々に増やす
  • BatchNormalization:学習の安定化に効果的
  • Dropout:過学習防止(特に全結合層で重要)
  • コールバック:EarlyStopping + ReduceLROnPlateauの組み合わせ
💡 CIFAR-10の目安精度

70%台:基本的なCNN
80%台:BatchNorm + Dropoutを適切に使用
85%以上:データ拡張を使用
90%以上:転移学習を使用

🚀 次のステップへ

CNNアーキテクチャを構築できたので、次のSTEP 19ではデータ拡張(Data Augmentation)を学びます。

限られたデータから多様な訓練データを生成し、精度を向上させましょう!

📝 練習問題

問題1 やさしい

CIFAR-10の特徴

CIFAR-10データセットの特徴として、正しいものを選んでください。

  • A. 画像サイズは28×28ピクセル
  • B. グレースケール画像
  • C. 10クラスのカラー画像
  • D. 100クラスの分類問題
正解:C

CIFAR-10は32×32ピクセルのカラー画像(RGB 3チャンネル)で、10クラス(飛行機、自動車、鳥、猫など)の分類問題です。

問題2 やさしい

CNNブロックの順序

典型的なCNNブロックの順序として、最も一般的なものを選んでください。

  • A. Pool → Conv → ReLU → BatchNorm
  • B. Conv → BatchNorm → ReLU → Pool
  • C. BatchNorm → Conv → Pool → ReLU
  • D. ReLU → Conv → BatchNorm → Pool
正解:B

Conv → BatchNorm → ReLU → Poolの順序が最も一般的です。畳み込み→正規化→活性化→プーリングの流れで特徴を抽出します。

問題3 ふつう

フィルター数の設計

CNNの層を深くするにつれて、フィルター数はどのように設計するのが一般的ですか?

  • A. 徐々に減らす(128→64→32)
  • B. 徐々に増やす(32→64→128)
  • C. 常に同じ数を維持(64→64→64)
  • D. ランダムに設定
正解:B

層が深くなるにつれてフィルター数を増やすのが一般的です。浅い層では低レベルな特徴を少数のフィルターで、深い層では高レベルな特徴を多数のフィルターで抽出します。

問題4 ふつう

入力形状

CIFAR-10のカラー画像をCNNに入力する場合、input_shapeはどのように指定しますか?

  • A. (32, 32)
  • B. (32, 32, 1)
  • C. (32, 32, 3)
  • D. (3, 32, 32)
正解:C

Kerasでは(高さ, 幅, チャンネル数)の順序で指定します。CIFAR-10は32×32のRGBカラー画像なので、(32, 32, 3)となります。

問題5 むずかしい

過学習の対策

CIFAR-10で訓練精度95%、検証精度75%となった場合、最も効果的な対策を選んでください。

  • A. 学習率を上げる
  • B. エポック数を増やす
  • C. Dropoutを追加/増加、データ拡張を適用
  • D. フィルター数を増やす
正解:C
訓練精度95%、検証精度75% → 20%の差は過学習の兆候 【対策】 ✅ Dropoutを追加/増加(例:0.3→0.5) ✅ データ拡張(次のステップで学習) ✅ 正則化(L2正則化など) ✅ モデルを簡略化(フィルター数を減らす) ❌ 学習率を上げる → 関係ない ❌ エポック数を増やす → さらに過学習が進む ❌ フィルター数を増やす → モデルが複雑になり過学習が悪化
問題6 むずかしい

特徴マップのサイズ

入力32×32×3に対して、以下の層を順に適用した場合の出力サイズは?
Conv2D(32, (3,3), padding=’same’) → MaxPooling2D((2,2)) → Conv2D(64, (3,3), padding=’same’) → MaxPooling2D((2,2))

  • A. 8×8×64
  • B. 16×16×64
  • C. 8×8×32
  • D. 4×4×64
正解:A
入力: 32×32×3 ↓ Conv2D(32, padding=’same’): 32×32×32 ↓ MaxPooling2D(2,2): 16×16×32(縦横半分) ↓ Conv2D(64, padding=’same’): 16×16×64 ↓ MaxPooling2D(2,2): 8×8×64(縦横半分) padding=’same’は出力サイズを維持 MaxPooling(2,2)は縦横を半分に縮小
📝

学習メモ

ディープラーニング基礎 - Step 18

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE