天天看點

“萬物皆可embedding”

不知道大家有沒有這種感受,在學習推薦系統算法模型時,少不了embedding的應用,有的推薦算法模型甚至可以說就是在做embedding的過程,可見embedding在推薦系統中的重要性。

這篇文章就專門把embedding單獨提出來,梳理一下embedding在推薦系統中的應用。以下内容主要從深度學習方法和傳統的協同過濾方法兩個方面加深和了解在推薦系統領域對embedding的認識,感受下“embedding”這一重要思想。

▌深度學習方法

先拿一篇推薦系統領域中最為經典的論文之一“Deep Neural Networks for YouTubeRecommendations”來講,Youtube的這篇視訊推薦模型架構基本上奠定了後面推薦系統的主要步驟:召回和排序,如下圖所示:

“萬物皆可embedding”

其中召回階段(candidate generation)就是要從推薦的百萬級别的視訊庫中篩選出使用者可能感興趣的視訊,把推薦的視訊庫量級從百萬級降到幾百個。但是到底怎樣才能快速高效的完成篩選呢?

要知道youtube是非常活躍的視訊網站,每秒同時通路的人數成千上萬,要同時實作每秒對每個使用者都個性化的從百萬視訊候選集中挑出幾百個使用者感興趣的視訊,想想都不容易,是以每次做使用者召回都跑一遍模型是不可能的,其解決方法就和接下來要介紹的embedding應用相關。如下圖 1 所示為youtube召回階段的模型:

“萬物皆可embedding”

▲ 圖1. YouTube召回模型

在離線的模型訓練階段,采用的是簡單粗暴的softmax來對視訊庫中的所有視訊進行分類,label為使用者Next watched video的那個視訊,是以整個召回階段構模組化型的思想就是預測某一時刻某一使用者在對百萬級以上的視訊庫哪個視訊感興趣,它最想點選和觀看的視訊是哪一個。

這裡有一個很重要的問題就是百萬級别以上的視訊做softmax是很費計算資源和時間的,是以在召回模型的離線訓練階段采用了word2vec中的Negative Sample思想。可是即便是這樣,面對百萬級别的視訊庫,以及每秒成千上萬的召回請求,線上上還是無法滿足需求,不能直接使用模型去對視訊做softmax,按照機率大小選取TopN來做召回,是以就有了embedding做召回的方法。

如上圖 1 所示主要思想是把softmax的前一層的輸出作為user的embedding,而softmax層中的權重矩陣的每一行向量作為video的embedding,這樣在模型的部署過程中,就沒有必要部署整個神經網絡來完成從原始特征向量到最終輸出的預測過程,隻需要将User Embedding和video Embedding存儲到線上記憶體資料庫,通過内積運算再排序的方法就可以得到video的排名,這大大加快了召回效率。

“萬物皆可embedding”

這裡再用圖示的方法具體介紹一下哪個是user embedding,哪些是video embedding,為什麼可以向量内積召回,為什麼内積得到的值大小就可以反映出使用者對視訊的興趣程度。如上圖所示,把圖1 中的倒數第二層和最後一層softmax單獨拿出來分析,實際上圖 1 中最後一個softmax是一個加了softmax函數的全連接配接層,該全連接配接層(圖中softmax)的神經元個數和需要分類的視訊個數相同,都為T,softmax函數對該全連接配接層(圖中softmax)的輸出再進行歸一化得到每個視訊對應的機率值。

這個全連接配接層(圖中softmax)的每一個神經元都對應有上一層全連接配接層(圖中relu)輸出的權重向量,為上圖中W[T×N]權重矩陣的每一行,而這每一行權重向量就是video embedding,個數和神經元的個數相同都是視訊庫中視訊的個數T,上一層全連接配接層(圖中relu)的輸出為user embedding,是上圖中的X[N×1]。是以通過内積user embedding和video embedding其實得到的正是未經過softmax函數歸一化的每個視訊的預測值,從一定程度上反映了預測機率的大小。

是以user embedding和video embedding内積值越大,則反應該使用者對該視訊感興趣的機率值大,是以可以提前将User Embedding和video Embedding存儲到線上記憶體資料庫,通過内積運算再排序的方法得到video的排名,以此來提高召回速度和效率。

總結一句話就是,為了提高召回速度和效率,相當于把召回模型的inference轉換成了通過embedding向量内積方法快速得到使用者對視訊得分的方法。從這個例子可以看出embedding的應用之一:通過計算使用者和物品的Embedding相似度,Embedding可以直接作為推薦系統的召回層或者召回方法之一。

其實像embedding的這種應用非常多,像微軟的一篇論文Item2Vec: Neural Item Embeddingfor Collaborative Filtering,專門訓練item的embedding,然後通過計算item之間的embedding相似度來做基于物品的協同過濾,實際上通過這種方式也可以縮小推薦候選物品的範圍,用來直接做物品的相似推薦。

而專門學習item embedding的方法還有很多,比如通過graph embedding方式的deepwalk,LINE,Node2vec和SDNE等等。是以再結合這些embedding的應用例子,再對embedding在召回方面的應用濃縮總結一下就是:通過計算使用者和物品或物品和物品的Embedding相似度,來縮小推薦候選庫的範圍。

除此之外,通過總結目前主流的ctr預估模型比如wide&deep,deepFM,PNN和DCN等等可以發現,embedding還有一個非常普遍的應用就是實作高維稀疏特征向量向低維稠密特征向量的轉換,通俗來講就是把離散特征經過獨熱編碼後的稀疏向量表達轉化成稠密的特征向量表達。

