用Mxnet实现矩阵分解

在《关于LDA, pLSA, SVD, Word2Vec的一些看法》一文中我们提到了SVD的算法。之前TensorFlow刚出来时,就听说可以很容易的用TF实现这个算法(参考这篇文章)。所以,就一直想着怎么用mxnet也搞一把。我们先看看公式

r(ui) = dot(p(u), q(i))

一开始卡在了dot这个操作上,没有找到mxnet支持的这个操作。后来经人提醒,发现mxnet的python库中重载了symbol类的运算符。所以elementwise的乘法可以直接写成

a = b * c

所以,迅速就可以写出网络结构了:

def get_net(max_user, max_item):
    hidden = 500
    user = mx.symbol.Variable('user')
    item = mx.symbol.Variable('item')
    score = mx.symbol.Variable('score')
    user = mx.symbol.Embedding(data = user, input_dim = max_user, output_dim = 1000)
    user = mx.symbol.Flatten(data = user)
    user = mx.symbol.FullyConnected(data = user, num_hidden = hidden)
    item = mx.symbol.Embedding(data = item, input_dim = max_item, output_dim = 1000)
    item = mx.symbol.FullyConnected(data = item, num_hidden = hidden)
    item = mx.symbol.Flatten(data = item)
    pred = user * item
    pred = mx.symbol.sum_axis(data = pred, axis = 1)
    pred = mx.symbol.Flatten(data = pred)
    pred = mx.symbol.LinearRegressionOutput(data = pred, label = score)
    return pred

这里user和item各自通过一个embedding和fc层变成了2个latent factor。然后pred是这两个lantent factor的点积。然后最后通过一个LinearRegressionOutput转成一个回归问题。

训练了一下,发现效果很好,RMSE可以很容易的收敛到0.8x。所以,我们再次领略了自动求导框架的威力。而且这个程序还是GPU就可以train的。
全部的程序见这里。数据集就是用的简单的movielens数据集。

其实,这个程序可以很容易的扩展成word2vec的程序,有兴趣的同学可以试一下。另外,还有一个思路,是关于图片的。如果我们有一个很大的关于图片相似度的数据集,那么我们可以用CNN讲图片embeding到一个vector,然后两个图片的vector点击作为它们的相似度目标,不知道可以train出什么效果。(不要问我从哪儿弄到很大的图片相似度的数据集)

推荐阅读更多精彩内容