閱讀586 返回首頁    go 技術社區[雲棲]


揭秘Keras推薦係統如何建立模型、獲取用戶愛好

你是否有過這樣的經曆?當你在亞馬遜商城瀏覽一些書籍,或者購買過一些書籍後,你的偏好就會被係統學到,係統會基於一些假設為你推薦相關書目。為什麼係統會知道,在這背後又藏著哪些秘密呢?

          圖片描述
 
  推推薦係統可以從百萬甚至上億的內容或商品中把有用的東西高效地顯示給用戶,這樣可以為用戶節省很多自行查詢的時間,也可以提示用戶可能忽略的內容或商品,使用戶更有黏性,更願意花時間待在網站上,從而使商家賺取更多的利潤,即使流量本身也會使商家從廣告中受益。
  
  **那麼推薦係統背後的魔術是什麼呢?其實任何推薦係統本質上都是在做排序。**

  你可能注意到了,排序的前提是對喜好的預測。那麼喜好的數據從哪裏來呢?這裏有幾個渠道,比如你和產品有過互動,看過亞馬遜商城的一些書,或者買過一些書,那麼你的偏好就會被係統學到,係統會基於一些假設給你建立畫像和構建模型。你和產品的互動越多,數據點就越多,畫像就越全麵。除此之外,如果你有跨平台的行為,那麼各個平台的數據匯總,也可以綜合學到你的偏好。比如穀歌搜索、地圖和應用商城等都有你和穀歌產品的互動信息,這些平台的數據可以通用,應用的場景有很大的想象力。平台還可以利用第三方數據,比如訂閱一些手機運營商的數據,用來多維度刻畫用戶

那推薦係統又是如何建立模型、知道用戶愛好的?作者提供了兩種重要的算法:矩陣分解模型和深度模型,快來一起探個究竟吧!

1.矩陣分解模型

  矩陣分解可以認為是一種信息壓縮。這裏有兩種理解。第一種理解,用戶和內容不是孤立的,用戶喜好有相似性,內容也有相似性。壓縮是把用戶和內容數量化,壓縮成 k 維的向量。把用戶向量維度進行壓縮,使得向量維度變小,本身就是信息壓縮的一種形式;向量之間還可以進行各種計算,比如餘弦(Cosine)相似性,就可以數量化向量之間的距離、相似度等。第二種理解,從深度學習的角度,用戶表示輸入層(User Representation)通常用 One Hot編碼,這沒問題,但是通過第一層全連接神經網絡就可以到達隱藏層,就是所謂的嵌入層(Embedding Layer),也就是我們之前提到的向量壓縮過程。緊接著這個隱藏層,再通過一層全連接網絡就是最終輸入層,通常用來和實際標注數據進行比較,尋找差距,用來更新網絡權重。從這個意義上講,完全可以把整個數據放進神經係統的框架中,通過淺層學習把權重求出來,就是我們要的向量集合了。經過這麼分析,矩陣分解在推薦係統中是如何應用的就顯而易見了。
  
  這兩種情形都可以用矩陣分解來解決。假設數據庫裏m 個用戶和 n 部電影,那麼用戶電影矩陣的大小就是 m×n。每個單元 (i,j) 用R ij 表示用戶是否看了該電影,即0 或 1。我們把用戶和電影用類似 Word2Vec 的方法分別進行向量表示,把每個用戶 i 表示成 d 維向量 X i ,把每部電影 j 表示成 d 維向量 Y j 。我們要尋找 X i 和 Y j ,使得 X i ×Y j和用戶電影矩陣 R ij 盡可能接近,如圖所示。這樣對於沒出現過的用戶電影對,通過 X i ×Y j 的表達式可以預測任意用戶對電影的評分值。
  
            圖片描述
           

  用數學表達式可以這麼寫:
           圖片描述
  注意:這裏d 是一個遠小於m; n 的數。從機器學習的角度來說,模型是為了抓住數據的主要特征,去掉噪聲。越複雜、越靈活的模型帶來的噪聲越多,降低維度則可以有效地避免過度擬合現象的出現。

