STEP 26:モデル評価と可視化

📊 STEP 26: モデル評価と可視化

学習曲線、混同行列、Grad-CAMでモデルを深く理解!

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

  • 学習曲線(Loss、Accuracy)の可視化と解釈
  • 混同行列(Confusion Matrix)の作成と分析
  • 適合率、再現率、F1スコアの理解
  • 誤分類サンプルの分析
  • Grad-CAM(クラス活性化マップ)の基礎
  • モデル改善のヒントの見つけ方

📈 1. 学習曲線の可視化

1-1. 学習曲線とは?

学習曲線は、エポックごとの損失(Loss)や精度(Accuracy)をプロットしたグラフです。
訓練データと検証データの両方を表示することで、過学習学習不足を診断できます。

import matplotlib.pyplot as plt def plot_learning_curves(history): “””学習曲線をプロット””” fig, axes = plt.subplots(1, 2, figsize=(14, 5)) # 損失の推移 axes[0].plot(history.history[‘loss’], label=’訓練’) axes[0].plot(history.history[‘val_loss’], label=’検証’) axes[0].set_title(‘損失(Loss)の推移’) axes[0].set_xlabel(‘エポック’) axes[0].set_ylabel(‘損失’) axes[0].legend() axes[0].grid(True, alpha=0.3) # 精度の推移 axes[1].plot(history.history[‘accuracy’], label=’訓練’) axes[1].plot(history.history[‘val_accuracy’], label=’検証’) axes[1].set_title(‘精度(Accuracy)の推移’) axes[1].set_xlabel(‘エポック’) axes[1].set_ylabel(‘精度’) axes[1].legend() axes[1].grid(True, alpha=0.3) plt.tight_layout() plt.show() # 使用例 # plot_learning_curves(history)

1-2. 学習曲線の解釈

【学習曲線のパターン】 ■ 理想的な学習 Loss Accuracy │\ │ ┌──── │ \__訓練 │ / │ \__検証 │ / └─────────── エポック └─────────── エポック → 両方が収束、差が小さい ■ 過学習(Overfitting) Loss Accuracy │\ │ 訓練 ──── │ \訓練 │ / │ ──検証(増加) │ 検証 ── └─────────── エポック └─────────── エポック → 訓練と検証の差が大きい(検証が悪化) → 対策:Dropout増加、データ拡張、正則化 ■ 学習不足(Underfitting) Loss Accuracy │ │ │ ────訓練 │ ────訓練 │ ────検証 │ ────検証 └─────────── エポック └─────────── エポック → 両方とも改善しない → 対策:モデルを大きく、学習率調整、エポック増加

🔢 2. 混同行列(Confusion Matrix)

2-1. 混同行列とは?

混同行列は、予測結果と実際のラベルの関係を表す表です。
どのクラスが混同されやすいかを一目で把握できます。

【2クラス分類の混同行列】 予測 正 | 負 ──────┼────── 実際 正 │ TP │ FN │ ──────┼────── 負 │ FP │ TN │ ──────┴────── TP(True Positive):正しく「正」と予測 TN(True Negative):正しく「負」と予測 FP(False Positive):間違って「正」と予測(偽陽性) FN(False Negative):間違って「負」と予測(偽陰性)

2-2. 混同行列の作成

import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay from tensorflow.keras.datasets import mnist from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Flatten from tensorflow.keras.utils import to_categorical # データ準備 (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train.astype(‘float32’) / 255.0 X_test = X_test.astype(‘float32′) / 255.0 y_train_cat = to_categorical(y_train, 10) y_test_cat = to_categorical(y_test, 10) # モデル構築・学習(簡略化) model = Sequential([ Flatten(input_shape=(28, 28)), Dense(128, activation=’relu’), Dense(10, activation=’softmax’) ]) model.compile(optimizer=’adam’, loss=’categorical_crossentropy’, metrics=[‘accuracy’]) model.fit(X_train, y_train_cat, epochs=5, validation_split=0.1, verbose=0) # 予測 y_pred_prob = model.predict(X_test) y_pred = np.argmax(y_pred_prob, axis=1) # 混同行列の作成 cm = confusion_matrix(y_test, y_pred) # 可視化 plt.figure(figsize=(10, 8)) disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=range(10)) disp.plot(cmap=’Blues’, values_format=’d’) plt.title(‘MNIST 混同行列’) plt.show() # 各クラスの精度 for i in range(10): class_acc = cm[i, i] / cm[i].sum() print(f”クラス {i}: {class_acc:.2%}”)
実行結果:
クラス 0: 98.67%
クラス 1: 99.12%
クラス 2: 96.80%
クラス 3: 97.23%
クラス 4: 97.56%
クラス 5: 96.19%
クラス 6: 98.02%
クラス 7: 96.79%
クラス 8: 95.48%  ← 最も精度が低い
クラス 9: 96.33%

