深度学习模型是黑箱?本课学习如何解释模型的决策,理解它"为什么这么做"。
计算输出对输入的梯度:∂y/∂x
梯度大的像素对决策影响大
利用最后卷积层的梯度,生成类激活图
αₖᶜ = (1/Z)ΣᵢΣⱼ ∂yᶜ/∂Aᵏᵢⱼ(全局平均池化梯度)
LGrad-CAM = ReLU(Σₖ αₖᶜAᵏ)
基于博弈论的Shapley值,分配每个特征的贡献。
import torch
import torch.nn as nn
import torch.nn.functional as F
# Grad-CAM实现
class SimpleCNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 16, 3, padding=1), nn.ReLU(),
nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(),
nn.AdaptiveAvgPool2d(1),
)
self.classifier = nn.Linear(32, 10)
def forward(self, x):
feat = self.features(x)
feat = feat.view(feat.size(0), -1)
return self.classifier(feat)
model = SimpleCNN()
X = torch.randn(16, 1, 28, 28)
y = torch.randint(0, 10, (16,))
# 训练
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
for epoch in range(50):
optimizer.zero_grad()
loss = nn.CrossEntropyLoss()(model(X), y)
loss.backward()
optimizer.step()
# 显著图(Saliency Map)
print("=== 显著图 (Saliency Map) ===")
x_single = X[0:1].clone().requires_grad_(True)
output = model(x_single)
target_class = output.argmax(1).item()
output[0, target_class].backward()
saliency = x_single.grad.data.abs().squeeze()
print(f"目标类别: {target_class}")
print(f"显著图统计: max={saliency.max():.4f}, mean={saliency.mean():.4f}")
print(f"最重要的5个像素位置: {saliency.flatten().topk(5).indices.tolist()}")
# 特征重要性(积分梯度简化版)
print("\n=== 特征重要性 ===")
baseline = torch.zeros_like(X[0:1])
x_input = X[0:1].clone().requires_grad_(True)
# 简化:在几个插值点计算梯度
n_steps = 10
integrated_grads = torch.zeros_like(X[0:1])
for step in range(n_steps):
alpha = (step + 1) / n_steps
interpolated = baseline + alpha * (x_input - baseline)
interpolated.requires_grad_(True)
output = model(interpolated)
model.zero_grad()
output[0, target_class].backward()
integrated_grads += interpolated.grad
integrated_grads /= n_steps
ig_importance = (X[0:1] - baseline) * integrated_grads
print(f"积分梯度: max={ig_importance.abs().max():.4f}, mean={ig_importance.abs().mean():.4f}")
# SHAP值概念(简化)
print("\n=== SHAP值概念 ===")
print("SHAP基于博弈论Shapley值")
print("φᵢ = Σ_{S⊆N\{i}} (|S|!(|N|-|S|-1)!/|N|!) [f(S∪{i}) - f(S)]")
print("计算每个特征对预测的边际贡献")
# 特征消融
print("\n=== 特征消融实验 ===")
perm_accs = []
for feat_idx in range(min(5, 10)):
model.eval()
with torch.no_grad():
orig_pred = model(X[:5]).argmax(1)
# 置换某个特征
X_perm = X[:5].clone()
# 对于展平后的特征进行置换
flat_idx = feat_idx
X_perm[:, 0, flat_idx//28, flat_idx%28] = torch.randn(5)
perm_pred = model(X_perm).argmax(1)
changed = (orig_pred != perm_pred).float().mean().item()
perm_accs.append(changed)
print(f"置换特征{feat_idx}: 预测变化率={changed:.2%}")
本课的核心知识点构成了训练技巧学习的重要一环。让我们从更高维度审视这些知识之间的关系:
⚠️ 初学者常犯的错误:
💡 最佳实践:
深度学习是一个整体——每一课的知识都不是孤立的:
💡 继续深入的学习路径:
对预训练模型实现Grad-CAM,生成热力图。
用SHAP库分析一个模型的特征重要性。
实现TCAV方法,测试模型是否依赖特定概念。
⚠️ 需要避免的典型错误:
💡 提升模型性能的系统方法:
理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:
建立正确的直觉比记住公式更重要:
1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)
2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的
3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构
4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)
本课作为训练技巧阶段的核心内容,与前后课程紧密关联:
| 关联课程 | 关联点 | 协同效应 |
|---|---|---|
| 前序课程 | 提供了本课的基础知识 | 循序渐进的理解 |
| 后续课程 | 本课内容是后续的基础 | 逐步构建能力 |
| 平行课程 | 同一阶段的互补知识 | 多角度深入理解 |
| 实战项目 | 综合运用所有知识 | 理论与实践结合 |
💡 准备面试时,确保能回答以下问题:
掌握本课内容后,可以通过以下方式继续深入:
随着AI系统在关键领域的广泛应用(医疗、金融、自动驾驶),可解释性越来越重要。未来的方向包括:
打开黑箱——你已经能解释模型为什么这么做!