到底是什麼特徵影響著CNN的效能?

AI科技大本營發表於2019-01-27

640?wx_fmt=jpeg


作者 | 劉暢 

編輯 | Jane
出品 | AI科技大本營(ID:rgznai100)


開門見山。最近閱讀了一篇論文,加上看了一些之前的工作。記錄一下,CNN 到底學到了什麼東西,或者換句話講。到底是什麼樣的特徵在影響著CNN 的效能?


先放論文:

IMAGENET-TRAINED CNNS ARE BIASED TOWARDS TEXTURE; INCREASING SHAPE BIAS IMPROVES ACCURACY AND ROBUSTNESS

論文地址:

https://openreview.net/pdf?id=Bygh9j09KX


JeremyRifkin 在書《The end of Work》中寫道,“時至今日,當科學家們探討人工智慧時,他們通常是在講一門能執行人們所希望機器表現的智慧藝術”。這是我比較喜歡的關於人工智慧的定義。因為它避免了大談特談如今的人工智慧技術離真正的智慧化有多遠。而是享受當下。不過,作為一名研究人員,我覺得揭開大腦的運作原理和創造真正的智慧機器是非常重要的。目前深度學習主要做的研究是關於從資料中學到規則並將其自動化的一個過程。這已經帶來了非常多的好處,舉一個簡單的例子。在醫學領域引入深度學習技術,可以將許多診斷過程全自動化,因此可以讓貧窮地區或國家的人們享受到頂級的治療。


開篇完畢,現在進入正題。儘管深度學習技術的到來給人們的生活帶來了更多的便利。但是神經網路看待和解釋世界的方式仍然是一個黑盒子。因此我們需要嘗試更好的理解它,以便我們對深度學習網路做出進一步的改進,以及嘗試去解釋某些深度學習行為。有兩種主要的方法可以嘗試理解神經網路。一種是在資料集中查詢導致特徵圖有高啟用響應值的圖片,另一種是在隨機的一張圖片中,通過優化畫素值來生成模式。接下來,通過一些例子來展示一下,CNN 到底學到了什麼?


特徵視覺化

640?wx_fmt=png


這本書《Deep Learning with Python》裡面講了如何生成模式。包括濾波器是如何響應模式(紋理)等。接下來我們先觀察一下這些模式。以 VGG16 為例。


第7層卷積(64,128)

640?wx_fmt=png

濾波器12,16,86,110(從左到右,從上到下)


第14層卷積(128,256)

640?wx_fmt=png

濾波器1, 6,31,32,54, 77(從左到右,從上到下)


第20層卷積(256,256)

640?wx_fmt=png

濾波器3,34,39,55,62,105(從左到右,從上到下)


第30層卷積(512,512)

640?wx_fmt=png

濾波器54,62,67,92,123,141(從左到右,從上到下)


第40層卷積(512,512)——網路頂部

640?wx_fmt=png

256,261,265,277,286,462(從左到右,從上到下)


這些得到的中間結果看著非常漂亮。方法就是在網路中最大化某個啟用值就可以得到這些結果。看一下第 40 層的幾張圖。已經有了明顯的形狀。比如羽毛、鐵鏈等。接下來我們分析一下這些結果。


模式識別


我們先從下面這張圖片開始吧。這張圖片看著像是拱門。於是去資料集裡面找來了一張拱門的圖片,也就是右圖。


640?wx_fmt=png


接下來我們來檢驗一下,是不是由這張圖來確定的圖片的分類。首先記住,這張圖是最後一層的第 286 個濾波器。如何檢驗呢?我們只需要將這張圖片輸入進網路,並繪製第 40 層的平均啟用響應,如下圖。


640?wx_fmt=png


可以看到在特徵圖第 286 的地方,出現了強烈的飆升。顯然它就是檢測拱形結構的濾波器。但是注意,這樣的形狀結構可能對應著幾個不同的類別。


那我們再看一個例子吧。左邊這個看著像是雞頭(最後一層,第 256 個)。因此找了右邊這一張圖片來測試。同樣的測試方法。


640?wx_fmt=png

640?wx_fmt=png


我們來看一看特徵響應圖。


640?wx_fmt=png


好像似乎也印證了我的想法,可能是某種形狀導致了最後的輸出類別。也就是說,影響 CNN 效果的其實是形狀特徵(猜想)。


不過讓我們再關注一個例子,用同樣的方法。輸入一張鳥類的圖。


640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

濾波器172,288,437,495(從左到右,從上到下)


我們發現了多個高響應的特徵圖。上面的特徵圖有像是鳥腿、眼睛和喙的東西?但是下面的特徵圖,看不出來是什麼,可能與影像的背景有關,或者一些只有網路能理解的東西。這部分現在仍然是黑匣子。也許之前的猜想是錯的。


接下來放一下程式碼(PyTorch):