📏 3. 評価指標

3-1. 適合率・再現率・F1スコア

📐 評価指標の計算式

適合率(Precision):
「正」と予測したもののうち、実際に「正」だった割合
Precision = TP / (TP + FP)

再現率(Recall):
実際の「正」のうち、「正」と予測できた割合
Recall = TP / (TP + FN)

F1スコア:
適合率と再現率の調和平均
F1 = 2 × (Precision × Recall) / (Precision + Recall)

3-2. 分類レポート

from sklearn.metrics import classification_report # 分類レポートの出力 print(classification_report(y_test, y_pred, digits=4))
実行結果:
              precision    recall  f1-score   support

           0     0.9867    0.9867    0.9867       980
           1     0.9912    0.9912    0.9912      1135
           2     0.9680    0.9680    0.9680      1032
           3     0.9723    0.9723    0.9723      1010
           4     0.9756    0.9756    0.9756       982
           5     0.9619    0.9619    0.9619       892
           6     0.9802    0.9802    0.9802       958
           7     0.9679    0.9679    0.9679      1028
           8     0.9548    0.9548    0.9548       974
           9     0.9633    0.9633    0.9633      1009

    accuracy                         0.9722     10000
   macro avg     0.9722    0.9722    0.9722     10000
weighted avg     0.9722    0.9722    0.9722     10000

🔍 4. 誤分類サンプルの分析

4-1. 誤分類サンプルの抽出と可視化

def show_misclassified(X_test, y_test, y_pred, n_samples=16): “””誤分類されたサンプルを表示””” # 誤分類のインデックスを取得 misclassified_idx = np.where(y_test != y_pred)[0] # ランダムに選択 sample_idx = np.random.choice(misclassified_idx, min(n_samples, len(misclassified_idx)), replace=False) # 表示 fig, axes = plt.subplots(4, 4, figsize=(10, 10)) for i, idx in enumerate(sample_idx): ax = axes[i // 4, i % 4] ax.imshow(X_test[idx], cmap=’gray’) ax.set_title(f’実際:{y_test[idx]} 予測:{y_pred[idx]}’, fontsize=10) ax.axis(‘off’) plt.suptitle(‘誤分類サンプル’, fontsize=14) plt.tight_layout() plt.show() return misclassified_idx # 誤分類サンプルを表示 misclassified = show_misclassified(X_test, y_test, y_pred)

4-2. 混同しやすいクラスペアの特定

def find_confused_pairs(cm, n_pairs=5): “””最も混同しやすいクラスペアを特定””” # 対角成分(正解)を0に cm_errors = cm.copy() np.fill_diagonal(cm_errors, 0) # 最も多い誤分類ペアを見つける pairs = [] for _ in range(n_pairs): idx = np.unravel_index(np.argmax(cm_errors), cm_errors.shape) pairs.append((idx[0], idx[1], cm_errors[idx])) cm_errors[idx] = 0 print(“混同しやすいクラスペア:”) for actual, pred, count in pairs: print(f” 実際:{actual} → 予測:{pred} : {count}件”) return pairs # 混同しやすいペアを特定 confused_pairs = find_confused_pairs(cm)
実行結果:
混同しやすいクラスペア:
  実際:4 → 予測:9 : 18件
  実際:9 → 予測:4 : 15件
  実際:3 → 予測:5 : 14件
  実際:7 → 予測:9 : 12件
  実際:2 → 予測:7 : 11件

→ 4と9、3と5が混同されやすい
→ これらのクラスに注力して改善

🔥 5. Grad-CAM(クラス活性化マップ)

5-1. Grad-CAMとは?

Grad-CAM(Gradient-weighted Class Activation Mapping)は、CNNが「画像のどこを見て判断したか」を可視化する技術です。

🐱 猫の分類例

モデルが「猫」と判断したとき…

Grad-CAMで可視化すると、猫の顔や耳の部分が赤く(重要)表示される
→ モデルが正しい特徴を見ていることを確認できる

もし背景が赤く表示されたら…
→ モデルは間違った特徴で判断している可能性

5-2. Grad-CAMの実装