或者從另一個角度看,embedding本身就是對事物的多元度特征表示,是以在ctr預估模型中,訓練好的embedding可以當作輸入深度學習模型的特征,比如FNN利用FM預訓練好的embedding來當作模型的輸入,然後通過特征交叉操作比如多層感覺機得到這些embedding的交叉特征。具體的交叉特征分析以及有關推薦系統中對于特征的處理可以檢視公衆号中的特征處理系列文章。

有關深度學習方法中的embedding應用就介紹到這,這裡再着重介紹一下最近學習的有關協同過濾的傳統推薦方法中embedding思想的展現。

▌傳統方法

雖然目前有關推薦系統的模型中深度學習越來越占據重要地位,但是embedding的重要思想卻貫穿始終,在傳統的推薦方法中依然可以看到embedding的影子。例如基于矩陣分解的協同過濾模型,如下圖所示:

“萬物皆可embedding”

通過将使用者對物品的打分矩陣Rating Matrix分解成User Matrix和Item Matrix兩個矩陣相乘,我們可以把User Matrix和Item Matrix相乘分别看作是A,B,C,D四個user embedding和W,X,Y,Z四個item embedding相乘。

可以看到打分矩陣比較稀疏,說明有的user沒有給item打分,是以矩陣分解的目的就是通過分解的user embedding和item embedding相乘來填充user沒有打分的item,進而可以進行推薦。而模型通過user embedding和item embedding相乘拟合user已給item的打分來學習embedding參數。

如上圖所示,分解的user embedding B([1.4,0.9])和item embedding W([1.5,1.7])相乘得到3.63要盡量接近Rating Matrix中的B行W列也就是4.0,根據這種拟合學習得到embedding,最終再根據模型學習的user embedding和item embedding相乘得到user沒有給item的打分,比如Rating Matrix中的A行W列的得分為user embedding A([1.2,0.8])和item embedding W([1.5,1.7])相乘得到3.16.

因為模型比較簡單,這裡直接給出利用tensorflow實作的模型的代碼:

def build_model(user_indices, item_indices, rank, ratings, user_cnt, item_cnt, lr, lamb, mu, init_value):
    
    W_user = tf.Variable(tf.truncated_normal([user_cnt, rank], stddev=init_value/math.sqrt(float(rank)), mean=0), 
                         name = 'user_embedding', dtype=tf.float32)
    W_item = tf.Variable(tf.truncated_normal([item_cnt, rank], stddev=init_value/math.sqrt(float(rank)), mean=0), 
                         name = 'item_embedding', dtype=tf.float32)
    
    W_user_bias = tf.concat([W_user, tf.ones((user_cnt,1), dtype=tf.float32)], 1, name='user_embedding_bias')
    W_item_bias = tf.concat([tf.ones((item_cnt,1), dtype=tf.float32), W_item], 1, name='item_embedding_bias')
    
    user_feature = tf.nn.embedding_lookup(W_user_bias, user_indices, name = 'user_feature')
    item_feature = tf.nn.embedding_lookup(W_item_bias, item_indices, name = 'item_feature') 
    
    preds = tf.add(tf.reduce_sum( tf.multiply(user_feature , item_feature) , 1), mu)
    
    square_error = tf.sqrt(tf.reduce_mean( tf.squared_difference(preds, ratings)))
    loss = square_error + lamb*(tf.reduce_mean(tf.nn.l2_loss(W_user)) + tf.reduce_mean(tf.nn.l2_loss(W_item)))
        
    tf.summary.scalar('square_error', square_error)
    tf.summary.scalar('loss', loss)
    merged_summary = tf.summary.merge_all()
    #tf.global_variables_initializer()
    train_step = tf.train.GradientDescentOptimizer(lr).minimize(loss)   # tf.train.AdadeltaOptimizer(learning_rate=lr).minimize(loss)    #

    return train_step, square_error, loss, merged_summary           

複制

雖然模型比較簡單,但是可以發現embedding的思想其實貫穿在整個模型當中。

除了基于矩陣分解的協同過濾,還有基于自編碼器的協同過濾,自編碼器做協同過濾的思想主要是把使用者對所有物品的打分組成一個固定次元的向量(沒有打分的填充為0)然後通過自編碼器對該打分向量進行編碼解碼然後得到和該打分向量次元相同的向量,該自編碼器模型的輸出向量就是為了拟合輸入向量。如圖所示為自編碼器模型:

“萬物皆可embedding”

先對輸入向量通過兩個全連接配接層進行編碼,然後再通過兩個全連接配接層進行解碼最後得到拟合輸入向量的輸出向量。該模型同樣也是通過拟合已經有的打分來學習整個模型的參數,模型學習好之後,之前填充為0的物品打分就可以通過模型輸出向量的對應位置得到。

雖然這個模型沒有很明顯的embedding思想的展現,但是以我個人對embedding的了解,在模型最終輸出的使用者對所有物品的打分稠密向量是否可以用來當作表示使用者興趣的user embedding向量呢?

▌總結

通過這篇文章對embedding的分析,總結embedding有以下三個作用:

  • 通過計算使用者和物品或物品和物品的Embedding相似度,來縮小推薦候選庫的範圍。
  • 實作高維稀疏特征向量向低維稠密特征向量的轉換。
  • 訓練好的embedding可以當作輸入深度學習模型的特征。

無論embedding在模型中最終起到哪些重要的作用,在對embedding的本質了解上,它自始至終都是用一個多元稠密向量來對事物從多元度進行的特征刻畫。