基於神經網路嵌入的推薦系統:利用深度學習和維基百科構建圖書推薦系統
深度學習 ofollow,noindex" target="_blank">應用甚廣 ,在諸多方面的表現,如影象分割、時序預測和自然語言處理,都優於其他機器學習方法。以前,你只能在 學術論文 或者大型 商業公司 中看到它的身影,但如今,我們已能利用自己的電腦進行深度學習計算。本文將利用深度學習和維基百科構建圖書推薦系統。
該推薦系統基於假設:連結到類似的維基百科頁面的書籍彼此相似。
Most Similar Books to Stephen Hawking’s A Brief History of Time
完整程式碼詳見 Jupyter Notebook on GitHub 。如果你沒有GPU也沒關係,可以通過 notebook on Kaggle 獲取免費的GPU。
神經網路嵌入(Neural Network Embeddings)
嵌入(embedding),即用連續向量表示離散變數的方法。與獨熱編碼不同的是,神經網路嵌入維度較低,並能令相似實體在嵌入空間中相鄰。
神經網路嵌入的主要用途有三種:
- 在嵌入空間中找到最近鄰。
- 作為有監督的機器學習模型的輸入。
- 挖掘變數間的關係。
資料集:來自維基百科
與以往的資料科學專案一樣,我們需要從資料集入手。 點選此處 ,檢視如何下載和處理維基百科上的每一篇文章,以及搜尋書籍頁面。我們儲存了圖書標題、基本資訊以、wikilinks(wikiLinks 在搜尋介面中集成了維基百科與維基詞典兩項服務,可以根據自己的不同需求在頁面上方自由切換,而搜尋歷史與收藏的詞條則位於螢幕右上角,點選即可跳轉)。
資料下載完成後,我們需要對其進行探索和清洗,此時你可能會發現一些原始資料之間的關係。如下圖,展示了與維基百科圖書中的頁面關聯性最強的連結:
Wikipedia pages most often linked to by books on Wikipedia.
從上圖可看出,排名前四的都是常用頁面,對構建推薦系統沒有任何幫助。就像書籍的裝訂版本,是平裝(paperback)還是精裝(hardcover)對我們瞭解圖書的內容沒有任何作用,並且神經網路無法根據這個特徵判別書籍是否相似。因此,可以選擇過濾掉這些無用的特徵。
仔細思考哪些資料對構建推薦系統是有幫助的,哪些是無用的,有用的保留,無用的過濾,這樣的資料清洗工作才算到位。
接下來,找出與其他書籍聯絡最緊密的書籍。以下是前10本“聯絡最緊密”的書籍:
Books on Wikipedia most often linked to by other books on Wikipedia.
完成資料清洗後,我們的資料集中剩餘41758條wikilinks以及37020本圖書。接下來,我們需要引入有監督的機器學習方法。
監督學習
監督學習就是最常見的分類問題,即通過已有的訓練樣本去訓練得到一個最優模型,再利用這個模型將所有的輸入對映為相應的輸出,對輸出進行簡單的判斷從而實現分類的目的。 基於我們預先給定的假設:類似的書籍會連結到類似的維基百科頁面, 我們可將監督學習的任務定義為:給定(book title,wikilink)對,確定wikilink是否出現在書籍的某一章中。
我們將提供數十萬個由書籍名稱,wikilink以及標籤組成的訓練示例,同時給神經網路提供一些正確的訓練示例,即資料集中包含的,以及一些錯誤的示例,以促使神經網路學會區分wikilink是否出現在書籍的某一章中。
嵌入是為特定的任務而學習的,並且只與該問題有關。如果我們的任務是想要確定哪些書籍由Jane Austen撰寫,嵌入會根據該任務將Austen所寫的書對映在嵌入空間中更相鄰的地方。或者我們希望通過訓練來判斷書籍的頁面中是否有指定的wikilink頁面,此時神經網路會根據內容使相似書籍在嵌入空間中相鄰。
一旦我們定義了學習任務,接下來便可開始編寫程式碼進行實現。由於神經網路只能接受整數輸入,我們會將書籍分別對映為整數:
對連結我們也進行同樣的對映,並建立一個訓練集。對所有書籍進行遍歷,並記錄頁面上記錄出現的wikilink,列出所有的(book,wikilink)對:
最終有772798個示例用於模型訓練。接下來,隨機選擇連結索引和book索引,如果它們不在(book,wikilink)對中,那麼它們就是能用於增強模型的學習能力false examples。
訓練集及測試集
雖然在有監督的機器學習任務中需要劃分驗證集(validation set)以及測試集,但本文的目的不在於得到精確的模型,只是想訓練神經網路模型完成預測任務。訓練結束後,我們也不需要在新的資料集中測試我們的模型,所以並不需要評估模型的效能或者使用驗證集以防止過擬合。為了更好的學習嵌入,我們將所有的示例都用於訓練。
嵌入模型
神經網路嵌入雖然聽上去十分複雜,但使用 Keras深度學習框架 實現它們卻相對容易。
嵌入模型分為5層:
- Input: 並行輸入書籍和連結
- Embedding: 設定代表book和link兩個類別的向量長度為50
- Dot: 進行點積運算
- Reshape: 把點積reshape成一個一維向量
- Dense: 一個帶sigmod啟用函式的輸出神經元
在 嵌入神經網路 中,能夠通過訓練權重最小化損失函式。神經網路將一本書和一個連結作為輸入,輸出一個0到1之間的預測值,並與真實值進行比較,模型採用 Adam優化器 。
模型程式碼如下:
from keras.layers import Input, Embedding, Dot, Reshape, Dense from keras.models import Model def book_embedding_model(embedding_size = 50, classification = False): """Model to embed books and wikilinks using the Keras functional API. Trained to discern if a link is present in on a book's page""" # Both inputs are 1-dimensional book = 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) # Squash outputs for classification out = Dense(1, activation = 'sigmoid')(merged) model = Model(inputs = [book, link], outputs = out) # Compile using specified optimizer and loss model.compile(optimizer = 'Adam', loss = 'binary_crossentropy', metrics = ['accuracy']) return model
這個框架可以擴充套件至各類嵌入模型。並且,我們並不關心模型是否精準,只想獲取嵌入。在嵌入模型中,權重才是目標,預測只是學習嵌入的手段。
本模型約含400萬個權重,如下所示:
__________________________________________________________________________________________________ Layer (type)Output ShapeParam #Connected to ================================================================================================== book (InputLayer)(None, 1)0 __________________________________________________________________________________________________ link (InputLayer)(None, 1)0 __________________________________________________________________________________________________ book_embedding (Embedding)(None, 1, 50)1851000book[0][0] __________________________________________________________________________________________________ link_embedding (Embedding)(None, 1, 50)2087900link[0][0] __________________________________________________________________________________________________ dot_product (Dot)(None, 1, 1)0book_embedding[0][0] link_embedding[0][0] __________________________________________________________________________________________________ reshape_1 (Reshape)(None, 1)0dot_product[0][0] ================================================================================================== Total params: 3,938,900 Trainable params: 3,938,900 Non-trainable params: 0
利用上述方法,我們不僅可以得到書籍的嵌入,還可以得到連結的嵌入,這意味著我們可以比較所有通過書籍連結的維基百科頁面。
生成訓練示例
神經網路是 batch learners ,因為它們是基於一小批樣本進行訓練的,對所有的資料批次都進行了一次迭代稱為epochs。常用的神經網路訓練方法是使用 生成器 ,它能產生批量樣本函式,優點是不需要將所有的訓練集都載入到記憶體中。
下面的程式碼完整地顯示了生成器:
import numpy as np import random random.seed(100) def generate_batch(pairs, n_positive = 50, negative_ratio = 1.0): """Generate batches of samples for training. Random select positive samples from pairs and randomly select negatives.""" # Create empty array to hold batch batch_size = n_positive * (1 + negative_ratio) batch = np.zeros((batch_size, 3)) # Continue to yield samples while True: # Randomly choose positive examples for idx, (book_id, link_id) in enumerate(random.sample(pairs, n_positive)): batch[idx, :] = (book_id, link_id, 1) idx += 1 # Add negative examples until reach batch size while idx < batch_size: # Random selection random_book = random.randrange(len(books)) random_link = random.randrange(len(links)) # Check to make sure this is not a positive example if (random_book, random_link) not in pairs_set: # Add to batch and increment index batch[idx, :] = (random_book, random_link, neg_label) idx += 1 # Make sure to shuffle order np.random.shuffle(batch) yield {'book': batch[:, 0], 'link': batch[:, 1]}, batch[:, 2]
其中n_positive表示每個batch中正例樣本的數量,negative_ration表示每個batch中負例樣本與正例樣本的比率。
在有監督的學習任務、生成器、嵌入模型都準備完畢的情況下,我們正式進入圖書推薦系統的構建。
訓練模型
有一些訓練引數是可以調節的,如每個批次中正例樣本的數量。通常,我會從一小批量開始嘗試,直到效能開始下降。同樣,我們需要通過嘗試調整負例樣本與正例樣本的比率。
一旦神經網路開始訓練,我們就能獲取權重:
構建推薦系統
嵌入本身不那麼有趣,無非是50維向量。
然而我們可以利用這些向量些有趣的事,例如構建圖書推薦系統。為了在嵌入空間中找到與所查詢書籍最接近的書,我們取那本書的向量,並計算它與所有其他書的向量的點積。如果我們的嵌入是標準化的,那麼向量之間的範圍會從-1,最不相似,到+1,最相似。
以查詢 《戰爭與和平》 為例,相似書籍如下:
上圖所示全是 經典的俄羅斯小說 ,說明我們推薦系統是可用的。
除了對書籍進行嵌入,我們也對連結做了嵌入,以此查詢與維基百科頁面最為相似的連結:
目前,我正在閱讀Stephen Jay Gould的經典著作 《Bully for Brontosaurus》 ,將其輸入構建的推薦系統便可以知道接下來應該讀什麼:
Recommendations for my next book.
嵌入視覺化
嵌入的優點是可以將所學到的嵌入進行視覺化處理,以顯示哪些類別是相似的。首先需要將這些權重的維度降低為2-D或3-D。然後,在散點圖上視覺化這些點,以檢視它們在空間中的分離情況。目前最流行的降維方法是—— t-Distributed Stochastic Neighbor Embedding (TSNE) 。
我們將37000維的圖書通過神經網路嵌入對映為50維,接著使用TSNE將維數將至為2。
下圖展示了降維後圖書在向量空間中的分佈情況:
通過顏色對書本型別進行區分,可以快速的找出相似流派的書籍。
同樣的,我們可以對Country進行嵌入:
此外,你還可以根據自己的需求對嵌入進行視覺化,以開展後續的分析工作。
互動式視覺化
剛才所展示的圖片均為靜態效果,為了更好的檢視變數之間的關係,點選[此處]()以獲取動態效果。
總結
神經網路嵌入能夠將離散的資料表示為連續的低維向量,克服了傳統編碼方法的侷限性,能查詢最近鄰,作為另一個模型的輸入以及進行視覺化,是處理離散變數的有效工具,也是深度學習的有效應用。在本文中,我們基於連結到相似頁面間彼此相似的假設,利用神經網路嵌入構建了圖書推薦系統。
構建神經網路嵌入的步驟總結如下:
- 收集資料
- 制定一個有監督的學習任務
- 訓練嵌入神經網路模型
- 進行推薦實戰及視覺化
完整的專案可點選 此處 獲取。
以上為譯文
本文由阿里云云棲社群組織翻譯。
文章原標題《Building a Recommendation System Using Neural Network Embeddings》,作者: William Koehrsen ,譯者:Elaine,審校:袁虎。
文章為簡譯,更為詳細的內容,請檢視 原文