import tensorflow as tf import numpy as np import matplotlib.pyplot as plt def make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None): “””Grad-CAMヒートマップを生成””” # 勾配を取得するためのモデルを作成 grad_model = tf.keras.models.Model( [model.inputs], [model.get_layer(last_conv_layer_name).output, model.output] ) # 勾配を計算 with tf.GradientTape() as tape: conv_outputs, predictions = grad_model(img_array) if pred_index is None: pred_index = tf.argmax(predictions[0]) class_channel = predictions[:, pred_index] # 勾配を取得 grads = tape.gradient(class_channel, conv_outputs) # チャンネルごとの重要度を計算 pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) # ヒートマップを生成 conv_outputs = conv_outputs[0] heatmap = conv_outputs @ pooled_grads[…, tf.newaxis] heatmap = tf.squeeze(heatmap) # 正規化 heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap) return heatmap.numpy() def display_gradcam(img, heatmap, alpha=0.4): “””Grad-CAMを元画像に重ねて表示””” # ヒートマップをリサイズ import cv2 heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) # カラーマップを適用 heatmap = np.uint8(255 * heatmap) jet = plt.cm.get_cmap(“jet”) jet_colors = jet(np.arange(256))[:, :3] jet_heatmap = jet_colors[heatmap] # 重ね合わせ superimposed = jet_heatmap * alpha + img superimposed = superimposed / superimposed.max() return superimposed
💡 Grad-CAMの活用場面
  • モデルのデバッグ:間違った特徴を見ていないか確認
  • 信頼性の検証:正しい根拠で判断しているか
  • 説明可能性:なぜその判断をしたか説明
  • 医療AI:診断根拠の可視化

📝 STEP 26 のまとめ

✅ このステップで学んだこと
  • 学習曲線:過学習・学習不足を診断
  • 混同行列:クラスごとの予測結果を可視化
  • 評価指標:適合率、再現率、F1スコア
  • 誤分類分析:間違えやすいパターンを特定
  • Grad-CAM:CNNが見ている領域を可視化
💡 覚えておくべきコード
# 混同行列 from sklearn.metrics import confusion_matrix, classification_report cm = confusion_matrix(y_test, y_pred) print(classification_report(y_test, y_pred)) # 学習曲線 plt.plot(history.history[‘loss’], label=’訓練’) plt.plot(history.history[‘val_loss’], label=’検証’)
🚀 次のステップへ

モデル評価と可視化を習得しました!次のSTEP 27からは総合プロジェクトに入ります。

これまで学んだ全ての知識を使って、実践的なプロジェクトを完成させましょう!

📝 練習問題

問題1 やさしい

過学習の判断

学習曲線で「訓練損失は下がり続けるが、検証損失が上がり始める」場合、何が起きていますか?

  • A. 学習不足
  • B. 過学習
  • C. 正常な学習
  • D. データの問題
正解:B

訓練データに過度に適合し、検証データへの汎化性能が低下しています。Dropout追加、データ拡張、正則化などで対策します。

問題2 やさしい

混同行列の読み方

混同行列でFP(False Positive)が多い場合、どのような問題がありますか?

  • A. 実際に正なのに負と予測している
  • B. 実際に負なのに正と予測している
  • C. 全ての予測が正しい
  • D. 全ての予測が間違っている
正解:B

FP(False Positive)は「偽陽性」で、実際は負(Negative)なのに正(Positive)と誤って予測しています。

問題3 ふつう

再現率の重要性

「病気の検出」タスクで特に重要視すべき指標はどれですか?

  • A. 適合率(Precision)
  • B. 再現率(Recall)
  • C. 精度(Accuracy)
  • D. 損失(Loss)
正解:B

病気の検出では、実際に病気の人を見逃さないこと(FNを減らす)が重要です。再現率(Recall)は「実際の陽性のうち、どれだけ検出できたか」を表すため、医療診断では特に重視されます。

問題4 むずかしい

Grad-CAMの目的

Grad-CAMの主な目的として、最も適切なものを選んでください。

  • A. モデルの学習速度を上げる
  • B. CNNが画像のどこを見て判断したか可視化する
  • C. データ拡張を自動化する
  • D. ハイパーパラメータを最適化する
正解:B

Grad-CAMは、CNNの最後の畳み込み層の勾配を使って、モデルが画像のどの部分に注目して判断したかをヒートマップとして可視化します。モデルの解釈可能性を高める技術です。

📝

学習メモ

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

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