推荐系统算法中有两个根本性的思路,一是用户和条目表征,二是特征交叉。在传统算法中,隐语义模型从用户和条目表征(Embedding, 或称为“嵌入”)出发,以用户表征向量与条目表征向量的乘(内积)表示用户对条目的喜好。而因子分解机(FM)则致力于解决特征交叉问题。在上一篇中的AutoRec则是首个使用深度学习从用户和条目表征的角度解决问题的方案。当然,其结构过于简单,没有应对特征交叉的能力,模型本身的非线性能力也不足。而NeuralCF[1]是第一个深度学习下的同时处理这两个问题的模型。
NeuralCF网络可以分解为两个子网络,一个被称为Generalized Matrix Factorization (GMF, 广义矩阵分解),另一个是Multi-Layer Perceptron (MLP, 多层感知机). 这两个子网络都包含用户和条目的表征部分:
embedding_user = torch.nn.Embedding(num_embeddings=num_users, embedding_dim=latent_dim)
embedding_item = torch.nn.Embedding(num_embeddings=num_items, embedding_dim=latent_dim)
自然地,就有两个问题:1)如何优化表征 以及2)如何做特征交叉。
对于问题2),是使用直接的表征向量内积来实现的:
user_embedding = embedding_user(user)
item_embedding = embedding_item(item)
element_product = torch.mul(user_embedding, item_embedding)
也就是 , 其中 为向量内积
然后使用优化方法解决问题1),这同样也包括两个部分,对于GMF部分,内积向量被输入到全连接层,然后通过softmax进行预估,即
优化目标: (1). 可见,单独拿出来看,GMF部分几乎完全等价于隐语义模型(LFM).
对于MLP部分,先载入GMF训练好的用户和条目表征权重,然后直接cancat用户和条目表征向量,输入多层感知机网络,使用非线性激活函数进行优化:
......
user_embedding = embedding_user(user)
item_embedding = embedding_item(item)
vector = torch.cat([user_embedding, item_embedding], dim=-1)
#载入预训练表征权重:
embedding_user.weight.data = gmf_model.embedding_user.weight.data
embedding_item.weight.data = gmf_model.embedding_item.weight.data
优化目标同(1)式。
以上按顺序分别训练GMF和MLP, 然后载入它们的权重,进行整体网络的优化。在这一步的优化过程中,GMF和MLP部分的用户和条目表征分开:
这一点从代码上理解更直观:
embedding_user_mlp = torch.nn.Embedding(num_embeddings=num_users, embedding_dim=latent_dim_mlp)
embedding_item_mlp = torch.nn.Embedding(num_embeddings=num_items, embedding_dim=latent_dim_mlp)
embedding_user_mf = torch.nn.Embedding(num_embeddings=num_users, embedding_dim=latent_dim_mf)
embedding_item_mf = torch.nn.Embedding(num_embeddings=num_items, embedding_dim=latent_dim_mf)
#载入预训练表征权重:
embedding_user_mlp.weight.data = mlp_model.embedding_user.weight.data
embedding_item_mlp.weight.data = mlp_model.embedding_item.weight.data
embedding_user_mf.weight.data = gmf_model.embedding_user.weight.data
embedding_item_mf.weight.data = gmf_model.embedding_item.weight.data
#forward:
user_embedding_mlp = embedding_user_mlp(user)
item_embedding_mlp = embedding_item_mlp(item)
user_embedding_mf = embedding_user_mf(user)
item_embedding_mf = embedding_item_mf(item)
mlp_vector = torch.cat([user_embedding_mlp, item_embedding_mlp], dim=-1)
mf_vector =torch.mul(user_embedding_mf, item_embedding_mf)
for idx, _ in enumerate(range(len(self.fc_layers))):
mlp_vector = self.fc_layers[idx](mlp_vector)
mlp_vector = torch.nn.ReLU()(mlp_vector)
vector = torch.cat([mlp_vector, mf_vector]
上面部分也可以不使用GMF和MLP的预训练权重,而直接从头开始训练。当然,也可以对GMF和MLP部分使用同样的用户和条目表征。不过这样做的预测效果更差,这也是符合直觉和逻辑的。
以今天视角来看,NeuralCF所使用的一些操作不过是网络设计中的常规做法。但它实际上是一个深度学习框架下基础性推荐算法结构,对用户和条目表征和特征交叉都做出了针对性的处理,以此为基础可以做出很多优化。
参考
- ^He, X., Liao, L., Zhang, H., Nie, L., Hu, X., & Chua, T. (2017). Neural Collaborative Filtering. the web conference.
来源:oschina
链接:https://my.oschina.net/u/4272511/blog/4404534