基於神經網絡嵌入的推薦系統:利用深度學習和維基百科構建圖書推薦系統

摘要: 快來利用深度學習和維基百科構建一個屬於你本身的圖書推薦系統吧,手把手教學,夠簡單夠酷炫。

深度學習應用甚廣,在諸多方面的表現,如圖像分割、時序預測和天然語言處理,都優於其餘機器學習方法。之前,你只能在學術論文或者大型商業公司中看到它的身影,但現在,咱們已能利用本身的電腦進行深度學習計算。本文將利用深度學習和維基百科構建圖書推薦系統。html

該推薦系統基於假設:連接到相似的維基百科頁面的書籍彼此類似。python

Most Similar Books to Stephen Hawking’s A Brief History of Time

完整代碼詳見Jupyter Notebook on GitHub。若是你沒有GPU也不要緊,能夠經過notebook on Kaggle獲取免費的GPU。git

神經網絡嵌入(Neural Network Embeddings)

嵌入(embedding),即用連續向量表示離散變量的方法。與獨熱編碼不一樣的是,神經網絡嵌入維度較低,並能令類似實體在嵌入空間中相鄰。github

神經網絡嵌入的主要用途有三種:網絡

  1. 在嵌入空間中找到最近鄰。
  2. 做爲有監督的機器學習模型的輸入。
  3. 挖掘變量間的關係。

數據集:來自維基百科

與以往的數據科學項目同樣,咱們須要從數據集入手。點擊此處,查看如何下載和處理維基百科上的每一篇文章,以及搜索書籍頁面。咱們保存了圖書標題、基本信息以、wikilinks(wikiLinks 在搜索界面中集成了維基百科與維基詞典兩項服務,能夠根據本身的不一樣需求在頁面上方自由切換,而搜索歷史與收藏的詞條則位於屏幕右上角,點擊便可跳轉)。框架

數據下載完成後,咱們須要對其進行探索和清洗,此時你可能會發現一些原始數據之間的關係。以下圖,展現了與維基百科圖書中的頁面關聯性最強的連接:dom

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層:

  1. Input:並行輸入書籍和連接
  2. Embedding:設置表明book和link兩個類別的向量長度爲50
  3. Dot:進行點積運算
  4. Reshape:把點積reshape成一個一維向量
  5. 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 Shape         Param #     Connected to                     
==================================================================================================
book (InputLayer)               (None, 1)            0                                            
__________________________________________________________________________________________________
link (InputLayer)               (None, 1)            0                                            
__________________________________________________________________________________________________
book_embedding (Embedding)      (None, 1, 50)        1851000     book[0][0]                       
__________________________________________________________________________________________________
link_embedding (Embedding)      (None, 1, 50)        2087900     link[0][0]                       
__________________________________________________________________________________________________
dot_product (Dot)               (None, 1, 1)         0           book_embedding[0][0]             
                                                                 link_embedding[0][0]             
__________________________________________________________________________________________________
reshape_1 (Reshape)             (None, 1)            0           dot_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進行嵌入:

此外,你還能夠根據本身的需求對嵌入進行可視化,以開展後續的分析工做。

交互式可視化

剛纔所展現的圖片均爲靜態效果,爲了更好的查看變量之間的關係,點擊[此處]()以獲取動態效果。

總結

神經網絡嵌入可以將離散的數據表示爲連續的低維向量,克服了傳統編碼方法的侷限性,能查找最近鄰,做爲另外一個模型的輸入以及進行可視化,是處理離散變量的有效工具,也是深度學習的有效應用。在本文中,咱們基於連接到類似頁面間彼此類似的假設,利用神經網絡嵌入構建了圖書推薦系統。

構建神經網絡嵌入的步驟總結以下:

  1. 收集數據
  2. 制定一個有監督的學習任務
  3. 訓練嵌入神經網絡模型
  4. 進行推薦實戰及可視化

完整的項目可點擊此處獲取。

本文做者:【方向】

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索