當前位置:
首頁 > 科技 > 教程 | 通過可視化隱藏表示,更好地理解神經網路

教程 | 通過可視化隱藏表示,更好地理解神經網路


選自

rakeshchada


作者:

Rakesh Chada


機器之心編譯


參與:

高璇、路






本文介紹了如何利用隱藏表示可視化來更加直觀地理解神經網路訓練過程。本文使用的工具是 Neural Embedding Animator,大家可以利用該工具更好地理解模型行為、理解訓練過程中數據表示的變化、對比模型、了解此詞嵌入的變化。





詞嵌入的互動式可視化




將神經網路可視化是非常有趣的。對於監督學習而言,神經網路的訓練過程可以看做是學習如何將一組輸入數據點轉換為可由線性分類器進行分類的表示。本文我想利用這些(隱藏)表示進行可視化,從而更加直觀地了解訓練過程。這種可視化可以為神經網路的性能提供有趣的見解。



我聯想到很多想法,最終從 Andrej Karpathy 的研究(t-SNE visualization of CNN codes)中獲得了理論支持。




這個想法很簡單,可以由以下步驟簡單說明:




1. 訓練一個神經網路。


2. 一旦經過訓練,網路可為驗證/測試數據中的每個數據點生成最終的隱藏表示 (嵌入)。這個隱藏表示基本上就是神經網路中最後一層的權重。該表示近似於神經網路對數據的分類。

3. 為便於可視化,需要將權重降維到二維或三維。然後,在散點圖上可視化這些點以觀察它們是如何在空間中分離的。有一些比較流行的降維技術,如 T-SNE 或 UMAP。




儘管上述步驟是對訓練完成後的數據點進行可視化,但我認為可以實現一個有趣的拓展,即在訓練過程中在多個時間點進行可視化。這樣我們就可以單獨觀察每一個可視化,對事物如何變化產生一些見解。例如,我們可以在每一個 epoch 後進行可視化直到訓練完成,然後對它們進行對比。它的進一步擴展是生成可視化動畫。這可以通過這些靜態可視化圖和它們之間的插入控制點來實現——從而實現逐點轉換。




這個想法讓我很興奮。為了生成這些可視化,我開發了基於 D3.js 的 Javascript 工具。它能產生靜態可視化圖和動圖。對於動態圖,我們需要上傳兩個我們想要進行對比的 csv 文件,這些文件包含隱藏表示。該工具能使文件中的點動起來。我們也可以控制動畫,以便觀察一組特定的點在訓練過程中的移動軌跡。本文開頭有一個例子,讀者可以去試一下。






  • 工具(Neural Embedding Animator)地址:https://bl.ocks.org/rakeshchada/raw/43532fc344082fc1c5d4530110817306/



  • README:https://bl.ocks.org/rakeshchada/43532fc344082fc1c5d4530110817306




這絕對不是個複雜的工具。我只是想把我的設想付諸實踐。




但是,該動畫方法有一個問題:在 T-SNE/UMAP 完成後,每個 2D/3D 表示存在不一致性。首先,設置超參數和隨機種子的時候要格外小心。其次,據我所知,T-SNE 只是嘗試以這種方式嵌入:使相似的對象靠近,而不同的對象遠離。所以當我們基於兩個可視化圖製作動畫時,比如 epoch1 和 2,我們可能很難區分由純粹隨機性引起的運動和神經網路實際學習過程中的權重變化。也就是說,在我的實驗中,我有時能夠創作出合理的動畫,幫助我得到一些有趣的結論。



動圖一覽:







這個可視化框架有很多有趣的應用。以下是分類問題的一些例子:






  • 更好地了解關於數據的模型行為



  • 理解神經網路訓練過程中數據表示的變化



  • 在給定數據集上對比模型——包括超參數更改,甚至架構更改



  • 了解訓練過程中詞嵌入的變化(當調整時)




下文將用具體的實際例子對上述情況進行說明。




更好地理解關於數據的模型行為




惡意評論分類任務




我們在這裡使用的第一個例子是 Kaggle 的一項有趣的自然語言處理競賽:惡意評論分類,當時我正在開發這個工具。該競賽的目標是將文本評論分為不同類別:toxic、obscene、threat、insult 等。這是一個多標籤分類問題。




在神經網路模型中,我嘗試了幾種架構,從最簡單的(沒有卷積/循環的前饋神經網路)到更複雜的架構。我在神經網路的最後一層使用了二進位交叉熵損失和 sigmoid 激活函數。這樣,它只為每個標籤輸出兩個概率,從而實現多標籤分類。為得到演示結果,我們使用來自雙向 LSTM 的隱藏表示,該 LSTM 使用未調優的預訓練詞嵌入進行初始化。