1generate_image.py
2class FilterVisualizer():
3    def __init__(self, size=56, upscaling_steps=12, upscaling_factor=1.2):
4        self.size, self.upscaling_steps, self.upscaling_factor = size, upscaling_steps, upscaling_factor
5        self.model = vgg16(pre=True).cuda().eval()
6        set_trainable(self.model, False)
7
8    def visualize(self, layer, filter, lr=0.1, opt_steps=20, blur=None):
9        sz = self.size
10        img = np.uint8(np.random.uniform(150180, (sz, sz, 3)))/255  # generate random image
11        activations = SaveFeatures(list(self.model.children())[layer])  # register hook
12
13        for _ in range(self.upscaling_steps):  # scale the image up upscaling_steps times
14            train_tfms, val_tfms = tfms_from_model(vgg16, sz)
15            img_var = V(val_tfms(img)[None], requires_grad=True)  # convert image to Variable that requires grad
16            optimizer = torch.optim.Adam([img_var], lr=lr, weight_decay=1e-6)
17            for n in range(opt_steps):  # optimize pixel values for opt_steps times
18                optimizer.zero_grad()
19                self.model(img_var)
20                loss = -activations.features[0, filter].mean()
21                loss.backward()
22                optimizer.step()
23            img = val_tfms.denorm(img_var.data.cpu().numpy()[0].transpose(1,2,0))
24            self.output = img
25            sz = int(self.upscaling_factor * sz)  # calculate new image size
26            img = cv2.resize(img, (sz, sz), interpolation = cv2.INTER_CUBIC)  # scale image up
27            if blur is not None: img = cv2.blur(img,(blur,blur))  # blur image to reduce high frequency patterns
28        self.save(layer, filter)
29        activations.close()
30
31    def save(self, layer, filter):
32        plt.imsave("layer_"+str(layer)+"_filter_"+str(filter)+".jpg", np.clip(self.output, 01))
33
34
35pytorch_hook.py
36
37class  SaveFeatures():
38    def  __init__selfmodule):
39        self .hook = module.register_forward_hookself .hook_fn
40    def  hook_fnselfmoduleinputoutput):
41        self .features = torch.tensoroutputrequires_grad = True).cuda()
42    def  closeself):
43        self .hook.remove()
44
45
46filter_visualizer.py
47
48layer = 40
49filter = 265
50FV = FilterVisualizer(size=56, upscaling_steps=12, upscaling_factor=1.2)
51FV.visualize(layer, filter, blur=5)
52


你以為到這裡就完了嗎?還沒到這篇文章的重點內容,新鮮出爐的 2019 ICLR 的論文:《Imagenet-trained CNNs are biased towards texture; Increasing shape bias improves accuracy and robustness》


看標題,就知道。我們之前的猜想是錯誤的!CNN 學到的應該是紋理特徵。真讓人頭疼!


作者以一個問題入手,一隻披著象皮的貓,神經網路會把它識別為大象還是貓?最後根據實驗結果得出結論。神經網路應該是根據物體的紋理特徵來進行識別,而並非我們以為的形狀特徵。也就是說我們常瞭解的一些視覺化技術如 Deconv 都是具有誤導性的,它們的結果僅僅只是影像的重建部分,而與網路如何做出最後的決策關係不大。


其實接觸過影像風格遷移技術的技術人員應該都非常清楚,深度學習模型在裡面提取的影像的繪畫風格就是紋理特徵。貼上一張經典圖片,生成的是一張具有梵高《星月夜》圖畫風格的建築圖片。


640?wx_fmt=jpeg


在論文裡面,作者為了更清楚的瞭解,影像識別到底是基於形狀還是基於紋理。做了以下的實驗。使用三張生成的圖片,分別是帶有大象紋理的貓 , 帶有鐘錶紋理的汽車 和 帶有水瓶紋理的熊


640?wx_fmt=jpeg


作者通過實驗,採用了多個神經網路(AlexNet、VGG-16、GoogLeNet、ResNet-50、ResNet-152、DenseNet-121、SqueezeNet1_1)進行輸出結果。為了對照,還召集了大約 100 名人類來做對照實驗。這個實驗結果就是一隻帶有象皮紋理的貓被深度神經網路判斷為大象,但對人類來說仍然是貓。帶有時鐘紋理的汽車被深度神經網路判斷為時鐘,帶有水瓶紋理的熊被深度神經網路判斷為水瓶。顯然!該實驗支援了這一說法,即目前用於物體識別的深度學習技術主要依賴紋理,而不是物體形狀。


640?wx_fmt=png


當然,作者還做了更多的對比實驗。得出了一些具有啟發性的結論。比如對於只包含紋理圖片的資料集,神經網路能取得特別高的準確率。採用原圖和灰度圖,神經網路都可以取得非常高的準確率,而對於只包含輪廓和只包含邊緣的圖片,神經網路的預測準確率則顯著降低。


更多的實驗細節,可以檢視論文。總結一下,有幾點結論還是很有啟發性的:


第一、回答了影響CNN識別效能的是形狀還是紋理的問題。

第二、如何針對性的引導神經網路訓練或者學習想要它學習的特徵。(有意的抑制某個特徵)


原文連結:

https://blog.csdn.net/u012395979/article/details/86651808


(本文為 AI科技大本營投稿文章,轉載請微信聯絡 1092722531 


———————————————  徵稿  ————————————————

640?wx_fmt=png


推薦閱讀:

640?wx_fmt=png

相關文章