# One Hot Encoding Categoricalsbooks = ["War and Peace", "Anna Karenina", "The Hitchhiker"s Guide to the Galaxy"]books_encoded = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]Similarity (dot product) between First and Second = 0Similarity (dot product) between Second and Third = 0Similarity (dot product) between First and Third = 0
# Idealized Representation of Embeddingbooks = ["War and Peace", "Anna Karenina", "The Hitchhiker"s Guide to the Galaxy"]books_encoded_ideal = [[0.53, 0.85], [0.60, 0.80], [-0.78, -0.62]]Similarity (dot product) between First and Second = 0.99Similarity (dot product) between Second and Third = -0.94Similarity (dot product) between First and Third = -0.97
# Both inputs are 1-dimensionalbook = Input(name = "book", shape = [1])link = Input(name = "link", shape = [1])# Embedding the book (shape will be (None, 1, 50))book_embedding = Embedding(name = "book_embedding", input_dim = len(book_index), output_dim = embedding_size)(book)# Embedding the link (shape will be (None, 1, 50))link_embedding = Embedding(name = "link_embedding", input_dim = len(link_index), output_dim = embedding_size)(link)# Merge the layers with a dot product along the second axis (shape will be (None, 1, 1))merged = Dot(name = "dot_product", normalize = True, axes = 2)([book_embedding, link_embedding])# Reshape to be a single number (shape will be (None, 1))merged = Reshape(target_shape = [1])(merged)# Output neuronout = Dense(1, activation = "sigmoid")(merged)model = Model(inputs = [book, link], outputs = out)# Minimize binary cross entropymodel.compile(optimizer = "Adam", loss = "binary_crossentropy", metrics = ["accuracy"])
Books closest to War and Peace.Book: War and Peace Similarity: 1.0Book: Anna Karenina Similarity: 0.79Book: The Master and Margarita Similarity: 0.77Book: Doctor Zhivago (novel) Similarity: 0.76Book: Dead Souls Similarity: 0.75
深度學習可以怎樣將《戰爭與和平》表示成一個向量?藉助神經網路嵌入就能實現。神經網路嵌入是很多機器學習語言處理應用的基礎性技術之一,Feature Labs 的資料科學家 William Koehrsen 透過一個基於維基百科的書籍推薦專案對詞嵌入進行了介紹。
專案地址:https://github.com/WillKoehrsen/wikipedia-data-science/blob/master/notebooks/Book%20Recommendation%20System.ipynb
最近幾年,神經網路的應用範圍已經從影象分割顯著擴充套件到了自然語言處理以及時間序列預測領域。深度學習一大顯著成功的用途是嵌入(embedding),這是一種可用於將離散變量表示成連續向量的方法。這項技術的實際應用包括用於機器翻譯的詞嵌入和用於類別變數的實體嵌入。
在這篇文章中,我將解釋神經網路嵌入的定義,我們使用它們的原因,以及它們的學習方式。我將在我正在研究的一個真實問題的背景中介紹這些概念:將維基百科上的所有書籍都表示成向量以建立一個書籍推薦系統。
維基百科上所有書籍的神經網路嵌入
嵌入嵌入是離散的(類別化的)變數向連續數值向量的對映。在神經網路語境中,嵌入是離散變數的低維度的學習得到的連續向量表示。神經網路嵌入很有用,因為它們可以降低類別化變數的維度以及能夠在變換後的空間中有意義地表示類別。
神經網路嵌入有三個主要用途:
尋找嵌入空間中的最近鄰。這可被用於基於使用者興趣或聚類類別來進行推薦;
可作為機器學習模型的輸入來學習監督式任務;
可實現概念和類別之間的關係的視覺化。
對於我們的書籍專案,這就意味著我們可以使用神經網路嵌入將維基百科上的 37000 篇書籍文章都各自表示成一個僅具有 50 個數字的向量。此外,因為嵌入是學習得到的,所以對於我們的學習問題而言,更相似的書籍在這個嵌入空間中具有更接近的位置。
神經網路嵌入能夠克服常用的類別變量表示方法 one-hot 編碼的兩大侷限。
one-hot 編碼的侷限
one-hot 編碼的類別變數的操作實際上是一種簡單的嵌入,其中每個類別都被對映成了不同的向量。其過程是將離散的實體的每個觀察都對映成由一定數量的 0 和單個 1 構成的向量,這個 1 指示了特定的類別。
one-hot 編碼技術具有兩大主要缺陷:
對於高基數變數(即有很多特有類別的變數),變換得到的向量的維度將難以掌控。
這種對映方式資訊完全不充分:「近似」的類別在嵌入空間中並不處於相近的位置。
第一個問題很容易理解:每增加一個類別(成為實體),我們都必須為 one-hot 編碼的向量增加一個數。如果我們有維基百科上的 37000 本書,那麼表示它們就將需要 37000 維的向量,基於這種表示方式訓練任何機器學習模型都難以實現。
第二個問題具有同等的侷限性:one-hot 編碼並不會將相似的實體放在向量空間中相近的位置。如果使用餘弦距離來衡量向量之間的相似性,那麼在經過 one-hot 編碼後,每一對比較的實體之間的相似度都是零。
這意味著,如果我們使用 one-hot 編碼,《戰爭與和平》與《安娜·卡列尼娜》這樣的實體(都是列夫·托爾斯泰的經典著作)不會比《戰爭與和平》與《銀河系漫遊指南》之間的距離更近。
# One Hot Encoding Categoricalsbooks = ["War and Peace", "Anna Karenina", "The Hitchhiker"s Guide to the Galaxy"]books_encoded = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]Similarity (dot product) between First and Second = 0Similarity (dot product) between Second and Third = 0Similarity (dot product) between First and Third = 0考慮到這兩個問題,則表示類別變數的理想方案是數字量位元有類別的數量更少,而且相似的類別能具有更近的距離。
# Idealized Representation of Embeddingbooks = ["War and Peace", "Anna Karenina", "The Hitchhiker"s Guide to the Galaxy"]books_encoded_ideal = [[0.53, 0.85], [0.60, 0.80], [-0.78, -0.62]]Similarity (dot product) between First and Second = 0.99Similarity (dot product) between Second and Third = -0.94Similarity (dot product) between First and Third = -0.97為了構建一種更好的類別實體表徵,我們可以使用嵌入神經網路和學習嵌入的監督式網路。
學習嵌入
one-hot 編碼的主要問題是其變換並不依賴於任何監督。透過在一個監督任務上使用神經網路來學習它們,我們可以對嵌入實現極大的提升。這些嵌入會構成網路的引數(權重),這些引數會得到調整以最小化在任務上的損失。所得到的嵌入向量是類別的表徵,其中相似的任務(相對任務而言)的距離更近。
舉個例子,如果我們有一個包含 50000 個詞的電影評論彙集的詞彙庫,我們可以使用一個嵌入神經網路來為每個詞學習 100 維的嵌入,訓練目的是預測這些評論的情緒。(這個應用的詳情請參閱:https://goo.gl/6rxG11)在這個詞彙庫中,「出色」和「很贊」這樣積極的評論詞會處於嵌入空間中更近的位置,因為網路已經學習到這些詞都與積極評論相關。
電影情緒詞嵌入
在上面提到的書籍案例中,我們的監督式任務會變成「識別一本書是否是列夫·托爾斯泰寫的」,而由列夫·托爾斯泰寫的書的嵌入會更近。找到如何建立監督式任務以得出相關表徵的方法是嵌入設計中最困難的部分。
實現
在維基百科書籍專案中,監督學習任務的目標是預測給定維基百科頁面的連結是否出現在了描述某本書的文章中。我們輸入的資料是包含正例和負例的訓練樣本對(書籍題目,連結)。這種設定方式基於這樣一個假設:連結到相似維基百科頁面的書籍彼此更加相似。因此所得到的嵌入也應該在向量空間中將相似的資料放置在更相近的位置。
我使用的網路有兩個並行的嵌入層,它們會將書籍和維基連結分別對映成 50 維的向量,另外還有一個點積層將這些嵌入結合成單個數值以供預測。這些嵌入是網路的引數,或者說權重,可以在訓練過程中調整以最小化在該監督式任務上的損失。
用 Keras 程式碼表示就像是下面這樣(看不懂程式碼也不要緊,可以直接跳過去看後面的圖片):
# Both inputs are 1-dimensionalbook = Input(name = "book", shape = [1])link = Input(name = "link", shape = [1])# Embedding the book (shape will be (None, 1, 50))book_embedding = Embedding(name = "book_embedding", input_dim = len(book_index), output_dim = embedding_size)(book)# Embedding the link (shape will be (None, 1, 50))link_embedding = Embedding(name = "link_embedding", input_dim = len(link_index), output_dim = embedding_size)(link)# Merge the layers with a dot product along the second axis (shape will be (None, 1, 1))merged = Dot(name = "dot_product", normalize = True, axes = 2)([book_embedding, link_embedding])# Reshape to be a single number (shape will be (None, 1))merged = Reshape(target_shape = [1])(merged)# Output neuronout = Dense(1, activation = "sigmoid")(merged)model = Model(inputs = [book, link], outputs = out)# Minimize binary cross entropymodel.compile(optimizer = "Adam", loss = "binary_crossentropy", metrics = ["accuracy"])儘管監督式機器學習任務的目標通常是訓練一個模型來在新資料上進行預測,但在這個嵌入模型中,預測本身僅僅是實現最終目的的一種方式。我們想要的是嵌入權重,即作為連續向量的書籍和連結表示。
嵌入本身並不是那麼有趣:它們都只是些數值的向量:
來自書籍推薦嵌入模型的嵌入示例
但是,這些嵌入也可被用於之前列出的三個目的;對於這個專案,我們主要感興趣的是基於最近鄰推薦書籍。為了計算相似度,我們取一個查詢書籍,然後得出其向量與所有其它書籍的向量之間的點積。(如果我們的嵌入經過了歸一化,那麼這個點積就是向量之間的餘弦距離,其範圍從最不相似的 -1 到最相似的 +1。我們也可以使用歐幾里德距離來衡量相似度。)
下面給出了我構建的書籍嵌入模型的輸出結果:
Books closest to War and Peace.Book: War and Peace Similarity: 1.0Book: Anna Karenina Similarity: 0.79Book: The Master and Margarita Similarity: 0.77Book: Doctor Zhivago (novel) Similarity: 0.76Book: Dead Souls Similarity: 0.75(一個向量與其自身的餘弦相似度肯定是 1.0)。經過一定的降維之後,我們可以得到下面的影象:
與最近鄰一起的嵌入書籍
我們可以清楚地看到學習嵌入的價值!現在,對於維基百科上的每一本書,我們都有一個 50 數字的表示,其中更相似的書籍也彼此更接近。
嵌入視覺化嵌入最值得關注的一大優勢是它們可被用於概念的視覺化,比如小說與非小說之間的相對性。這需要進一步的降維技術將維度降至二或三維。最流行的降維技術本身也是一種嵌入方法:t-分佈隨機近鄰嵌入(TSNE)。
我們可以使用神經網路嵌入將維基百科上所有書籍的 37000 個原始維度對映成 50 維,然後再使用 TSNE 將其對映成二維。結果如下:
維基百科上所有 37000 本書的嵌入
(TSNE 是一種流形學習技術,也就是說它會試圖將高維資料對映成更低維度的流形,這個過程中會建立一個嵌入來維持資料中的區域性結構。這基本上只在視覺化時使用,因為其輸出是隨機的,不支援轉換成新資料。另一種正在迅猛發展的新方法是統一流形近似和投影/UMAP,它的速度要快得多,而且也支援轉換成嵌入空間中的新資料。)
這些視覺化本身並不非常有用,但如果我們根據不同的書籍型別給它加上顏色,就能看出一些見解了。
根據書籍型別上色後的嵌入
可以清楚看到,書籍根據各自不同的型別聚集在了一起。這並不完美,但仍然讓人印象深刻,畢竟我們僅用 2 個數字就表示了維基百科上的所有書籍,而且這種表示方法還能展現出不同型別之間的差異。
這個書籍專案示例表明了神經網路嵌入的價值:我們能得到分類目標的向量表示,這個向量表示是低維的,並且相似的實體在嵌入空間中處於相近的位置。
額外獎勵:互動式視覺化
靜態圖表的問題是我們不能真正地探索資料以及研究變數之間的分組和關係。為了解決這個問題,TensorFlow 開發了 projector:https://projector.tensorflow.org/,這是一個讓我們可以視覺化嵌入並與之互動的線上應用。我後面會寫一篇文章介紹使用這一工具的方法,但這裡我們看看結果就好:
使用 projector 實現對書籍嵌入的互動式探索
總結神經網路嵌入是學習到的離散資料的低維連續向量表示。這些嵌入克服了傳統編碼方法的侷限,並可被用於尋找最近鄰、作為另一個模型的輸入以及視覺化等目的。
儘管本文用一些學術術語談到了很多深度學習概念,但神經網路嵌入很直觀而且實現方法也相對簡單。我確信任何人都可以學會深度學習,並且使用 Keras 這樣的庫來構建深度學習解決方案。嵌入是一種能有效處理離散變數的工具,是深度學習的一個很有價值的應用。