def __init__(self, args): ########################################################################################################################################## seed = args.seed np.random.seed(seed) random.seed(seed) self.device = torch.device("cuda:0" if torch.cuda.is_available() and not args.no_cuda else "cpu") ########################################################################################################################################## self.model_name = args.model_name self.data_path = args.data_path self.learning_rate = args.l_r#l_r# self.weight_decay = args.weight_decay#weight_decay# self.batch_size = args.batch_size self.concat = args.concat self.num_workers = args.num_workers self.num_epoch = args.num_epoch self.num_user = args.num_user self.num_item = args.num_item self.dim_latent = args.dim_latent self.aggr_mode = args.aggr_mode#aggr_mode# self.num_layer = args.num_layer self.has_id = args.has_id self.dim_v = 2048 self.dim_a = 128 self.dim_t = 100 ########################################################################################################################################## print('Data loading ...') self.train_dataset = MyDataset('./Data/', self.num_user, self.num_item) self.train_dataloader = DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=True, num_workers=self.num_workers) self.edge_index = np.load('./Data/train.npy') self.val_dataset = np.load('./Data/val.npy') self.test_dataset = np.load('./Data/test.npy') self.val_test_dataset = np.load('./Data/val_test.npy') self.v_feat = np.load('./Data/FeatureVideo_normal.npy') self.a_feat = np.load('./Data/FeatureAudio_avg_normal.npy') self.t_feat = np.load('./Data/FeatureText_stl_normal.npy') print('Data has been loaded.') ########################################################################################################################################## if self.model_name == 'MMGCN': self.features = [self.v_feat, self.a_feat, self.t_feat] self.model = MMGCN(self.features, self.edge_index, self.batch_size, self.num_user, self.num_item, self.aggr_mode, self.concat, self.num_layer, self.has_id, self.dim_latent).cuda() elif self.model_name == 'VBPR': self.dim_feat = self.dim_v+self.dim_a+self.dim_t self.features = torch.tensor(np.concatenate((self.v_feat, self.a_feat, self.t_feat), axis=1), dtype=torch.float) self.model = VBPR_model(self.num_user, self.num_item, self.dim_latent, self.dim_feat, self.features).to(self.device) elif self.model_name == 'GraphSAGE': self.dim_feat = self.dim_v+self.dim_a+self.dim_t self.features = torch.tensor(np.concatenate((self.v_feat, self.a_feat, self.t_feat), axis=1), dtype=torch.float) self.model = MMGraphSAGE(self.features, self.edge_index, self.batch_size, self.num_user, self.num_item, self.dim_latent, self.dim_feat).cuda() elif self.model_name == 'NGCF': self.model = NGCF(self.v_feat, self.a_feat, self.t_feat, self.edge_index, self.batch_size, self.num_user, self.num_item, self.dim_latent).cuda() if args.PATH_weight_load and os.path.exists(args.PATH_weight_load): self.model.load_state_dict(torch.load(args.PATH_weight_load)) print('module weights loaded....') ########################################################################################################################################## self.optimizer = torch.optim.Adam([{'params': self.model.parameters(), 'lr': self.learning_rate}], weight_decay=self.weight_decay)
def __init__(self, args, n_user, n_item, norm_adj): super(Meta, self).__init__() self.update_lr = args.update_lr self.meta_lr = args.meta_lr self.task_num = args.batch_size self.update_step = args.update_step self.update_step_test = args.update_step_test self.net = NGCF(n_user, n_item, norm_adj, args) self.meta_optim = optim.Adam(self.net.parameters(), lr=self.meta_lr)
class Meta(nn.Module): def __init__(self, args, n_user, n_item, norm_adj): super(Meta, self).__init__() self.update_lr = args.update_lr self.meta_lr = args.meta_lr self.task_num = args.batch_size self.update_step = args.update_step self.update_step_test = args.update_step_test self.net = NGCF(n_user, n_item, norm_adj, args) self.meta_optim = optim.Adam(self.net.parameters(), lr=self.meta_lr) def forward(self, users, pos_items, neg_items, test_pos_items, test_neg_items): losses_q = [0 for _ in range(self.update_step + 1) ] # losses_q[i] is the loss on step i # 1. run the i-th task and compute loss for k=0 u_g_embedding, pos_i_g_embedding, neg_i_g_embedding = self.net( users, pos_items, neg_items, vars=None) loss, _, _ = self.net.create_bpr_loss(u_g_embedding, pos_i_g_embedding, neg_i_g_embedding) grad = torch.autograd.grad(loss, self.net.parameters()) fast_weights = list( map(lambda p: p[1] - self.update_lr * p[0], zip(grad, self.net.parameters()))) # this is the loss and accuracy before first update with torch.no_grad(): u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, self.net.parameters()) loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[0] += loss_q # this is the loss and accuracy after the first update with torch.no_grad(): u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, fast_weights) loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[1] += loss_q for k in range(1, self.update_step): # 1. run the i-th task and compute loss for k=1~K-1 u_g_embedding, pos_i_g_embedding, neg_i_g_embedding = self.net( users, pos_items, neg_items, fast_weights) loss, _, _ = self.net.create_bpr_loss(u_g_embedding, pos_i_g_embedding, neg_i_g_embedding) # 2. compute grad on theta_pi grad = torch.autograd.grad(loss, self.net.parameters()) # 3. theta_pi = theta_pi - train_lr * grad fast_weights = list( map(lambda p: p[1] - self.update_lr * p[0], zip(grad, fast_weights))) u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, fast_weights) # loss_q will be overwritten and just keep the loss_q on last update step. loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[k + 1] += loss_q # end of all tasks loss_q = losses_q[-1] # optimize theta parameters self.meta_optim.zero_grad() loss_q.backward() self.meta_optim.step() # average testing acc on batch tasks for different uodate step return [one.tolist() for one in losses_q] def finetunning(self, users, pos_items, neg_items, test_pos_items, test_neg_items): losses_q = [0 for _ in range(self.update_step_test + 1) ] # losses_q[i] is the loss on step i # 1. run the i-th task and compute loss for k=0 u_g_embedding, pos_i_g_embedding, neg_i_g_embedding = self.net( users, pos_items, neg_items, vars=None) loss, _, _ = self.net.create_bpr_loss(u_g_embedding, pos_i_g_embedding, neg_i_g_embedding) grad = torch.autograd.grad(loss, self.net.parameters()) fast_weights = list( map(lambda p: p[1] - self.update_lr * p[0], zip(grad, self.net.parameters()))) # this is the loss and accuracy before first update with torch.no_grad(): u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, self.net.parameters()) loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[0] += loss_q # this is the loss and accuracy after the first update with torch.no_grad(): # [setsz, nway] u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, fast_weights) loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[1] += loss_q for k in range(1, self.update_step_test): # 1. run the i-th task and compute loss for k=1~K-1 u_g_embedding, pos_i_g_embedding, neg_i_g_embedding = self.net( users, pos_items, neg_items, fast_weights) loss, _, _ = self.net.create_bpr_loss(u_g_embedding, pos_i_g_embedding, neg_i_g_embedding) # 2. compute grad on theta_pi grad = torch.autograd.grad(loss, self.net.parameters()) # 3. theta_pi = theta_pi - train_lr * grad fast_weights = list( map(lambda p: p[1] - self.update_lr * p[0], zip(grad, fast_weights))) u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q = self.net( users, test_pos_items, test_neg_items, fast_weights) # loss_q will be overwritten and just keep the loss_q on last update step. loss_q, _, _ = self.net.create_bpr_loss(u_g_embedding_q, pos_i_g_embedding_q, neg_i_g_embedding_q) losses_q[k + 1] += loss_q return [one.tolist() for one in losses_q]
import warnings warnings.filterwarnings('ignore') from time import time if __name__ == '__main__': args.device = torch.device('cuda:' + str(args.gpu_id)) plain_adj, norm_adj, mean_adj = data_generator.get_adj_mat() args.node_dropout = eval(args.node_dropout) args.mess_dropout = eval(args.mess_dropout) model = NGCF(data_generator.n_users, data_generator.n_items, norm_adj, args).to(args.device) t0 = time() """ ********************************************************* Train. """ cur_best_pre_0, stopping_step = 0, 0 optimizer = optim.Adam(model.parameters(), lr=args.lr) loss_loger, pre_loger, rec_loger, ndcg_loger, hit_loger = [], [], [], [], [] for epoch in range(args.epoch): t1 = time() loss, mf_loss, emb_loss = 0., 0., 0. n_batch = data_generator.n_train // args.batch_size + 1
pretrain_data = np.load(pretrain_path) print('load the pretrained embeddings.') return pretrain_data pretrain_data = None if args.pretrain == -1: try: pretrain_data = load_pretrained_data() except Exception: raise RuntimeError("pretrain embedding not found.") adj_list = dataset.get_adj_mat() model = NGCF(adj_list, dataset.user_attr, dataset.item_attr, data_config=data_config, args=args, pretrain_data=pretrain_data) """ ********************************************************* Save the model parameters. """ weight_list = [ model.weights[key] for key in model.weights if key not in ('user_embedding', 'item_embedding') ] saver = tf.train.Saver(var_list=list(model.weights.values())) config = tf.ConfigProto() config.gpu_options.allow_growth = True sess = tf.Session(config=config)
import torch from NGCF import NGCF from utility.batch_test import * from utility.helper import * if __name__ == '__main__': args.device = torch.device('cuda:' + str(args.gpu_id)) adj_mat, norm_adj_mat, mean_adj_mat = data_generator.get_adj_mat() model = NGCF(data_generator.n_users, data_generator.n_items, norm_adj_mat, args).to(args.device) t0 = time() """ ********************************************************* Train. """ cur_best_pre_0, stopping_step = 0, 0 optimizer = torch.optim.Adam(model.parameters(), lr=args.lr) loss_loger, pre_loger, rec_loger, ndcg_loger, hit_loger = [], [], [], [], [] for epoch in range(args.epoch): model.train() t1 = time() loss, mf_loss, emb_loss = 0., 0., 0. n_batch = data_generator.n_train // args.batch_size + 1 for idx in range(n_batch): users, pos_items, neg_items = data_generator.sample()
class Net: def __init__(self, args): ########################################################################################################################################## seed = args.seed np.random.seed(seed) random.seed(seed) self.device = torch.device("cuda:0" if torch.cuda.is_available() and not args.no_cuda else "cpu") ########################################################################################################################################## self.model_name = args.model_name self.data_path = args.data_path self.learning_rate = args.l_r#l_r# self.weight_decay = args.weight_decay#weight_decay# self.batch_size = args.batch_size self.concat = args.concat self.num_workers = args.num_workers self.num_epoch = args.num_epoch self.num_user = args.num_user self.num_item = args.num_item self.dim_latent = args.dim_latent self.aggr_mode = args.aggr_mode#aggr_mode# self.num_layer = args.num_layer self.has_id = args.has_id self.dim_v = 2048 self.dim_a = 128 self.dim_t = 100 ########################################################################################################################################## print('Data loading ...') self.train_dataset = MyDataset('./Data/', self.num_user, self.num_item) self.train_dataloader = DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=True, num_workers=self.num_workers) self.edge_index = np.load('./Data/train.npy') self.val_dataset = np.load('./Data/val.npy') self.test_dataset = np.load('./Data/test.npy') self.val_test_dataset = np.load('./Data/val_test.npy') self.v_feat = np.load('./Data/FeatureVideo_normal.npy') self.a_feat = np.load('./Data/FeatureAudio_avg_normal.npy') self.t_feat = np.load('./Data/FeatureText_stl_normal.npy') print('Data has been loaded.') ########################################################################################################################################## if self.model_name == 'MMGCN': self.features = [self.v_feat, self.a_feat, self.t_feat] self.model = MMGCN(self.features, self.edge_index, self.batch_size, self.num_user, self.num_item, self.aggr_mode, self.concat, self.num_layer, self.has_id, self.dim_latent).cuda() elif self.model_name == 'VBPR': self.dim_feat = self.dim_v+self.dim_a+self.dim_t self.features = torch.tensor(np.concatenate((self.v_feat, self.a_feat, self.t_feat), axis=1), dtype=torch.float) self.model = VBPR_model(self.num_user, self.num_item, self.dim_latent, self.dim_feat, self.features).to(self.device) elif self.model_name == 'GraphSAGE': self.dim_feat = self.dim_v+self.dim_a+self.dim_t self.features = torch.tensor(np.concatenate((self.v_feat, self.a_feat, self.t_feat), axis=1), dtype=torch.float) self.model = MMGraphSAGE(self.features, self.edge_index, self.batch_size, self.num_user, self.num_item, self.dim_latent, self.dim_feat).cuda() elif self.model_name == 'NGCF': self.model = NGCF(self.v_feat, self.a_feat, self.t_feat, self.edge_index, self.batch_size, self.num_user, self.num_item, self.dim_latent).cuda() if args.PATH_weight_load and os.path.exists(args.PATH_weight_load): self.model.load_state_dict(torch.load(args.PATH_weight_load)) print('module weights loaded....') ########################################################################################################################################## self.optimizer = torch.optim.Adam([{'params': self.model.parameters(), 'lr': self.learning_rate}], weight_decay=self.weight_decay) ########################################################################################################################################## def run(self): max_recall = 0.0 max_pre = 0.0 max_ndcg = 0.0 step = 0 for epoch in range(self.num_epoch): self.model.train() print('Now, training start ...') pbar = tqdm(total=len(self.train_dataset)) sum_loss = 0.0 for data in self.train_dataloader: self.optimizer.zero_grad() self.loss = self.model.loss(data) self.loss.backward() self.optimizer.step() pbar.update(self.batch_size) sum_loss += self.loss print(sum_loss/self.batch_size) pbar.close() if epoch % 5 == 0: print('Validation start...') self.model.eval() with torch.no_grad(): precision, recall, ndcg_score = self.model.accuracy(self.val_dataset, topk=10) print('---------------------------------Val: {0}-th epoch {1}-th top Precition:{2:.4f} Recall:{3:.4f} NDCG:{4:.4f}---------------------------------'.format( epoch, 10, precision, recall, ndcg_score)) if epoch % 10 == 0: self.model.eval() with torch.no_grad(): precision, recall, ndcg_score = self.model.accuracy(self.test_dataset, topk=10) print('---------------------------------Test: {0}-th epoch {1}-th top Precition:{2:.4f} Recall:{3:.4f} NDCG:{4:.4f}---------------------------------'.format( epoch, 10, precision, recall, ndcg_score)) return max_recall, max_pre, max_ndcg
from NGCF import NGCF # data will be loaded in batch_test from utility.batch_test import * from time import time from tqdm import tqdm if __name__ == '__main__': args.device = torch.device('cuda:' + str(args.gpu_id)) norm_adj = data_generator.get_adj_mat() args.node_dropout = eval(args.node_dropout) args.mess_dropout = eval(args.mess_dropout) model = NGCF(data_generator.n_users, data_generator.n_items, norm_adj, args).to(args.device) t0 = time() """ ********************************************************* Train. """ cur_best_pre_0, stopping_step = 0, 0 optimizer = optim.Adam(model.parameters(), lr=args.lr) for epoch in range(args.epoch): t1 = time() loss, mf_loss, emb_loss = 0., 0., 0. n_batch = data_generator.n_train // args.batch_size + 1