Hi, I'm very interested in your resaerch, I tried to implement the LightGCN model according to the paper and my own understanding, but there is a big gap with the results reported in the paper. I wonder if you can provide the code corresponding to the LightGCN model? The following is my implementation:
class LightGCN(nn.Module):
def __init__(self, user_size, item_size, n_layers, beta=4.0, feature_type='both', drop_out=0.2, latent_size=64, reg=0.01):
super(LightGCN, self).__init__()
self.user_embed=torch.nn.Embedding(user_size,latent_size)
self.item_embed=torch.nn.Embedding(item_size,latent_size)
nn.init.xavier_normal_(self.user_embed.weight)
nn.init.xavier_normal_(self.item_embed.weight)
self.n_layers=n_layers
self.beta=beta
self.reg=reg
self.drop_out=drop_out
if drop_out!=0:
self.m=torch.nn.Dropout(drop_out)
if feature_type=='smoothed':
user_filter=torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_user_values.npy')).cuda()
item_filter=torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_item_values.npy')).cuda()
user_vector=torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_user_features.npy')).cuda()
item_vector=torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_item_features.npy')).cuda()
elif feature_type=='both':
user_filter=torch.cat([torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_user_values.npy')).cuda()\
,torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_rough_user_values.npy')).cuda()])
item_filter=torch.cat([torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_item_values.npy')).cuda()\
,torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_rough_item_values.npy')).cuda()])
user_vector=torch.cat([torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_user_features.npy')).cuda(),\
torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_rough_user_features.npy')).cuda()],1)
item_vector=torch.cat([torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_smooth_item_features.npy')).cuda(),\
torch.Tensor(np.load(r'./'+dataset+ r'/'+dataset+'_rough_item_features.npy')).cuda()],1)
else:
print('error')
exit()
self.L_u=(user_vector*user_filter).mm(user_vector.t())
self.L_i=(item_vector*item_filter).mm(item_vector.t())
del user_vector,item_vector,user_filter, item_filter
gc.collect()
torch.cuda.empty_cache()
# epochs: 180 nDCG@20: 0.381 Recall@20: 0.357
def forward(self, user, pos_item, nega_item, loss_type='bpr'):
user_emb, item_emb, nega_emb = self.user_embed.weight, self.item_embed.weight, self.item_embed.weight
user_embs, item_embs, nega_embs = [user_emb], [item_emb], [nega_emb]
for layer in range(self.n_layers):
if self.drop_out==0:
user_emb,item_emb,nega_emb=self.L_u.mm(user_emb),self.L_i.mm(item_emb),self.L_i.mm(nega_emb)
else:
user_emb,item_emb,nega_emb=(self.m(self.L_u)*(1-self.drop_out)).mm(user_emb),(self.m(self.L_i)*(1-self.drop_out)).mm(item_emb),\
(self.m(self.L_i)*(1-self.drop_out)).mm(nega_emb)
user_embs.append(user_emb), item_embs.append(item_emb), nega_embs.append(nega_emb)
user_embs, item_embs, nega_embs = torch.stack(user_embs, dim=1), torch.stack(item_embs, dim=1), torch.stack(nega_embs, dim=1)
final_user,final_pos,final_nega=torch.mean(user_embs, dim=1)[u],torch.mean(item_embs, dim=1)[i],torch.mean(nega_embs, dim=1)[nega]
if loss_type=='adaptive':
res_nega=(final_user*final_nega).sum(1)
nega_weight=(1-(1-res_nega.sigmoid().clamp(max=0.99)).log10()).detach()
out=((final_user*final_pos).sum(1)-nega_weight*res_nega).sigmoid()
else:
out=((final_user*final_pos).sum(1)-(final_user*final_nega).sum(1)).sigmoid()
reg_term=self.reg*(final_user**2+final_pos**2+final_nega**2).sum()
return (-torch.log(out).sum()+reg_term)/batch_size