def attack(attacker, attacker_name, model, features, support, y, mask, placeholders, sess, **kw): mask_split = [] results = [] cost, acc = 0, 0 for i in range(len(mask)): if mask[i] == True: mask_tmp = mask.copy() mask_tmp[:i] = False mask_tmp[i + 1:] = False mask_tmp[i] = True mask_split.append(mask_tmp) results.append([]) if attacker_name.lower() == 'fgsm': assert ('epsilon' in kw) for i in tqdm(range(len(mask_split))): results[i].append( fgsm(model=model, feed_dict=construct_feed_dict(features, support, y, mask_split[i], placeholders), features=features, sess=sess, epsilon=kw['epsilon'])) cost_tmp, acc_tmp, _ = evaluate(results[i][-1], support, y, mask_split[i], placeholders) cost += cost_tmp acc += acc_tmp elif attacker_name.lower() == 'flip_single': assert ('n_flip' in kw) for i in tqdm(range(len(mask_split))): features_tmp = features.copy() for it in range(kw['n_flip']): features_tmp = flip_single(model=model, feed_dict=construct_feed_dict( features_tmp, support, y, mask_split[i], placeholders), features=features_tmp, sess=sess) results[i].append(features_tmp) cost_tmp, acc_tmp, _ = evaluate(results[i][-1], support, y, mask_split[i], placeholders) cost += cost_tmp acc += acc_tmp else: assert False return results, cost / len(mask_split), acc / len(mask_split)
def evaluate(sess, model, val_features_batches, val_support_batches, y_val_batches, val_mask_batches, val_data, placeholders): """evaluate GCN model.""" total_pred = [] total_lab = [] total_loss = 0 total_acc = 0 num_batches = len(val_features_batches) for i in range(num_batches): features_b = val_features_batches[i] support_b = val_support_batches[i] y_val_b = y_val_batches[i] val_mask_b = val_mask_batches[i] num_data_b = np.sum(val_mask_b) if num_data_b == 0: continue else: feed_dict = utils.construct_feed_dict(features_b, support_b, y_val_b, val_mask_b, placeholders) outs = sess.run([model.loss, model.accuracy, model.outputs], feed_dict=feed_dict) total_pred.append(outs[2][val_mask_b]) total_lab.append(y_val_b[val_mask_b]) total_loss += outs[0] * num_data_b total_acc += outs[1] * num_data_b total_pred = np.vstack(total_pred) total_lab = np.vstack(total_lab) loss = total_loss / len(val_data) acc = total_acc / len(val_data) micro, macro = utils.calc_f1(total_pred, total_lab, FLAGS.multilabel) return loss, acc, micro, macro
def evaluate(labels_mask, noise=0., dropout=0.): feed_dict_val = construct_feed_dict(features, support, labels, labels_mask, placeholders, noise, dropout) outs_val = sess.run([model.loss, model.accuracy], feed_dict=feed_dict_val) return outs_val[0], outs_val[1]
def run_model(session, params, adj, num_cv, features, y, mask, output_dir): """ """ # compute support matrices support, num_supports = utils.get_support_matrices(adj, params['support']) # construct placeholders & model placeholders = { 'support': [tf.sparse_placeholder(tf.float32, name='support_{}'.format(i)) for i in range(num_supports)], 'features': tf.placeholder(tf.float32, shape=features.shape, name='Features'), 'labels': tf.placeholder(tf.float32, shape=(None, y.shape[1]), name='Labels'), 'labels_mask': tf.placeholder(tf.int32, shape=mask.shape, name='LabelsMask'), 'dropout': tf.placeholder_with_default(0., shape=(), name='Dropout') } model = EMOGI(placeholders=placeholders, input_dim=features.shape[1], learning_rate=params['learningrate'], weight_decay=params['weight_decay'], num_hidden_layers=len(params['hidden_dims']), hidden_dims=params['hidden_dims'], pos_loss_multiplier=params['loss_mul'], logging=False ) # where the results go accs = [] losses = [] auprs = [] num_preds = [] k_sets = gcnPreprocessing.cross_validation_sets(y=y, mask=mask, folds=num_cv ) for cv_run in range(num_cv): # train model y_train, y_val, train_mask, val_mask = k_sets[cv_run] model = fit_model(model=model, sess=session, features=features, placeholders=placeholders, support=support, epochs=params['epochs'], dropout_rate=params['dropout'], y_train=y_train, train_mask=train_mask, y_val=y_val, val_mask=val_mask, output_dir=os.path.join(output_dir, 'cv_{}'.format(cv_run)) ) # Compute performance on validation set performance_ops = model.get_performance_metrics() sess.run(tf.local_variables_initializer()) d = utils.construct_feed_dict(features, support, y_val, val_mask, placeholders) val_performance = sess.run(performance_ops, feed_dict=d) predictions = sess.run(model.predict(), feed_dict=d) accs.append(val_performance[1]) losses.append(val_performance[0]) auprs.append(val_performance[2]) num_preds.append((predictions > 0.5).sum()) return accs, losses, num_preds, auprs
def main(args): # save_dir = args.save_dir log_dir = args.log_dir train_dir = args.data_dir if not os.path.exists(save_dir): os.makedirs(save_dir) if not os.path.exists(log_dir): os.makedirs(log_dir) adj, features, y_train, y_val, y_test, train_mask, val_mask, test_mask = utils.load_data( args.data_type) features = utils.preprocess_features(features) support = [utils.preprocess_adj(adj)] args.num_supports = 1 args.input_size, args.features_size = features[2][1], features[2] args.output_size = y_train.shape[1] config_proto = utils.get_config_proto() sess = tf.Session(config=config_proto) model = GCN(args, sess, name="gcn") summary_writer = tf.summary.FileWriter(log_dir) for epoch in range(1, args.nb_epoch + 1): epoch_start_time = time.time() feed_dict = utils.construct_feed_dict(model, features, support, y_train, train_mask) _, train_loss, train_acc, summaries = model.train(feed_dict) if epoch % args.summary_epoch == 0: summary_writer.add_summary(summaries, epoch) if epoch % args.print_epoch == 0: feed_dict_val = utils.construct_feed_dict(model, features, support, y_val, val_mask) val_loss, val_acc = model.evaluate(feed_dict_val) print "epoch %d, train_loss %f, train_acc %f, val_loss %f, val_acc %f, time %.5fs" % \ (epoch, train_loss, train_acc, val_loss, val_acc, time.time()-epoch_start_time) if args.anneal and epoch >= args.anneal_start: sess.run(model.lr_decay_op) model.saver.save(sess, os.path.join(save_dir, "model.ckpt")) print "Model stored...."
def evaluate(features, adjacency, labels, mask, placeholders): t_test = time.time() feed_dict_val = construct_feed_dict(features, adjacency, labels, mask, adjacency, placeholders) outs_val = sess.run([model.loss, model.accuracy, model.predict()], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test), outs_val[2]
def evaluate(features, support, labels, mask, placeholders): t_test = time.time() feed_dict_val = construct_feed_dict(features, support, labels, mask, placeholders) feed_dict_val.update( {placeholders['support'][i]: support[i] for i in range(len(support))}) outs_val = sess.run([model.attack_loss, model.accuracy], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test)
def evaluate(sess, model, features, support, labels, mask, placeholders): t_test = time.time() feed_dict_val = utils.construct_feed_dict(features, support, labels, mask, placeholders, sparse_inputs=False) outs_val = sess.run([model.loss, model.accuracy, model.y_pred], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], outs_val[2], (time.time() - t_test)
def single_cv_run(session, support, num_supports, features, y_train, y_test, train_mask, test_mask, node_names, feature_names, args, model_dir): hidden_dims = [int(x) for x in args['hidden_dims']] placeholders = { 'support': [ tf.sparse_placeholder(tf.float32, name='support_{}'.format(i)) for i in range(num_supports) ], 'features': tf.placeholder(tf.float32, shape=features.shape, name='Features'), 'labels': tf.placeholder(tf.float32, shape=(None, y_train.shape[1]), name='Labels'), 'labels_mask': tf.placeholder(tf.int32, shape=train_mask.shape, name='LabelsMask'), 'dropout': tf.placeholder_with_default(0., shape=(), name='Dropout') } # construct model (including computation graph) model = EMOGI(placeholders=placeholders, input_dim=features.shape[1], learning_rate=args['lr'], weight_decay=args['decay'], num_hidden_layers=len(hidden_dims), hidden_dims=hidden_dims, pos_loss_multiplier=args['loss_mul'], logging=True) # fit the model model = fit_model(model, session, features, placeholders, support, args['epochs'], args['dropout'], y_train, train_mask, y_test, test_mask, model_dir) # Compute performance on test set performance_ops = model.get_performance_metrics() session.run(tf.local_variables_initializer()) d = utils.construct_feed_dict(features, support, y_test, test_mask, placeholders) test_performance = session.run(performance_ops, feed_dict=d) print("Validataion/test set results:", "loss=", "{:.5f}".format(test_performance[0]), "accuracy=", "{:.5f}".format(test_performance[1]), "aupr=", "{:.5f}".format(test_performance[2]), "auroc=", "{:.5f}".format(test_performance[3])) # predict all nodes (result from algorithm) predictions = predict(session, model, features, support, y_test, test_mask, placeholders) gcnIO.save_predictions(model_dir, node_names, predictions) gcnIO.write_train_test_sets(model_dir, y_train, y_test, train_mask, test_mask) return test_performance
def evaluate(sess, model, features, support, labels, placeholders, mask, dropout=0., alfa=0, beta=1): feed_dict_val = construct_feed_dict(features, support, labels, mask, placeholders, dropout, alfa, beta) outs_val = sess.run([model.loss, model.accuracy], feed_dict=feed_dict_val) return outs_val[0], outs_val[1]
def evaluate(sess, model, val_features_batches, val_support_batches, y_val_batches, val_mask_batches, val_data, placeholders, clusters_adj): """evaluate GCN model.""" total_pred = [] total_lab = [] total_loss = 0 total_acc = 0 num_batches = len(val_features_batches) for batch_id in range(num_batches): features_b = val_features_batches[batch_id] support_b = val_support_batches[batch_id] y_val_b = y_val_batches[batch_id] val_mask_b = val_mask_batches[batch_id] num_data_b = np.sum(val_mask_b) if clusters_adj is not None: cluster_adj = clusters_adj[batch_id] if num_data_b == 0: continue else: feed_dict = utils.construct_feed_dict(features_b, support_b, y_val_b, val_mask_b, placeholders) outs = sess.run([model.loss, model.accuracy, model.outputs], feed_dict=feed_dict) total_pred.append(outs[2][val_mask_b]) total_lab.append(y_val_b[val_mask_b]) total_loss += outs[0] * num_data_b total_acc += outs[1] * num_data_b total_pred = np.vstack(total_pred) total_lab = np.vstack(total_lab) # import pdb; pdb.set_trace() sp.save_npz(f'cluster/clusters_adj', clusters_adj) np.save(f'cluster/cluster_y', total_lab) np.save(f'cluster/total_pred', total_pred) loss = total_loss / len(val_data) acc = total_acc / len(val_data) micro, macro = utils.calc_f1(total_pred, total_lab, FLAGS.multilabel) return loss, acc, micro, macro
train_support_t = sparse_to_tuple(train_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] # 使用二部图输入作为训练输出的idx以及损失函数的label # train_labels, train_u_indices, train_v_indices, u_dict, v_dict = get_original_labels() # Feed_dicts for validation and test set stay constant over different update steps train_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, train_support, train_support_t, train_labels, train_u_indices, train_v_indices, class_values, DO, train_u_features_side, train_v_features_side) # No dropout for validation and test runs val_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, val_support, val_support_t, val_labels, val_u_indices, val_v_indices, class_values, 0., val_u_features_side, val_v_features_side) # Collect all variables to be logged into summary merged_summary = tf.summary.merge_all() sess = tf.Session() sess.run(tf.global_variables_initializer())
def test_compatibility(args): args = namedtuple("Args", args.keys())(*args.values()) load_from = args.load_from config_file = load_from + '/results.json' log_file = load_from + '/log.json' with open(config_file) as f: config = json.load(f) with open(log_file) as f: log = json.load(f) # Dataloader DATASET = config['dataset'] if DATASET == 'polyvore': # load dataset dl = DataLoaderPolyvore() orig_train_features, adj_train, train_labels, train_r_indices, train_c_indices = dl.get_phase( 'train') full_train_adj = dl.train_adj orig_val_features, adj_val, val_labels, val_r_indices, val_c_indices = dl.get_phase( 'valid') orig_test_features, adj_test, test_labels, test_r_indices, test_c_indices = dl.get_phase( 'test') full_test_adj = dl.test_adj dl.setup_test_compatibility(resampled=args.resampled) elif DATASET == 'ssense': dl = DataLoaderFashionGen() orig_train_features, adj_train, train_labels, train_r_indices, train_c_indices = dl.get_phase( 'train') orig_val_features, adj_val, val_labels, val_r_indices, val_c_indices = dl.get_phase( 'valid') orig_test_features, adj_test, test_labels, test_r_indices, test_c_indices = dl.get_phase( 'test') adj_q, q_r_indices, q_c_indices, q_labels, q_ids, q_valid = dl.get_test_questions( ) full_train_adj = dl.train_adj full_test_adj = dl.test_adj dl.setup_test_compatibility(resampled=args.resampled) else: raise NotImplementedError( 'A data loader for dataset {} does not exist'.format(DATASET)) NUMCLASSES = 2 BN_AS_TRAIN = False ADJ_SELF_CONNECTIONS = True def norm_adj(adj_to_norm): return normalize_nonsym_adj(adj_to_norm) train_features, mean, std = dl.normalize_features(orig_train_features, get_moments=True) val_features = dl.normalize_features(orig_val_features, mean=mean, std=std) test_features = dl.normalize_features(orig_test_features, mean=mean, std=std) train_support = get_degree_supports(adj_train, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) val_support = get_degree_supports(adj_val, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) test_support = get_degree_supports(adj_test, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) for i in range(1, len(train_support)): train_support[i] = norm_adj(train_support[i]) val_support[i] = norm_adj(val_support[i]) test_support[i] = norm_adj(test_support[i]) num_support = len(train_support) placeholders = { 'row_indices': tf.compat.v1.placeholder(tf.int32, shape=(None, )), 'col_indices': tf.compat.v1.placeholder(tf.int32, shape=(None, )), 'dropout': tf.compat.v1.placeholder_with_default(0., shape=()), 'weight_decay': tf.compat.v1.placeholder_with_default(0., shape=()), 'is_train': tf.compat.v1.placeholder_with_default(True, shape=()), 'support': [ tf.compat.v1.sparse_placeholder(tf.float32, shape=(None, None)) for sup in range(num_support) ], 'node_features': tf.compat.v1.placeholder(tf.float32, shape=(None, None)), 'labels': tf.compat.v1.placeholder(tf.float32, shape=(None, )) } model = CompatibilityGAE(placeholders, input_dim=train_features.shape[1], num_classes=NUMCLASSES, num_support=num_support, hidden=config['hidden'], learning_rate=config['learning_rate'], logging=True, batch_norm=config['batch_norm']) # Construct feed dicts for train, val and test phases train_feed_dict = construct_feed_dict(placeholders, train_features, train_support, train_labels, train_r_indices, train_c_indices, config['dropout']) val_feed_dict = construct_feed_dict(placeholders, val_features, val_support, val_labels, val_r_indices, val_c_indices, 0., is_train=BN_AS_TRAIN) test_feed_dict = construct_feed_dict(placeholders, test_features, test_support, test_labels, test_r_indices, test_c_indices, 0., is_train=BN_AS_TRAIN) # Add ops to save and restore all the variables. saver = tf.compat.v1.train.Saver() def eval(): # use this as a control value, if the model is ok, the value will be the same as in log val_avg_loss, val_acc, conf, pred = sess.run( [model.loss, model.accuracy, model.confmat, model.predict()], feed_dict=val_feed_dict) print("val_loss=", "{:.5f}".format(val_avg_loss), "val_acc=", "{:.5f}".format(val_acc)) with tf.compat.v1.Session() as sess: saver.restore(sess, load_from + '/' + 'best_epoch.ckpt') count = 0 preds = [] labels = [] # evaluate the the model for accuracy prediction eval() prob_act = tf.nn.sigmoid K = args.k for outfit in dl.comp_outfits: before_item = time.time() items, score = outfit num_new = test_features.shape[0] new_adj = sp.csr_matrix((num_new, num_new)) # no connections if args.k > 0: # add edges to the adj matrix available_adj = dl.test_adj.copy() available_adj = available_adj.tolil() i = 0 for idx_from in items[:-1]: for idx_to in items[i + 1:]: # remove outfit edges, they won't be expanded available_adj[idx_to, idx_from] = 0 available_adj[idx_from, idx_to] = 0 i += 1 available_adj = available_adj.tocsr() available_adj.eliminate_zeros() if args.subset: # use only a subset (of size 3) of the outfit items = np.random.choice(items, 3) new_features = test_features # predict edges between the items query_r = [] query_c = [] i = 0 item_indexes = items for idx_from in item_indexes[:-1]: for idx_to in item_indexes[i + 1:]: query_r.append(idx_from) query_c.append(idx_to) i += 1 if args.k > 0: G = Graph(available_adj) nodes_to_expand = np.unique(items) for node in nodes_to_expand: edges = G.run_K_BFS(node, K) for edge in edges: u, v = edge new_adj[u, v] = 1 new_adj[v, u] = 1 query_r = np.array(query_r) query_c = np.array(query_c) new_adj = new_adj.tocsr() new_support = get_degree_supports( new_adj, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS, verbose=False) for i in range(1, len(new_support)): new_support[i] = norm_adj(new_support[i]) new_support = [sparse_to_tuple(sup) for sup in new_support] new_feed_dict = construct_feed_dict(placeholders, new_features, new_support, train_labels, query_r, query_c, 0., is_train=BN_AS_TRAIN) pred = sess.run(prob_act(model.outputs), feed_dict=new_feed_dict) predicted_score = pred.mean() print("[{}] Mean scores between outfit: {:.4f}, label: {}".format( count, predicted_score, score)) # TODO: remove this print print("Total Elapsed: {:.4f}".format(time.time() - before_item)) count += 1 preds.append(predicted_score) labels.append(score) preds = np.array(preds) labels = np.array(labels) AUC = compute_auc(preds, labels) # use this as a control value, if the model is ok, the value will be the same as in log eval() print('The AUC compat score is: {}'.format(AUC)) print('Best val score saved in log: {}'.format(config['best_val_score'])) print('Last val score saved in log: {}'.format(log['val']['acc'][-1])) print("mean positive prediction: {}".format( preds[labels.astype(bool)].mean())) print("mean negative prediction: {}".format(preds[np.logical_not( labels.astype(bool))].mean()))
def run(DATASET='douban', DATASEED=1234, random_seed=123, NB_EPOCH=200, DO=0, HIDDEN=[100, 75], FEATHIDDEN=64, LR=0.01, decay_rate=1.25, consecutive_threshold=5, FEATURES=False, SYM=True, TESTING=False, ACCUM='stackRGGCN', NUM_LAYERS=1, GCMC_INDICES=False): np.random.seed(random_seed) tf.set_random_seed(random_seed) SELFCONNECTIONS = False SPLITFROMFILE = True VERBOSE = False BASES = 2 WRITESUMMARY = False SUMMARIESDIR = 'logs/' if DATASET == 'ml_1m' or DATASET == 'ml_100k' or DATASET == 'douban': NUMCLASSES = 5 elif DATASET == 'ml_10m': NUMCLASSES = 10 print( '\n WARNING: this might run out of RAM, consider using train_minibatch.py for dataset %s' % DATASET) print( 'If you want to proceed with this option anyway, uncomment this.\n' ) sys.exit(1) elif DATASET == 'flixster': NUMCLASSES = 10 elif DATASET == 'yahoo_music': NUMCLASSES = 71 if ACCUM == 'sum': print( '\n WARNING: combining DATASET=%s with ACCUM=%s can cause memory issues due to large number of classes.' ) print( 'Consider using "--accum stack" as an option for this dataset.' ) print( 'If you want to proceed with this option anyway, uncomment this.\n' ) sys.exit(1) # Splitting dataset in training, validation and test set if DATASET == 'ml_1m' or DATASET == 'ml_10m': if FEATURES: datasplit_path = 'data/' + DATASET + '/withfeatures_split_seed' + str( DATASEED) + '.pickle' else: datasplit_path = 'data/' + DATASET + '/split_seed' + str( DATASEED) + '.pickle' elif FEATURES: datasplit_path = 'data/' + DATASET + '/withfeatures.pickle' else: datasplit_path = 'data/' + DATASET + '/nofeatures.pickle' if DATASET == 'flixster' or DATASET == 'douban' or DATASET == 'yahoo_music': u_features, v_features, adj_train, train_labels, train_u_indices, train_v_indices, \ val_labels, val_u_indices, val_v_indices, test_labels, \ test_u_indices, test_v_indices, class_values = load_data_monti(DATASET, TESTING) elif DATASET == 'ml_100k': print( "Using official MovieLens dataset split u1.base/u1.test with 20% validation set size..." ) u_features, v_features, adj_train, train_labels, train_u_indices, train_v_indices, \ val_labels, val_u_indices, val_v_indices, test_labels, \ test_u_indices, test_v_indices, class_values = load_official_trainvaltest_split(DATASET, TESTING) else: print("Using random dataset split ...") u_features, v_features, adj_train, train_labels, train_u_indices, train_v_indices, \ val_labels, val_u_indices, val_v_indices, test_labels, \ test_u_indices, test_v_indices, class_values = create_trainvaltest_split(DATASET, DATASEED, TESTING, datasplit_path, SPLITFROMFILE, VERBOSE) num_users, num_items = adj_train.shape num_side_features = 0 # feature loading if not FEATURES: u_features = sp.identity( num_users, format='csr') # features is just one-hot vector! v_features = sp.identity(num_items, format='csr') u_features, v_features = preprocess_user_item_features( u_features, v_features) elif FEATURES and u_features is not None and v_features is not None: # use features as side information and node_id's as node input features print("Normalizing feature vectors...") u_features_side = normalize_features(u_features) v_features_side = normalize_features(v_features) u_features_side, v_features_side = preprocess_user_item_features( u_features_side, v_features_side) u_features_side = np.array(u_features_side.todense(), dtype=np.float32) v_features_side = np.array(v_features_side.todense(), dtype=np.float32) num_side_features = u_features_side.shape[1] # node id's for node input features id_csr_v = sp.identity(num_items, format='csr') id_csr_u = sp.identity(num_users, format='csr') u_features, v_features = preprocess_user_item_features( id_csr_u, id_csr_v) else: raise ValueError( 'Features flag is set to true but no features are loaded from dataset ' + DATASET) # print("User features shape: " + str(u_features.shape)) # print("Item features shape: " + str(v_features.shape)) # print("adj_train shape: " + str(adj_train.shape)) # global normalization support = [] support_t = [] adj_train_int = sp.csr_matrix(adj_train, dtype=np.int32) for i in range(NUMCLASSES): # build individual binary rating matrices (supports) for each rating support_unnormalized = sp.csr_matrix(adj_train_int == i + 1, dtype=np.float32) if support_unnormalized.nnz == 0 and DATASET != 'yahoo_music': # yahoo music has dataset split with not all ratings types present in training set. # this produces empty adjacency matrices for these ratings. sys.exit( 'ERROR: normalized bipartite adjacency matrix has only zero entries!!!!!' ) support_unnormalized_transpose = support_unnormalized.T support.append(support_unnormalized) support_t.append(support_unnormalized_transpose) support = globally_normalize_bipartite_adjacency(support, symmetric=SYM) support_t = globally_normalize_bipartite_adjacency(support_t, symmetric=SYM) if SELFCONNECTIONS: support.append(sp.identity(u_features.shape[0], format='csr')) support_t.append(sp.identity(v_features.shape[0], format='csr')) num_support = len(support) support = sp.hstack(support, format='csr') support_t = sp.hstack(support_t, format='csr') # support and support_t become 3000x15000 (for douban with 3000 users/items and 5 ratings) # support is n_users x (n_items*n_ratings). support_t is n_items x (n_users*ratings) # NOTE: support is sparse matrix so the shape may not be as large as expected (?) # When is num_support ever not == num_rating_classes? # print('support shape: ' + str(support.shape)) # print('support_t shape: ' + str(support_t.shape)) if ACCUM == 'stack' or ACCUM == 'stackRGGCN': div = HIDDEN[0] // num_support if HIDDEN[0] % num_support != 0: print( """\nWARNING: HIDDEN[0] (=%d) of stack layer is adjusted to %d such that it can be evenly split in %d splits.\n""" % (HIDDEN[0], num_support * div, num_support)) HIDDEN[0] = num_support * div ################################################################################################################## """ support contains only training set ratings. index into support using user/item indices to create test set support. """ test_support = val_support = train_support = support test_support_t = val_support_t = train_support_t = support_t if GCMC_INDICES: # Collect all user and item nodes for test set test_u = list(set(test_u_indices)) test_v = list(set(test_v_indices)) test_support = support[np.array(test_u)] test_support_t = support_t[np.array(test_v)] # Collect all user and item nodes for validation set val_u = list(set(val_u_indices)) val_v = list(set(val_v_indices)) val_support = support[np.array(val_u)] val_support_t = support_t[np.array(val_v)] # Collect all user and item nodes for train set train_u = list(set(train_u_indices)) train_v = list(set(train_v_indices)) train_support = support[np.array(train_u)] train_support_t = support_t[np.array(train_v)] test_u_dict = {n: i for i, n in enumerate(test_u)} test_v_dict = {n: i for i, n in enumerate(test_v)} test_u_indices = np.array([test_u_dict[o] for o in test_u_indices]) test_v_indices = np.array([test_v_dict[o] for o in test_v_indices]) val_u_dict = {n: i for i, n in enumerate(val_u)} val_v_dict = {n: i for i, n in enumerate(val_v)} val_u_indices = np.array([val_u_dict[o] for o in val_u_indices]) val_v_indices = np.array([val_v_dict[o] for o in val_v_indices]) train_u_dict = {n: i for i, n in enumerate(train_u)} train_v_dict = {n: i for i, n in enumerate(train_v)} print('max train_u_indices: {}'.format(max(train_u_indices))) train_u_indices = np.array( [train_u_dict[o] for o in train_u_indices] ) ### HERE IS WHERE indices get changed to suit the new indexing into smaller set of users train_v_indices = np.array([train_v_dict[o] for o in train_v_indices]) print('max train_u_indices after: {}'.format(max(train_u_indices))) # print('train_support_shape: {}'.format(train_support.shape)) # if GCMC_INDICES, THIS IS NO LONGER (n_users, n_items*n_rating_types). but < n_users ################################################################################################################## # features as side info if FEATURES: test_u_features_side = u_features_side[np.array(test_u)] test_v_features_side = v_features_side[np.array(test_v)] val_u_features_side = u_features_side[np.array(val_u)] val_v_features_side = v_features_side[np.array(val_v)] train_u_features_side = u_features_side[np.array(train_u)] train_v_features_side = v_features_side[np.array(train_v)] else: test_u_features_side = None test_v_features_side = None val_u_features_side = None val_v_features_side = None train_u_features_side = None train_v_features_side = None placeholders = { 'u_features': tf.sparse_placeholder(tf.float32, shape=np.array(u_features.shape, dtype=np.int64)), 'v_features': tf.sparse_placeholder(tf.float32, shape=np.array(v_features.shape, dtype=np.int64)), 'u_features_nonzero': tf.placeholder(tf.int32, shape=()), 'v_features_nonzero': tf.placeholder(tf.int32, shape=()), 'labels': tf.placeholder(tf.int32, shape=(None, )), 'u_features_side': tf.placeholder(tf.float32, shape=(None, num_side_features)), 'v_features_side': tf.placeholder(tf.float32, shape=(None, num_side_features)), 'user_indices': tf.placeholder(tf.int32, shape=(None, )), 'item_indices': tf.placeholder(tf.int32, shape=(None, )), 'class_values': tf.placeholder(tf.float32, shape=class_values.shape), 'dropout': tf.placeholder_with_default(0., shape=()), 'weight_decay': tf.placeholder_with_default(0., shape=()), 'support': tf.sparse_placeholder(tf.float32, shape=(None, None)), 'support_t': tf.sparse_placeholder(tf.float32, shape=(None, None)), } ################################################################################################################## E_start, E_end = get_edges_matrices(adj_train) # E_start = sp.hstack(E_start, format='csr') # confirm if vstack is correct and not hstack # E_end = sp.hstack(E_end, format='csr') # placeholders['E_start'] = tf.sparse_placeholder(tf.float32, shape=(None, None, None)) # placeholders['E_end'] = tf.sparse_placeholder(tf.float32, shape=(None, None, None)) placeholders['E_start_list'] = [] placeholders['E_end_list'] = [] for i in range(num_support): placeholders['E_start_list'].append( tf.sparse_placeholder(tf.float32, shape=(None, None))) placeholders['E_end_list'].append( tf.sparse_placeholder(tf.float32, shape=(None, None))) # print('shape of E_end for first rating type: {}'.format(E_end[0].toarray().shape)) ################################################################################################################## # create model if FEATURES: model = RecommenderSideInfoGAE(placeholders, input_dim=u_features.shape[1], feat_hidden_dim=FEATHIDDEN, num_classes=NUMCLASSES, num_support=num_support, self_connections=SELFCONNECTIONS, num_basis_functions=BASES, hidden=HIDDEN, num_users=num_users, num_items=num_items, accum=ACCUM, learning_rate=LR, num_side_features=num_side_features, logging=True) else: model = RecommenderGAE(placeholders, input_dim=u_features.shape[1], num_classes=NUMCLASSES, num_support=num_support, self_connections=SELFCONNECTIONS, num_basis_functions=BASES, hidden=HIDDEN, num_users=num_users, num_items=num_items, accum=ACCUM, learning_rate=LR, num_layers=NUM_LAYERS, logging=True) # Convert sparse placeholders to tuples to construct feed_dict. sparse placeholders expect tuple of (indices, values, shape) test_support = sparse_to_tuple(test_support) test_support_t = sparse_to_tuple(test_support_t) val_support = sparse_to_tuple(val_support) val_support_t = sparse_to_tuple(val_support_t) train_support = sparse_to_tuple(train_support) train_support_t = sparse_to_tuple(train_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][ 1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] # setting E_start to be the same for train, val, and test. E_start already only contains train edges (from preprocessing script) train_E_start = [] train_E_end = [] # print('LENGTH OF E_START: {}'.format(len(E_start))) # print('NUM_SUPPORT: {}'.format(num_support)) for i in range(num_support): train_E_start.append(sparse_to_tuple(E_start[i])) train_E_end.append(sparse_to_tuple(E_end[i])) val_E_start = test_E_start = train_E_start val_E_end = test_E_end = train_E_end # Feed_dicts for validation and test set stay constant over different update steps train_feed_dict = construct_feed_dict( placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, train_support, train_support_t, train_labels, train_u_indices, train_v_indices, class_values, DO, train_u_features_side, train_v_features_side, train_E_start, train_E_end) # No dropout for validation and test runs. DO = dropout. input for val and test is same u_features and v_features. val_feed_dict = construct_feed_dict( placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, val_support, val_support_t, val_labels, val_u_indices, val_v_indices, class_values, 0., val_u_features_side, val_v_features_side, val_E_start, val_E_end) test_feed_dict = construct_feed_dict( placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, test_support, test_support_t, test_labels, test_u_indices, test_v_indices, class_values, 0., test_u_features_side, test_v_features_side, test_E_start, test_E_end) # Collect all variables to be logged into summary merged_summary = tf.summary.merge_all() sess = tf.Session() sess.run(tf.global_variables_initializer()) if WRITESUMMARY: train_summary_writer = tf.summary.FileWriter(SUMMARIESDIR + '/train', sess.graph) val_summary_writer = tf.summary.FileWriter(SUMMARIESDIR + '/val') else: train_summary_writer = None val_summary_writer = None best_val_score = np.inf best_val_loss = np.inf best_epoch = 0 wait = 0 print('Training...') #### COUTNING PARAMS total_parameters = 0 for variable in tf.trainable_variables(): # shape is an array of tf.Dimension shape = variable.get_shape() variable_parameters = 1 for dim in shape: variable_parameters *= dim.value total_parameters += variable_parameters print('Total params: {}'.format(total_parameters)) # FOR A VARIABLE LEARNING RATE assign_placeholder = tf.placeholder(tf.float32) assign_op = model.learning_rate.assign(assign_placeholder) old_loss = float('inf') # print('Original learning rate is {}'.format(sess.run(model.optimizer._lr))) train_rmses, val_rmses, train_losses, val_losses = [], [], [], [] for epoch in tqdm(range(NB_EPOCH)): t = time.time() # Run single weight update # outs = sess.run([model.opt_op, model.loss, model.rmse], feed_dict=train_feed_dict) # with exponential moving averages outs = sess.run([model.training_op, model.loss, model.rmse], feed_dict=train_feed_dict) train_avg_loss = outs[1] train_rmse = outs[2] val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) # if train_avg_loss > 0.999*old_loss: # consecutive += 1 # if consecutive >= consecutive_threshold: # LR /= decay_rate # sess.run(assign_op, feed_dict={assign_placeholder: LR}) # print('New learning rate is {}'.format(sess.run(model.optimizer._lr))) # consecutive = 0 # else: # consecutive = 0 # old_loss = train_avg_loss train_rmses.append(train_rmse) val_rmses.append(val_rmse) train_losses.append(train_avg_loss) val_losses.append(val_avg_loss) if VERBOSE: print("[*] Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(train_avg_loss), "train_rmse=", "{:.5f}".format(train_rmse), "val_loss=", "{:.5f}".format(val_avg_loss), "val_rmse=", "{:.5f}".format(val_rmse), "\t\ttime=", "{:.5f}".format(time.time() - t)) if val_rmse < best_val_score: best_val_score = val_rmse best_epoch = epoch if epoch % 20 == 0 and WRITESUMMARY: # Train set summary summary = sess.run(merged_summary, feed_dict=train_feed_dict) train_summary_writer.add_summary(summary, epoch) train_summary_writer.flush() # Validation set summary summary = sess.run(merged_summary, feed_dict=val_feed_dict) val_summary_writer.add_summary(summary, epoch) val_summary_writer.flush() if epoch % 100 == 0 and epoch > 1000 and not TESTING and False: saver = tf.train.Saver() save_path = saver.save(sess, "tmp/%s_seed%d.ckpt" % (model.name, DATASEED), global_step=model.global_step) # load polyak averages variables_to_restore = model.variable_averages.variables_to_restore( ) saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) print('polyak val loss = ', val_avg_loss) print('polyak val rmse = ', val_rmse) # Load back normal variables saver = tf.train.Saver() saver.restore(sess, save_path) # store model including exponential moving averages saver = tf.train.Saver() save_path = saver.save(sess, "tmp/%s.ckpt" % model.name, global_step=model.global_step) if VERBOSE: print("\nOptimization Finished!") print('best validation score =', best_val_score, 'at iteration', best_epoch) if TESTING: test_avg_loss, test_rmse = sess.run([model.loss, model.rmse], feed_dict=test_feed_dict) print('test loss = ', test_avg_loss) print('test rmse = ', test_rmse) # restore with polyak averages of parameters variables_to_restore = model.variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) test_avg_loss, test_rmse = sess.run([model.loss, model.rmse], feed_dict=test_feed_dict) print('polyak test loss = ', test_avg_loss) print('polyak test rmse = ', test_rmse) sess.close() tf.reset_default_graph() return train_rmses, val_rmses, train_losses, val_losses, test_rmse else: # restore with polyak averages of parameters variables_to_restore = model.variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) print('polyak val loss = ', val_avg_loss) print('polyak val rmse = ', val_rmse) sess.close() tf.reset_default_graph() return train_rmses, val_rmses, train_losses, val_losses, val_rmse
def run(user_features, movie_features, learning_rate=0.01, epochs=500, hidden=[500, 75], feat_hidden=64, accumulation='sum', dropout=0.7, num_basis_functions=2, features=False, symmetric=True, testing=True): """accumulation can be sum or stack""" # Set random seed # seed = 123 # use only for unit testing seed = int(time.time()) np.random.seed(seed) tf.set_random_seed(seed) tf.reset_default_graph() # Settings # ap = argparse.ArgumentParser() # # ap.add_argument("-d", "--dataset", type=str, default="ml_100k", # # choices=['ml_100k', 'ml_1m', 'ml_10m', 'douban', 'yahoo_music', 'flixster'], # # help="Dataset string.") # ap.add_argument("-lr", "--learning_rate", type=float, default=0.01, # help="Learning rate") # ap.add_argument("-e", "--epochs", type=int, default=2500, # help="Number training epochs") # ap.add_argument("-hi", "--hidden", type=int, nargs=2, default=[500, 75], # help="Number hidden units in 1st and 2nd layer") # ap.add_argument("-fhi", "--feat_hidden", type=int, default=64, # help="Number hidden units in the dense layer for features") # ap.add_argument("-ac", "--accumulation", type=str, default="sum", choices=['sum', 'stack'], # help="Accumulation function: sum or stack.") # ap.add_argument("-do", "--dropout", type=float, default=0.7, # help="Dropout fraction") # ap.add_argument("-nb", "--num_basis_functions", type=int, default=2, # help="Number of basis functions for Mixture Model GCN.") # ap.add_argument("-ds", "--data_seed", type=int, default=1234, # help="""Seed used to shuffle data in data_utils, taken from cf-nade (1234, 2341, 3412, 4123, 1324). # Only used for ml_1m and ml_10m datasets. """) # ap.add_argument("-sdir", "--summaries_dir", type=str, default='logs/' + str(datetime.datetime.now()).replace(' ', '_'), # help="Directory for saving tensorflow summaries.") # # Boolean flags # fp = ap.add_mutually_exclusive_group(required=False) # fp.add_argument('-nsym', '--norm_symmetric', dest='norm_symmetric', # help="Option to turn on symmetric global normalization", action='store_true') # fp.add_argument('-nleft', '--norm_left', dest='norm_symmetric', # help="Option to turn on left global normalization", action='store_false') # ap.set_defaults(norm_symmetric=True) # fp = ap.add_mutually_exclusive_group(required=False) # fp.add_argument('-f', '--features', dest='features', # help="Whether to use features (1) or not (0)", action='store_true') # fp.add_argument('-no_f', '--no_features', dest='features', # help="Whether to use features (1) or not (0)", action='store_false') # ap.set_defaults(features=False) # fp = ap.add_mutually_exclusive_group(required=False) # fp.add_argument('-ws', '--write_summary', dest='write_summary', # help="Option to turn on summary writing", action='store_true') # fp.add_argument('-no_ws', '--no_write_summary', dest='write_summary', # help="Option to turn off summary writing", action='store_false') # ap.set_defaults(write_summary=False) # fp = ap.add_mutually_exclusive_group(required=False) # fp.add_argument('-t', '--testing', dest='testing', # help="Option to turn on test set evaluation", action='store_true') # fp.add_argument('-v', '--validation', dest='testing', # help="Option to only use validation set evaluation", action='store_false') # ap.set_defaults(testing=False) # args = vars(ap.parse_args()) # print('Settings:') # print(args, '\n') # Define parameters DATASET = 'ml_100k' DATASEED = 1234 NB_EPOCH = epochs DO = dropout HIDDEN = hidden FEATHIDDEN = feat_hidden BASES = num_basis_functions LR = learning_rate WRITESUMMARY = False SUMMARIESDIR = 'logs/' + str(datetime.datetime.now()).replace(' ', '_') FEATURES = features SYM = symmetric TESTING = testing ACCUM = accumulation SELFCONNECTIONS = False SPLITFROMFILE = True VERBOSE = True NUMCLASSES = 5 # Splitting dataset in training, validation and test set print("Using official MovieLens dataset split u1.base/u1.test with 20% validation set size...") u_features = user_features v_features = movie_features _, _, adj_train, train_labels, train_u_indices, train_v_indices, \ val_labels, val_u_indices, val_v_indices, test_labels, \ test_u_indices, test_v_indices, class_values = load_official_trainvaltest_split('ml_100k', TESTING) num_users, num_items = adj_train.shape num_side_features = 0 # feature loading if not FEATURES: u_features = sp.identity(num_users, format='csr') v_features = sp.identity(num_items, format='csr') u_features, v_features = preprocess_user_item_features(u_features, v_features) elif FEATURES and u_features is not None and v_features is not None: # use features as side information and node_id's as node input features print("Normalizing feature vectors...") u_features_side = normalize_features(u_features) v_features_side = normalize_features(v_features) u_features_side, v_features_side = preprocess_user_item_features(u_features_side, v_features_side) u_features_side = np.array(u_features_side.todense(), dtype=np.float32) v_features_side = np.array(v_features_side.todense(), dtype=np.float32) num_side_features = u_features_side.shape[1] # node id's for node input features id_csr_v = sp.identity(num_items, format='csr') id_csr_u = sp.identity(num_users, format='csr') u_features, v_features = preprocess_user_item_features(id_csr_u, id_csr_v) else: raise ValueError('Features flag is set to true but no features are loaded from dataset ' + DATASET) # global normalization support = [] support_t = [] adj_train_int = sp.csr_matrix(adj_train, dtype=np.int32) for i in range(NUMCLASSES): # build individual binary rating matrices (supports) for each rating support_unnormalized = sp.csr_matrix(adj_train_int == i + 1, dtype=np.float32) if support_unnormalized.nnz == 0 and DATASET != 'yahoo_music': # yahoo music has dataset split with not all ratings types present in training set. # this produces empty adjacency matrices for these ratings. sys.exit('ERROR: normalized bipartite adjacency matrix has only zero entries!!!!!') support_unnormalized_transpose = support_unnormalized.T support.append(support_unnormalized) support_t.append(support_unnormalized_transpose) support = globally_normalize_bipartite_adjacency(support, symmetric=SYM) support_t = globally_normalize_bipartite_adjacency(support_t, symmetric=SYM) if SELFCONNECTIONS: support.append(sp.identity(u_features.shape[0], format='csr')) support_t.append(sp.identity(v_features.shape[0], format='csr')) num_support = len(support) support = sp.hstack(support, format='csr') support_t = sp.hstack(support_t, format='csr') if ACCUM == 'stack': div = HIDDEN[0] // num_support if HIDDEN[0] % num_support != 0: print("""\nWARNING: HIDDEN[0] (=%d) of stack layer is adjusted to %d such that it can be evenly split in %d splits.\n""" % (HIDDEN[0], num_support * div, num_support)) HIDDEN[0] = num_support * div # Collect all user and item nodes for test set test_u = list(set(test_u_indices)) test_v = list(set(test_v_indices)) test_u_dict = {n: i for i, n in enumerate(test_u)} test_v_dict = {n: i for i, n in enumerate(test_v)} test_u_indices = np.array([test_u_dict[o] for o in test_u_indices]) test_v_indices = np.array([test_v_dict[o] for o in test_v_indices]) test_support = support[np.array(test_u)] test_support_t = support_t[np.array(test_v)] # Collect all user and item nodes for validation set val_u = list(set(val_u_indices)) val_v = list(set(val_v_indices)) val_u_dict = {n: i for i, n in enumerate(val_u)} val_v_dict = {n: i for i, n in enumerate(val_v)} val_u_indices = np.array([val_u_dict[o] for o in val_u_indices]) val_v_indices = np.array([val_v_dict[o] for o in val_v_indices]) val_support = support[np.array(val_u)] val_support_t = support_t[np.array(val_v)] # Collect all user and item nodes for train set train_u = list(set(train_u_indices)) train_v = list(set(train_v_indices)) train_u_dict = {n: i for i, n in enumerate(train_u)} train_v_dict = {n: i for i, n in enumerate(train_v)} train_u_indices = np.array([train_u_dict[o] for o in train_u_indices]) train_v_indices = np.array([train_v_dict[o] for o in train_v_indices]) train_support = support[np.array(train_u)] train_support_t = support_t[np.array(train_v)] # features as side info if FEATURES: test_u_features_side = u_features_side[np.array(test_u)] test_v_features_side = v_features_side[np.array(test_v)] val_u_features_side = u_features_side[np.array(val_u)] val_v_features_side = v_features_side[np.array(val_v)] train_u_features_side = u_features_side[np.array(train_u)] train_v_features_side = v_features_side[np.array(train_v)] else: test_u_features_side = None test_v_features_side = None val_u_features_side = None val_v_features_side = None train_u_features_side = None train_v_features_side = None placeholders = { 'u_features': tf.sparse_placeholder(tf.float32, shape=np.array(u_features.shape, dtype=np.int64)), 'v_features': tf.sparse_placeholder(tf.float32, shape=np.array(v_features.shape, dtype=np.int64)), 'u_features_nonzero': tf.placeholder(tf.int32, shape=()), 'v_features_nonzero': tf.placeholder(tf.int32, shape=()), 'labels': tf.placeholder(tf.int32, shape=(None,)), 'u_features_side': tf.placeholder(tf.float32, shape=(None, num_side_features)), 'v_features_side': tf.placeholder(tf.float32, shape=(None, num_side_features)), 'user_indices': tf.placeholder(tf.int32, shape=(None,)), 'item_indices': tf.placeholder(tf.int32, shape=(None,)), 'class_values': tf.placeholder(tf.float32, shape=class_values.shape), 'dropout': tf.placeholder_with_default(0., shape=()), 'weight_decay': tf.placeholder_with_default(0., shape=()), 'support': tf.sparse_placeholder(tf.float32, shape=(None, None)), 'support_t': tf.sparse_placeholder(tf.float32, shape=(None, None)), } # create model if FEATURES: model = RecommenderSideInfoGAE(placeholders, input_dim=u_features.shape[1], feat_hidden_dim=FEATHIDDEN, num_classes=NUMCLASSES, num_support=num_support, self_connections=SELFCONNECTIONS, num_basis_functions=BASES, hidden=HIDDEN, num_users=num_users, num_items=num_items, accum=ACCUM, learning_rate=LR, num_side_features=num_side_features, logging=True) else: model = RecommenderGAE(placeholders, input_dim=u_features.shape[1], num_classes=NUMCLASSES, num_support=num_support, self_connections=SELFCONNECTIONS, num_basis_functions=BASES, hidden=HIDDEN, num_users=num_users, num_items=num_items, accum=ACCUM, learning_rate=LR, logging=True) # Convert sparse placeholders to tuples to construct feed_dict test_support = sparse_to_tuple(test_support) test_support_t = sparse_to_tuple(test_support_t) val_support = sparse_to_tuple(val_support) val_support_t = sparse_to_tuple(val_support_t) train_support = sparse_to_tuple(train_support) train_support_t = sparse_to_tuple(train_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] # Feed_dicts for validation and test set stay constant over different update steps train_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, train_support, train_support_t, train_labels, train_u_indices, train_v_indices, class_values, DO, train_u_features_side, train_v_features_side) # No dropout for validation and test runs val_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, val_support, val_support_t, val_labels, val_u_indices, val_v_indices, class_values, 0., val_u_features_side, val_v_features_side) test_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, test_support, test_support_t, test_labels, test_u_indices, test_v_indices, class_values, 0., test_u_features_side, test_v_features_side) # Collect all variables to be logged into summary merged_summary = tf.summary.merge_all() #sess = tf.Session() sess = tf.InteractiveSession() sess.run(tf.global_variables_initializer()) if WRITESUMMARY: train_summary_writer = tf.summary.FileWriter(SUMMARIESDIR + '/train', sess.graph) val_summary_writer = tf.summary.FileWriter(SUMMARIESDIR + '/val') else: train_summary_writer = None val_summary_writer = None best_val_score = np.inf best_val_loss = np.inf best_epoch = 0 wait = 0 print('Training...') train_loss_values = [] train_rmse_values = [] val_loss_values = [] val_rmse_values = [] list_embeddings = [] for epoch in range(NB_EPOCH): t = time.time() # Run single weight update # outs = sess.run([model.opt_op, model.loss, model.rmse], feed_dict=train_feed_dict) # with exponential moving averages outs = sess.run([model.training_op, model.loss, model.rmse], feed_dict=train_feed_dict) #print(len(model.embeddings)) train_avg_loss = outs[1] train_rmse = outs[2] val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) train_loss_values.append(train_avg_loss) train_rmse_values.append(train_rmse) val_loss_values.append(val_avg_loss) val_rmse_values.append(val_rmse) if VERBOSE: print("[*] Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(train_avg_loss), "train_rmse=", "{:.5f}".format(train_rmse), "val_loss=", "{:.5f}".format(val_avg_loss), "val_rmse=", "{:.5f}".format(val_rmse), "\t\ttime=", "{:.5f}".format(time.time() - t)) if epoch==NB_EPOCH - 1: embedding_users = model.embeddings[0].eval(feed_dict=train_feed_dict) embedding_movies = model.embeddings[1].eval(feed_dict=train_feed_dict) if val_rmse < best_val_score: best_val_score = val_rmse best_epoch = epoch if epoch % 20 == 0 and WRITESUMMARY: # Train set summary summary = sess.run(merged_summary, feed_dict=train_feed_dict) train_summary_writer.add_summary(summary, epoch) train_summary_writer.flush() # Validation set summary summary = sess.run(merged_summary, feed_dict=val_feed_dict) val_summary_writer.add_summary(summary, epoch) val_summary_writer.flush() if epoch % 100 == 0 and epoch > 1000 and not TESTING and False: saver = tf.train.Saver() save_path = saver.save(sess, "tmp/%s_seed%d.ckpt" % (model.name, DATASEED), global_step=model.global_step) # load polyak averages variables_to_restore = model.variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) print('polyak val loss = ', val_avg_loss) print('polyak val rmse = ', val_rmse) # Load back normal variables saver = tf.train.Saver() saver.restore(sess, save_path) # store model including exponential moving averages saver = tf.train.Saver() save_path = saver.save(sess, "tmp/%s.ckpt" % model.name, global_step=model.global_step) if VERBOSE: print("\nOptimization Finished!") print('best validation score =', best_val_score, 'at iteration', best_epoch+1) if TESTING: test_avg_loss, test_rmse = sess.run([model.loss, model.rmse], feed_dict=test_feed_dict) print('test loss = ', test_avg_loss) print('test rmse = ', test_rmse) # restore with polyak averages of parameters variables_to_restore = model.variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) test_avg_loss, test_rmse = sess.run([model.loss, model.rmse], feed_dict=test_feed_dict) print('polyak test loss = ', test_avg_loss) print('polyak test rmse = ', test_rmse) else: # restore with polyak averages of parameters variables_to_restore = model.variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) saver.restore(sess, save_path) val_avg_loss, val_rmse = sess.run([model.loss, model.rmse], feed_dict=val_feed_dict) print('polyak val loss = ', val_avg_loss) print('polyak val rmse = ', val_rmse) print('global seed = ', seed) sess.close() return embedding_users, embedding_movies, train_loss_values, train_rmse_values, val_loss_values, val_rmse_values
val_support_t = sparse_to_tuple(val_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][ 1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] # Feed_dicts for validation and test set stay constant over different update steps # No dropout for validation and test runs val_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, val_support, val_support_t, val_labels, val_u_indices, val_v_indices, class_values, 0.) test_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, test_support, test_support_t, test_labels, test_u_indices, test_v_indices, class_values, 0.) # Collect all variables to be logged into summary merged_summary = tf.summary.merge_all() sess = tf.Session() sess.run(tf.global_variables_initializer())
feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test), outs_val[2] # Init variables sess.run(tf.global_variables_initializer()) cost_val = [] # Train model for epoch in range(FLAGS.epochs): t = time.time() # Construct feed dictionary feed_dict = construct_feed_dict(features, support, y_train, train_mask, placeholders, train=True) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) # Validation cost, acc, duration, _ = evaluate(features, support, y_val, val_mask, placeholders) cost_val.append(cost) # Print results print("Epoch:", '%04d' % (epoch + 1), "train_loss=",
def test_fitb(args): args = namedtuple("Args", args.keys())(*args.values()) load_from = args.load_from config_file = load_from + '/results.json' log_file = load_from + '/log.json' with open(config_file) as f: config = json.load(f) with open(log_file) as f: log = json.load(f) DATASET = config['dataset'] NUMCLASSES = 2 BN_AS_TRAIN = False ADJ_SELF_CONNECTIONS = True def norm_adj(adj_to_norm): return normalize_nonsym_adj(adj_to_norm) # Dataloader if DATASET == 'fashiongen': dl = DataLoaderFashionGen() elif DATASET == 'polyvore': dl = DataLoaderPolyvore() train_features, adj_train, train_labels, train_r_indices, train_c_indices = dl.get_phase( 'train') val_features, adj_val, val_labels, val_r_indices, val_c_indices = dl.get_phase( 'valid') test_features, adj_test, test_labels, test_r_indices, test_c_indices = dl.get_phase( 'test') adj_q, q_r_indices, q_c_indices, q_labels, q_ids, q_valid = dl.get_test_questions( ) train_features, mean, std = dl.normalize_features(train_features, get_moments=True) val_features = dl.normalize_features(val_features, mean=mean, std=std) test_features = dl.normalize_features(test_features, mean=mean, std=std) train_support = get_degree_supports(adj_train, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) val_support = get_degree_supports(adj_val, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) test_support = get_degree_supports(adj_test, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) q_support = get_degree_supports(adj_q, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) for i in range(1, len(train_support)): train_support[i] = norm_adj(train_support[i]) val_support[i] = norm_adj(val_support[i]) test_support[i] = norm_adj(test_support[i]) q_support[i] = norm_adj(q_support[i]) num_support = len(train_support) placeholders = { 'row_indices': tf.placeholder(tf.int32, shape=(None, )), 'col_indices': tf.placeholder(tf.int32, shape=(None, )), 'dropout': tf.placeholder_with_default(0., shape=()), 'weight_decay': tf.placeholder_with_default(0., shape=()), 'is_train': tf.placeholder_with_default(True, shape=()), 'support': [ tf.sparse_placeholder(tf.float32, shape=(None, None)) for sup in range(num_support) ], 'node_features': tf.placeholder(tf.float32, shape=(None, None)), 'labels': tf.placeholder(tf.float32, shape=(None, )) } model = CompatibilityGAE(placeholders, input_dim=train_features.shape[1], num_classes=NUMCLASSES, num_support=num_support, hidden=config['hidden'], learning_rate=config['learning_rate'], logging=True, batch_norm=config['batch_norm']) # Construct feed dicts for train, val and test phases train_feed_dict = construct_feed_dict(placeholders, train_features, train_support, train_labels, train_r_indices, train_c_indices, config['dropout']) val_feed_dict = construct_feed_dict(placeholders, val_features, val_support, val_labels, val_r_indices, val_c_indices, 0., is_train=BN_AS_TRAIN) test_feed_dict = construct_feed_dict(placeholders, test_features, test_support, test_labels, test_r_indices, test_c_indices, 0., is_train=BN_AS_TRAIN) q_feed_dict = construct_feed_dict(placeholders, test_features, q_support, q_labels, q_r_indices, q_c_indices, 0., is_train=BN_AS_TRAIN) # Add ops to save and restore all the variables. saver = tf.train.Saver() sigmoid = lambda x: 1 / (1 + np.exp(-x)) with tf.Session() as sess: saver.restore(sess, load_from + '/' + 'best_epoch.ckpt') val_avg_loss, val_acc, conf, pred = sess.run( [model.loss, model.accuracy, model.confmat, model.predict()], feed_dict=val_feed_dict) print("val_loss=", "{:.5f}".format(val_avg_loss), "val_acc=", "{:.5f}".format(val_acc)) test_avg_loss, test_acc, conf = sess.run( [model.loss, model.accuracy, model.confmat], feed_dict=test_feed_dict) print("test_loss=", "{:.5f}".format(test_avg_loss), "test_acc=", "{:.5f}".format(test_acc)) num_processed = 0 correct = 0 kwargs = { 'K': args.k, 'subset': args.subset, 'resampled': args.resampled, 'expand_outfit': args.expand_outfit } for question_adj, out_ids, choices_ids, labels, valid in dl.yield_test_questions_K_edges( **kwargs): q_support = get_degree_supports(question_adj, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS, verbose=False) for i in range(1, len(q_support)): q_support[i] = norm_adj(q_support[i]) q_support = [sparse_to_tuple(sup) for sup in q_support] q_feed_dict = construct_feed_dict(placeholders, test_features, q_support, q_labels, out_ids, choices_ids, 0., is_train=BN_AS_TRAIN) # compute the output (correct or not) for the current FITB question preds = sess.run(model.outputs, feed_dict=q_feed_dict) preds = sigmoid(preds) outs = preds.reshape((-1, 4)) outs = outs.mean( axis=0 ) # pick the item with average largest probability, averaged accross all edges gt = labels.reshape((-1, 4)).mean(axis=0) predicted = outs.argmax() gt = gt.argmax() num_processed += 1 correct += int(predicted == gt) print("[{}] Acc: {}".format(num_processed, correct / num_processed)) print('Best val score saved in log: {}'.format(config['best_val_score'])) print('Last val score saved in log: {}'.format(log['val']['acc'][-1]))
def evaluate(features, support, labels, mask, placeholders): t_test = time.time() feed_dict_val = construct_feed_dict(features_dense, support, labels, mask, placeholders) outs_val = sess.run([model.loss, model.accuracy], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test)
outs_val = sess.run([model.loss, model.accuracy, model.predict()], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test), outs_val[2] # Init variables sess.run(tf.global_variables_initializer()) cost_val = [] # Train model for epoch in range(FLAGS.epochs): t = time.time() # Construct feed dictionary feed_dict = construct_feed_dict(features, adjacency, y_train, train_mask, adjacency, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) # Validation cost, acc, duration, _ = evaluate(features, adjacency, y_val, val_mask, placeholders) cost_val.append(cost) if VERBOSE_TRAINING: # Print results print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(outs[1]), "train_acc=", "{:.5f}".format(outs[2]), "val_loss=", "{:.5f}".format(cost), "val_acc=", "{:.5f}".format(acc), "time=", "{:.5f}".format(time.time() - t))
best_acc, best_loss = 0, 1e8 attack = PGDAttack(sess, model, features, eps, FLAGS.att_steps, mu, adj, FLAGS.perturb_ratio) for n in range(FLAGS.train_steps): print( '\n\n============================= iteration {}/{} ==============================' .format(n + 1, FLAGS.train_steps)) print('TRAIN') train_label = attack_label train_label_mask = train_mask + test_mask old_adv_support = adv_support[:] adv_support = new_adv_support[:] print('support diff:', np.sum(old_adv_support[0] - adv_support[0])) train_feed_dict = construct_feed_dict(features, adv_support, train_label, train_label_mask, placeholders) train_feed_dict.update({ placeholders['support'][i]: adv_support[i] for i in range(len(adv_support)) }) train_feed_dict.update({placeholders['lmd']: lmd}) train_feed_dict.update({placeholders['dropout']: FLAGS.dropout}) train_feed_dict.update( {placeholders['adj'][i]: adj for i in range(num_supports)}) # feed ori adj all the time train_feed_dict.update({ placeholders['s'][i]: np.zeros([n_node, n_node]) for i in range(num_supports) }) train_label_mask_expand = np.tile(train_label_mask, [train_label.shape[1], 1]).transpose()
def main(unused_argv): """Main function for running experiments.""" # Load data (train_adj, full_adj, train_feats, test_feats, y_train, y_val, y_test, train_mask, val_mask, test_mask, _, val_data, test_data, num_data, visible_data) = load_data(FLAGS.data_prefix, FLAGS.dataset, FLAGS.precalc, FLAGS.dataset, FLAGS.graph_dir) # Partition graph and do preprocessing if FLAGS.bsize > 1: parts_file = FLAGS.dataset + "-parts-txt" parts_pickle_file = FLAGS.dataset + "-parts-pickle" if ( FLAGS.dataset != 'None') else FLAGS.custom_data + "-parts-pickle" print("parts_pickle_file", parts_pickle_file) if False and os.path.exists(parts_pickle_file): f = open(parts_pickle_file, 'rb') parts = pickle.load(f) f.close() else: _, parts = partition_utils.partition_graph(train_adj, visible_data, FLAGS.num_clusters) #f = open(parts_pickle_file, 'wb') #pickle.dump(parts, f) #f.close() if not os.path.exists(parts_file): with open(parts_file, 'w') as f: s = "{" part_i = 0 for part in parts: s += '"%d"' % part_i + ':' + str(part) + "\n" if part_i != len(parts) - 1: s += ',' part_i += 1 f.write(s + "}") parts = [np.array(pt) for pt in parts] else: (parts, features_batches, support_batches, y_train_batches, train_mask_batches) = utils.preprocess(train_adj, train_feats, y_train, train_mask, visible_data, FLAGS.num_clusters, FLAGS.diag_lambda) # (_, val_features_batches, val_support_batches, y_val_batches, # val_mask_batches) = utils.preprocess(full_adj, test_feats, y_val, val_mask, # np.arange(num_data), # FLAGS.num_clusters_val, # FLAGS.diag_lambda) # (_, test_features_batches, test_support_batches, y_test_batches, # test_mask_batches) = utils.preprocess(full_adj, test_feats, y_test, # test_mask, np.arange(num_data), # FLAGS.num_clusters_test, # FLAGS.diag_lambda) idx_parts = list(range(len(parts))) # Some preprocessing model_func = models.GCN # Define placeholders placeholders = { 'support': tf.sparse_placeholder(tf.float32), 'features': tf.placeholder(tf.float32), 'labels': tf.placeholder(tf.float32, shape=(None, y_train.shape[1])), 'labels_mask': tf.placeholder(tf.int32), 'dropout': tf.placeholder_with_default(0., shape=()), 'num_features_nonzero': tf.placeholder(tf.int32) # helper variable for sparse dropout } # Create model model = model_func(placeholders, input_dim=test_feats.shape[1], logging=True, multilabel=FLAGS.multilabel, norm=FLAGS.layernorm, precalc=FLAGS.precalc, num_layers=FLAGS.num_layers) # Initialize session sess = tf.Session() tf.set_random_seed(seed) # Init variables sess.run(tf.global_variables_initializer()) saver = tf.train.Saver() cost_val = [] total_training_time = 0.0 sampling_time = 0 training_time = 0 extraction_time = 0 # Train model for epoch in range(FLAGS.epochs): t = time.time() np.random.shuffle(idx_parts) if FLAGS.bsize > 1: t0 = time.time() (features_batches, support_batches, y_train_batches, train_mask_batches, t) = utils.preprocess_multicluster( train_adj, parts, train_feats, y_train, train_mask, FLAGS.num_clusters, FLAGS.bsize, FLAGS.diag_lambda) t1 = time.time() extraction_time += t sampling_time += t1 - t0 for pid in range(len(features_batches)): # Use preprocessed batch data features_b = features_batches[pid] support_b = support_batches[pid] y_train_b = y_train_batches[pid] train_mask_b = train_mask_batches[pid] # Construct feed dictionary feed_dict = utils.construct_feed_dict(features_b, support_b, y_train_b, train_mask_b, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) t0 = time.time() # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) t1 = time.time() training_time += t1 - t0 else: np.random.shuffle(idx_parts) for pid in idx_parts: # Use preprocessed batch data features_b = features_batches[pid] support_b = support_batches[pid] y_train_b = y_train_batches[pid] train_mask_b = train_mask_batches[pid] # Construct feed dictionary feed_dict = utils.construct_feed_dict(features_b, support_b, y_train_b, train_mask_b, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) total_training_time += time.time() - t print_str = 'Epoch: %04d ' % ( epoch + 1) + 'training time: {:.5f} '.format( total_training_time) + 'train_acc= {:.5f} '.format(outs[2]) print("sampling_time (clustergcn)", sampling_time) print("training_time:", training_time) #print(sampling_time,"Total sampling time") #print(training_time,"Total training time") #print(extraction_time,"Total extraction time") # return # # Validation # if FLAGS.validation: # cost, acc, micro, macro = evaluate(sess, model, val_features_batches, # val_support_batches, y_val_batches, # val_mask_batches, val_data, # placeholders) # cost_val.append(cost) # print_str += 'val_acc= {:.5f} '.format( # acc) + 'mi F1= {:.5f} ma F1= {:.5f} '.format(micro, macro) # tf.logging.info(print_str) # if epoch > FLAGS.early_stopping and cost_val[-1] > np.mean( # cost_val[-(FLAGS.early_stopping + 1):-1]): # tf.logging.info('Early stopping...') # break # tf.logging.info('Optimization Finished!') return # Save model saver.save(sess, FLAGS.save_name) # Load model (using CPU for inference) with tf.device('/cpu:0'): sess_cpu = tf.Session(config=tf.ConfigProto(device_count={'GPU': 0})) sess_cpu.run(tf.global_variables_initializer()) saver = tf.train.Saver() saver.restore(sess_cpu, FLAGS.save_name) # Testing test_cost, test_acc, micro, macro = evaluate( sess_cpu, model, test_features_batches, test_support_batches, y_test_batches, test_mask_batches, test_data, placeholders) print_str = 'Test set results: ' + 'cost= {:.5f} '.format( test_cost) + 'accuracy= {:.5f} '.format( test_acc) + 'mi F1= {:.5f} ma F1= {:.5f}'.format(micro, macro) tf.logging.info(print_str)
# Train model for epoch in range(FLAGS.epochs): t = time.time() if epoch >= 20: # Generate adversarial examples for adversarial training if args.method == 'flip': # Flip n_flip = 5 features_dense_adv = features_dense for i in range(n_flip): features_dense_adv = flip(model=model, feed_dict=construct_feed_dict( features_dense_adv, support, y_test, test_mask, placeholders), features=features_dense_adv, sess=sess) elif args.method == 'fgsm': # FGSM epsilon = 0.1 features_dense_adv = fgsm(model=model, feed_dict=construct_feed_dict( features_dense, support, y_test, test_mask, placeholders), features=features_dense, sess=sess, epsilon=epsilon) else:
def train_model(model_func, num_supports, support, features, y_train, y_val, y_test, train_mask, val_mask, test_mask, sub_sampled_support=None, VERBOSE_TRAINING=False, seed=13, list_adj=None): if model_func is None: return knn_hop(y_train, y_val, y_test, train_mask, val_mask, test_mask, list_adj) tf.set_random_seed(seed) # Define placeholders placeholders = { 'sub_sampled_support': [tf.sparse_placeholder(tf.float32) for _ in range(num_supports)], 'support': [tf.sparse_placeholder(tf.float32) for _ in range(num_supports)], 'features': tf.sparse_placeholder(tf.float32, shape=tf.constant(features[2], dtype=tf.int64)), 'labels': tf.placeholder(tf.float32, shape=(None, y_train.shape[1])), 'labels_mask': tf.placeholder(tf.int32), 'dropout': tf.placeholder_with_default(0., shape=()), 'num_features_nonzero': tf.placeholder(tf.int32) # helper variable for sparse dropout } # Create model model = model_func(placeholders, input_dim=features[2][1], logging=True) # Initialize session sess = tf.Session() # Define model evaluation function def evaluate(features, support, labels, mask, sub_sampled_support, placeholders): t_test = time.time() feed_dict_val = construct_feed_dict(features, support, labels, mask, sub_sampled_support, placeholders) outs_val = sess.run([model.loss, model.accuracy, model.predict()], feed_dict=feed_dict_val) return outs_val[0], outs_val[1], (time.time() - t_test), outs_val[2] # Init variables sess.run(tf.global_variables_initializer()) cost_val = [] # Train model for epoch in range(FLAGS.epochs): t = time.time() # Construct feed dictionary feed_dict = construct_feed_dict(features, support, y_train, train_mask, sub_sampled_support, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) # Validation cost, acc, duration, _ = evaluate(features, support, y_val, val_mask, sub_sampled_support, placeholders) cost_val.append(cost) if VERBOSE_TRAINING: # Print results print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(outs[1]), "train_acc=", "{:.5f}".format(outs[2]), "val_loss=", "{:.5f}".format(cost), "val_acc=", "{:.5f}".format(acc), "time=", "{:.5f}".format(time.time() - t)) if FLAGS.early_stopping is not None and epoch > FLAGS.early_stopping and cost_val[ -1] > np.mean(cost_val[-(FLAGS.early_stopping + 1):-1]): print("Early stopping...") break print("Optimization Finished!") # Testing test_cost, test_acc, test_duration, predicted_labels = evaluate( features, support, y_test, test_mask, sub_sampled_support, placeholders) print("Test set results:", "cost=", "{:.5f}".format(test_cost), "accuracy=", "{:.5f}".format(test_acc), "time=", "{:.5f}".format(test_duration)) labels_equal = (np.equal(np.argmax(predicted_labels, axis=1), np.argmax(y_test, axis=1))) list_node_correctly_classified = np.argwhere(labels_equal).reshape(-1) list_node_correctly_classified_test = list( filter(lambda x: test_mask[x], list(list_node_correctly_classified))) tf.reset_default_graph() return test_acc, list_node_correctly_classified_test
def run(seed, gamma, beta, hidden, lr, NB_EPOCH=300): """ Main function. Run the architecture for the initialization defined by seed and by the hyperparameters gamma, beta, hidden, lr Inputs: seed : seed to defined the initialization of the training/testing/validation split, gamma, beta, hidden, lr: hyperparameters of the architecture NB_EPOCH: number of runs to do of the same architecture with different weight initializations. Default: 1000 Outputs: auc_test, auc_train, auc_val: AUC on the test, train and validation sets """ tf.reset_default_graph() training_set_mask, testing_set_mask, idx_training, idx_testing = preprocessing_dataset.split_train_test( 0.8, M_str, seed, labels) #create a training and test mask on the data Otraining = preprocessing_dataset.load_mask(training_set_mask, M_str, nrRows, nrCols) Otest = preprocessing_dataset.load_mask(testing_set_mask, M_str, nrRows, nrCols) new_labels_train = np.copy(labels) new_labels_train[idx_testing] = -1 #split train set into 4 parts to create a validation set training_set_mask, validation_set_mask, idx_training, idx_validation = preprocessing_dataset.split_train_validation_4( 3, M_str, seed, new_labels_train) Otraining = preprocessing_dataset.load_mask(training_set_mask, M_str, nrRows, nrCols) Ovalidation = preprocessing_dataset.load_mask(validation_set_mask, M_str, nrRows, nrCols) Otraining = np.concatenate((Otraining, training_set_mask), axis=1) Ocol = np.zeros((Otest.shape[0], 1)) Otest_support = np.concatenate((Otest, Ocol), axis=1) Ovalidation_support = np.concatenate((Ovalidation, Ocol), axis=1) Osupport_t = Otraining + Otest_support + Ovalidation_support Ovalidation = np.concatenate((Ovalidation, validation_set_mask), axis=1) Otest = np.concatenate((Otest, testing_set_mask), axis=1) u_features, v_features, train_labels, train_u_indices, train_v_indices, val_labels, val_u_indices, val_v_indices, test_labels, test_u_indices, test_v_indices = load_data_monti_tadpole( M, Otraining, Otest, Ovalidation) m, n = M.shape # global normalization support = [] support_t = [] path_support_women = "women_synth_noteasy.csv" women_support, _, _ = read_tadpole.load_csv_no_header(path_support_women) women_support = preprocessing_dataset.str_to_float(women_support) women_support = women_support * M_sup women_support = sp.csr_matrix(women_support, dtype=np.float32) support.append(women_support) support_t.append(women_support.T) path_support_men = "men_synth_noteasy.csv" men_support, _, _ = read_tadpole.load_csv_no_header(path_support_men) men_support = preprocessing_dataset.str_to_float(men_support) men_support = men_support * M_sup men_support = sp.csr_matrix(men_support, dtype=np.float32) support.append(men_support) support_t.append(men_support.T) path_support_women_84 = "age_84_92_women_synth_noteasy.csv" women_84_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_84) women_84_support = preprocessing_dataset.str_to_float(women_84_support) women_84_support = women_84_support * M_sup women_84_support = sp.csr_matrix(women_84_support, dtype=np.float32) support.append(women_84_support) support_t.append(women_84_support.T) path_support_men_84 = "age_84_92_men_synth_noteasy.csv" men_84_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_84) men_84_support = preprocessing_dataset.str_to_float(men_84_support) men_84_support = men_84_support * M_sup men_84_support = sp.csr_matrix(men_84_support, dtype=np.float32) support.append(men_84_support) support_t.append(men_84_support.T) path_support_84 = "age_84_92_synth_noteasy.csv" age84_support, _, _ = read_tadpole.load_csv_no_header(path_support_84) age84_support = preprocessing_dataset.str_to_float(age84_support) age84_support = age84_support * M_sup age84_support = sp.csr_matrix(age84_support, dtype=np.float32) support.append(age84_support) support_t.append(age84_support.T) path_support_women_79 = "age_79_84_women_synth_noteasy.csv" women_79_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_79) women_79_support = preprocessing_dataset.str_to_float(women_79_support) women_79_support = women_79_support * M_sup women_79_support = sp.csr_matrix(women_79_support, dtype=np.float32) support.append(women_79_support) support_t.append(women_79_support.T) path_support_men_79 = "age_79_84_men_synth_noteasy.csv" men_79_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_79) men_79_support = preprocessing_dataset.str_to_float(men_79_support) men_79_support = men_79_support * M_sup men_79_support = sp.csr_matrix(men_79_support, dtype=np.float32) support.append(men_79_support) support_t.append(men_79_support.T) path_support_79 = "age_79_84_synth_noteasy.csv" age79_support, _, _ = read_tadpole.load_csv_no_header(path_support_79) age79_support = preprocessing_dataset.str_to_float(age79_support) age79_support = age79_support * M_sup age79_support = sp.csr_matrix(age79_support, dtype=np.float32) support.append(age79_support) support_t.append(age79_support.T) path_support_women_74 = "age_74_79_women_synth_noteasy.csv" women_74_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_74) women_74_support = preprocessing_dataset.str_to_float(women_74_support) women_74_support = women_74_support * M_sup women_74_support = sp.csr_matrix(women_74_support, dtype=np.float32) support.append(women_74_support) support_t.append(women_74_support.T) path_support_men_74 = "age_74_79_men_synth_noteasy.csv" men_74_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_74) men_74_support = preprocessing_dataset.str_to_float(men_74_support) men_74_support = men_74_support * M_sup men_74_support = sp.csr_matrix(men_74_support, dtype=np.float32) support.append(men_74_support) support_t.append(men_74_support.T) path_support_74 = "age_74_79_synth_noteasy.csv" age74_support, _, _ = read_tadpole.load_csv_no_header(path_support_74) age74_support = preprocessing_dataset.str_to_float(age74_support) age74_support = age74_support * M_sup age74_support = sp.csr_matrix(age74_support, dtype=np.float32) support.append(age74_support) support_t.append(age74_support.T) path_support_women_69 = "age_69_74_women_synth_noteasy.csv" women_69_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_69) women_69_support = preprocessing_dataset.str_to_float(women_69_support) women_69_support = women_69_support * M_sup women_69_support = sp.csr_matrix(women_69_support, dtype=np.float32) support.append(women_69_support) support_t.append(women_69_support.T) path_support_men_69 = "age_69_74_men_synth_noteasy.csv" men_69_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_69) men_69_support = preprocessing_dataset.str_to_float(men_69_support) men_69_support = men_69_support * M_sup men_69_support = sp.csr_matrix(men_69_support, dtype=np.float32) support.append(men_69_support) support_t.append(men_69_support.T) path_support_69 = "age_69_74_synth_noteasy.csv" age69_support, _, _ = read_tadpole.load_csv_no_header(path_support_69) age69_support = preprocessing_dataset.str_to_float(age69_support) age69_support = age69_support * M_sup age69_support = sp.csr_matrix(age69_support, dtype=np.float32) support.append(age69_support) support_t.append(age69_support.T) path_support_women_64 = "age_64_69_women_synth_noteasy.csv" women_64_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_64) women_64_support = preprocessing_dataset.str_to_float(women_64_support) women_64_support = women_64_support * M_sup women_64_support = sp.csr_matrix(women_64_support, dtype=np.float32) support.append(women_64_support) support_t.append(women_64_support.T) path_support_men_64 = "age_64_69_men_synth_noteasy.csv" men_64_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_64) men_64_support = preprocessing_dataset.str_to_float(men_64_support) men_64_support = men_64_support * M_sup men_64_support = sp.csr_matrix(men_64_support, dtype=np.float32) support.append(men_64_support) support_t.append(men_64_support.T) path_support_64 = "age_64_69_synth_noteasy.csv" age64_support, _, _ = read_tadpole.load_csv_no_header(path_support_64) age64_support = preprocessing_dataset.str_to_float(age64_support) age64_support = age64_support * M_sup age64_support = sp.csr_matrix(age64_support, dtype=np.float32) support.append(age64_support) support_t.append(age64_support.T) path_support_women_59 = "age_59_64_women_synth_noteasy.csv" women_59_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_59) women_59_support = preprocessing_dataset.str_to_float(women_59_support) women_59_support = women_59_support * M_sup women_59_support = sp.csr_matrix(women_59_support, dtype=np.float32) support.append(women_59_support) support_t.append(women_59_support.T) path_support_men_59 = "age_59_64_men_synth_noteasy.csv" men_59_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_59) men_59_support = preprocessing_dataset.str_to_float(men_59_support) men_59_support = men_59_support * M_sup men_59_support = sp.csr_matrix(men_59_support, dtype=np.float32) support.append(men_59_support) support_t.append(men_59_support.T) path_support_59 = "age_59_64_synth_noteasy.csv" age59_support, _, _ = read_tadpole.load_csv_no_header(path_support_59) age59_support = preprocessing_dataset.str_to_float(age59_support) age59_support = age59_support * M_sup age59_support = sp.csr_matrix(age59_support, dtype=np.float32) support.append(age59_support) support_t.append(age59_support.T) path_support_women_54 = "age_54_59_women_synth_noteasy.csv" women_54_support, _, _ = read_tadpole.load_csv_no_header( path_support_women_54) women_54_support = preprocessing_dataset.str_to_float(women_54_support) women_54_support = women_54_support * M_sup women_54_support = sp.csr_matrix(women_54_support, dtype=np.float32) support.append(women_54_support) support_t.append(women_54_support.T) path_support_men_54 = "age_54_59_men_synth_noteasy.csv" men_54_support, _, _ = read_tadpole.load_csv_no_header(path_support_men_54) men_54_support = preprocessing_dataset.str_to_float(men_54_support) men_54_support = men_54_support * M_sup men_54_support = sp.csr_matrix(men_54_support, dtype=np.float32) support.append(men_54_support) support_t.append(men_54_support.T) path_support_54 = "age_54_59_synth_noteasy.csv" age54_support, _, _ = read_tadpole.load_csv_no_header(path_support_54) age54_support = preprocessing_dataset.str_to_float(age54_support) age54_support = age54_support * M_sup age54_support = sp.csr_matrix(age54_support, dtype=np.float32) support.append(age54_support) support_t.append(age54_support.T) num_support = len(support) mask_support_t = [] Osupport_t = sp.csr_matrix(Osupport_t, dtype=np.int) for i in range(num_support): mask_support_t.append(Osupport_t.T) mask_support_t = sp.hstack(mask_support_t, format='csr') support = sp.hstack(support, format='csr') support_t = sp.hstack(support_t, format='csr') # Collect all user and item nodes for test set test_u = list(set(test_u_indices)) test_v = list(set(test_v_indices)) test_u_dict = {n: i for i, n in enumerate(test_u)} test_v_dict = {n: i for i, n in enumerate(test_v)} test_u_indices = np.array([test_u_dict[o] for o in test_u_indices]) test_v_indices = np.array([test_v_dict[o] for o in test_v_indices]) test_support = support[np.array(test_u)] for i in range(test_support.shape[0]): for j in range(563, test_support.shape[1], 564): test_support[i, j] = 0.0 test_support_t = sp.csr_matrix.multiply(support_t, mask_support_t) # Collect all user and item nodes for validation set val_u = list(set(val_u_indices)) val_v = list(set(val_v_indices)) val_u_dict = {n: i for i, n in enumerate(val_u)} val_v_dict = {n: i for i, n in enumerate(val_v)} val_u_indices = np.array([val_u_dict[o] for o in val_u_indices]) val_v_indices = np.array([val_v_dict[o] for o in val_v_indices]) val_support = support[np.array(val_u)] for i in range(val_support.shape[0]): for j in range(563, val_support.shape[1], 564): val_support[i, j] = 0.0 val_support_t = sp.csr_matrix.multiply(support_t, mask_support_t) # Collect all user and item nodes for train set train_u = list(set(train_u_indices)) train_v = list(set(train_v_indices)) train_u_dict = {n: i for i, n in enumerate(train_u)} train_v_dict = {n: i for i, n in enumerate(train_v)} train_u_indices = np.array([train_u_dict[o] for o in train_u_indices]) train_v_indices = np.array([train_v_dict[o] for o in train_v_indices]) train_support = support[np.array(train_u)] train_support_t = sp.csr_matrix.multiply(support_t, mask_support_t) placeholders = { 'u_features': tf.sparse_placeholder(tf.float32, shape=np.array(u_features.shape, dtype=np.int64)), 'v_features': tf.sparse_placeholder(tf.float32, shape=np.array(v_features.shape, dtype=np.int64)), 'u_features_nonzero': tf.placeholder(tf.int32, shape=()), 'v_features_nonzero': tf.placeholder(tf.int32, shape=()), 'labels': tf.placeholder(tf.float32, shape=(None, )), 'indices_labels': tf.placeholder(tf.int32, shape=(None, )), 'user_indices': tf.placeholder(tf.int32, shape=(None, )), 'item_indices': tf.placeholder(tf.int32, shape=(None, )), 'dropout': tf.placeholder_with_default(0., shape=()), 'weight_decay': tf.placeholder_with_default(0., shape=()), 'support': tf.sparse_placeholder(tf.float32, shape=(None, None)), 'support_t': tf.sparse_placeholder(tf.float32, shape=(None, None)), } div = hidden[0] // num_support if hidden[0] % num_support != 0: print( """\nWARNING: HIDDEN[0] (=%d) of stack layer is adjusted to %d such that it can be evenly split in %d splits.\n""" % (hidden[0], num_support * div, num_support)) hidden[0] = num_support * div # create model model = MG_GAE(placeholders, input_dim=u_features.shape[1], num_support=num_support, hidden=hidden, num_users=m, num_items=n, learning_rate=lr, gamma=gamma, beta=beta, logging=True) # Convert sparse placeholders to tuples to construct feed_dict test_support = sparse_to_tuple(test_support) test_support_t = sparse_to_tuple(test_support_t) val_support = sparse_to_tuple(val_support) val_support_t = sparse_to_tuple(val_support_t) train_support = sparse_to_tuple(train_support) train_support_t = sparse_to_tuple(train_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][ 1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] indices_labels = [563] * train_labels.shape[0] indices_labels_val = [563] * val_labels.shape[0] indices_labels_test = [563] * test_labels.shape[0] # Feed_dicts for validation and test set stay constant over different update steps train_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, train_support, train_support_t, train_labels, indices_labels, train_u_indices, train_v_indices, 0.) # No dropout for validation and test runs val_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, val_support, val_support_t, val_labels, indices_labels_val, val_u_indices, val_v_indices, 0.) test_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, test_support, test_support_t, test_labels, indices_labels_test, test_u_indices, test_v_indices, 0.) # Collect all variables to be logged into summary merged_summary = tf.summary.merge_all() sess = tf.Session() sess.run(tf.global_variables_initializer()) auc_train = [] auc_test = [] auc_val = [] test_pred = [] for epoch in range(NB_EPOCH): t = time.time() # Run single weight update outs = sess.run([ model.training_op, model.loss, model.indices, model.labels, model.outputs, model.labels_class, model.classification, model.inputs, model.gcn_u, model.gcn_v, model.loss_frob, model.binary_entropy, model.u_inputs, model.v_inputs, model.weight, model.input_u, model.input_v, model.u_indices, model.v_indices ], feed_dict=train_feed_dict) train_avg_loss = outs[1] label_train = outs[5] output_train = outs[6] fpr_train, tpr_train, thresholds_train = roc_curve( label_train, output_train, pos_label=label_train.max()) roc_auc_train = auc(fpr_train, tpr_train) auc_train.append(roc_auc_train) val_avg_loss, val_classification, val_labels_corres = sess.run( [model.loss, model.classification, model.labels_class], feed_dict=val_feed_dict) #test_feed_dict)# fpr_val, tpr_val, thresholds_train = roc_curve( val_labels_corres, val_classification, pos_label=label_train.max()) roc_auc_val = auc(fpr_val, tpr_val) auc_val.append(roc_auc_val) test_avg_loss, test_classification, test_labels_corres = sess.run( [model.loss, model.classification, model.labels_class], feed_dict=test_feed_dict) fpr_test, tpr_test, thresholds_test = roc_curve( test_labels_corres, test_classification, pos_label=label_train.max()) roc_auc_test = auc(fpr_test, tpr_test) auc_test.append(roc_auc_test) test_pred.append(test_classification) if VERBOSE: print("[*] Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(train_avg_loss), "train_auc=", "{:.5f}".format(roc_auc_train), "val_loss=", "{:.5f}".format(val_avg_loss), "val_auc=", "{:.5f}".format(roc_auc_val), "\t\ttime=", "{:.5f}".format(time.time() - t)) print('test auc = ', roc_auc_test) sess.close() return auc_test, auc_train, auc_val
num_edges=num_edges) # Initialize session sess = tf.Session() sess.run(tf.global_variables_initializer()) adj_label = adj_train + sp.eye(adj_train.shape[0]) adj_label = sparse_to_tuple(adj_label) # Train model for epoch in range(FLAGS.epochs): t = time.time() # Construct feed dictionary # placeholdersに代入する辞書作り feed_dict = construct_feed_dict(adj_norm, adj_label, features, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # One update of parameter matrices _, avg_cost = sess.run([opt.opt_op, opt.cost], feed_dict=feed_dict) # optimizeして, コスト関数を出力 # Performance on validation set roc_curr, ap_curr = get_roc_score(val_edges, val_edges_false) # ただ各エポックで精度を見るためだけのもの print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(avg_cost), "val_roc=", "{:.5f}".format(roc_curr), "val_ap=", "{:.5f}".format(ap_curr), "time=", "{:.5f}".format(time.time() - t)) print('Optimization Finished!') roc_score, ap_score = get_roc_score(test_edges, test_edges_false)
def main(unused_argv): """Main function for running experiments.""" # Load data (train_adj, full_adj, train_feats, test_feats, y_train, y_val, y_test, train_mask, val_mask, test_mask, _, val_data, test_data, num_data, visible_data) = load_data(FLAGS.data_prefix, FLAGS.dataset, FLAGS.precalc) # Partition graph and do preprocessing if FLAGS.bsize > 1: _, parts = partition_utils.partition_graph(train_adj, visible_data, FLAGS.num_clusters) parts = [np.array(pt) for pt in parts] else: (parts, features_batches, support_batches, y_train_batches, train_mask_batches) = utils.preprocess(train_adj, train_feats, y_train, train_mask, visible_data, FLAGS.num_clusters, FLAGS.diag_lambda) (_, val_features_batches, val_support_batches, y_val_batches, val_mask_batches) = utils.preprocess(full_adj, test_feats, y_val, val_mask, np.arange(num_data), FLAGS.num_clusters_val, FLAGS.diag_lambda) (_, test_features_batches, test_support_batches, y_test_batches, test_mask_batches) = utils.preprocess(full_adj, test_feats, y_test, test_mask, np.arange(num_data), FLAGS.num_clusters_test, FLAGS.diag_lambda) idx_parts = list(range(len(parts))) # Some preprocessing model_func = models.GCN # Define placeholders placeholders = { 'support': tf.sparse_placeholder(tf.float32), 'features': tf.placeholder(tf.float32), 'labels': tf.placeholder(tf.float32, shape=(None, y_train.shape[1])), 'labels_mask': tf.placeholder(tf.int32), 'dropout': tf.placeholder_with_default(0., shape=()), 'num_features_nonzero': tf.placeholder(tf.int32) # helper variable for sparse dropout } # Create model model = model_func( placeholders, input_dim=test_feats.shape[1], logging=True, multilabel=FLAGS.multilabel, norm=FLAGS.layernorm, precalc=FLAGS.precalc, num_layers=FLAGS.num_layers) # Initialize session sess = tf.Session() tf.set_random_seed(seed) # Init variables sess.run(tf.global_variables_initializer()) saver = tf.train.Saver() cost_val = [] total_training_time = 0.0 # Train model for epoch in range(FLAGS.epochs): t = time.time() np.random.shuffle(idx_parts) if FLAGS.bsize > 1: (features_batches, support_batches, y_train_batches, train_mask_batches) = utils.preprocess_multicluster( train_adj, parts, train_feats, y_train, train_mask, FLAGS.num_clusters, FLAGS.bsize, FLAGS.diag_lambda) for pid in range(len(features_batches)): # Use preprocessed batch data features_b = features_batches[pid] support_b = support_batches[pid] y_train_b = y_train_batches[pid] train_mask_b = train_mask_batches[pid] # Construct feed dictionary feed_dict = utils.construct_feed_dict(features_b, support_b, y_train_b, train_mask_b, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) else: np.random.shuffle(idx_parts) for pid in idx_parts: # Use preprocessed batch data features_b = features_batches[pid] support_b = support_batches[pid] y_train_b = y_train_batches[pid] train_mask_b = train_mask_batches[pid] # Construct feed dictionary feed_dict = utils.construct_feed_dict(features_b, support_b, y_train_b, train_mask_b, placeholders) feed_dict.update({placeholders['dropout']: FLAGS.dropout}) # Training step outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) total_training_time += time.time() - t print_str = 'Epoch: %04d ' % (epoch + 1) + 'training time: {:.5f} '.format( total_training_time) + 'train_acc= {:.5f} '.format(outs[2]) # Validation if FLAGS.validation: cost, acc, micro, macro = evaluate(sess, model, val_features_batches, val_support_batches, y_val_batches, val_mask_batches, val_data, placeholders) cost_val.append(cost) print_str += 'val_acc= {:.5f} '.format( acc) + 'mi F1= {:.5f} ma F1= {:.5f} '.format(micro, macro) tf.logging.info(print_str) if epoch > FLAGS.early_stopping and cost_val[-1] > np.mean( cost_val[-(FLAGS.early_stopping + 1):-1]): tf.logging.info('Early stopping...') break tf.logging.info('Optimization Finished!') # Save model saver.save(sess, FLAGS.save_name) # Load model (using CPU for inference) with tf.device('/cpu:0'): sess_cpu = tf.Session(config=tf.ConfigProto(device_count={'GPU': 0})) sess_cpu.run(tf.global_variables_initializer()) saver = tf.train.Saver() saver.restore(sess_cpu, FLAGS.save_name) # Testing test_cost, test_acc, micro, macro = evaluate( sess_cpu, model, test_features_batches, test_support_batches, y_test_batches, test_mask_batches, test_data, placeholders) print_str = 'Test set results: ' + 'cost= {:.5f} '.format( test_cost) + 'accuracy= {:.5f} '.format( test_acc) + 'mi F1= {:.5f} ma F1= {:.5f}'.format(micro, macro) tf.logging.info(print_str)
test_support = sparse_to_tuple(test_support) test_support_t = sparse_to_tuple(test_support_t) u_features = sparse_to_tuple(u_features) v_features = sparse_to_tuple(v_features) assert u_features[2][1] == v_features[2][ 1], 'Number of features of users and items must be the same!' num_features = u_features[2][1] u_features_nonzero = u_features[1].shape[0] v_features_nonzero = v_features[1].shape[0] # No dropout for test runs test_feed_dict = construct_feed_dict(placeholders, u_features, v_features, u_features_nonzero, v_features_nonzero, test_support, test_support_t, test_labels, test_u_indices, test_v_indices, class_values, 0., test_u_features_side, test_v_features_side) sess = tf.Session() sess.run(tf.global_variables_initializer()) model.load(sess) # store model including exponential moving averages saver = tf.train.Saver() save_path = saver.save(sess, "models/%s.ckpt" % model.name, global_step=model.global_step) # test_avg_loss, test_rmse = sess.run([model.loss, model.rmse], feed_dict=test_feed_dict)
def test_amazon(args): args = namedtuple("Args", args.keys())(*args.values()) load_from = args.load_from config_file = load_from + '/results.json' log_file = load_from + '/log.json' with open(config_file) as f: config = json.load(f) with open(log_file) as f: log = json.load(f) NUMCLASSES = 2 BN_AS_TRAIN = False ADJ_SELF_CONNECTIONS = True # evaluate in the specified version print("Trained with {}, evaluating with {}".format(config['amz_data'], args.amz_data)) cat_rel = args.amz_data dp = DataLoaderAmazon(cat_rel=cat_rel) train_features, adj_train, train_labels, train_r_indices, train_c_indices = dp.get_phase( 'train') _, adj_val, val_labels, val_r_indices, val_c_indices = dp.get_phase( 'valid') _, adj_test, test_labels, test_r_indices, test_c_indices = dp.get_phase( 'test') full_adj = dp.adj def norm_adj(adj_to_norm): return normalize_nonsym_adj(adj_to_norm) train_features, mean, std = dp.normalize_features(train_features, get_moments=True) train_support = get_degree_supports(adj_train, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) val_support = get_degree_supports(adj_val, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) test_support = get_degree_supports(adj_test, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS) for i in range(1, len(train_support)): train_support[i] = norm_adj(train_support[i]) val_support[i] = norm_adj(val_support[i]) test_support[i] = norm_adj(test_support[i]) num_support = len(train_support) num_support = len(train_support) placeholders = { 'row_indices': tf.compat.v1.placeholder(tf.int32, shape=(None, )), 'col_indices': tf.compat.v1.placeholder(tf.int32, shape=(None, )), 'dropout': tf.compat.v1.placeholder_with_default(0., shape=()), 'weight_decay': tf.compat.v1.placeholder_with_default(0., shape=()), 'is_train': tf.compat.v1.placeholder_with_default(True, shape=()), 'support': [ tf.compat.v1.sparse_placeholder(tf.float32, shape=(None, None)) for sup in range(num_support) ], 'node_features': tf.compat.v1.placeholder(tf.float32, shape=(None, None)), 'labels': tf.compat.v1.placeholder(tf.float32, shape=(None, )) } model = CompatibilityGAE(placeholders, input_dim=train_features.shape[1], num_classes=NUMCLASSES, num_support=num_support, hidden=config['hidden'], learning_rate=config['learning_rate'], logging=True, batch_norm=config['batch_norm']) train_feed_dict = construct_feed_dict(placeholders, train_features, train_support, train_labels, train_r_indices, train_c_indices, config['dropout']) # No dropout for validation and test runs val_feed_dict = construct_feed_dict(placeholders, train_features, val_support, val_labels, val_r_indices, val_c_indices, 0., is_train=BN_AS_TRAIN) test_feed_dict = construct_feed_dict(placeholders, train_features, test_support, test_labels, test_r_indices, test_c_indices, 0., is_train=BN_AS_TRAIN) # Add ops to save and restore all the variables. saver = tf.compat.v1.train.Saver() with tf.compat.v1.Session() as sess: saver.restore(sess, load_from + '/' + 'best_epoch.ckpt') val_avg_loss, val_acc, conf, pred = sess.run( [model.loss, model.accuracy, model.confmat, model.predict()], feed_dict=val_feed_dict) print("val_loss=", "{:.5f}".format(val_avg_loss), "val_acc=", "{:.5f}".format(val_acc)) test_avg_loss, test_acc, conf = sess.run( [model.loss, model.accuracy, model.confmat], feed_dict=test_feed_dict) print("test_loss=", "{:.5f}".format(test_avg_loss), "test_acc=", "{:.5f}".format(test_acc)) # rerun for K=0 (all in parallel) k_0_adj = sp.csr_matrix(adj_val.shape) k_0_support = get_degree_supports(k_0_adj, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS, verbose=False) for i in range(1, len(k_0_support)): k_0_support[i] = norm_adj(k_0_support[i]) k_0_support = [sparse_to_tuple(sup) for sup in k_0_support] k_0_val_feed_dict = construct_feed_dict(placeholders, train_features, k_0_support, val_labels, val_r_indices, val_c_indices, 0., is_train=BN_AS_TRAIN) k_0_test_feed_dict = construct_feed_dict(placeholders, train_features, k_0_support, test_labels, test_r_indices, test_c_indices, 0., is_train=BN_AS_TRAIN) val_avg_loss, val_acc, conf, pred = sess.run( [model.loss, model.accuracy, model.confmat, model.predict()], feed_dict=k_0_val_feed_dict) print("for k=0 val_loss=", "{:.5f}".format(val_avg_loss), "for k=0 val_acc=", "{:.5f}".format(val_acc)) test_avg_loss, test_acc, conf = sess.run( [model.loss, model.accuracy, model.confmat], feed_dict=k_0_test_feed_dict) print("for k=0 test_loss=", "{:.5f}".format(test_avg_loss), "for k=0 test_acc=", "{:.5f}".format(test_acc)) K = args.k available_adj = dp.full_valid_adj + dp.full_train_adj available_adj = available_adj.tolil() for r, c in zip(test_r_indices, test_c_indices): available_adj[r, c] = 0 available_adj[c, r] = 0 available_adj = available_adj.tocsr() available_adj.eliminate_zeros() G = Graph(available_adj) get_edges_func = G.run_K_BFS new_adj = sp.csr_matrix(full_adj.shape) new_adj = new_adj.tolil() for r, c in zip(test_r_indices, test_c_indices): before = time.time() if K > 0: #expand the edges nodes_to_expand = [r, c] for node in nodes_to_expand: edges = get_edges_func(node, K) for edge in edges: i, j = edge new_adj[i, j] = 1 new_adj[j, i] = 1 new_adj = new_adj.tocsr() new_support = get_degree_supports(new_adj, config['degree'], adj_self_con=ADJ_SELF_CONNECTIONS, verbose=False) for i in range(1, len(new_support)): new_support[i] = norm_adj(new_support[i]) new_support = [sparse_to_tuple(sup) for sup in new_support] new_feed_dict = construct_feed_dict(placeholders, train_features, new_support, test_labels, test_r_indices, test_c_indices, 0., is_train=BN_AS_TRAIN) loss, acc = sess.run([model.loss, model.accuracy], feed_dict=new_feed_dict) print("for k={} test_acc=".format(K), "{:.5f}".format(acc)) print('Best val score saved in log: {}'.format(config['best_val_score'])) print('Last val score saved in log: {}'.format(log['val']['acc'][-1]))
def exp(dataset, data_seed, init_seed): ''' dataset - name of dataset data_seed - data_seed corresponds to train/dev/test split init_seed - seed for initializing NN weights ''' print('running {} on {}'.format(FLAGS.model, dataset)) tf.reset_default_graph() adj, subgraphs, features, labels, train_mask, val_mask, test_mask = load_data( dataset, data_seed) features = preprocess_features(features) # if early_stopping is not used, then put validation data into the testing data if FLAGS.early_stop == 0: mask = np.logical_or(val_mask, test_mask) test_mask = mask val_mask = mask config = tf.ConfigProto() config.graph_options.optimizer_options.global_jit_level = tf.OptimizerOptions.ON_1 #config.log_device_placement = True config.gpu_options.allow_growth = True train_loss = [] train_acc = [] valid_loss = [] valid_acc = [] with tf.Graph().as_default(): random.seed(init_seed) np.random.seed(init_seed) tf.set_random_seed(init_seed) with tf.Session(config=config) as sess: model, support, placeholders = build_model(adj, features, labels.shape[1], subgraphs) sess.run(tf.global_variables_initializer()) def evaluate(labels_mask, noise=0., dropout=0.): feed_dict_val = construct_feed_dict(features, support, labels, labels_mask, placeholders, noise, dropout) outs_val = sess.run([model.loss, model.accuracy], feed_dict=feed_dict_val) return outs_val[0], outs_val[1] start_t = time.time() for epoch in range(FLAGS.epochs): feed_dict = construct_feed_dict(features, support, labels, train_mask, placeholders, FLAGS.fisher_noise, FLAGS.dropout) feed_dict.update({tf.keras.backend.learning_phase(): 1}) outs = sess.run([model.opt_op, model.loss, model.accuracy], feed_dict=feed_dict) train_loss.append(outs[1]) train_acc.append(outs[2]) # Validation outs = evaluate(val_mask) valid_loss.append(outs[0]) valid_acc.append(outs[1]) if (epoch + 1) % 10 == 0: print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(train_loss[-1]), "train_acc=", "{:.5f}".format(train_acc[-1]), "val_loss=", "{:.5f}".format(valid_loss[-1]), "val_acc=", "{:.5f}".format(valid_acc[-1])) #print( 'perterbation radius:', sess.run( pradius ) ) if FLAGS.early_stop == 0: if epoch > 10 and (train_loss[-1] > 1.5 * train_loss[0] or np.isnan(train_loss[-1])): print("Early stopping at epoch {}...".format(epoch)) break elif FLAGS.early_stop == 1: # simple early stopping if epoch > 20 and valid_loss[-1] > np.mean( valid_loss[-10:] ) \ and valid_acc[-1] < np.mean( valid_acc[-10:] ): print("Early stopping at epoch {}...".format(epoch)) break elif FLAGS.early_stop == 2: # more strict conditions if epoch > 100 \ and np.mean( valid_loss[-10:] ) > np.mean( valid_loss[-100:] ) \ and np.mean( valid_acc[-10:] ) < np.mean( valid_acc[-100:] ): print("Early stopping at epoch {}...".format(epoch)) break else: print('unknown early stopping strategy:', FLAGS.early_stop) sys.exit(0) test_loss, test_acc = evaluate(test_mask) sec_per_epoch = (time.time() - start_t) / epoch print("Test set results:", "loss=", "{:.5f}".format(test_loss), "accuracy=", "{:.5f}".format(test_acc), "epoch_secs=", "{:.2f}".format(sec_per_epoch)) tf.reset_default_graph() return { 'train_loss': train_loss, 'train_acc': train_acc, 'valid_loss': valid_loss, 'valid_acc': valid_acc, 'test_loss': test_loss, 'test_acc': test_acc, }