1. 程式人生 > >基於神經網絡的embeddding來構建推薦系統

基於神經網絡的embeddding來構建推薦系統

驗證 撰寫 ive single pap dex lai 最終 you

  在之前的博客中,我主要介紹了embedding用於處理類別特征的應用,其實,在學術界和工業界上,embedding的應用還有很多,比如在推薦系統中的應用。本篇博客就介紹了如何利用embedding來構建一個圖書的推薦系統。
  
  本文主要譯自《Building a Recommendation System Using Neural Network Embeddings》,完整詳細的代碼見官方GitHub。
  
  目錄
  
  一、背景&數據集讀取
  
  1.1 神經網絡嵌入(Neural Network Embeddings)
  
  1.2 數據集:來自維基百科
  
  1.3 數據集清洗
  
  二、監督學習
  
  2.1 定義機器學習的任務
  
  2.2 關於訓練集及測試集的劃分
  
  2.3 嵌入模型
  
  2.4 生成訓練示例
  
  2.5 訓練模型
  
  三、構建推薦系統
  
  四、嵌入可視化
  
  五、總結
  
  參考文獻
  
  一、背景&數據集讀取
  
  深度學習應用甚廣,在諸多方面的表現,如圖像分割、時序預測和自然語言處理,都優於其他機器學習方法。以前,你只能在學術論文或者大型商業公司中看到它的身影,但如今,我們已能利用自己的電腦進行深度學習計算。本文將利用深度學習和維基百科構建圖書推薦系統。
  
  該推薦系統基於假設:鏈接到相似的維基百科頁面的書籍彼此相似。(註:必須要理解本文所用的數據集才能這句話的深層含義。稍後會講解數據集的含義)
  
  1.1 神經網絡嵌入(Neural Network Embeddings)
  
  嵌入(embedding),即用連續向量表示離散變量的方法。與獨熱編碼不同的是,神經網絡嵌入維度較低,並能令相似實體在嵌入空間中相鄰。
  
  神經網絡嵌入的主要用途有三種:
  
  在嵌入空間中找到最近鄰。
  
  作為有監督的機器學習模型的輸入。
  
  挖掘變量間的關系。
  
  1.2 數據集:來自維基百科
  
  與以往的數據科學項目一樣,我們需要從數據集入手。點擊此處,查看如何下載和處理維基百科上的每一篇文章,以及搜索書籍頁面。在本文的數據集中,我們保存了圖書標題、基本信息、圖書頁面上指向其它維基百科頁面的鏈接(wikilinks)和外部網站的鏈接。為了創建一個推薦系統,我們僅僅使用圖書標題和wikilinks。
  
  (註:我們在這裏仔細解釋下wikilinks:所謂的wikilinks就是在圖書的維基百科頁面上的介紹該書的一些詞組,比如說《戰爭與和平》,那麽它的wikilinks可能就是列夫托爾斯泰,俄國,俄語等。因為這些詞語在介紹《戰爭與和平》時肯定會出現,而有的讀者可能對這些詞語感興趣,因此,在《戰爭與和平》的頁面上會有跳往這些詞語的鏈接,這就是所謂的wikilinks。
  
  因此,該推薦系統基於假設:鏈接到相似的維基百科頁面的書籍彼此相似。這句話的意義就很明顯了,如果2本書籍的wikilinks都指向了列夫托爾斯泰,俄國,俄語等,那麽這2本書可能就是很相似。比如說《戰爭與和平》《安娜·卡列尼娜》。)
  
  這是一本書和它的wikilinks:
  
  1.3 數據集清洗
  
  數據下載完成後,我們需要對其進行探索和清洗,此時你可能會發現一些原始數據之間的關系。如下圖,展示了與維基百科圖書中的頁面關聯性最強的wikilinks:
  
  從上圖可看出,排名前四的都是常用link,對構建推薦系統沒有任何幫助。就像書籍的裝訂版本,是平裝(paperback)還是精裝(hardcover)對我們了解圖書的內容沒有任何作用,並且神經網絡無法根據這個特征判別書籍是否相似。因此,可以選擇過濾掉這些無用的特征。
  
  (註:我們指的相似性是內容的相似性)
  
  仔細思考哪些數據對構建推薦系統是有幫助的,哪些是無用的,有用的保留,無用的過濾,這樣的數據清洗工作才算到位。
  
  完成數據清洗後,我們的數據集中剩余41758條wikilinks以及37020本圖書。接下來,我們需要引入有監督的機器學習方法。
  
  二、監督學習
  
  2.1 定義機器學習的任務
  
  監督學習就是最常見的分類問題,即通過已有的訓練樣本去訓練得到一個最優模型,再利用這個模型將所有的輸入映射為相應的輸出,對輸出進行簡單的判斷從而實現分類的目的。基於我們預先給定的假設:類似的書籍會鏈接到類似的維基百科頁面,我們可將監督學習的任務定義為:給定(book title,wikilink)對,確定wikilink是否出現在書籍的維基百科頁面中。
  
  我們將提供數十萬個由書籍名稱,wikilink以及標簽組成的訓練示例,同時給神經網絡提供一些正確的訓練示例,即數據集中包含的,以及一些錯誤的示例,以促使神經網絡學會區分wikilink是否出現在書籍的維基百科頁面中。
  
  嵌入是為特定的任務而學習的,並且只與該問題有關。如果我們的任務是想要確定哪些書籍由Jane Austen撰寫,嵌入會根據該任務將Austen所寫的書映射在嵌入空間中更相鄰的地方。或者我們希望通過訓練來判斷書籍的頁面中是否有指定的wikilink頁面,此時神經網絡會根據內容使相似書籍在嵌入空間中相鄰。
  
  一旦我們定義了學習任務,接下來便可開始編寫代碼進行實現。由於神經網絡只能接受整數輸入,我們會將書籍分別映射為整數:
  
  # Mapping of books to index and index to books
  
  book_index = {book[0]: idx for idx, book in enumerate(books)}
  
  book_index[‘Anna Karenina‘]
  
  22494
  
  (註:本文的代碼是Git中的部分代碼,完整代碼的獲取請參看GitHub)
  
  對鏈接我們也進行同樣的映射,並創建一個訓練集。對所有書籍進行遍歷,並記錄頁面上記錄出現的wikilink,列出所有的(book,wikilink)對:
  
  pairs = []
  
  # Iterate through each book
  
  for book in books:
  
  title = book[0]
  
  book_links = book[2]
  
  # Iterate through wikilinks in book article
  
  for link in book_links:
  
  # Add index of book and index of link to pairs
  
  pairs.extend((book_index[title],
  
  link_index[link]))
  
  最終有772798個示例用於模型訓練。接下來,隨機選擇鏈接索引和book索引,如果它們不在(book,wikilink)對中,那麽它們就是能用於增強模型的學習能力false examples。
  
  2.2 關於訓練集及測試集的劃分
  
  雖然在有監督的機器學習任務中需要劃分驗證集(validation set)以及測試集,但本文的目的不在於得到精確的模型,只是想訓練神經網絡模型完成預測任務。訓練結束後,我們也不需要在新的數據集中測試我們的模型,所以並不需要評估模型的性能或者使用驗證集以防止過擬合。為了更好的學習嵌入,我們將所有的示例都用於訓練。
  
  2.3 嵌入模型
  
  神經網絡嵌入雖然聽上去十分復雜,但使用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_www.leyouzaixian2.com size)(book)
  
  # Embedding the link (shape will be (None, 1, 50))
  
  link_embedding www.furong157.com= 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, www.michenggw.com 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 =www.gcyl159.com [book, link], outputs = out)
  
  # Compile using specified optimizer and loss
  
  model.compile(optimizer www.gcyl152.com/= ‘Adam‘, loss = ‘binary_crossentropy‘,
  
  metrics = [‘accuracy‘])
  
  return model
  
  這個框架可以擴展至各類嵌入模型。並且,我們並不關心模型是否精準,只想獲取嵌入。在嵌入模型中,權重才是目標,預測只是學習嵌入的手段。
  
  (註:這句話不明白的話,可以參看我之前介紹embedding的博客)
  
  本模型約含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
  
  利用上述方法,我們不僅可以得到書籍的嵌入,還可以得到鏈接的嵌入。
  
  2.4 生成訓練示例
  
  神經網絡是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中負例樣本與正例樣本的比率。
  
  在有監督的學習任務、生成器、嵌入模型都準備完畢的情況下,我們正式進入圖書推薦系統的構建。
  
  2.5 訓練模型
  
  有一些訓練參數是可以調節的,如每個批次中正例樣本的數量。通常,我會從一小批量開始嘗試,直到性能開始下降。同樣,我們需要通過嘗試調整負例樣本與正例樣本的比率。
  
  n_positive = 1024
  
  gen = generate_batch(pairs, n_positive, negative_ratio = 2)
  
  # Train
  
  h = model.fit_generator(gen, epochs = 15,
  
  steps_per_epoch = len(pairs) // n_positive)
  
  一旦神經網絡開始訓練,我們就能獲取權重:
  
  # Extract embeddings
  
  book_layer = model.get_layer(‘book_embedding‘)
  
  book_weights = book_layer.get_weights()[0]
  
  三、構建推薦系統
  
  嵌入本身不那麽有趣,無非是50維向量。
  
  然而我們可以利用這些向量做些有趣的事,例如構建圖書推薦系統。為了在嵌入空間中找到與所查詢書籍最接近的書,我們取那本書的向量,並計算它與所有其他書的向量的點積。如果我們的嵌入是標準化的,那麽向量之間的範圍會從-1,最不相似,到+1,最相似。
  
  (註:在代碼裏先進行了l2範數的標準化,因此,2個向量點積之後就是余弦相似度,範圍從-1到1)
  
  以查詢《戰爭與和平》為例,相似書籍如下:
  
  除了對書籍進行嵌入,我們也對wikilink也做了嵌入,以此查詢與wikilink最為相似的鏈接:
  
  再比如,目前,我正在閱讀Stephen Jay Gould的經典著作《Bully for Brontosaurus》,將其輸入構建的推薦系統便可以知道接下來應該讀什麽:
  
  (註:通過上述的介紹,我們已經看到了如何利用神經網絡的embeddding來構建推薦系統。本質上,這仍然是一個協調過濾的思想,即根據相似性來尋找某本書籍的最近鄰居,然後把最近鄰居推薦給喜歡某本書籍的人。但是,這裏與傳統的協調過濾方法明顯的不同的地方有:
  
  ①基於embedding的推薦方法並不要求書籍向量的”同一化“,即某本書不需要再像以前那樣,必須由長度完全相等的向量來表示,在現在世界中,構造這樣的數據集很困難,即便構造出來,數據也很稀疏。
  
  ②基於embedding的推薦方法可以通過”關系“來捕捉相似性,以此來保證embedding後的向量仍然可以保證這種相似性。我們在這裏理解維基百科的數據,可以認為書名到wikilinks存在著某種關系。那麽給我們的啟發是什麽呢?比如,我們想求得成人奶粉這個類目下所有sku的相似性,我們就可以類似文中構造訓練集的方法那樣來構造關於成人奶粉sku的數據集。)
  
  四、嵌入可視化
  
  嵌入的優點是可以將所學到的嵌入進行可視化處理,以顯示哪些類別是相似的。首先需要將這些權重的維度降低為2-D或3-D。然後,在散點圖上可視化這些點,以查看它們在空間中的分離情況。目前最流行的降維方法是——t-Distributed Stochastic Neighbor Embedding (TSNE)。
  
  我們將37000多維的圖書通過神經網絡嵌入映射為50維,接著使用TSNE將維數將至為2。
  
  似乎有一些明顯的團塊。然而,由於我們沒有以任何方式區分書籍,因此很難從上圖中得出有任何意義的東西。
  
  我們需要其它的一些信息讓我們看到我們對圖書做的embedding是有效的。
  
  在數據集裏,有個字段是圖書的類別genre。
  
  讓我們用genre畫出embeddings,它包含在每本書的Infobox模板數據中。我們將其限制為10種最流行的genres。
  
  我們可以看到,經過embedding後的圖書,原來類別很相似的,降維後仍然相似。
  
  更多可視化的探索可以參看源代碼。
  
  五、總結
  
  神經網絡嵌入能夠將離散的數據表示為連續的低維向量,克服了傳統編碼方法的局限性,能查找最近鄰,作為另一個模型的輸入以及進行可視化,是處理離散變量的有效工具,也是深度學習的有效應用。在本文中,我們基於鏈接到相似頁面間彼此相似的假設,利用神經網絡嵌入構建了圖書推薦系統。
  
  構建基於神經網絡嵌入的推薦系統的步驟總結如下:
  
  收集數據
  
  制定一個有監督的學習任務
  
  訓練嵌入神經網絡模型
  
  進行推薦實戰及可視化
  
  參考文獻
  
  【1】基於神經網絡嵌入的推薦系統:利用深度學習和維基百科構建圖書推薦系統
  
  【2】Wikipedia Data Science: Working with the World’s Largest Encyclopedia
  
  【3】 Neural Network Embeddings Explained
  
  【4】How to Use t-SNE Effectively
  
  【5】詮釋數據降維算法:一文講盡t-分布鄰域嵌入算法(t-SNE)如何有效利用

基於神經網絡的embeddding來構建推薦系統