打開黑盒子 Open Black Boxes 1: CAM

William Huang
Jarvis Toward Intelligence
8 min readMar 28, 2020
From Deep Dream Generator

前言

在機器學習大行其道的今天,我們已經有不少開源的模型可供我們在下游的任務中使用,並不斷的在圖像與文字等等領域達到令人驚豔的成果,且僅僅是藉由足夠多的資料來訓練模型便可完成了。

眾所周知,機器學習擁有強大的學習能力,但卻也帶了另一個隱憂:人們無法解釋模型為何做如此決定。這個問題的主要原因是由於模型過於複雜,尤其是類神經網絡,因擁有成千上萬個參數而被視為黑箱。然而,即便是簡單的決策樹,只要深度超過三層,就算是專家也很難完全理解箇中的原理,更別說實務上通常是使用 Xgboost 或 LightGBM 等更複雜的樹模型。

除此之外,在現實世界中並不是只要做好預測的任務就結束了,人們除了檢驗模型是否存在偏差,也需要知道模型做決策的理由,以此判斷是否該相信模型的決策。舉例來說,我們訓練好一個圖像分類模型能正確得到某張照片裡有條魚的結果,但實際上模型卻是看到周遭有水的存在才如此判定。

如果無法很好的解釋一個模型,就會因為沒辦法在很多領用的應用理給出可靠的訊息而受到限制。例如:

  • 模型是根據應徵者的能力還是性別來決定錄取與否?
  • 模型是根據具體事證還是膚色來判斷罪犯是否可以假釋?
  • 模型協助醫生做醫療診斷時是根據何種病理特徵來判定結果?
  • 金融相關的決策依法需要提供理由,像是為何拒絕給某人貸款?

為了解決以上種種問題,人們需要能很好解釋模型的技術。而這個系列文將會為各位介紹各式各樣的可解釋性分析技術,其中包含其原理與使用的方法。

可解釋性分析

具體來說,可解釋性分析應該要做到什麼樣的程度呢?即便是最簡單的 ResNet18 也有高達一千一百萬多個參數!顯然易見的是我們不需要也做不到針對每一個參數做細粒度的解釋,且過於粗粒度會無法精準的解釋。可解釋性分析其實就像是一段光譜,在光譜的兩端,過細或過粗均無法達到很好效果,必須在光譜的中間找到一個可以接受的範圍內進行解釋。

From pngtree

可解釋性分析可用以下的定義來概括:

Interpretation is the process of giving explanations to Human.

可解釋性分析注重在於是否能讓人們易於理解。換句話說,讓機器可以說人話!一個強大但無法易於理解的解釋方法是無法為人們帶來任何價值!

以下將以最經典的 CAM 來一睹可解釋性分析的強大威力!

CAM (Class Activation Mapping)

From Learning Deep Features for Discriminative Localization

CAM 技術簡單來說,當一個 CNN 模型看完原始圖像後,CAM 可以顯示其模型會對哪塊小區域給予較大的關注。

如上圖所示,當一張大小為 𝐶×𝐻×𝑊 的圖像(註 1)輸入至 CNN 模型裡,會先經過好幾層的卷積層並不斷地抽取圖像的特徵,最終輸出 𝐶′ 張大小為 𝐻′×𝑊′ 的特徵圖。每一張特徵圖都是模型所學習到的特徵(filter)與圖像的匹配程度,特徵圖的像素值越大,就代表了匹配的程度越高。

再進入 CAM 之前,我們需要全局池化層(GAP)將特徵圖形成長度為 𝐶′ 的向量,隨後用權重 𝐖 相乘再經過 softmax 歸一化後得知分類『Australian terrier』的機率值最大,於是模型就預測該圖像是屬於『Australian terrier』這個分類。

全局池化層 Global Average Pooling (GAP) 的原理

使用全局池化層的理由是因為在 CNN 模型裡,全連接層的參數佔了整體模型參數相當大的比例,而過多的參數會有過擬合的風險。用全局池化層來代替全連接層,藉由空間平均(spatial average)的操作來將原本大小為 𝐶′×𝐻′×𝑊′ 的特徵圖壓縮成 𝐶′×1×1 的向量,如此一來便可用更少參數的全連接層來輸出預測值。這些 𝐶′ 的數值就反映出特徵圖整體的匹配程度。

全連接層與全局池化層的比較