所以我採取了上述相同的步驟,從最後一層提取驗證集中每個文本評論的隱藏表示,執行 T-SNE/UMAP 操作將它們降維到 2 維,並使用該工具進行可視化。在早停之前,訓練進行了 5 個 epoch。使用 UMAP 的一個優點是它的速度提高了一個數量級,並且仍能有高質量的表現。谷歌最近發布了實時 TSNE,但我還沒去研究。




這是第 5 個 epoch 結束時可視化的放大版本。接受可視化的類別是 insult,所以紅點是_insult_s,綠點是_non-insult_s。







讓我們看一下上圖藍色箭頭指向的兩個點。其中一個是 insult,另一個不是。那文本說的什麼意思呢?






  • Text1(帶藍箭頭的綠點):「廢話廢話廢話廢話廢話廢話」



  • Text2(帶藍箭頭的紅點):「我討厭你我討厭你我討厭你我討厭你我討厭你我討厭你」




有趣的是,模型怎麼將兩個重複的文本放在一起的呢?而且這裡 insult 的意味似乎比較微弱!




我也很好奇紅色點簇中心的一些綠點。為什麼模型會分不清它們?他們的文本是什麼樣的?例如,這是上圖中黑色箭頭指向的點的文本:




「不要喊我麻煩製造者,你和 XYZ 一樣是種族主義右翼」(我對原文進行了一些稍微改動,包括名稱代指)。




嗯,這似乎是 insult——所以它算一個錯誤的標籤!這裡應該是一個紅點!




可能並非所有被錯誤放置的點都是錯誤標籤,但按照上述步驟通過可視化進行深入挖掘,可能會發現數據的所有特徵。




我也認為這有助於我們揭示分詞/預處理等操作對模型性能的影響。在上面的 Text2 中,標點符號正確(可能是在每次「我討厭你」之後用一個句號)可能對模型有所幫助。還有其他一些例子,我認為大寫可能有所幫助。




Yelp 評論情感分類任務




