Pytorch實現Grad-CAM

2020-08-11 20:47:11

因爲有一個分類模型始終得不到比較好的結果,所以查閱資料發現可以使用類啓用圖(CAM)的方式來看看模型究竟學到了什麼,是不是重點關注我們希望的區域,所以特此記錄一下學習過程。

簡介

CAM全稱是Class Activation Map,即類啓用圖。可以理解爲模型某次預測中,對哪個區域的響應最大,可以說這個區域很大程度上決定了模型這次預測結果。以貓狗大戰爲例,如下面 下麪這張圖
在这里插入图片描述一個任意的分類網路,輸入一個既包含着一隻狗,又包含着一隻貓的貓狗合影圖片,它會輸出一個2維度的概率向量,分別對應着圖片分類爲貓和圖片分類爲狗的概率。那麼這兩個概率,與圖片中的哪些部分的關係更大,那些部分的關係更小呢?換句話講,輸出的概率的大小與輸入圖片中哪些區域的畫素值更敏感呢?如果找出這個敏感度的一個熱力圖,越敏感的地方,溫度越高,越不敏感的地方,溫度月底,那就是類啓用熱力圖,如下圖中c和i所示就分別時預測貓類別的CAM和預測狗類別的CAM,它很直觀地告訴了我們模型是「看到了」貓的身體所以才認爲圖中有貓,「看到了」狗的臉才認爲圖中有狗。

網上已經有很多關於CAM原理和公式推導,本人水平不高,就不獻醜了,各位感興趣可以去網上自行搜尋。在這裏講講我個人的理解。一般來說,分類網路將其分成兩個部分組成,一個是特徵提取部分,一個是分類預測部分。特徵提取就是將圖片對映成特徵圖的形式,比如說VGG16的特徵層可以將一張224224的圖片對映爲77*512(即下採樣32倍),後面分類部分就是將這個特徵圖再次對映到類別向量,最後得到預測結果。現在問題來了,我們如何知道模型是根據什麼資訊對圖片做出預測呢?一個比較直觀上的思路就是將特徵圖與原圖聯繫起來,畢竟我們一般都認爲特徵圖是原圖語意資訊的對映,它反映了模型提取的資訊(這語意資訊不一定是我們想要的)。所以CAM就是幹這種事的,將特徵圖與原圖聯繫起來,並以熱力圖的形式展示出來。

CAM和Grad-cam是兩種不同生成熱力圖的方式,關於它們的區別,下面 下麪這篇部落格講的很清晰並且附帶了Keras版本的復現
keras CAM和Grad-cam原理簡介與實現:https://blog.csdn.net/MrR1ght/article/details/92799591

整個流程爲:

  1. 求影象經過特徵提取後最後一次折積後得到的特徵圖(如VGG16 conv5_3的特徵圖(7x7x512)),大小爲H×W×C。
  2. C張feature map在全連線層分類的權重肯定不同,利用反向傳播求出每張特徵圖的權重。注意Grad-cam這裏的權重是指梯度的均值,反向傳播回來得到的梯度剛開始也是H×W×C(也就是特徵圖尺寸),然後對每一個通道的H*W求均值,最後得到(C,)的梯度,也就是每張特徵圖的權重。
  3. 用每張特徵圖乘以權重得到帶權重的特徵圖(7x7x512),在第三維求均值得到H×W(7x7)的map(np.mean(axis=-1)),relu啓用,歸一化處理(避免有些值不在0-255範圍內)。

程式碼實現

如果想用pytorch實現Grad-cam,那就必須先瞭解pytorch中hook機制 機製。下面 下麪的部落格清晰明瞭的介紹了相關概念。
部落格鏈接:PyTorch的hook及其在Grad-CAM中的應用
pytorch實現範例:https://github.com/TingsongYu/PyTorch_Tutorial/blob/master/Code/4_viewer/6_hook_for_grad_cam.py