自動編碼器的評級預測
AutoRec: Rating Prediction with Autoencoders
雖然矩陣分解模型在評級預測任務上取得了不錯的效果,但本質上是一個線性模型。因此,這樣的模型不能捕捉複雜的非線性和複雜的關係,這些關係可以預測用戶的偏好。在本文中,介紹了一個非線性神經網絡協同過濾模型AutoRec[Sedhain et al.,2015]。將協同過濾(CF)與自動編碼器架構相結合,並在顯式反饋的基礎上將非線性轉換整合到CF中。神經網絡具有逼近任意連續函數的能力,適合於解決矩陣分解的侷限性,豐富了矩陣分解的表達能力。
一方面,AutoRec具有與autocoder相同的結構,由輸入層、隱藏層和重構(輸出)層組成。自動編碼器是一種神經網絡,學習將輸入複製到輸出,以便將輸入編碼到隱藏(通常是低維)表示中。在AutoRec中,不顯式地將用戶/項目嵌入低維空間,而是使用交互矩陣的列/行作爲輸入,然後在輸出層重構交互矩陣。
另一方面,AutoRec不同於傳統的自動編碼器:AutoRec專注於學習/重建輸出層,而不是學習隱藏的表示。使用一個部分觀察到的交互矩陣作爲輸入,旨在重建一個完整的評級矩陣。同時,在輸出層通過重構將缺失的輸入項填充到輸出層,以達到推薦的目的。
AutoRec有兩種變體:基於用戶的和基於項目的。爲了簡潔起見,這裏只介紹了基於項目的AutoRec。基於用戶的AutoRec可以相應地導出。
- Model
from d2l import mxnet as d2l
from mxnet import autograd, gluon, np, npx
from mxnet.gluon import nn
import mxnet as mx
import sys
npx.set_np()
- Implementing the Model
典型的自動編碼器由編碼器和解碼器組成。編碼器將輸入投影到隱藏表示,解碼器將隱藏層映射到重建層。遵循這一實踐,並創建具有密集層的編碼器和解碼器。編碼器的激活默認設置爲sigmoid,解碼器不激活。在編碼轉換後加入了Dropout,以減少過擬合。未觀察到的輸入的梯度被屏蔽,以確保只有觀察到的評級有助於模型學習過程。
class AutoRec(nn.Block):
def __init__(self, num_hidden, num_users, dropout=0.05):
super(AutoRec, self).__init__()
self.encoder = nn.Dense(num_hidden, activation='sigmoid',
use_bias=True)
self.decoder = nn.Dense(num_users, use_bias=True)
self.dropout = nn.Dropout(dropout)
def forward(self, input):
hidden = self.dropout(self.encoder(input))
pred = self.decoder(hidden)
if autograd.is_training(): # mask the gradient during training.
return pred * np.sign(input)
else:
return pred
- Reimplementing the Evaluator
由於輸入和輸出都發生了變化,需要重新實現評估函數,而仍然使用RMSE作爲精度度量。
def evaluator(network, inter_matrix, test_data, ctx):
scores = []
for values in inter_matrix:
feat = gluon.utils.split_and_load(values, ctx, even_split=False)
scores.extend([network(i).asnumpy() for i in feat])
recons = np.array([item for sublist in scores for item in sublist])
# Calculate the test RMSE.
rmse = np.sqrt(np.sum(np.square(test_data - np.sign(test_data) * recons))
/ np.sum(np.sign(test_data)))
return float(rmse)
- Training and Evaluating the Model
現在,讓在MovieLens數據集上訓練和評估AutoRec。可以清楚地看到,測試RMSE低於矩陣分解模型,證實了神經網絡在評級預測任務中的有效性。
ctx = d2l.try_all_gpus()
# Load the MovieLens 100K dataset
df, num_users, num_items = d2l.read_data_ml100k()
train_data, test_data = d2l.split_data_ml100k(df, num_users, num_items)
_, _, _, train_inter_mat = d2l.load_data_ml100k(train_data, num_users,
num_items)
_, _, _, test_inter_mat = d2l.load_data_ml100k(test_data, num_users,
num_items)
num_workers = 0 if sys.platform.startswith(“win”) else 4
train_iter = gluon.data.DataLoader(train_inter_mat, shuffle=True,
last_batch="rollover", batch_size=256,
num_workers=num_workers)
test_iter = gluon.data.DataLoader(np.array(train_inter_mat), shuffle=False,
last_batch="keep", batch_size=1024,
num_workers=num_workers)
# Model initialization, training, and evaluation
net = AutoRec(500, num_users)
net.initialize(ctx=ctx, force_reinit=True, init=mx.init.Normal(0.01))
lr, num_epochs, wd, optimizer = 0.002, 25, 1e-5, ‘adam’
loss = gluon.loss.L2Loss()
trainer = gluon.Trainer(net.collect_params(), optimizer,
{"learning_rate": lr, 'wd': wd})
d2l.train_recsys_rating(net, train_iter, test_iter, loss, trainer, num_epochs,
ctx, evaluator, inter_mat=test_inter_mat)
train loss 0.000, test RMSE 0.898
37035493.5 examples/sec on [gpu(0), gpu(1)]
5. Summary
· We can frame the matrix factorization algorithm with autoencoders, while integrating non-linear layers and dropout regularization.
· Experiments on the MovieLens 100K dataset show that AutoRec achieves superior performance than matrix factorization.