雷鋒網 AI科技評論按:本文作者陳仲銘,雷鋒網 AI科技評論獲其授權發布。
為什麼我的CNN網絡模型訓練出來的東西總是過度擬合?已經改了很多次參數都不行,到底是樣本有問題還是網絡模型定義有問題?問題在哪來?
CNN網絡模型中的每一層學習的是些什麼特徵?為什麼有的人說第一層卷積核提取的是邊緣信息特徵,有的人卻說第一層卷積核提取的是顏色特徵?到底是兩者都有還是什麼回事?
CNN網絡可不可以減掉幾層然後保持相同的精度和損失率呢?減掉幾層可以減少網絡參數,本來我的GPU顯存不是很大,太大的網絡塞不下,不想重新買GPU只能減層,有沒有大神可以教教我怎麼操作啊?
很多時候我們會遇到上面的問題,然後道聽途說地開始給別人瞎粑粑吹吹牛皮。在這之前,連我自己都不知道VGG16網絡最後兩層block5 conv2,block5 conv3訓練到最後幾乎沒有太多的紋理特徵。你知道嗎?不知道的話可以跟我一起學習學習,我也是個初學者,在國內CNN還沒有太流行起來之前就開始跳坑,到現在蹲坑已深。棄坑 ing。。。。
最近為自己所在的公司寫了一個工具來分析訓練出來的CNN網絡模型,如下圖所示:從第一張圖我們可以看到這張圖有一些goldfish金魚的模型,好像有很多條魚尾巴,然後中間有好多鱗片,一張很奇怪的圖像,但是別嫌棄這張圖像,因為假設你把這張圖像扔到經過ImageNet數據集訓練過的VGGNet模型,出來為goldfish的概率絕對是99%的,你多試100次看是不是都為goldfish。
同理,第2張圖,第3張圖,都是這樣的結果,連我學文科的妹紙看到這些圖就yaya叫,這是什麼,好噁心,怎麼第3張有點像鳥但是有不是鳥的呢。對,我們搞神經網絡的就喜歡這些噁心的圖片。越噁心特徵越明顯。
通過梯度上升獲得可視化卷積圖
假設人工合成的可視化卷積核圖為 x,我們希望這張合成圖 x 能夠使其對應的神經元(卷積核)具有最高的激活值。所得到的這張合成圖像就是該卷基層的卷積核「想要看到的」或者「正在尋找的紋理特徵」。也就是說我們希望找到一張圖像經過CNN網絡,傳播到指定的卷積核的時候,這張圖片可以使得該卷積核的得分最高。
為了合成這一張圖片,我們開始從一張帶有隨機噪聲的圖像開始,每個像素值隨機選取一種顏色。
接下來,我們使用這張噪聲圖作為CNN網絡的輸入向前傳播,然後取得其在網絡中第 i 層 j 個卷積核的激活 a_ij(x),然後做一個反向傳播計算 delta a_i(x)/delta x 的梯度,最後我們把該噪聲圖的卷積核梯度來更新噪聲圖。目標是希望通過改變每個像素的顏色值以增加對該卷積核的激活,這裡就使用了梯度上升法:
其中 itselong 為梯度上升的學習率。不斷重複上述過程,直到圖像 x 能夠讓第 i 層第 j 個卷積核具有較高的激活值。
對於具體的實現我們需要定義一個損失函數,該損失函數將用於最大化某個指定卷積核的激活值。以該損失函數作為優化目標,我們可以了解到底什麼樣的圖片才可以使得這個卷積核取得更好的激活值。
現在我們使用Keras的後端來完成這個損失函數, gradients(loss, variables)為返回loss函數關於variables的梯度。
start_time = time.time() # The loss is the activation of the neuron for the chosen class loss = layer_output[0, class_index] # we compute the gradient of the input picture wrt this loss grads = K.gradients(loss, input_img)[0] # this function returns the loss and grads given the input picture # also add a flag to disable the learning phase (in our case dropout) iterate = K.function([input_img, K.learning_phase()], [loss, grads]) np.random.seed(1337) # for reproducibility # we start from a gray image with some random noise input_img_data = np.random.normal(0, 10, (1,) + model.input_shape[1:]) # (1,) for batch axis
注意這裡有個小小的trick——對計算出來的梯度進行了L2正則化操作,使得梯度不會過小或過大,其帶來的好處是使梯度上升的過程平滑進行。
後端函數function用傳遞來的參數實例化一個Keras的Function類返回。這相當於Function的對象當作函數來使用,相當於重載了括號運算符,如outputs = self.train_function(inputs)。
根據剛剛定義的損失函數iterate_fun,現在可以根據梯度上升對卷積核的激活值進行梯度上升計算。
# we run gradient ascent for 1000 steps for i in range(1000): loss_value, grads_value = iterate([input_img_data, 0]) # 0 for test phase input_img_data += grads_value * learning_rate # Apply gradient to image print('Current loss value:', loss_value) # decode the resulting input image and add it to the list img = deprocess(input_img_data[0]) kept_images.append((img, loss_value)) end_time = time.time() print('Filter %d processed in %ds' % (class_index, end_time - start_time))
最後輸出的圖像如下圖所示,這是魚頭?還是羊頭?不看ImageNet的連接我也不知道是什麼頭。不過這樣的方法是我們讓輸入的圖像儘量與卷積核希望看到的東西一樣,通過該層卷積核的損失和梯度進行上升補充,對輸入的原圖進行填充細節,最後得到可視化卷積核圖。
可視化所有卷積核圖
可視化卷積核是本例子最有趣的部分,也是筆者最喜歡的部分。通過分析CNN網絡模型中的卷積核,我們將會看到每一層卷積核到底提取的是什麼樣的內容、紋理、特徵。當我們深入了解CNN模型提取特徵背後的意義,就可以有足夠信心去修改卷積神經網絡CNN的參數。
下面我們將會利用已經訓練好的VGG16網絡模型,來系統地可視化各個網絡層的各個卷積核,看看CNN是對輸入進行逐層分解提取特徵的到底都是些什麼。
最後的執行結果如下圖所示,Block1_Conv1的卷積核主要完成如顏色、方向等編碼,到了Block2_Conv2的卷積核明顯比Block1_Conv1多了更多的紋理和不同的紋理方向,所表達的顏色也更加豐富多樣,並且在邊緣處可以看到有部分凹凸表現。
隨著VGG16網絡模型繼續深入,這些顏色和方向與基本的紋理進行組合,逐漸生成特殊紋理。當進入Block3_Conv1後,方向和顏色的表現開始變少,開始出現更加複雜的紋理特徵(圓形、螺旋形、多邊形、波浪等形狀組合),到了Block5_Conv1後可以清晰看到其紋理更加特別,卷積核隨著網絡空間信息的增長而出現了更加精細和複雜的特徵。
卷積核變得越來越複雜,因為他們開始納入越來越大的空間範圍信息中,所呈現和表達的信息進一步豐富。
細心的讀者經過實際的嘗試之後或許會發現:在同一卷積層中會出現少量的可視化卷積核是空白或者相同,這意味著該卷積核對後續的操作並沒有產生實際的作用,可以通過Dropout這些卷積核以減少網絡的計算量和減少過度擬合的可能性。
另外,也會有部分可視化卷積核可以通過旋轉平移,獲得另外一個可視化卷積核。這是一個很有趣的研究方向,我們或許可以通過尋找一種旋轉不變性的方法來潛在地代替網絡層中的其他卷積核,從而壓縮卷積核的數量。驚訝的是即使對於級別相對高的濾波器,如Block4_Conv1中,通過旋轉、平移獲得相同的可視化卷積核仍然成立。
可是到了block5 conv3的最後,經過代碼實踐之後,我們會發現512個卷積核裡面只有65個卷積核loss不為0,也就是其餘的卷積核已經不能再繼續提取高維紋理特徵信息了,這是怎麼一回事?為什麼沒有了呢?這也是ResNet或者GoogleNet對於VGGNet的改進,可能有時候CNN網絡不是每一個卷積核(神經元)都能參與網絡的計算,發揮作用,提取到高維特徵。下圖為ResNet的跳層方式,因為VGG的block5 conv3、block5 conv2開始出現大量沒有用的卷積核,而block4 conv3卻有很多有用的信息可以向後傳遞。
有了對CNN網絡模型的可視化分析,我們更加深一步地理解卷積神經網絡CNN的具體操作過程,具體提取的是什麼樣的紋理特徵信息。如果你有精力,還可以自己動手指定dropout的神經元,查看自己的卷積神經網絡為什麼會過度擬合,可以怎麼修剪網絡。這是一個很有趣的過程,也是一個考驗人類耐心的過程。
CNN真的理解視覺嗎
卷積神經網絡CNN的兩個主要作用是:1)把輸入的視覺空間圖像,解耦成分層次的卷積核組合。2)通過分層次的卷積核把輸入的數據映射到不同的幾何空間。
有的人會宣稱卷積神經網絡CNN通過分層思想對輸入的圖像進行解耦,這一過程模擬了人類視覺皮層,因此才能獲得如此精妙的效果。可事實真的是這樣嗎?從科學的角度來看,這並不意味著我們真的在某種程度上解決了計算機視覺的問題,我們只是使用了數學的方法對輸入的圖像數據進行抽樣和幾何空間映射。即使科學是這麼解釋,但究其竟並沒有反駁視覺皮層不是這種工作方式。
深度學習雖然不能表達真正的智力,但毋庸置疑的是其預測效果如此驚人,以至於在近年來沒有其他算法可以比擬,甚至在某些情況下超過了人類的預測精度!我們不期待著算法學習我們的思考方式,而應去擁抱數學,用其特殊的方式去為人類服務,繼續發現、繼續創造、繼續在模擬數字領域領跑!
參考文獻:
Yosinski__2015__ICML_DL__Understanding_Neural_Networks_Through_Deep_Visualization
How convolutional neural networks see the world
地址:https://blog.keras.io/how-convolutional-neural-networks-see-the-world.html
雷鋒網 AI科技評論。