数据集
何向南老师github:
https://github.com/hexiangnan/neural_collaborative_filtering
我们先看一下数据集组成 。
然后今天说的是 load_dataset做了什么事情 。
先上代码:
导包
import pandas as pdimport numpy as npimport mathfrom collections import defaultdictimport heapqimport scipy.sparse as spimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.utils.dataimport torch.backends.cudnn as cudnnimport os 载入数据 。
def load_dataset(test_num=100):train_data = https://tazarkount.com/read/pd.read_csv("./ncf_data/ml-1m.train.rating", \sep='\t', header=None, names=['user', 'item'], \usecols=[0, 1], dtype={0: np.int32, 1: np.int32})user_num = train_data['user'].max() + 1item_num = train_data['item'].max() + 1train_data = train_data.values.tolist()#load ratings as a dok matrixtrain_mat = sp.dok_matrix((user_num,item_num),dtype=np.float32)for x in train_data:train_mat[x[0], x[1]] = 1.0test_data = https://tazarkount.com/read/[]with open("/data/fjsdata/ctKngBase/ml/ml-1m.test.negative", 'r') as fd:line = fd.readline()while line != None and line != '':arr = line.split('\t')u = eval(arr[0])[0]test_data.append([u, eval(arr[0])[1]])#one postive itemfor i in arr[1:]:test_data.append([u, int(i)]) #99 negative itemsline = fd.readline()return train_data, test_data, user_num, item_num, train_mat 先说一下 ml-1m.train.rating 文件
这个文件有列,分别是user,item,评分,时间戳(这个我也记不清是不是了) 。
#load ratings as a dok matrixtrain_mat = sp.dok_matrix((user_num,item_num),dtype=np.float32)for x in train_data:train_mat[x[0], x[1]] = 1.0 上面这段代码是把所有打分交互过的用户,项目,组成一个矩阵,数据结构是这个样子的:(User,Item):1
这里补充一下,哪怕是用户打分只有1分,对应字典也是1.0
如图:
处理test_data
先看一下数据格式:
这里说明一下,由于作者在paper中没有明确说明(也可能是我没仔细看)
这个元组里面是用户项目交互,元组外面的一堆是未交互
所以在这里我们代码意思是把元组拿出来,作为积极,剩下的u对应下面这一串未交互的为消极 。
test_data = https://tazarkount.com/read/[]with open("./ncf_data/ml-1m.test.negative", 'r') as fd:line = fd.readline()while line != None and line != '':arr = line.split('\t')u = eval(arr[0])[0]test_data.append([u, eval(arr[0])[1]])#one postive itemfor i in arr[1:]:test_data.append([u, int(i)]) #99 negative itemsline = fd.readline() GMF模型
所谓GMF也就是广义的矩阵分解模型 。看一下通用框架 。
实验中就是把用户(user)和项目(item)用one_hot编码的形式映射为 latent vector维度 。所谓广义,就是这个模型可以多种用途,不一定就是处理这一类模型 。上代码一看究竟:
class GMF(nn.Module):def __init__(self, user_num, item_num, factor_num):super(GMF, self).__init__()‘’‘user_num:用户数量item_num:项目数量factor_映射维度’‘’self.embed_user_GMF = nn.Embedding(user_num, factor_num)self.embed_item_GMF = nn.Embedding(item_num, factor_num)self.predict_layer = nn.Linear(factor_num, 1)self._init_weight_()def _init_weight_(self):nn.init.normal_(self.embed_user_GMF.weight, std=0.01)nn.init.normal_(self.embed_item_GMF.weight, std=0.01)def forward(self, user, item):embed_user_GMF = self.embed_user_GMF(user)embed_item_GMF = self.embed_item_GMF(item)#GMF部分就是求两个embedding的内积output_GMF = embed_user_GMF * embed_item_GMFprediction = self.predict_layer(output_GMF)return prediction.view(-1)
MLP模型
这里同样是把user,item映射,但是走MLP映射的维度与上面不同 。毕竟模型不同 。
上代码:
class MLP(nn.Module):def __init__(self, user_num, item_num, factor_num, num_layers, dropout):super(MLP, self).__init__()self.embed_user_MLP = nn.Embedding(user_num, factor_num * (2 ** (num_layers - 1)))self.embed_item_MLP = nn.Embedding(item_num, factor_num * (2 ** (num_layers - 1)))MLP_modules = []for i in range(num_layers):input_size = factor_num * (2 ** (num_layers - i))MLP_modules.append(nn.Dropout(p=dropout))MLP_modules.append(nn.Linear(input_size, input_size//2))MLP_modules.append(nn.ReLU())'''这里解释一下,这里是把每一层的定义放在列表里,然后nn.Sequential(*MLP_modules)函数直接取列表顺序定义网络,每一层的激活函数都是relu'''self.MLP_layers = nn.Sequential(*MLP_modules)self.predict_layer = nn.Linear(factor_num, 1)self._init_weight_()def _init_weight_(self):nn.init.normal_(self.embed_user_MLP.weight, std=0.01)nn.init.normal_(self.embed_item_MLP.weight, std=0.01)for m in self.MLP_layers:if isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight)nn.init.kaiming_uniform_(self.predict_layer.weight,a=1, nonlinearity='sigmoid')def forward(self, user, item):embed_user_MLP = self.embed_user_MLP(user)embed_item_MLP = self.embed_item_MLP(item)interaction = torch.cat((embed_user_MLP, embed_item_MLP), -1)output_MLP = self.MLP_layers(interaction)prediction = self.predict_layer(output_MLP)return prediction.view(-1) NCF模型
就是将两个模型在倒数第二层(输出前一层融合) 。这里要看一下这两个向量的融合方式 。
class NCF(nn.Module): def __init__(self, user_num, item_num, factor_num, num_layers,dropout, model, GMF_model=None, MLP_model=None):super(NCF, self).__init__()"""user_num: number of users;item_num: number of items;factor_num: number of predictive factors;num_layers: the number of layers in MLP model;dropout: dropout rate between fully connected layers;model: 'MLP', 'GMF', 'NeuMF-end', and 'NeuMF-pre';GMF_model: pre-trained GMF weights;MLP_model: pre-trained MLP weights."""self.dropout = dropoutself.model = modelself.GMF_model = GMF_modelself.MLP_model = MLP_modelself.embed_user_GMF = nn.Embedding(user_num, factor_num)self.embed_item_GMF = nn.Embedding(item_num, factor_num)self.embed_user_MLP = nn.Embedding(user_num, factor_num * (2 ** (num_layers - 1)))self.embed_item_MLP = nn.Embedding(item_num, factor_num * (2 ** (num_layers - 1)))MLP_modules = []for i in range(num_layers):input_size = factor_num * (2 ** (num_layers - i))MLP_modules.append(nn.Dropout(p=self.dropout))MLP_modules.append(nn.Linear(input_size, input_size//2))MLP_modules.append(nn.ReLU())self.MLP_layers = nn.Sequential(*MLP_modules)if self.model in ['MLP', 'GMF']:predict_size = factor_numelse:predict_size = factor_num * 2self.predict_layer = nn.Linear(predict_size, 1)self._init_weight_() def _init_weight_(self):""" We leave the weights initialization here. """if not self.model == 'NeuMF-pre':nn.init.normal_(self.embed_user_GMF.weight, std=0.01)nn.init.normal_(self.embed_user_MLP.weight, std=0.01)nn.init.normal_(self.embed_item_GMF.weight, std=0.01)nn.init.normal_(self.embed_item_MLP.weight, std=0.01)for m in self.MLP_layers:if isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight)nn.init.kaiming_uniform_(self.predict_layer.weight,a=1, nonlinearity='sigmoid')for m in self.modules():if isinstance(m, nn.Linear) and m.bias is not None:m.bias.data.zero_()else:# embedding layersself.embed_user_GMF.weight.data.copy_(self.GMF_model.embed_user_GMF.weight)self.embed_item_GMF.weight.data.copy_(self.GMF_model.embed_item_GMF.weight)self.embed_user_MLP.weight.data.copy_(self.MLP_model.embed_user_MLP.weight)self.embed_item_MLP.weight.data.copy_(self.MLP_model.embed_item_MLP.weight)# mlp layersfor (m1, m2) in zip(self.MLP_layers, self.MLP_model.MLP_layers):if isinstance(m1, nn.Linear) and isinstance(m2, nn.Linear):m1.weight.data.copy_(m2.weight)m1.bias.data.copy_(m2.bias)# predict layerspredict_weight = torch.cat([self.GMF_model.predict_layer.weight,self.MLP_model.predict_layer.weight], dim=1)precit_bias = self.GMF_model.predict_layer.bias + \self.MLP_model.predict_layer.biasself.predict_layer.weight.data.copy_(0.5 * predict_weight)self.predict_layer.bias.data.copy_(0.5 * precit_bias) def forward(self, user, item):if not self.model == 'MLP':embed_user_GMF = self.embed_user_GMF(user)embed_item_GMF = self.embed_item_GMF(item)output_GMF = embed_user_GMF * embed_item_GMFif not self.model == 'GMF':embed_user_MLP = self.embed_user_MLP(user)embed_item_MLP = self.embed_item_MLP(item)interaction = torch.cat((embed_user_MLP, embed_item_MLP), -1)output_MLP = self.MLP_layers(interaction)if self.model == 'GMF':concat = output_GMFelif self.model == 'MLP':concat = output_MLPelse:concat = torch.cat((output_GMF, output_MLP), -1)prediction = self.predict_layer(concat)return prediction.view(-1) 【pytorch复现NCF】
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
