深度學習與電腦視覺教程(15) | 視覺模型可視化與可解釋性(CV通關指南·完結)
- 作者:韓信子@ShowMeAI
- 教程地址://www.showmeai.tech/tutorials/37
- 本文地址://www.showmeai.tech/article-detail/274
- 聲明:版權所有,轉載請聯繫平台與作者並註明出處
- 收藏ShowMeAI查看更多精彩內容
本系列為 斯坦福CS231n 《深度學習與電腦視覺(Deep Learning for Computer Vision)》的全套學習筆記,對應的課程影片可以在 這裡 查看。更多資料獲取方式見文末。
前言
深度可視化技術是深度學習中一個仍處於探索階段的學術研究熱點,它可以幫助我們更直觀地理解模型做的事情。
以電腦視覺為例,CNN 中有著數以千計的卷積濾波器。深度神經網路中不同的濾波器會從輸入影像中提取不同特徵表示。
己有的研究表明低層的卷積核提取了影像的低級語義特性(如邊緣、角點),高層的卷積濾波器提取了影像的高層語義特性(如影像類別)。
但是,由於深度神經網路會以逐層複合的方式從輸入數據中提取特徵,我們仍然無法像Sobel運算元提取的影像邊緣結果圖一樣直觀地觀察到深度神經網路中的卷積濾波器從輸入影像中提取到的特徵表示。
本篇內容ShowMeAI和大家來看看對模型的理解,包括CNN 可視化與理解的方法,也包含一些有趣的應用如DeepDream、影像神經風格遷移等。
本篇重點
- 特徵/濾波器可視化
- DeepDream
- 影像神經風格遷移
1.特徵可視化
我們在之前的課程里看到CNN的各種應用,在電腦視覺各項任務中發揮很大的作用,但我們一直把它當做黑盒應用,本節內容我們先來看看特徵可視化,主要針對一些核心問題:
- CNN工作原理是什麼樣的
- CNN的中間層次都在尋找匹配哪些內容
- 我們對模型理解和可視化有哪些方法
1.1 第一個卷積層
1) 可視化卷積核
第一個卷積層相對比較簡單,可以把第一層的所有卷積核可視化來描述卷積層在原始影像匹配和關注什麼。
可視化卷積核的背後原理是,卷積就是卷積核與影像區域做內積的結果,當影像上的區域和卷積核很相似時,卷積結果就會最大化。我們對卷積核可視化來觀察卷積層在影像上匹配尋找什麼。
常見的CNN架構第一層卷積核如下:
從圖中可以看到,不同網路的第一層似乎都在匹配有向邊和顏色,這和動物視覺系統開始部分組織的功能很接近。
1.2 中間層
第二個卷積層就相對複雜一些,不是很好觀察了。
第一個卷積層使用 \(16\) 個 \(7 \times 7 \times 3\) 的卷積核,第二層使用 \(20\) 個 \(7 \times 7 \times 16\) 的卷積核。由於第二層的數據深度變成 \(16\) 維,不能直接可視化。一種處理方法是對每個卷積核畫出 \(16\) 個 \(7 \times 7\) 的灰度圖,一共畫 \(20\) 組。
然而第二層卷積不和圖片直接相連,卷積核可視化後並不能直接觀察到有清晰物理含義的資訊。
1) 可視化激活圖
與可視化卷積核相比,將激活圖可視化更有觀察意義。
比如可視化 AlexNet 的第五個卷積層的 \(128\) 個 \(13 \times 13\) 的特徵圖,輸入一張人臉照片,畫出 Conv5 的 \(128\) 個特徵灰度圖,發現其中有激活圖似乎在尋找人臉(不過大部分都是雜訊)。
2) Maximally Activating Patches(最大激活區塊)
可視化輸入圖片中什麼類型的小塊可以最大程度的激活不同的神經元。
- 比如選擇 AlexNet 的 Conv5 里的第 \(17\) 個激活圖(共 \(128\) 個),然後輸入很多的圖片通過網路,並且記錄它們在 Conv5 第 \(17\) 個激活圖的值。
- 這個特徵圖上部分值會被輸入圖片集最大激活,由於每個神經元的感受野有限,我們可以畫出這些被最大激活的神經元對應在原始輸入圖片的小塊,通過這些小塊觀察不同的神經元在尋找哪些資訊。
如下圖所示,每一行都是某個神經元被最大激活對應的圖片塊,可以看到:
- 有的神經元在尋找類似眼睛的東西
- 有的在尋找彎曲的曲線等
如果不使用 Conv5 的激活圖,而是更後面的卷積層,由於卷積核視野的擴大,尋找的特徵也會更加複雜,比如人臉、相機等,對應圖中的下面部分。
1.3 倒數第二個全連接層
1) 最鄰近
關於最近鄰演算法的詳細知識也可以參考ShowMeAI的下述文章
另一個有價值的觀察對象是輸入到最後一層用於分類的全連接層的圖片向量,比如 AlexNet 每張圖片會得到一個 \(4096\) 維的向量。
使用一些圖片來收集這些特徵向量,然後在特徵向量空間上使用最鄰近的方法找出和測試圖片最相似的圖片。作為對比,是找出在原像素上最接近的圖片。
可以看到,在特徵向量空間中,即使原像素差距很大,但卻能匹配到實際很相似的圖片。
比如大象站在左側和站在右側在特徵空間是很相似的。
2) 降維
關於PCA降維演算法的詳細知識也可以參考ShowMeAI的下述文章
另一個觀察的角度是將 \(4096\) 維的向量壓縮到二維平面的點,方法有PCA,還有更複雜的非線性降維演算法比如 t-SNE(t-distributed stochastic neighbors embeddings,t-分布鄰域嵌入)。我們把手寫數字 0-9 的圖片經過CNN提取特徵降到2維畫出後,發現都是按數字簇分布的,分成10簇。如下圖所示:
同樣可以把這個方法用到 AlexNet 的 \(4096\) 維特徵向量降維中。
我們輸入一些圖片,得到它們的 \(4096\) 維特徵向量,然後使用 t-SNE 降到二維,畫出這些二維點的網格坐標,然後把這些坐標對應的原始圖片放在這個網格里。
如果大家做這個實驗,可以觀察到相似內容的圖片聚集在了一起,比如左下角都是一些花草,右上角聚集了藍色的天空。
1.4 哪些像素對分類起作用?
1) 遮擋實驗(Occlusion Experiments)
有一些方法可以判定原始圖片的哪些位置(像素)對最後的結果起作用了,比如遮擋實驗(Occlusion Experiments)是一種方法。
它在圖片輸入網路前,遮擋圖片的部分區域,然後觀察對預測概率的影響,可以想像得到,如果遮蓋住核心部分內容,將會導致預測概率明顯降低。
如下圖所示,是遮擋大象的不同位置,對「大象」類別預測結果的影響。
2) 顯著圖(Saliency Map)
除了前面介紹到的遮擋法,我們還有顯著圖(Saliency Map)方法,它從另一個角度來解決這個問題。
顯著圖(Saliency Map)方法是計算分類得分相對於影像像素的梯度,這將告訴我們在一階近似意義上對於輸入圖片的每個像素如果我們進行小小的擾動,那麼相應分類的分值會有多大的變化。
可以在下圖看到,基本上找出了小狗的輪廓。
進行語義分割的時候也可以運用顯著圖的方法,可以在沒有任何標籤的情況下可以運用顯著圖進行語義分割。
3) 引導式反向傳播
不像顯著圖那樣使用分類得分對圖片上的像素求導,而是使用卷積網路某一層的一個特定神經元的值對像素求導,這樣就可以觀察影像上的像素對特定神經元的影響。
但是這裡的反向傳播是引導式的,即 ReLU 函數的反向傳播時,只回傳大於 \(0\) 的梯度,具體如下圖所示。這樣的做法有點奇怪,但是效果很好,影像很清晰。
我們把引導式反向傳播計算的梯度可視化和最大激活塊進行對比,發現這兩者的表現很相似。
下圖左邊是最大激活塊,每一行代表一個神經元,右側是該神經元計算得到的對原始像素的引導式反向傳播梯度。
下圖的第一行可以看到,最大激活該神經元的影像塊都是一些圓形的區域,這表明該神經元可能在尋找藍色圓形狀物體,下圖右側可以看到圓形區域的像素會影響的神經元的值。
4) 梯度上升(Gradient Ascent)
引導式反向傳播會尋找與神經元聯繫在一起的影像區域,另一種方法是梯度上升,合成一張使神經元最大激活或分類值最大的圖片。
我們在訓練神經網路時用梯度下降來使損失最小,現在我們要修正訓練的卷積神經網路的權值,並且在影像的像素上執行梯度上升來合成影像,即最大化某些中間神將元和類的分值來改變像素值。
梯度上升的具體過程為:輸入一張所有像素為0或者高斯分布的初始圖片,訓練過程中,神經網路的權重保持不變,計算神經元的值或這個類的分值相對於像素的梯度,使用梯度上升改變一些影像的像素使這個分值最大化。
同時,我們還會用正則項來阻止我們生成的影像過擬合。
總之,生成影像具備兩個屬性:
- ① 使最大程度地激活分類得分或神經元的值
- ② 使我們希望這個生成的影像看起來是自然的。
正則項強制生成的影像看起來是自然的影像,比如使用 L2 正則來約束像素,針對分類得分生成的圖片如下所示:
也可以使用一些其他方法來優化正則,比如:
- 對生成的影像進行高斯模糊處理
- 去除像素值特別小或梯度值特別小的值
上述方法會使生成的影像更清晰。
也可以針對某個神經元進行梯度上升,層數越高,生成的結構越複雜。
添加多模態(multi-faceted)可視化可以提供更好的結果(加上更仔細的正則化,中心偏差)。通過優化 FC6 的特徵而不是原始像素,會得到更加自然的影像。
一個有趣的實驗是「愚弄網路」:
輸入一張任意影像,比如大象,給它選擇任意的分類,比如考拉,現在就通過梯度上升改變原始影像使考拉的得分變得最大,這樣網路認為這是考拉以後觀察修改後的影像,我們肉眼去看和原來的大象沒什麼區別,並沒有被改變成考拉,但網路已經識別為考拉(圖片在人眼看起來還是大象,然而網路分類已經把它分成考拉了)。
2.DeepDream
DeepDream是一個有趣的AI應用實驗,仍然利用梯度上升的原理,不再是通過最大化神經元激活來合成圖片,而是直接放大某些層的神經元激活特徵。
步驟如下:
- ① 首先選擇一張輸入的影像,通過神經網路運行到某一層
- ② 接著進行反向傳播並且設置該層的梯度等於激活值,然後反向傳播到影像並且不斷更新影像。
對於以上步驟的解釋:試圖放大神經網路在這張影像中檢測到的特徵,無論那一層上存在什麼樣的特徵,現在我們設置梯度等於特徵值,以使神經網路放大它在影像中所檢測到的特徵。
下圖:輸入一張天空的圖片,可以把網路中學到的特徵在原影像上生成:
程式碼實現可以參考google官方實現 //github.com/google/deepdream
3.影像神經風格遷移
關於影像神經網路風格遷移的講解也可以參考ShowMeAI的下述文章
3.1 特徵反演(Feature Inversion)
我們有一個查看不同層的特徵向量能保留多少原始的圖片資訊的方法,叫做「特徵反演」。
具體想法是:任選1張圖片,前向傳播到已經訓練好的 CNN,選取其在 CNN 某一層產生的特徵向量,保留這個向量。我們希望生成1張圖片,盡量讓它在該層產生一樣的特徵向量。
我們依舊使用梯度上升方法來完成,這個任務的目標函數定義為「最小化生成圖片的特徵向量與給定特徵向量的L2距離」,當然我們會加一些正則化項保證生成圖片的平滑,總體如下圖所示:
通過這個方法,我們可以看到不同層的特徵向量所包含的資訊完整度,如下圖所示:
解釋講解:
- 在 relu2_2 層,可以根據特徵向量幾乎無損地恢復出原圖片;
- 從 ReLU4_3 ReLU5_1 重構影像時,可以看到影像的一般空間結構被保留了下來,仍可以分辨出大象,蘋果和香蕉,但是許多低層次的細節並比如紋理、顏色在神經網路的較高層更容易損失。
3.2 紋理生成(Texture Synthesis)
下面我們聊到的是「紋理生成」,針對這個問題,傳統的方法有「近鄰法」:根據已經生成的像素查看當前像素周圍的鄰域,並在輸入影像的影像塊中計算近鄰,然後從輸入影像中複製像素。但是這類方法在面對複雜紋理時處理得並不好。
1) 格萊姆矩陣(Gram Matrix)
格萊姆矩陣計算方法:
紋理生成的神經網路做法會涉及到格萊姆矩陣(Gram Matrix),我們來介紹一下它,我們先看看格萊姆矩陣怎麼得到:
① 將一張圖片傳入一個已經訓練好的 CNN,選定其中一層激活,其大小是 \(C \times H \times W\),可以看做是 \(H \times W\) 個 \(C\) 維向量。
② 從這個激活圖中任意選取兩個C維向量,做矩陣乘法可以得到一個 \(C \times C\) 的矩陣。然後對激活圖中任意兩個 \(C\) 維向量的組合,都可以求出這樣一個矩陣。把這些矩陣求和並平均,就得到 Gram Matrix。
格萊姆矩陣含義:
格萊姆矩陣告訴我們兩個點代表的不同特徵的同現關係,矩陣中位置索引為 \(ij\) 的元素值非常大,這意味著這兩個輸入向量的位置索引為 \(i\) 和 \(j\) 的元素值非常大。
格萊姆矩陣捕獲了一些二階統計量,即「映射特徵圖中的哪些特徵傾向於在空間的不同位置一起激活」。
格萊姆矩陣其實是特徵之間的偏心協方差矩陣(即沒有減去均值的協方差矩陣)。其計算了每個通道特徵之間的相關性,體現的是哪些特徵此消彼長,哪些特徵同時出現。
我們可以認為格萊姆矩陣度量了圖片中的紋理特性,並且不包含影像的結構資訊,因為我們對影像中的每一點所對應的特徵向量取平均值,它只是捕獲特徵間的二階同現統計量,這最終是一個很好的紋理描述符。
事實上,使用協方差矩陣代替格萊姆矩陣也能取得很好的效果,但是格萊姆矩陣有更高效的計算方法:
- 將激活圖張量 \(C \times H \times W\) 展開成 \(C \times HW\) 的形式,然後將其乘以其轉置。
2) 神經紋理生成(Neural Texture Synthesis)
當我們有了格萊姆矩陣這一度量影像紋理特性的工具後,就可以使用類似於梯度上升演算法來產生特定紋理的影像。
演算法流程如下圖所示:
紋理生成步驟:
- ① 首先把含有紋理的影像輸入到一個預訓練網路中(例如VGG),記錄其每一層的激活圖並計算每一層的格萊姆矩陣。
- ② 接著隨機初始化一張要生成的新的影像,同樣把這張初始化影像通過預訓練網路並且計算每一層的 gram 矩陣。
- ③ 然後計算輸入影像紋理矩陣和生成影像紋理矩陣之間的加權 L2 損失,進行反向傳播,並計算相對於生成影像的像素的梯度。
- ④ 最後根據梯度上升一點點更新影像的像素,不斷重複這個過程,即計算兩個格萊姆矩陣的 L2 範數損失和反向傳播影像梯度,最終會生成與紋理影像相匹配的紋理影像。
生成的紋理效果如下圖所示:
上圖說明,如果以更高層格萊姆矩陣的 L2 距離作為損失函數,那麼生成影像就會更好地重建影像的紋理結構(這是因為更高層的神經元具有更大的感受野)。
3.3 影像神經風格遷移(Style Transfer)
如果我們結合特徵反演和紋理生成,可以實現非常熱門的一個網路應用「影像神經風格遷移(Style Transfer)」。它能根據指定的1張內容圖片和1張風格圖片,合併生成具有相似內容和風格的合成圖。
具體的做法是:準備兩張影像,一張影像稱為內容影像,需要引導我們生成影像的主題;另一張影像稱為風格影像,生成影像需要重建它的紋理結構。然後共同做特徵識別,最小化內容影像的特徵重構損失,以及風格影像的格萊姆矩陣損失。
使用下面的框架完成這個任務:
上圖所示的框架中,使用隨機雜訊初始化生成影像,同時優化特徵反演和紋理生成的損失函數(生成影像與內容影像激活特徵向量的 L2 距離以及與風格影像 gram 矩陣的 L2 距離的加權和),計算影像上的像素梯度,重複這些步驟,應用梯度上升對生成影像調整。
迭代完成後我們會得到風格遷移後的影像:它既有內容影像的空間結構,又有風格影像的紋理結構。
因為網路總損失是「特徵反演」和「紋理生成」的兩部分損失的加權和,我們調整損失中兩者的權重可以得到不同傾向的輸出,如下圖所示:
也可以改變風格影像的尺寸:
我們甚至可以使用不同風格的格萊姆矩陣的加權和,來生成多風格圖:
程式碼實現可以參考這裡://github.com/jcjohnson/neural-style
3.4 快速影像風格遷移(Fast style Transfer)
上面的風格遷移框架,每生成一張新的影像都需要迭代數次,計算量非常大。因此有研究提出了下面的 Fast style Transfer 的框架:
快速影像風格遷移方法,會在一開始訓練好想要遷移的風格,得到一個可以輸入內容影像的網路,直接前向運算,最終輸出風格遷移後的結果。
訓練前饋神經網路的方法是在訓練期間計算相同內容影像和風格影像的損失,然後使用相同梯度來更新前饋神經網路的權重,一旦訓練完成,只需在訓練好的網路上進行一次前向傳播。
程式碼實現可以參考這裡://github.com/jcjohnson/fast-neural-style
4.拓展學習
可以點擊 B站 查看影片的【雙語字幕】版本
[video(video-w7ZuTzh2-1655045006269)(type-bilibili)(url-//player.bilibili.com/player.html?aid=759478950&page=12)(image-//img-blog.csdnimg.cn/img_convert/fb8fff813d7a2f30032fa366c75942b7.png)(title-【字幕+資料下載】斯坦福CS231n | 面向視覺識別的卷積神經網路 (2017·全16講))]- 【課程學習指南】斯坦福CS231n | 深度學習與電腦視覺
- 【字幕+資料下載】斯坦福CS231n | 深度學習與電腦視覺 (2017·全16講)
- 【CS231n進階課】密歇根EECS498 | 深度學習與電腦視覺
- 【深度學習教程】吳恩達專項課程 · 全套筆記解讀
- 【Stanford官網】CS231n: Deep Learning for Computer Vision
5.參考資料
6.要點總結
- 理解CNN:
- 激活值:在激活值的基礎上理解這些神經元在尋找什麼特徵,方法有最鄰近、降維、最大化影像塊、遮擋;
- 梯度:使用梯度上升合成新影像來理解特徵的意義,比如顯著圖、類可視化、愚弄影像、特徵反演。
- 風格遷移:特徵反演+紋理生成。
ShowMeAI 斯坦福 CS231n 全套解讀
- 深度學習與電腦視覺教程(1) | CV引言與基礎 @CS231n
- 深度學習與電腦視覺教程(2) | 影像分類與機器學習基礎 @CS231n
- 深度學習與電腦視覺教程(3) | 損失函數與最優化 @CS231n
- 深度學習與電腦視覺教程(4) | 神經網路與反向傳播 @CS231n
- 深度學習與電腦視覺教程(5) | 卷積神經網路 @CS231n
- 深度學習與電腦視覺教程(6) | 神經網路訓練技巧 (上) @CS231n
- 深度學習與電腦視覺教程(7) | 神經網路訓練技巧 (下) @CS231n
- 深度學習與電腦視覺教程(8) | 常見深度學習框架介紹 @CS231n
- 深度學習與電腦視覺教程(9) | 典型CNN架構 (Alexnet, VGG, Googlenet, Restnet等) @CS231n
- 深度學習與電腦視覺教程(10) | 輕量化CNN架構 (SqueezeNet, ShuffleNet, MobileNet等) @CS231n
- 深度學習與電腦視覺教程(11) | 循環神經網路及視覺應用 @CS231n
- 深度學習與電腦視覺教程(12) | 目標檢測 (兩階段, R-CNN系列) @CS231n
- 深度學習與電腦視覺教程(13) | 目標檢測 (SSD, YOLO系列) @CS231n
- 深度學習與電腦視覺教程(14) | 影像分割 (FCN, SegNet, U-Net, PSPNet, DeepLab, RefineNet) @CS231n
- 深度學習與電腦視覺教程(15) | 視覺模型可視化與可解釋性 @CS231n
- 深度學習與電腦視覺教程(16) | 生成模型 (PixelRNN, PixelCNN, VAE, GAN) @CS231n
- 深度學習與電腦視覺教程(17) | 深度強化學習 (馬爾可夫決策過程, Q-Learning, DQN) @CS231n
- 深度學習與電腦視覺教程(18) | 深度強化學習 (梯度策略, Actor-Critic, DDPG, A3C) @CS231n
ShowMeAI 系列教程推薦
- 大廠技術實現:推薦與廣告計算解決方案
- 大廠技術實現:電腦視覺解決方案
- 大廠技術實現:自然語言處理行業解決方案
- 圖解Python編程:從入門到精通系列教程
- 圖解數據分析:從入門到精通系列教程
- 圖解AI數學基礎:從入門到精通系列教程
- 圖解大數據技術:從入門到精通系列教程
- 圖解機器學習演算法:從入門到精通系列教程
- 機器學習實戰:手把手教你玩轉機器學習系列
- 深度學習教程:吳恩達專項課程 · 全套筆記解讀
- 自然語言處理教程:斯坦福CS224n課程 · 課程帶學與全套筆記解讀
- 深度學習與電腦視覺教程:斯坦福CS231n · 全套筆記解讀