摘要: 快來利用深度學習和維基百科構建一個屬於你本身的圖書推薦系統吧,手把手教學,夠簡單夠酷炫。
深度學習應用甚廣,在諸多方面的表現,如圖像分割、時序預測和天然語言處理,都優於其餘機器學習方法。之前,你只能在學術論文或者大型商業公司中看到它的身影,但現在,咱們已能利用本身的電腦進行深度學習計算。本文將利用深度學習和維基百科構建圖書推薦系統。html
該推薦系統基於假設:連接到相似的維基百科頁面的書籍彼此類似。python
完整代碼詳見Jupyter Notebook on GitHub。若是你沒有GPU也不要緊,能夠經過notebook on Kaggle獲取免費的GPU。git
嵌入(embedding),即用連續向量表示離散變量的方法。與獨熱編碼不一樣的是,神經網絡嵌入維度較低,並能令類似實體在嵌入空間中相鄰。github
神經網絡嵌入的主要用途有三種:網絡
與以往的數據科學項目同樣,咱們須要從數據集入手。點擊此處,查看如何下載和處理維基百科上的每一篇文章,以及搜索書籍頁面。咱們保存了圖書標題、基本信息以、wikilinks(wikiLinks 在搜索界面中集成了維基百科與維基詞典兩項服務,能夠根據本身的不一樣需求在頁面上方自由切換,而搜索歷史與收藏的詞條則位於屏幕右上角,點擊便可跳轉)。框架
數據下載完成後,咱們須要對其進行探索和清洗,此時你可能會發現一些原始數據之間的關係。以下圖,展現了與維基百科圖書中的頁面關聯性最強的連接:dom
從上圖可看出,排名前四的都是經常使用頁面,對構建推薦系統沒有任何幫助。就像書籍的裝訂版本,是平裝(paperback)仍是精裝(hardcover)對咱們瞭解圖書的內容沒有任何做用,而且神經網絡沒法根據這個特徵判別書籍是否類似。所以,能夠選擇過濾掉這些無用的特徵。機器學習
仔細思考哪些數據對構建推薦系統是有幫助的,哪些是無用的,有用的保留,無用的過濾,這樣的數據清洗工做纔算到位。函數
接下來,找出與其餘書籍聯繫最緊密的書籍。如下是前10本「聯繫最緊密」的書籍:工具
完成數據清洗後,咱們的數據集中剩餘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層:
在嵌入神經網絡中,可以經過訓練權重最小化損失函數。神經網絡將一本書和一個連接做爲輸入,輸出一個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》,將其輸入構建的推薦系統即可以知道接下來應該讀什麼:
嵌入的優勢是能夠將所學到的嵌入進行可視化處理,以顯示哪些類別是類似的。首先須要將這些權重的維度下降爲2-D或3-D。而後,在散點圖上可視化這些點,以查看它們在空間中的分離狀況。目前最流行的降維方法是——t-Distributed Stochastic Neighbor Embedding (TSNE)。
咱們將37000維的圖書經過神經網絡嵌入映射爲50維,接着使用TSNE將維數將至爲2。
下圖展現了降維後圖書在向量空間中的分佈狀況:
經過顏色對書本類型進行區分,能夠快速的找出類似流派的書籍。
一樣的,咱們能夠對Country進行嵌入:
此外,你還能夠根據本身的需求對嵌入進行可視化,以開展後續的分析工做。
剛纔所展現的圖片均爲靜態效果,爲了更好的查看變量之間的關係,點擊[此處]()以獲取動態效果。
神經網絡嵌入可以將離散的數據表示爲連續的低維向量,克服了傳統編碼方法的侷限性,能查找最近鄰,做爲另外一個模型的輸入以及進行可視化,是處理離散變量的有效工具,也是深度學習的有效應用。在本文中,咱們基於連接到類似頁面間彼此類似的假設,利用神經網絡嵌入構建了圖書推薦系統。
構建神經網絡嵌入的步驟總結以下:
完整的項目可點擊此處獲取。
本文做者:【方向】
本文爲雲棲社區原創內容,未經容許不得轉載。