模型复现:
import torch from torch import nn import numpy as np import pandas as pd from torch import nn from torch.nn import functional as F class CoNet(nn.Module): def __init__(self, n_users, n_source_item, n_target_item, n_factors=80): super().__init__() self.user_factors = nn.Embedding(n_users + 1, n_factors, sparse=True) self.source_item_factors = nn.Embedding(n_source_item + 1, n_factors, sparse=True) #(1, 160) self.target_item_factors = nn.Embedding(n_target_item + 1, n_factors, sparse=True) #(1, 160) self.source_fc1 = nn.Linear(n_factors * 2, 128) #(160, 128) self.target_fc1 = nn.Linear(n_factors * 2, 64) #(160,64) self.cross_v1 = nn.Parameter(torch.randn(64, 128)) # (64,128) self.source_fc2 = nn.Linear(128, 64) self.target_fc2 = nn.Linear(64, 32) self.cross_v2 = nn.Parameter(torch.randn(32, 64)) self.source_fc3 = nn.Linear(64, 32) self.target_fc3 = nn.Linear(32, 16) self.source_out = nn.Linear(32, 2) self.target_out = nn.Linear(16, 2) def forward(self, user, source_item, target_item): source_embedding = torch.cat((self.user_factors(user), self.source_item_factors(source_item)), 1) # (1,160) target_embedding = torch.cat((self.user_factors(user), self.target_item_factors(target_item)) ,1) # (1,160) out_source_v1 = F.relu(self.source_fc1(source_embedding) + torch.mm(self.target_fc1(target_embedding), self.cross_v1)) # (1 * 128) + (1 * 64) * (64 * 128) out_target_v1 = F.relu(self.target_fc1(target_embedding) + torch.mm(self.source_fc1(source_embedding), torch.t(self.cross_v1))) #(1 * 64) +(1,128) (128, 64) out_source_v2 = F.relu(self.source_fc2(out_source_v1) + torch.mm(self.target_fc2(out_target_v1), self.cross_v2)) #(1,64) + (1, 32) * (32, 64) out_target_v2 = F.relu(self.target_fc2(out_target_v1) + torch.mm(self.source_fc2(out_source_v1), torch.t(self.cross_v2)) # (1,32) + (1, 64) * (64, 32) out_source = F.relu(self.source_fc3(out_source_v2)) out_target = F.relu(self.target_fc3(out_target_v2)) out_source = self.source_out(out_source) out_target = self.target_out(out_target) return out_source, out_target
最后,这里有两个问题论文中并没有提到:
1. CoNet模型在训练的时候使用的是源域和目标域之间的交集数据,那么对于只在源域中出现的用户(或者只在目标域中出现的用户)CoNet是怎么处理的呢?(我个人觉得CoNet比较像DSSM,DSSM是直接喂入0,但是不知道CoNet是怎么做的…)
2. 在使用模型做预测的时候,当我想预测目标域中的用户x是否会有交互行为,我们是否还需要用户在源域中的输入数据呢?(我个人理解是需要的,因为在forward的时候有weight transfer matrix W需要参与计算)如果需要的话,在众多源域用户x信息中,如何选取合适的一条作为输入呢?
在实验里,我是把user的embedding取了平均之后喂进去的,我给作者发了email,但是人家并没有回我……太忙了吧可能。
作者您好
我最近在做跨域推荐的对比实验的工作,作者关于了这个文章复现的完整代码方便发我一下么?还有能方便推荐几篇关于这个任务的论文么?我邮箱[email protected]
不胜感激
季皓(郑州大学 信息工程学院)
请查收邮件
作者您好,我想请教一下您,在训练的时候,是如何把同个用户的不同商品的数据进行配对的呢?是笛卡尔积的操作吗?遍历所有可能的(源域商品,目标域商品)对?这样会导致数据量激增吧?
还有就是为什么要把交叉的矩阵设成parameter而不是Linear呢?
我是上财的一名研究生,目前正在研究这方面的论文,望您抽空解答,谢谢!
我也想和您分享一些我的思考,有些地方不太成熟,欢迎批评指正:
1. 对于第一个问题,我觉得这个问题和多视角学习比较像,都是基于用户在多个领域下的样本进行随机匹配喂入模型,笛卡尔操作开销比较大,所以从领域A抽取用户A的一条样本,从领域B抽取用户U的一条样本,进行合成(先采样再合成),如果先合成再采样的话(先进行笛卡尔乘积)这样算法的开销太大了,得不偿失
2. 第二个问题,我的想法是,首先parameter要比linear具有更好的特征迁移能力。其次矩阵parameter有一个好处就是可以对齐参数,比如领域A的某一个层是(30 * 50), 领域B内的某一层是(40 * 60),那么我只需要用一个(50*60)的矩阵就完成了在两个层之间的参数迁移,这个在编程的时候也很方便 容易被并行化处理(只是多了一次矩阵运算而已)
不知道我的回答能否让您满意,期待和您的进一步交流
十分感谢您的解答,关于第一个问题,模型的输入应该是(用户u,领域A商品a,领域B商品b)这样的三元组,用户应该是一样的。如果我没理解错 您的意思的话,意思就是从领域A用户u交互过的商品中抽样一条,再从领域B用户u交互过的商品中抽样一条,这样组成三元组,然后重复多次构造训练数据,是吗?
第二个问题我理解了,谢谢您。
另外,如果可以的话,想学习一下您的复现代码,我的邮箱是[email protected],谢谢!
作者你好,
最近我在做一些跨域推荐的学习,想尝试复现CoNet,无奈没有官方代码,不知作者能否将你关于这篇论文复现的完整代码分享我一份?仅作交流用途,我的邮箱是[email protected],谢谢!
作者你好,
最近我也在复现CoNet的工作,但无奈没有官方代码,不知作者能否将你关于这篇论文复现的完整代码分享我一份?仅作交流用途,我的邮箱是[email protected],感谢!