接下來回到 CAM 那張圖,可觀察到分類『Australian terrier』的 logits 值(註 2)是由長度為 𝐶′ 的向量經過加權和所得到的;權重 𝑤ᵢ 的值越大反映出第 𝑖 張特徵圖對 logits 值影響越大,越接近 0 就越無關緊要。用前述的權重 𝑤ᵢ 來把特徵圖作加權和,所得到的結果就是分類『Australian terrier』所對應的 CAM 了。

可以用以下簡單的數學公式來表示 CAM 的核心概念:

𝑓ᵢ(𝑥, 𝑦) 代表第 𝑖 張特徵圖在 (𝑥, 𝑦) 座標下的像素值,𝑐 是代表何者分類。

用 PyTorch 來實作 CAM

儘管 CAM 可以視覺化 CNN 模型所關注的區域,但卻要求模型必須用一個全局池化層接在最後一層卷積層之後,並通過一個全連接層來輸出。這就意味著沒有上述結構的模型需要被修改,使之接上一個全局池化層,並再訓練來微調參數。這就大大限制 CAM 的使用時機。幸好,Inception V3 模型本身就滿足上述結構的要求,也可以免於再訓練的麻煩。接下來將以 Inception V3 來實作 CAM!

Inception V3 的結構圖

用開源模組pretrainedmodels 來載入 Inception V3。 pretrainedmodels 這個模組提供了各式各樣的預訓練 CNN 模型,並且提供方便的 API 可供操作。

觀察打印出模型結構的輸出:

Inception V3 的全連接層

可以發現在 Inception V3 裡全連接層的名稱為 last_linear,因此可以用下面第 10 行程式碼來取得全連接層的權重並儲存起來:

那該怎麼取得特徵圖呢?幸運的是,從 pretrainedmodels 載入的模型均有提供 model.features()model.logits() 兩種方法,從 source code 可看出model.features() 是回傳卷積層的輸出,也就是我們需要的特徵圖,而 model.logits() 接收前述的特徵圖再經過全局池化層和全連接層,最終輸出 logits 值。

將整個過程分成兩個步驟:

  1. 首先用model.features() 方法來產生特徵圖並儲存起來,
  2. 最後再用 model.logits() 方法接收特徵圖並輸出最終的 logits 值。

萬事俱備,只欠將特徵圖進行加權和:

要注意的是加權和是沿著 channel 維度來進行(對應到上面第 10 行的 axis=0),因此 heatmap 會是 𝐻′×𝑊′ 的灰度圖。為了能和原始圖像匹配,我們需要將 heatmap 放大至與原始圖像相同的大小。除了之外,也需要將 heatmap 做歸一化好讓每一個像素值都落在 0 到 1 之間,最後乘以 255 並轉型成 uint8 好顯示出來。

至此我們就已經將 CAM 的精髓給實作出來了!詳細的程式碼可至我的 GitHub 看看。廢話不多說了,馬上拿一張圖像來試試看吧!

可視化 CAM

我們使用下面這張滑雪的照片來進行可視化。在這張照片裡包含了很多物體,像是人物、白雪、山坡,以及天空。把照片交給 CNN 模型觀看,看看預測結果是否會跟 CAM 所顯示的區域相符。

我們挑出前三高預測機率的分類,依序是 ski(滑雪)、alp(高山),和bannister(欄杆)。可以看出 ski 所關注的區域正好是雙腳與周圍的區域,而 alp 所關注的是山坡,由此可知 CAM 可正確顯示出分類所對應的區域。

結語

這篇我們討論了可解釋性分析的重要性,不只是讓人們可以信任模型,也可以協助找出模型的缺陷或偏差,指引出修正的方向,好讓模型更有可靠性,甚至可能從可解釋性分析的結果得到珍貴的知識。

同時我們也介紹並實作 CNN 模型的可解釋性分析 CAM 這個技術,並得到合理的效果。然而,CAM 要求模型並須擁有全局池化層以及全連接層這個特殊的結構,這大大限制了可應用的 CNN 模型。除此之外,對於擁有多個全連接層,甚至更加複雜的模型而言,CAM 就束手無策了。在下一篇我們將會介紹基於梯度的 Grad-CAM 技術,一舉解決上述的問題!

備註

  • 註 1: 在 PyTorch 裡 tensor 的通道順序是 channel、height、width,而 TensorFlow 則是 height、width、channel。這裡我們以 PyTorch 為主。
  • 註 2: logits 值是指尚未經過 softmax 歸一化的數值。

--

--