作业所需数据 akti
作业参考答案
作业要求
在作业三中我们使用CNN编写了一个食物分类器,本次作业在作业三的基础对神经网络做一个解释工作,共有四个具体的Task,下面一个个分析。
Task1——Sailency Map
卷积网络可以很好的进行分类工作,测试集上能达到很高的准确率,但是要解释神经网络高性能的原因并不容易。对于我们来说神经网络就是一个黑箱模型,内部的机理完全不清楚,对于人类来说,无法解释的东西便是无法信任的,因此神经网络的解释工作是必需的。
当我们训练好了一个分辨食物的分类器,它能够很好的分辨食物,我们便会很好奇,这个分类器到底是如何分辨食物的?它是“真的”学习到了食物的特征,还是依靠其它方法“欺骗”了我们?
优化模型时,我们计算的是损失函数loss对model的参数的的偏微分值。但如果我们把model的参数视作特征输入,计算loss对原本是输入的图片的偏微分值。这样通过计算图片的一部分像素的梯度,可以得到这部分像素的重要性。
下面是参考代码的实现:
def normalize(image):
return (image - image.min()) / (image.max() - image.min())
#归一化
def compute_saliency_maps(x, y, model):
model.eval()
x = x.cuda()
# 最關鍵的一行 code
# 因為我們要計算 loss 對 input image 的微分,原本 input x 只是一個 tensor,預設不需要 gradient(梯度)
# 這邊我們明確的告知 pytorch 這個 input x 需要gradient,這樣我們執行 backward 後 x.grad 才會有微分的值
x.requires_grad_()
y_pred = model(x)
loss_func = torch.nn.CrossEntropyLoss()
loss = loss_func(y_pred, y.cuda())
loss.backward()
saliencies = x.grad.abs().detach().cpu() #detach()用于切断反向传播,这样不会被梯度改变
# saliencies: (batches, channels, height, weight)
'''
因為接下來我們要對每張圖片畫 saliency map,每張圖片的 gradient scale 很可能有巨大落差
可能第一張圖片的 gradient 在 100 ~ 1000,但第二張圖片的 gradient 在 0.001 ~ 0.0001
如果我們用同樣的色階去畫每一張 saliency 的話,第一張可能就全部都很亮,第二張就全部都很暗,
如此就看不到有意義的結果,我們想看的是「單一張 saliency 內部的大小關係」,
所以這邊我們要對每張 saliency 各自做 normalize。手法有很多種,這邊只採用最簡單的(平均值)
'''
saliencies = torch.stack([normalize(item) for item in saliencies])
return saliencies
# 指定想要一起 visualize 的圖片 indices
img_indices = [83, 4218, 4707, 8598] #随机选择4张图片
images, labels =<