📋 このステップで学ぶこと
- 学習曲線(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の最後の畳み込み層の勾配を使って、モデルが画像のどの部分に注目して判断したかをヒートマップとして可視化します。モデルの解釈可能性を高める技術です。
artnasekai
#artnasekai #学習メモ