推薦系統實踐 0x0f AutoRec

從這一篇開始,咱們開始學習深度學習推薦模型,與傳統的機器學習相比,深度學習模型的表達能力更強,而且更可以挖掘出數據中潛藏的模式。另外。深度學習模型結構也很是靈活,可以根據業務場景和數據結構進行調整。仍是原來的樣子,我會按照原理以及代碼實現,再就是一些優缺點進行逐一介紹。python

AutoRec

AutoRec能夠說是最小的深度學習推薦系統了,它是一種單隱層神經網絡推薦模型,將自編碼器與協同過濾相結合。那麼什麼是自編碼器呢?自編碼器能夠看作是一種壓縮維度的工具,不管是圖像、音頻、仍是文本,都可以經過自編碼器轉換成向量形式進行表達,假設咱們的輸入(不管是圖像、音頻等等)的數據向量是\(r\),那麼但願經過自編碼器的輸出向量儘量接近原來的數據輸入\(r\)git

如下是論文原文github

Our aim in this work is to design an item-based (user-based) autoencoder which can take as input each partially observed, project it into a low-dimensional latent (hidden) space, and then reconstruct in the output space to predict missing ratings for purposes of recommendation.網絡

假設自編碼器的重建函數是\(h(r;\theta)\),那麼自編碼器的目標函數是:數據結構

\[\min_{\theta}\sum_{r\in S}||r-h(r;\theta)||_2^2 \]

其中的\(S\)就是全部數據輸入的向量結合。機器學習

通常來講,重建函數\(h(r;\theta)\)的參數量遠遠小於輸入向量的維度,因此自編碼器至關於完成了數據壓縮和降維的工做。而且,經過自編碼器生成的輸出向量,使得自編碼器的編碼過程有必定的泛化能力,能夠預測丟失的維度信息,這也是自編碼器可以用於推薦系統的緣由。函數

模型結構

在以前的文章中咱們介紹了協同過濾的關鍵——共現矩陣。就是由於由\(m\)個用戶以及\(n\)的物品造成的\(m\times n\)的共現矩陣維度過高,因此咱們須要使用一個重建函數對共現矩陣裏面的評分向量進行壓縮,而後通過評分預估以及排序以後造成最終的排序列表。AutoRec使用了單隱層神經網絡結構來實現自編碼器的功能。以下圖所示。

藍色神經元表明模型的\(k\)維單隱層,也就是壓縮以後的向量,\(V\)以及\(W\)表明從輸入到隱層、從隱層到輸出層的參數矩陣。那麼寫成重建函數的形式就是工具

\[h(r;\theta)=f(W\cdot g(Vr+\mu)+b) \]

\(f(\cdot)\)以及\(g(\cdot)\)爲輸出層和隱層神經元的激活函數。爲了防止重構函數(單隱層神經網絡、或者說三層神經網絡)的過擬合,再加上\(L2\)正則化項,那麼AutoRec的目標函數就是學習

\[\min_{\theta}\sum_{r=1}^{n}||r^{(i)}-h(r;\theta)||_O^2+\frac{\lambda}{2}(||W||_{F}^{2}+|V||_{F}^2) \]

\(||\cdot||_F\)爲Frobenius範數.ui

推薦過程

當輸入物品\(i\)的評分向量\(r^{(i)}\)時,獲得的模型輸出向量\(h(r;\theta)\)就是全部用戶對物品\(i\)的評分預測。其中第\(u\)維就是用戶\(u\)對物品\(i\)的預測評分\(\hat{R}_{ui}\)。那麼再遍歷一遍物品向量就能夠獲得該用戶對全部物品的評分預測,而後進行排序就能夠獲得推薦列表。這種以物品評分向量做爲輸入的被稱爲I-AutoRec(Item based AutoRec),另一種就是以用戶評分向量做爲輸入的就是U-AutoRec(User based AutoRec)。U-Auto相比較於I-Auto優點是僅輸入一次目標用戶的用戶向量就能夠重建用戶對全部物品的評分向量,也就是說僅需一次推斷就能夠獲得用戶的推薦列表,可是用戶向量的稀疏性可能會影響模型推薦效果。

侷限性

沒法進行特徵交叉,表達能力相對於後面更復雜的深度學習模型仍是表達能力不足。因爲AutoRec的簡單明瞭,做爲入門的深度學習推薦模型再合適不過了。

代碼

## 模型部分
class Autorec(nn.Module):
    def __init__(self,args, num_items):
        super(Autorec, self).__init__()
        self.args = args
        #self.num_users = num_users
        self.num_items = num_items
        self.hidden_units = args.hidden_units
        self.lambda_value = args.lambda_value
        self.encoder = nn.Sequential(
            nn.Linear(self.num_items, self.hidden_units),
            nn.Sigmoid()
        )
        self.decoder = nn.Sequential(
            nn.Linear(self.hidden_units, self.num_items),
        )
    def forward(self,torch_input):
        encoder = self.encoder(torch_input)
        decoder = self.decoder(encoder)
        return decoder
## 損失函數部分
def loss(self, decoder, input, optimizer, mask_input):
    cost = 0
    temp2 = 0
    cost += ((decoder - input) * mask_input).pow(2).sum()
    rmse = cost
    for i in optimizer.param_groups:
        for j in i['params']:
            # print(type(j.data), j.shape,j.data.dim())
            if j.data.dim() == 2:
                temp2 += torch.t(j.data).pow(2).sum()
    cost += temp2 * self.lambda_value * 0.5
    return cost, rmse

參考

AutoRec: Autoencoders Meet Collaborative Filtering
Github:NeWnIx5991/AutoRec-for-CF

相關文章
相關標籤/搜索