手把手教你读推荐论文-SR-GNN
论文理解,参考沈向洋论文十问
-
论文试图解决什么问题?
序列推荐中,序列与序列之间相关性建模不足 -
这是否是一个新的问题?
这不是一个新的问题,但是一种新的解决方案 -
这篇文章要验证一个什么科学假设?
不同的序列之间存在着相关关系,可以更精确的生成商品表征 -
有哪些相关研究?如何归类?谁是这一课题在领域内值得关注的研究员?
归类为序列推荐问题,Dietmar Jannach, Hongzhi Yin -
论文中提到的解决方案之关键是什么?
把浏览序列建模为序列图,利用门控图神经网络和注意力机制,同时建模长期偏好和当前兴趣 -
论文中的实验是如何设计的?
控制embedding维度=100,将后续几天的会话设置为Yoochoose的测试集,将后续几周的会话设置为Diginetiva的测试集。 -
用于定量评估的数据集是什么?代码有没有开源?
Yoochoose http://2015.recsyschallenge.com/challege.html 和Diginetiva http://cikm2016.cs.iupui.edu/cikm-cup ,有开源https://github.com/CRIPAC-DIG/SR-GNN -
论文中的实验及结果有没有很好地支持需要验证的科学假设?
有,文中的消融实验证明了同时建模长期偏好和当前兴趣可以带来增益 -
这篇论文到底有什么贡献?
将图模型融入到序列推荐中,将会话的长期偏好和当前兴趣结合起来,从而更好地预测用户的下一步行动。 -
下一步呢?有什么工作可以继续深入?
感觉仅靠时间来划分session不太合理,应该有一些更好的能表征用户兴趣转移的节点来划分比较合适
代码工程学习
主要是学习了GatedGNN
class GatedGNN(nn.Layer):
#省略init
def GNNCell(self, A, hidden):
#常规的 H = AWX + B
input_in = paddle.matmul(A[:, :, :A.shape[1]], self.linear_edge_in(hidden)) + self.b_iah
input_out = paddle.matmul(A[:, :, A.shape[1]:], self.linear_edge_out(hidden)) + self.b_ioh
# [batch_size, max_session_len, embedding_size * 2]
# 这里融和不同方向的图表征,打比赛的时候看前排用过,应该比之间变成无向图效果会好。
inputs = paddle.concat([input_in, input_out], 2)
# gi.size equals to gh.size, shape of [batch_size, max_session_len, embedding_size * 3]
# 这就是Gated模块
# 下面两行其实等价于 Linear层
gi = paddle.matmul(inputs, self.w_ih) + self.b_ih
gh = paddle.matmul(hidden, self.w_hh) + self.b_hh
# (batch_size, max_session_len, embedding_size)
i_r, i_i, i_n = gi.chunk(3, 2)
h_r, h_i, h_n = gh.chunk(3, 2)
reset_gate = F.sigmoid(i_r + h_r)
input_gate = F.sigmoid(i_i + h_i)
new_gate = paddle.tanh(i_n + reset_gate * h_n)
hy = (1 - input_gate) * hidden + input_gate * new_gate
return hy
def forward(self, A, hidden):
for i in range(self.step):
hidden = self.GNNCell(A, hidden)
return hidden
评测细节:之前老是把recall和hitrate弄混,从这个代码来看,recall更多是针对item的,hitrate更多是以user为单位,这下分清了。
def evaluate(preds,test_gd, topN=50):
total_recall = 0.0
total_ndcg = 0.0
total_hitrate = 0
for user in test_gd.keys():
recall = 0
dcg = 0.0
item_list = test_gd[user]
for no, item_id in enumerate(item_list):
if item_id in preds[user][:topN]:
recall += 1
dcg += 1.0 / math.log(no+2, 2)
idcg = 0.0
for no in range(recall):
idcg += 1.0 / math.log(no+2, 2)
total_recall += recall * 1.0 / len(item_list)
if recall > 0:
total_ndcg += dcg / idcg
total_hitrate += 1
total = len(test_gd)
recall = total_recall / total
ndcg = total_ndcg / total
hitrate = total_hitrate * 1.0 / total
return {f'recall@{topN}': recall, f'ndcg@{topN}': ndcg, f'hitrate@{topN}': hitrate}