2.深度神經網絡模型

  下麵展示進階版的深度模型。我們將建立多層深度學習模型,並且加入 Dropout技術。
  
  這個模型非常靈活。因為如果有除用戶、電影之外的數據,比如用戶年齡、地區、電影屬性、演員等外在變量,則統統可以加入模型中,用嵌入的思想把它們串在一起,作為輸入層,然後在上麵搭建各種神經網絡模型,最後一層可以用評分等作為輸出層,這樣的模型可以適用於很多場景。深度模型的的架構如下圖所示。
  
             圖片描述
           
  首先,做用戶和電影的嵌入層。

1 k = 128
2 model1 = Sequential()
3 model1.add(Embedding(n_users + 1, k, input_length = 1))
4 model1.add(Reshape((k,)))
5 model2 = Sequential()
6 model2.add(Embedding(n_movies + 1, k, input_length = 1))
7 model2.add(Reshape((k,)))

  第三個小神經網絡,在第一、二個網絡的基礎上把用戶和電影向量結合在一起。

1 model = Sequential()
2 model.add(Merge([model1, model2], mode = 'concat'))

  然後加入Dropout 和relu 這個非線性變換項,構造多層深度模型。

1 model.add(Dropout(0.2))
2 model.add(Dense(k, activation = 'relu'))
3 model.add(Dropout(0.5))
4 model.add(Dense(int(k/4), activation = 'relu'))
5 model.add(Dropout(0.5))
6 model.add(Dense(int(k/16), activation = 'relu'))
7 model.add(Dropout(0.5))

  因為是預測連續變量評分,最後一層直接上線性變化。當然,讀者可以嚐試分類問
題,用Softmax 去模擬每個評分類別的概率。

model.add(Dense(1, activation = 'linear'))

  將輸出層和最後的評分數進行對比,後向傳播去更新網絡參數。

model.compile(loss = 'mse', optimizer = "adam")

  接下來要給模型輸入訓練數據。

  首先,收集用戶索引數據和電影索引數據。

1 users = ratings['user_id'].values
2 movies = ratings['movie_id'].values

5 推薦係統

  收集評分數據。

label = ratings['rating'].values

  構造訓練數據。

1 X_train = [users, movies]
2 y_train = label

  然後,用小批量更新權重。

model.fit(X_train, y_train, batch_size = 100, epochs = 50)

  模型訓練完以後,預測未給的評分。

1 i,j = 10,99
2 pred = model.predict([np.array([users[i]]), np.array([movies[j]])])

  最後,對訓練集進行誤差評估。

1 sum = 0
2 for i in range(ratings.shape[0]):
3 sum += (ratings['rating'][i] - model.predict([np.array([ratings['user_id'
][i]]), np.array([ratings['movie_id'][i]])])) ** 2
4 mse = math.sqrt(sum/ratings.shape[0])
5 print(mse)

  訓練數據的誤差在0.8226 左右,大概一個評分等級不到的誤差。

  你可能會問,為什麼這個誤差和之前矩陣分解的淺層模型誤差的差距比較大?作者的理解是,這裏的Dropout 正則項起了很大的作用。雖然我們建了深層網絡,但是由於有了Dropout 這個正則項,必然會造成訓練數據的信息丟失(這種丟失會讓我們在測試數據時受益)。就好比加了L1, L2 之類的正則項以後,估計的參數就不是無偏的了。因此,Dropout 是訓練誤差增加的原因,這是設計模型的必然結果。但是,需要記住的是,我們始終要對測試集上的預測做評估,訓練集的誤差隻是看優化方向和算法是否大致有效。
  
  本文選自《Keras快速上手:基於Python的深度學習實戰》,點此鏈接可在博文視點官網查看此書。
  
                    圖片描述
  想及時獲得更多精彩文章,可在微信中搜索“博文視點”或者掃描下方二維碼並關注。
                        圖片描述

最後更新:2017-08-13 22:28:10

  上一篇:go  《資本說》如何幫助企業從“0”到“1”,看王波玩轉投資攻略
  下一篇:go  《資本說》突圍BAT,你還缺一份完美BP