def train_mfips(sess: tf.Session, model: MFIPS, data: str, train: np.ndarray, val: np.ndarray, test: np.ndarray, max_iters: int = 500, batch_size: int = 2**9, model_name: str = 'mf', seed: int = 0) -> Tuple: """Train and evaluate the MF-IPS model.""" train_loss_list = [] val_loss_list = [] test_mse_list = [] test_mae_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # count the num of training data and estimate the propensity scores. num_train = train.shape[0] train_mcar, test = train_test_split(test, test_size=0.95, random_state=12345) pscore_train, pscore_val = estimate_pscore(train=train, train_mcar=train_mcar, val=val, model_name=model_name) labels_train = np.expand_dims(train[:, 2], 1) labels_val = np.expand_dims(val[:, 2], 1) labels_test = np.expand_dims(test[:, 2], 1) # start running training a recommender np.random.seed(12345) for iter_ in np.arange(max_iters): # mini-batch sampling idx = np.random.choice(np.arange(num_train), size=batch_size) train_batch, pscore_batch, labels_batch = train[idx], pscore_train[idx], labels_train[idx] # update user-item latent factors _, loss = sess.run([model.apply_grads, model.loss], feed_dict={model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: labels_batch, model.scores: pscore_batch}) train_loss_list.append(loss) # calculate validation loss val_loss = sess.run(model.weighted_mse, feed_dict={model.users: val[:, 0], model.items: val[:, 1], model.labels: labels_val, model.scores: pscore_val}) val_loss_list.append(val_loss) # calculate test loss mse_score, mae_score = sess.run([model.mse, model.mae], feed_dict={model.users: test[:, 0], model.items: test[:, 1], model.labels: labels_test}) test_mse_list.append(mse_score) test_mae_list.append(mae_score) u_emb, i_emb, i_bias = sess.run([model.user_embeddings, model.item_embeddings, model.item_bias]) sess.close() return (np.min(val_loss_list), test_mse_list[np.argmin(val_loss_list)], test_mae_list[np.argmin(val_loss_list)], u_emb, i_emb, i_bias)
class ModelClass(object): '''Properties and behaviour that different embedding models share.''' def fit(self, head, tail, label, score): '''Trains the model on a batch of weighted statements.''' feed = { self.batch_h: head, self.batch_t: tail, self.batch_l: label, self.batch_y: score } return self.__session.run([self.__training, self.__loss], feed)[1] def predict(self, head, tail, label): '''Evaluates the model's scores on a batch of statements.''' from numpy import arange, full # transform wildcard parameters # require otherwise scalar parameters E, R = self.base if head is None: if tail is None: if label is None: raise NotImplementedError('universal prediction') raise NotImplementedError('full-relation prediction') elif label is None: raise NotImplementedError('full-tail prediction') head, tail, label = arange(E), full([E], tail), full([E], label) elif tail is None: if label is None: raise NotImplementedError('full-head prediction') head, tail, label = full([E], head), arange(E), full([E], label) elif label is None: head, tail, label = full([R], head), full([R], tail), arange(R) # perform prediction feed = { self.predict_h: head, self.predict_t: tail, self.predict_l: label } return self.__session.run(self.__prediction, feed) def relation(self, label=None): '''Embeds a batch of predicates.''' if head is None: with self.__graph.as_default(): with self.__session.as_default(): return self.__session.run(self._rel_embeddings) feed = {self.predict_l: label} return self.__session.run(self._relation, feed) def entity(self, head=None): '''Embeds a batch of subjects.''' if head is None: with self.__session.as_default(): return self.__session.run(self._ent_embeddings) feed = {self.predict_h: head} return self.__session.run(self._entity, feed) def save(self, fileprefix): '''Writes the model's state into persistent memory.''' self.__saver.save(self.__session, fileprefix) def restore(self, fileprefix): '''Reads a model from persistent memory.''' self.__saver.restore(self.__session, fileprefix) def __iter__(self): '''Iterates all parameter fields of the model.''' return iter(self.__parameters) def __getitem__(self, key): '''Retrieves the values of a parameter field.''' return self.__session.run(self.__parameters[key]) def __setitem__(self, key, value): '''Updates the values of a parameter field.''' with self.__graph.as_default(): with self.__session.as_default(): self.__parameters[key].assign(value).eval() def embedding_def(self): pass def loss_def(self): raise NotImplementedError('loss impossible without model') def predict_def(self): raise NotImplementedError('prediction impossible without model') def __init__(self, baseshape, batchshape=None, optimizer=None, norm=None): '''Creates a new model. baseshape A pair of numbers describing the amount of entities and relations. batchshape A pair of numbers describing the amount of training statements per iteration and the amount of variants per statement. The first variant is considered true while the rest is considered false. default: Model not intended for training optimizer The optimization algorithm used to approximate the optimal model in each iteration. default: Stochastic Gradient Descent with learning factor of 1%. norm The used vector norm to compute a scalar score from the model's prediction. default: L1 norm (sum of absolute features).''' from tensorflow import name_scope, transpose, reshape, placeholder, int64, float32, Session, Graph, global_variables_initializer, variable_scope, nn, AUTO_REUSE from tensorflow.contrib.layers import xavier_initializer from tensorflow.python.training.saver import Saver self.base = baseshape if batchshape is None: batchshape = 0, 0 self.batchsize = batchshape[0] self.negatives = batchshape[1] - 1 self.__parameters = dict() if optimizer is None: import tensorflow optimizer = tensorflow.train.GradientDescentOptimizer(.01) if norm is None: from .norm import l1 norm = l1 self._norm = norm B, N = self.batchsize, self.negatives S = B * (N + 1) self.__graph = Graph() with self.__graph.as_default(): self.__session = Session() with self.__session.as_default(): initializer = xavier_initializer(uniform=True) with variable_scope('model', reuse=AUTO_REUSE, initializer=initializer): with name_scope('input'): self.batch_h = placeholder(int64, [S]) self.batch_t = placeholder(int64, [S]) self.batch_l = placeholder(int64, [S]) self.batch_y = placeholder(float32, [S]) self.all_h = transpose( reshape(self.batch_h, [1 + N, -1]), [1, 0]) self.all_t = transpose( reshape(self.batch_t, [1 + N, -1]), [1, 0]) self.all_l = transpose( reshape(self.batch_l, [1 + N, -1]), [1, 0]) self.all_y = transpose( reshape(self.batch_y, [1 + N, -1]), [1, 0]) self.postive_h = transpose( reshape(self.batch_h[:B], [1, -1]), [1, 0]) self.postive_t = transpose( reshape(self.batch_t[:B], [1, -1]), [1, 0]) self.postive_l = transpose( reshape(self.batch_l[:B], [1, -1]), [1, 0]) self.negative_h = transpose( reshape(self.batch_h[B:], [N, -1]), [1, 0]) self.negative_t = transpose( reshape(self.batch_t[B:], [N, -1]), [1, 0]) self.negative_l = transpose( reshape(self.batch_l[B:], [N, -1]), [1, 0]) self.predict_h = placeholder(int64, [None]) self.predict_t = placeholder(int64, [None]) self.predict_l = placeholder(int64, [None]) with name_scope('embedding'): for k, v in self._embedding_def(): self.__parameters[k] = v with name_scope('loss'): self.__loss = self._loss_def() with name_scope('predict'): self.__prediction = self._predict_def() grads_and_vars = optimizer.compute_gradients(self.__loss) self.__training = optimizer.apply_gradients(grads_and_vars) self.__saver = Saver() self.__session.run(global_variables_initializer()) def _positive_instance(self, in_batch=True): if in_batch: return self.postive_h, self.postive_t, self.postive_l B = self.batchsize return self.batch_h[:B], self.batch_t[:B], self.batch_l[:B] def _negative_instance(self, in_batch=True): if in_batch: return self.negative_h, self.negative_t, self.negative_l B = self.batchsize return self.batch_h[B:], self.batch_t[B:], self.batch_l[B:] def _all_instance(self, in_batch=False): if in_batch: return self.all_h, self.all_t, self.all_l return self.batch_h, self.batch_t, self.batch_l def _all_labels(self, in_batch=False): if in_batch: return self.all_y return self.batch_y def _predict_instance(self): return [self.predict_h, self.predict_t, self.predict_l] def __del__(self): self.__session.close()
def pairwise_trainer(sess: tf.Session, data: str, model: PairwiseRecommender, train: np.ndarray, train_point: np.ndarray, test_point: np.ndarray, max_iters: int = 1000, batch_size: int = 2**12, model_name: str = 'bpr') -> None: """Train and evaluate implicit pairwise recommenders.""" train_loss_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # count the num of training data. num_train = train.shape[0] # train the given implicit recommender np.random.seed(12345) for i in np.arange(max_iters): # mini-batch samples idx = np.random.choice(np.arange(num_train, dtype=int), size=np.int(batch_size)) train_batch = train[idx] # update user-item latent factors if model_name in 'bpr': scores = np.ones((batch_size, 1)) labels2 = np.zeros((batch_size, 1)) _, loss = sess.run( [model.apply_grads, model.loss], feed_dict={ model.users: train_batch[:, 0], model.pos_items: train_batch[:, 1], model.scores1: scores, model.items2: train_batch[:, 2], model.labels2: labels2, model.scores2: scores }) elif 'ubpr' in model_name: _, loss = sess.run( [model.apply_grads, model.loss], feed_dict={ model.users: train_batch[:, 0], model.pos_items: train_batch[:, 1], model.scores1: np.expand_dims(train_batch[:, 4], 1), model.items2: train_batch[:, 2], model.labels2: np.expand_dims(train_batch[:, 3], 1), model.scores2: np.expand_dims(train_batch[:, 5], 1) }) train_loss_list.append(loss) # save embeddings. u_emb, i_emb = sess.run([model.user_embeddings, model.item_embeddings]) np.save(file=f'../logs/{model_name}/embeds/user_embed.npy', arr=u_emb) np.save(file=f'../logs/{model_name}/embeds/item_embed.npy', arr=i_emb) # save train and val loss curves. np.save(file=f'../logs/{model_name}/loss/train.npy', arr=np.array(train_loss_list)) sess.close()
def pointwise_trainer(sess: tf.Session, data: str, model: PointwiseRecommender, train: np.ndarray, test: np.ndarray, propensity: np.ndarray, max_iters: int = 1000, batch_size: int = 2**12, model_name: str = 'relmf') -> None: """Train and evaluate implicit pointwise recommender.""" train_loss_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # propensity for train propensity = propensity[train[:, 1].astype(np.int)] # positive and unlabeled data for training set pos_train = train[train[:, 2] == 1] prop_pos_train = propensity[train[:, 2] == 1] num_pos = np.sum(train[:, 2]) unlabeled_train = train[train[:, 2] == 0] prop_unlabeled_train = propensity[train[:, 2] == 0] num_unlabeled = np.sum(1 - train[:, 2]) # train the given implicit recommender np.random.seed(12345) for i in np.arange(max_iters): # positive mini-batch sampling # the same num. of postive and negative samples are used in each batch # for the pointwise training pos_idx = np.random.choice(np.arange(num_pos, dtype=int), size=np.int(batch_size / 2)) unlabeled_idx = np.random.choice(np.arange(num_unlabeled, dtype=int), size=np.int(batch_size / 2)) # mini-batch samples train_batch = np.r_[pos_train[pos_idx], unlabeled_train[unlabeled_idx]] train_label = train_batch[:, 2] # define propensity score prop_ = np.r_[prop_pos_train[pos_idx], prop_unlabeled_train[unlabeled_idx]] train_score = np.expand_dims(prop_, 1) # update user-item latent factors and calculate training loss _, loss = sess.run( [model.apply_grads, model.weighted_mse], feed_dict={ model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: np.expand_dims(train_label, 1), model.scores: train_score }) train_loss_list.append(loss) # save embeddings. u_emb, i_emb = sess.run([model.user_embeddings, model.item_embeddings]) np.save(file=f'../logs/{model_name}/embeds/user_embed.npy', arr=u_emb) np.save(file=f'../logs/{model_name}/embeds/item_embed.npy', arr=i_emb) # save train and val loss curves. np.save(file=f'../logs/{model_name}/loss/train.npy', arr=np.array(train_loss_list)) sess.close()
blocksize] #.astype(precision) t = time() noisy[0, :-blocksize, 0] = noisy[0, blocksize:, 0] noisy[0, -blocksize:, 0] = data clean = G_loaded.predict(noisy) data = overlap * ( cleanb + clean[0, buffer_blocksize - blocksize:buffer_blocksize, 0]) cleanb = clean[0, buffer_blocksize:, 0] t_total1 += time() - t mean_time = t_total1 / ie t_total += mean_time mean_time = 1000 * t_total / args.iterations print('Average processing time: %f ms' % mean_time) if save_flag: f = open('processing_times_' + frontend + '.txt', 'a') f.write('Buffersize = ' + str(buffersize) + '\n') f.write('Overlap = ' + str(overlap) + '\n') f.write(str(mean_time) + '\n') f.close() if frontend == 'tensorflow': sess.close() tf.reset_default_graph() else: clear_session() command = 'killall jackd' check_call(command.split())
def _close_session(self, session: tf.Session): session.probe_stream.close() session.close()
def train_mfips_with_at(sess: tf.Session, model: MFIPS, mfips1: MFIPS, mfips2: MFIPS, data: str, train: np.ndarray, val: np.ndarray, test: np.ndarray, epsilon: float, pre_iters: int = 500, post_iters: int = 50, post_steps: int = 5, batch_size: int = 2**9, model_name: str = 'naive-at', seed: int = 0) -> Tuple: """Train and evaluate the MF-IPS model with asymmetric tri-training.""" train_loss_list = [] val_loss_list = [] test_mse_list = [] test_mae_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # count the num of training data and estimate the propensity scores. num_train = train.shape[0] train_mcar, test = train_test_split(test, test_size=0.95, random_state=12345) pscore_train, pscore_val = estimate_pscore(train=train, train_mcar=train_mcar, val=val, model_name=model_name) labels_train = np.expand_dims(train[:, 2], 1) labels_val = np.expand_dims(val[:, 2], 1) labels_test = np.expand_dims(test[:, 2], 1) pscore_model = np.ones((batch_size, 1)) # start training a recommender np.random.seed(12345) # start pre-training step for i in np.arange(pre_iters): # mini-batch sampling idx = np.random.choice(np.arange(num_train), size=batch_size) idx1 = np.random.choice(np.arange(num_train), size=batch_size) idx2 = np.random.choice(np.arange(num_train), size=batch_size) train_batch, train_batch1, train_batch2 = train[idx], train[idx1], train[idx2] labels_batch, labels_batch1, labels_batch2 = labels_train[idx], labels_train[idx1], labels_train[idx2] pscore_batch1, pscore_batch2 = pscore_train[idx1], pscore_train[idx2] # update user-item latent factors _, train_loss = sess.run([model.apply_grads, model.loss], feed_dict={model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: labels_batch, model.scores: pscore_model}) _ = sess.run(mfips1.apply_grads, feed_dict={mfips1.users: train_batch1[:, 0], mfips1.items: train_batch1[:, 1], mfips1.labels: labels_batch1, mfips1.scores: pscore_batch1}) _ = sess.run(mfips2.apply_grads, feed_dict={mfips2.users: train_batch2[:, 0], mfips2.items: train_batch2[:, 1], mfips2.labels: labels_batch2, mfips2.scores: pscore_batch2}) # start psuedo-labeling and final prediction steps all_data = pd.DataFrame(np.zeros((train[:, 0].max() + 1, train[:, 1].max() + 1))) all_data = all_data.stack().reset_index().values[:, :2] for k in np.arange(post_iters): for j in np.arange(post_steps): idx = np.random.choice(np.arange(all_data.shape[0]), size=num_train * 5) batch_data = all_data[idx] # create psuedo-labeled dataset (i.e., \tilde{\mathcal{D}}) preds1, preds2 = sess.run([mfips1.preds, mfips2.preds], feed_dict={mfips1.users: batch_data[:, 0], mfips1.items: batch_data[:, 1], mfips2.users: batch_data[:, 0], mfips2.items: batch_data[:, 1]}) idx = np.array(np.abs(preds1 - preds2) <= epsilon).flatten() target_users, target_items, pseudo_labels = batch_data[idx, 0], batch_data[idx, 1], preds1[idx] target_data = np.c_[target_users, target_items, pseudo_labels] # store information during the pseudo-labeleing step num_target = target_data.shape[0] # mini-batch sampling for the pseudo-labeleing step idx = np.random.choice(np.arange(num_target), size=batch_size) idx1 = np.random.choice(np.arange(num_target), size=batch_size) idx2 = np.random.choice(np.arange(num_target), size=batch_size) train_batch, train_batch1, train_batch2 = target_data[idx], target_data[idx1], target_data[idx2] # update user-item latent factors of the final prediction model _, train_loss = sess.run([model.apply_grads, model.mse], feed_dict={model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: np.expand_dims(train_batch[:, 2], 1), model.scores: np.ones((np.int(batch_size), 1))}) # calculate validation loss during the psuedo-labeleing step val_loss = sess.run(model.weighted_mse, feed_dict={model.users: val[:, 0], model.items: val[:, 1], model.scores: pscore_val, model.labels: labels_val}) # calculate test losses during the psuedo-labeleing step mse_score, mae_score = sess.run([model.mse, model.mae], feed_dict={model.users: test[:, 0], model.items: test[:, 1], model.labels: labels_test}) train_loss_list.append(train_loss) val_loss_list.append(val_loss) test_mse_list.append(mse_score) test_mae_list.append(mae_score) # re-update the model parameters of pre-trained models using pseudo-labeled data _ = sess.run(mfips1.apply_grads, feed_dict={mfips1.users: train_batch1[:, 0], mfips1.items: train_batch1[:, 1], mfips1.labels: np.expand_dims(train_batch1[:, 2], 1), mfips1.scores: np.ones((batch_size, 1))}) _ = sess.run(mfips2.apply_grads, feed_dict={mfips2.users: train_batch2[:, 0], mfips2.items: train_batch2[:, 1], mfips2.labels: np.expand_dims(train_batch2[:, 2], 1), mfips2.scores: np.ones((batch_size, 1))}) # obtain user-item embeddings u_emb, i_emb, i_bias = sess.run([model.user_embeddings, model.item_embeddings, model.item_bias]) sess.close() return (np.min(val_loss_list), test_mse_list[np.argmin(val_loss_list)], test_mae_list[np.argmin(val_loss_list)], u_emb, i_emb, i_bias)
def pointwise_trainer(sess: tf.Session, model: PointwiseRecommender, train: np.ndarray, test: np.ndarray, pscore: np.ndarray, max_iters: int = 1000, batch_size: int = 2**12, model_name: str = 'rmf') -> None: """Train and Evaluate Implicit Recommender.""" train_loss_list = [] test_dcg_list = [] test_map_list = [] test_recall_list = [] embed_path = Path(f'../logs/{model_name}/embeds/') embed_path.mkdir(parents=True, exist_ok=True) loss_path = Path(f'../logs/{model_name}/loss/') loss_path.mkdir(parents=True, exist_ok=True) ret_path = Path(f'../logs/{model_name}/results/') ret_path.mkdir(parents=True, exist_ok=True) # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # specify model type ips = 'rmf' in model_name # all positive data pos_data = np.r_[train[train[:, 2] == 1], test[test[:, 2] == 1]] # pscore for train pscore = pscore[train[:, 1].astype(np.int)] # positive and unlabeled data for training set pos_train = train[train[:, 2] == 1] pscore_pos_train = pscore[train[:, 2] == 1] num_pos = np.sum(train[:, 2]) unlabeled_train = train[train[:, 2] == 0] pscore_unlabeled_train = pscore[train[:, 2] == 0] num_unlabeled = np.sum(1 - train[:, 2]) # train the given implicit recommender np.random.seed(12345) for i in np.arange(max_iters): # positive mini-batch sampling # the same num. of postive and negative samples are used in each batch pos_idx = np.random.choice(np.arange(num_pos), size=np.int(batch_size / 2)) unlabeled_idx = np.random.choice(np.arange(num_unlabeled), size=np.int(batch_size / 2)) # mini-batch samples train_batch = np.r_[pos_train[pos_idx], unlabeled_train[unlabeled_idx]] train_label = train_batch[:, 2] # define pscore score pscore_ = np.r_[pscore_pos_train[pos_idx], pscore_unlabeled_train[unlabeled_idx]] train_score = pscore_ if ips else np.ones(batch_size) # update user-item latent factors and calculate training loss _, loss = sess.run( [model.apply_grads, model.weighted_mse], feed_dict={ model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: np.expand_dims(train_label, 1), model.scores: np.expand_dims(train_score, 1) }) train_loss_list.append(loss) # calculate ranking metrics if i % 25 == 0: u_emb, i_emb = sess.run( [model.user_embeddings, model.item_embeddings]) np.save(file=str(embed_path / 'user_embed.npy'), arr=u_emb) np.save(file=str(embed_path / 'item_embed.npy'), arr=i_emb) evaluator = AverageOverAllEvaluator(test=test, pos_data=pos_data, model_name=model_name, save=True) evaluator.evaluate(k=[5], rare='all') ret = pd.read_csv(str(ret_path / 'aoa_all.csv'), index_col=0) test_dcg_list.append(ret.loc['DCG@5', model_name]) test_map_list.append(ret.loc['MAP@5', model_name]) test_recall_list.append(ret.loc['Recall@5', model_name]) # save embeddings. u_emb, i_emb = sess.run([model.user_embeddings, model.item_embeddings]) np.save(file=str(embed_path / 'user_embed.npy'), arr=u_emb) np.save(file=str(embed_path / 'item_embed.npy'), arr=i_emb) # save train and val loss curves. np.save(file=str(loss_path / 'train.npy'), arr=train_loss_list) np.save(file=str(loss_path / 'dcg.npy'), arr=test_dcg_list) np.save(file=str(loss_path / 'recall.npy'), arr=test_recall_list) np.save(file=str(loss_path / 'map.npy'), arr=test_map_list) # close the session. sess.close()
class TfModel(NonAtomicOp): def __init__(self, overlap=None, aggregate=None, tile_size=1024, *args, verbose=VERBOSE, **kwargs): super().__init__(overlap=overlap, aggregate=aggregate, tile_size=tile_size, *args, verbose=verbose, **kwargs) self.model = None def __call__(self, func): def wrapper(inputs, model: str, overlap=None, gpu=True, *args, **kwargs): # multi-input ops work with tuples of inputs model_dir = model model = Model(model_dir) overlap = self.overlap if overlap is None else overlap if overlap is None: overlap = model.padding if overlap is None: raise ValueError('Overlap must be defined for this operation.') if gpu is False or self.con.env.has_gpu: inputs, stat = pack_list(inputs) if model.is_tf1(): res = self._handle_tf1(model, model_dir, func, inputs, overlap, gpu, args, kwargs) elif model.is_tf2(): raise NotImplementedError('Tf2 not supported yet.') else: raise ValueError('Unknown framework') res = unpack_list(res, stat) else: res = None return res return wrapper def _handle_tf1(self, model, model_dir, func, inputs, overlap, gpu, args, kwargs): self._start_tf1(model.directory, gpu) kwargs.update({ "model": model_dir, "_session": self.session, "_input_tensor": model.inputs_str, "_output_tensor": model.outputs_str, "_preprocessing": model.preprocessing, }) res = self.con(callback=func, i_objects=inputs, overlap=overlap, args=args, kwargs=kwargs, aggregate=self.aggregate, tile_size=self.tile_size, gpu=gpu) if self.con.has_gpu: self._stop_tf1() return res def _start_tf1(self, checkpoint, gpu): try: from tensorflow import Session, saved_model, ConfigProto config = ConfigProto() config.gpu_options.allow_growth = True if gpu is False or self.con.has_gpu is False: config.gpu_options.visible_device_list = '' else: config.gpu_options.visible_device_list = str( self.con.local_gpu_rank) print( f"Node {self.con.node_rank} rank {self.con.rank_gpu} starts session with GPU-ID:", config.gpu_options.visible_device_list) except ModuleNotFoundError: raise ModuleNotFoundError('Could not import from TensorFlow 1.X') self.session = Session(config=config) saved_model.loader.load(self.session, ['serve'], checkpoint) def _stop_tf1(self): if self.session is not None: self.session.close() self.session = None
def train_pointwise(sess: tf.Session, model: PointwiseRecommender, data: str, train: np.ndarray, val: np.ndarray, test: np.ndarray, pscore: np.ndarray, max_iters: int = 1000, batch_size: int = 256, model_name: str = 'wmf', is_optuna: bool = False) -> Tuple: """Train and evaluate implicit recommender.""" train_loss_list = [] test_loss_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) ips = model_name == 'relmf' # pscore for train pscore = pscore[train[:, 1].astype(int)] # positive and unlabeled data for training set pos_train = train[train[:, 2] == 1] pscore_pos_train = pscore[train[:, 2] == 1] num_pos = np.sum(train[:, 2]) unlabeled_train = train[train[:, 2] == 0] pscore_unlabeled_train = pscore[train[:, 2] == 0] num_unlabeled = np.sum(1 - train[:, 2]) # train the given implicit recommender np.random.seed(12345) for i in np.arange(max_iters): # positive mini-batch sampling # the same num. of postive and negative samples are used in each batch sample_size = np.int(batch_size / 2) pos_idx = np.random.choice(np.arange(num_pos), size=sample_size) unl_idx = np.random.choice(np.arange(num_unlabeled), size=sample_size) # mini-batch samples train_batch = np.r_[pos_train[pos_idx], unlabeled_train[unl_idx]] pscore_ = np.r_[pscore_pos_train[pos_idx], pscore_unlabeled_train[unl_idx]] if ips else np.ones(batch_size) # update user-item latent factors and calculate training loss _, train_loss = sess.run([model.apply_grads, model.unbiased_loss], feed_dict={model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: np.expand_dims(train_batch[:, 2], 1), model.scores: np.expand_dims(pscore_, 1)}) train_loss_list.append(train_loss) # calculate a validation score unl_idx = np.random.choice(np.arange(num_unlabeled), size=val.shape[0]) val_batch = np.r_[val, unlabeled_train[unl_idx]] pscore_ = np.r_[pscore[val[:, 1].astype(int)], pscore_unlabeled_train[unl_idx]] val_loss = sess.run(model.unbiased_loss, feed_dict={model.users: val_batch[:, 0], model.items: val_batch[:, 1], model.labels: np.expand_dims(val_batch[:, 2], 1), model.scores: np.expand_dims(pscore_, 1)}) u_emb, i_emb = sess.run([model.user_embeddings, model.item_embeddings]) if ~is_optuna: path = Path(f'../logs/{data}/{model_name}') (path / 'loss').mkdir(parents=True, exist_ok=True) np.save(file=str(path / 'loss/train.npy'), arr=train_loss_list) np.save(file=str(path / 'loss/test.npy'), arr=test_loss_list) (path / 'emb').mkdir(parents=True, exist_ok=True) np.save(file=str(path / 'emb/user_embed.npy'), arr=u_emb) np.save(file=str(path / 'emb/item_embed.npy'), arr=i_emb) sess.close() return u_emb, i_emb, val_loss
def train_pairwise(sess: tf.Session, model: PairwiseRecommender, data: str, train: np.ndarray, val: np.ndarray, test: np.ndarray, max_iters: int = 1000, batch_size: int = 1024, model_name: str = 'bpr', is_optuna: bool = False) -> Tuple: """Train and evaluate pairwise recommenders.""" train_loss_list = [] test_loss_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # count the num of training data. num_train, num_val = train.shape[0], val.shape[0] np.random.seed(12345) for i in np.arange(max_iters): idx = np.random.choice(np.arange(num_train), size=batch_size) train_batch = train[idx] # update user-item latent factors if model_name in 'bpr': _, loss = sess.run([model.apply_grads, model.loss], feed_dict={model.users: train_batch[:, 0], model.pos_items: train_batch[:, 1], model.scores1: np.ones((batch_size, 1)), model.items2: train_batch[:, 2], model.labels2: np.zeros((batch_size, 1)), model.scores2: np.ones((batch_size, 1))}) elif 'ubpr' in model_name: _, loss = sess.run([model.apply_grads, model.loss], feed_dict={model.users: train_batch[:, 0], model.pos_items: train_batch[:, 1], model.scores1: np.expand_dims(train_batch[:, 4], 1), model.items2: train_batch[:, 2], model.labels2: np.expand_dims(train_batch[:, 3], 1), model.scores2: np.expand_dims(train_batch[:, 5], 1)}) train_loss_list.append(loss) # calculate a test loss test_loss = sess.run(model.ideal_loss, feed_dict={model.users: test[:, 0], model.pos_items: test[:, 1], model.rel1: np.expand_dims(test[:, 3], 1), model.items2: test[:, 2], model.rel2: np.expand_dims(test[:, 4], 1)}) test_loss_list.append(test_loss) # calculate a validation loss if model_name in 'bpr': val_loss = sess.run(model.unbiased_loss, feed_dict={model.users: val[:, 0], model.pos_items: val[:, 1], model.scores1: np.ones((num_val, 1)), model.items2: val[:, 2], model.labels2: np.zeros((num_val, 1)), model.scores2: np.ones((num_val, 1))}) elif 'ubpr' in model_name: val_loss = sess.run(model.unbiased_loss, feed_dict={model.users: val[:, 0], model.pos_items: val[:, 1], model.scores1: np.expand_dims(val[:, 4], 1), model.items2: val[:, 2], model.labels2: np.expand_dims(val[:, 3], 1), model.scores2: np.expand_dims(val[:, 5], 1)}) u_emb, i_emb = sess.run([model.user_embeddings, model.item_embeddings]) if ~is_optuna: path = Path(f'../logs/{data}/{model_name}') (path / 'loss').mkdir(parents=True, exist_ok=True) np.save(file=str(path / 'loss/train.npy'), arr=train_loss_list) np.save(file=str(path / 'loss/test.npy'), arr=test_loss_list) (path / 'emb').mkdir(parents=True, exist_ok=True) np.save(file=str(path / 'emb/user_embed.npy'), arr=u_emb) np.save(file=str(path / 'emb/item_embed.npy'), arr=i_emb) sess.close() return u_emb, i_emb, val_loss
def pointwise_trainer(sess: tf.Session, data: str, model: PointwiseRecommender, train: np.ndarray, val: np.ndarray, test: np.ndarray, num_users, num_items, pscore: np.ndarray, inv_pscore: np.ndarray, item_freq: np.ndarray, max_iters: int = 1000, batch_size: int = 2**12, model_name: str = 'rel-mf', date_now: str = '1'): """Train and Evaluate Implicit Recommender.""" train_loss_list = [] test_dcg_list = [] test_map_list = [] test_recall_list = [] # initialise all the TF variables init_op = tf.global_variables_initializer() sess.run(init_op) # pscore for train pscore = pscore[train[:, 1].astype(np.int)] # train the given implicit recommender max_score = 0 er_stop_count = 0 best_u_emb = [] best_i_emb = [] all_tr = np.arange(len(train)) batch_size = batch_size early_stop = 5 for i in np.arange(max_iters): np.random.RandomState(12345).shuffle(all_tr) batch_num = int(len(all_tr) / batch_size) + 1 for b in range(batch_num): # mini-batch samples train_batch = train[all_tr[b * batch_size:(b + 1) * batch_size]] train_label = train_batch[:, 2] train_score = pscore[all_tr[b * batch_size:(b + 1) * batch_size]] train_inv_score = inv_pscore[train_batch[:, 1]] # update user-item latent factors and calculate training loss _, loss = sess.run( [model.apply_grads, model.mse], feed_dict={ model.users: train_batch[:, 0], model.items: train_batch[:, 1], model.labels: np.expand_dims(train_label, 1), model.scores: np.expand_dims(train_score, 1), model.inv_scores: np.expand_dims(train_inv_score, 1), # model.scores_normalization: np.expand_dims(train_score, 1), ################ # model.inv_scores_normalization: np.expand_dims(train_inv_score, 1) ################ }) ############### evaluation if i % 1 == 0: print(i, ": ", loss) u_emb, i_emb = sess.run( [model.user_embeddings, model.item_embeddings]) # validation at_k = 3 # We need an unbiased evaluation for validating val_ret = unbiased_evaluator(user_embed=u_emb, item_embed=i_emb, train=train, val=val, test=val, num_users=num_users, num_items=num_items, pscore=item_freq, model_name=model_name, at_k=[at_k], flag_test=False, flag_unbiased=True) dim = u_emb.shape[1] best_score = val_ret.loc[f'MAP@{at_k}', f'{model_name}_{dim}'] if max_score < best_score: max_score = best_score print(f"best_val_MAP@{at_k}: ", max_score) er_stop_count = 0 best_u_emb = u_emb best_i_emb = i_emb else: er_stop_count += 1 if er_stop_count > early_stop: print("stopped!") break sess.close() return best_u_emb, best_i_emb