當前位置:
首頁 > 新聞 > 觀點 | 如何可視化卷積網路分類圖像時關注的焦點

觀點 | 如何可視化卷積網路分類圖像時關注的焦點

在我們使用 CNN 進行圖片分類時,模型到底關注的是圖像的哪個區域?Grad-CAM 利用卷積網路最後一個特徵圖的信息,並加權對應的梯度而構建模型分類的熱力圖,通過該熱力圖,我們可以清楚地了解哪一塊區域對於類別是最重要的。

你在訓練神經網路進行圖片分類時,有沒有想過網路是否就是像人類感知信息一樣去理解圖像?這個問題很難回答,因為多數情況下深度神經網路都被視作黑箱。我們餵給它輸入數據進而得到輸出。整個流程如果出現問題很難去調試。儘管預測的已經相當精準,但這並不能說明他們足以和人類感知的方式媲美。

為何會這樣?

假設你需要對大象和企鵝進行二分類(我知道這個任務十分簡單)。現在你已經獲取了數據集,訓好了模型並完成部署。這個模型想必是適用於絕大多數數據的,但是總有可能會出現誤判。有人可能會把它看作是一個極端情況,但是你覺得對於 CNN 來說,什麼時候物體才是明確可辨的?

結合上述內容,顯然在圖像中,大象常伴著草木出現,企鵝常伴著冰雪出現。所以,實際上模型已經學會了分辨草木與冰雪的顏色/形狀,而不是真的學會了按對象分類。

由上文案例知,如顏色通道統計那樣的簡單圖像處理技術,與訓練模型是一樣的。因為在沒有智能的情況下,模型只能依靠顏色辯物。現在你或許會問,如何知道 CNN 究竟在尋找什麼?答案就是,Grad-CAM。

加權梯度類激活映射(Grad-CAM)

我們在本篇博客中實現了加權梯度類激活映射。首先,我們要知道這不是唯一的解決方案。原作說,

加權梯度類激活映射 (Grad-CAM) 通過任意目標概念的梯度(比如說類別「狗」的分對數甚至是「狗」這個字),將這些知識傳遞到最後的卷積層進而產生一張粗略的定點陣圖,用於凸顯圖像中對於預測相關概念至關重要的區域。

通俗點講,我們只取最終卷積層的特徵圖,然後將該特徵中的每個通道通過與該通道相關的類的梯度進行加權。這種方法只不過是輸入圖像如何通過每個通道對於類的重要性來激活不同的通道,最重要的是它不需要對現有架構進行任何重訓練或更改。

觀點 | 如何可視化卷積網路分類圖像時關注的焦點

特定類的特徵空間得分就是對應類的輸出值 y^c 關於特徵圖 A_ij 的偏導在 i 和 j 維上的特徵進行全局平均池化操作。然後,我們將結果與特徵圖沿其通道軸 k 相乘。最後,將結果在通道維度 k 上求平均/池化。因此,特徵空間的得分凸的大小是 i×j。Σ 符號用於描述池化和平均操作。

觀點 | 如何可視化卷積網路分類圖像時關注的焦點

ReLU 激活函數用於得分圖,隨後被歸一化以便輸出正區域預測。

實現

為了達到本篇博客的目的,我們套用一個預訓練好的 VGG 模型,並導入一些必要包開始實現代碼。

from keras.applications.vgg16 import VGG16, preprocess_input, decode_predictionsfrom keras.preprocessing import imageimport keras.backend as Kimport numpy as npimport cv2
import sys

我們使用 Keras 自帶的 VGG16 模型。並載入一些有助於載入和處理圖像的函數。

model = VGG16(weights="imagenet")img_path = sys.argv[1]img = image.load_img(img_path, target_size=(224, 224))x = image.img_to_array(img)x = np.expand_dims(x, axis=0)
x = preprocess_input(x)

我們先初始化模型並通過命令行參數載入圖片。VGG 網路只接受 (224×224×3) 大小的圖片,所以我們要把圖片放縮到指定大小。由於我們只通過網路傳遞一個圖像,因此需要擴展第一個維度,將其擴展為一個大小為 1 的批量。然後,我們通過輔助函數 preprocess_input 從輸入圖像中減去平均 RGB 值來實現圖像的歸一化。

preds = model.predict(x)class_idx = np.argmax(preds[0])class_output = model.output[:, class_idx]
last_conv_layer = model.get_layer("block5_conv3")

此處,我們來看看頂部預測的特徵圖。所以我們得到圖像的預測,並給得分靠前的類做個索引。請記住,我們可以為任意類計算特徵圖。然後,我們可以取出 VGG16 中最後一個卷積層的輸出 block5_conv3。得到的特徵圖大小應該是 14×14×512。

grads = K.gradients(class_output, last_conv_layer.output)[0]pooled_grads = K.mean(grads, axis=(0, 1, 2))iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])pooled_grads_value, conv_layer_output_value = iterate([x])for i in range(512):
conv_layer_output_value[:, :, i] *= pooled_grads_value[i]

如上所述,我們計算相類輸出值關於特徵圖的梯度。然後,我們沿著除了通道維度之外的軸對梯度進行池化操作。最後,我們用計算出的梯度值對輸出特徵圖加權。

heatmap = np.mean(conv_layer_output_value, axis=-1)heatmap = np.maximum(heatmap, 0)heatmap /= np.max(heatmap)

然後,我們沿著通道維度對加權的特徵圖求均值,從而得到大小為 14*14 的熱力圖。最後,我們對熱力圖進行歸一化處理,以使其值在 0 和 1 之間。

img = cv2.imread(img_path)heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))heatmap = np.uint8(255 * heatmap)heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)superimposed_img = cv2.addWeighted(img, 0.6, heatmap, 0.4, 0)cv2.imshow("Original", img)cv2.imshow("GradCam", superimposed_img)
cv2.waitKey(0)

最後,我們使用 OpenCV 來讀圖片,將獲取的熱力圖放縮到原圖大小。我們將原圖和熱力圖混合,以將熱力圖疊加到圖像上。

觀點 | 如何可視化卷積網路分類圖像時關注的焦點

從上面的圖片可以清楚地看到 CNN 在圖像中尋找的是區分這些類的地方。這種技術不僅適用於定位,還可用於視覺問答、圖像標註等。

此外,它在調試建立精確模型的數據需求方面非常有幫助。雖然此技術並未過多涉及調參,但我們可以使用額外的數據和數據增強技術更好地泛化模型。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 機器之心 的精彩文章:

DeepMind提出SPIRAL:使用強化對抗學習,實現會用畫筆的智能體
你的加密貨幣有價值嗎?這裡有一個深度學習ICO詐騙鑒別系統

TAG:機器之心 |