我還想在不同的數據集上嘗試這種方法。所以我選擇了 Kaggle 的 Yelp 評論數據(https://www.kaggle.com/yelp-dataset/yelp-dataset),並決定實現一個簡單的情感分類器。我將星級評分轉換為二進位——這樣更容易操作。所以 -1、2 和 3 星是消極的,4 星、5 星是積極的評論。同樣,我用一個簡單的前饋神經網路架構處理嵌入,壓縮嵌入,然後輸入全連接層並輸出概率。這是 NLP 分類任務的非常規架構,但我很想知道它是如何做的。在早停之前,訓練進行 10 個 epoch。




這是最後一個 epoch 結束時的可視化內容:







黑色箭頭所指的點的文本是:




「每次去這裡,食物都很美味。不幸的是服務不太好(not very good),我只為我喜歡的食物而來。」




這是個中立的評論,可能更傾向於積極的一面。因此,對於模型而言,將這一點放在積極的點簇中還算差強人意。此外,這個模型單獨處理單詞(沒有 n-gram),這解釋了漏掉上面文本「not very good」中的「not」這類現象。以下是與上圖消極點最接近的積極點的文本。




「喜歡這個地方。雖然基本菜單就是拉麵,但味道很好,而且服務很好。價格合理,氛圍優美。絕對是 neighborhood gem。」




模型將上面的兩個文本置於空間中非常接近的位置,這可能再次證實了該模型的局限性(諸如不捕捉 n-gram)。




我有時會想,這樣的分析可以幫助我們理解哪個例子對模型來說是「難」或者「簡單」。這可以通過觀察相鄰的被錯誤分類的點來理解。一旦我們理解這些,就可以利用這些知識來增加更多的人工提取特徵以幫助模型更好地理解這些示例,或者更改模型的架構,以便更好地理解那些「難」的示例。




理解神經網路訓練過程中數據表示的變化




我們將使用動畫來理解這一點。我理解動畫可視化的方式通常是選擇一個點的子集,並觀察其鄰域在訓練過程中如何發生變化。當神經網路學習時,該鄰域在分類任務中越來越有代表性。換句話說,如果我們定義分類任務的相似性,那麼當網路學習時,相似的點將在空間中更加接近。前面提到的 Neural Embedding Animator 工具中的滑塊可以幫助我們控制動畫,並持續關注這一組點。




下圖是一個動畫,展示了數據的隱藏表示在用於惡意評論分類任務的 4 個 epoch 中的演化過程(第 2 個 epoch 到第 5 個 epoch)。我選擇了一小組點,以便更容易地觀察它們的移動過程。綠點代表無惡意,紅點代表惡意類別。







有一些成對的點移動時相距範圍變化較大(F 和 G 或 C 和 I),也有一些點始終接近(D 和 K 或 N 和 O)。




因此,當我手動查看與這些點相對應的句子時,我可以了解到當前 epoch 的神經網路可能學到了什麼。如果我看到兩個完全不相關的句子挨在一起(例如,epoch2 中的 E 和 F),那麼我會認為模型仍需學習。有時我也會看到神經網路將相似的句子放在一起,而整個句子的含義並不同。隨著訓練的進行(驗證損失減少),這種影響會逐漸消失。




正如文章開頭所說,這種行為並不能保證一致性。有時候一個(些)點的鄰域根本沒有任何意義。但我確實希望,通過製作這些動畫,觀察點運動軌跡的顯著變化,我們能夠得出一些有用的見解。




我還使用 yelp 數據集重複了相同的實驗,並有相同發現。




以下是該神經網路在經過一個 epoch 的訓練後的結果:







這兩個類之間有很多重疊,網路沒有真正學習到類別間的清晰邊界。




以下是經過 5 個 epoch 的訓練後的表示演變動畫:







你可以看到兩個簇在各自的類上變得更密集,並且網路在分離這兩個類方面做得更好。




註:我正在為這些 epoch 間的表示變化製作動畫。所有人都應該更加細化這些內容——比如 mini-batch 或 half-epoch 或者其他。這可能有助於發現更細微的變化。




模型對比




這做起來非常直觀。我們只需在想要對比的模型的最後一個 epoch 結束時選擇表示,並將它們插入到工具即可。




這裡我比較的兩個模型是簡單的前饋神經網路(沒有卷積或循環)和雙向 LSTM。它們都使用預訓練的詞嵌入進行初始化。




因此,對於惡意評論分類挑戰,以及 obscene 類,下圖展示了模型之間的表示變化。




所有紅點代表 obscene 類,綠點代表非 non-obscene 類。







你可以看到,BiLSTM 在分離兩個類別方面表現更好。




詞嵌入可視化




我喜歡詞嵌入,在任何 NLP 相關的分析中都會嘗試詞嵌入。這個框架應該特別適合詞嵌入。那麼讓我們看看可以用它來理解什麼吧。




這是一個示例動畫,說明在 yelp 任務上調整模型時詞嵌入的變化。它們用 50 維 Glove 詞向量進行初始化。下圖與本文開頭的動圖相同。為了便於說明,我們將顏色去掉並將標籤添加到了幾個數據點上。







有趣的是,當我們對嵌入進行調整時,最初單詞「food」與「ramen」(拉麵)、「pork」(豬肉)等食物內含類別的空間距離相距甚遠,然後它們之間的距離逐漸接近。所以這個模型可能學習到「ramen」、「pork」等都屬於食物。同樣,我們也看到「table」靠近「restaurant」等等。該動畫可以很容易地發現這些有趣的模式。




另一個可嘗試的有趣事情是對該工具進行反向工程並進行一些自定義分析。例如,我很好奇惡意評論分類任務中惡意詞的嵌入如何發生變化。我在上述惡意評論分類任務中創建了一個模型,從頭開始學習嵌入(因此沒有使用預訓練嵌入進行權重初始化)。給定的數據量可能會對模型造成困難,但值得一試。該架構與 BiLSTM 相同。因此,我只是將所有惡意辭彙變成紅色並在動畫中追蹤它們。下圖展示了詞嵌入的變化軌跡:(PG-13 提示!)







這看起來是不是很吸引人?該模型將髒話(表達惡意的單詞)很好地分到一個集群中。




我希望這篇文章能讓大家了解以不同的方式可視化數據點的隱藏表示,以及它們如何對模型提供有用解讀。我期待將這些分析應用到越來越多的機器學習問題上。希望其他人也會這麼想,並從中獲得一些價值。我相信它們將有助於減少機器學習模型的黑盒子!




PS:我嘗試使用 PCA 將隱藏表示減少到兩個維度,然後從中生成動畫。PCA 的一個好處是它不是概率形式的,因此最終的表示是一致的。然而,PCA 中的局部鄰域可能不像 T-SNE 那樣具有可解釋性。所以這是一種權衡,但是如果有人對同時利用兩種方法的優勢有些想法,就太棒了!




參考原文:https://rakeshchada.github.io/Neural-Embedding-Animation.html






本文為機器之心編譯,

轉載請聯繫本公眾號獲得授權



?------------------------------------------------


加入機器之心(全職記者 / 實習生):hr@jiqizhixin.com


投稿或尋求報道:

content

@jiqizhixin.com


廣告 & 商務合作:bd@jiqizhixin.com

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

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


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

自然語言處理是如何工作的?一步步教你構建 NLP 流水線
一文簡述深度學習優化方法——梯度下降

TAG:機器之心 |