summaryrefslogtreecommitdiff
path: root/main.py
diff options
context:
space:
mode:
authorlyz <[email protected]>2023-06-06 10:55:16 +0400
committerlyz <[email protected]>2023-06-06 10:55:16 +0400
commitcca3fc80042dfa7942cfcf368cf949776367432e (patch)
treed10cd0d06cf26c8eb0f9410067442ca7d54b273d /main.py
Initial commit
Diffstat (limited to 'main.py')
-rw-r--r--main.py281
1 files changed, 281 insertions, 0 deletions
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..5d93d7c
--- /dev/null
+++ b/main.py
@@ -0,0 +1,281 @@
+# coding=utf-8
+import tf_geometric as tfg
+from sklearn.metrics import accuracy_score, f1_score, classification_report,confusion_matrix
+from tf_geometric.utils.graph_utils import negative_sampling
+from sklearn.model_selection import train_test_split
+#from keras.utils import plot_model
+import pydot
+from keras.utils.vis_utils import plot_model
+
+from opgl.model.module import MultiVariationalGCNWithDense
+
+import os
+import tensorflow as tf
+import numpy as np
+import argparse
+
+from opgl.utils.label_utils import reassign_labels, special_train_test_split
+
+from parameter_parser import parameter_parser
+from opgl.model.module import GoG
+from seal import SEALCITrainer
+
+learning_rate = 1e-3
+os.environ["CUDA_VISIBLE_DEVICES"] = "1"
+args = parameter_parser()
+#base_dir = "./"
+
+#base_data_dir = os.path.join(base_dir, "data")
+#parser = argparse.ArgumentParser()
+
+#args.add_argument("--dataset_name", type=str, default="cora")
+#args.add_argument("--unseen_num", type=int, default=1)
+
+# command = '--dataset_name cora --unseen_num 1'
+# sys.argv = sys.argv+command.split()
+
+#args = parser.parse_args()
+
+#dataset_name = args.dataset_name
+unseen_num = args.unseen_num
+
+training_rate = 0.7
+valid_rate = 0.1
+unseen_label_index = -1
+filter_unseen = True
+learning_rate = 1e-3
+drop_rate = 0.3
+train_seed = 100
+np.random.seed(train_seed)
+tf.random.set_seed(train_seed)
+
+
+use_softmax = True
+use_class_uncertainty = True
+use_VGAE = True
+uncertain_num_samplings = 100 if use_VGAE else 1
+
+
+#if dataset_name == "cora":
+# graph, _ = tfg.datasets.CoraDataset(base_data_dir).load_data()
+
+print(training_rate)
+print(valid_rate)
+
+dataset = SEALCITrainer(args)
+data = dataset.dataset_generator.graphs
+def construct_graph(graph_dict):
+ return tfg.Graph(
+ x=graph_dict['features'],
+ edge_index=graph_dict["edge"],
+ #y=graph_dict["graph_label"] # graph_dict["graph_label"] is a list with one int element
+ )
+graphs = [construct_graph(data[i]) for i in range(len(data))]
+graphs = tfg.BatchGraph.from_graphs(graphs)
+edges = dataset.macro_graph_edges
+
+original_num_classes = 6
+seen_labels = list(range(original_num_classes))
+seen_labels.remove(2)
+target = dataset.dataset_generator.target
+y_true = reassign_labels(target, seen_labels, unseen_label_index)
+train_indices, test_valid_indices = special_train_test_split(y_true, unseen_label_index=-1, test_size=1-training_rate)
+test_indices, valid_indices = train_test_split(test_valid_indices, test_size=valid_rate / (1-training_rate))
+num_classes = 5
+
+#print('data:{}\tseen_labels:{}\tuse_softmax:{}\trandom_seed:{}\tunseen_num:{}'.format(
+# dataset_name,
+# seen_labels,
+# use_softmax,
+# train_seed,
+# unseen_num))
+
+
+model = GoG(args, [32, 16, 5],
+ uncertain=use_VGAE,
+ output_list=True)
+
+def logits_to_probs(logits):
+ if use_softmax:
+ probs = tf.nn.softmax(logits)
+ else:
+ probs = tf.nn.sigmoid(logits)
+ return probs
+
+
+def compute_loss(outputs, kl, mask_indices):
+ # use negative_sampling
+ logits = outputs[-1]
+ h = outputs[-2]
+
+ if use_VGAE:
+ neg_edge_index = negative_sampling(
+
+ num_samples=edges.shape[1],
+ num_nodes=len(graphs.graphs),
+ edge_index=None,
+ replace=False
+ )
+
+ pos_logits = tf.reduce_sum(
+ tf.gather(h, edges[0]) * tf.gather(h, edges[1]),
+ axis=-1
+ )
+ neg_logits = tf.reduce_sum(
+ tf.gather(h, neg_edge_index[0]) * tf.gather(h, neg_edge_index[1]),
+ axis=-1
+ )
+
+ pos_losses = tf.nn.sigmoid_cross_entropy_with_logits(
+ logits=pos_logits,
+ labels=tf.ones_like(pos_logits)
+ )
+ neg_losses = tf.nn.sigmoid_cross_entropy_with_logits(
+ logits=neg_logits,
+ labels=tf.zeros_like(neg_logits)
+ )
+ gae_loss = tf.reduce_mean(pos_losses) + tf.reduce_mean(neg_losses)
+
+
+ all_indices = np.arange(0, tf.shape(logits)[0])
+ unmasked_indices = np.delete(all_indices, mask_indices)
+
+ unmasked_logits = tf.gather(logits, unmasked_indices)
+ #
+ loss_func = tf.nn.softmax_cross_entropy_with_logits if use_softmax else tf.nn.sigmoid_cross_entropy_with_logits
+
+ unmasked_probs = logits_to_probs(unmasked_logits)
+ unmasked_probs = tf.clip_by_value(unmasked_probs, 1e-7, 1.0)
+
+ unmasked_preds = tf.argmax(unmasked_probs, axis=-1)
+ unmasked_prob = tf.gather_nd(unmasked_probs, tf.stack([tf.range(unmasked_logits.shape[0], dtype=tf.int64), unmasked_preds], axis=1))
+
+ topk_indices = tf.where(tf.logical_and(
+ tf.greater(unmasked_prob, 1.0 / num_classes),
+ tf.less(unmasked_prob, 0.5)
+ ))
+
+ unmasked_probs = tf.gather(unmasked_probs, topk_indices)
+ class_uncertainty_losses = unmasked_probs * tf.math.log(unmasked_probs)
+
+ masked_logits = tf.gather(logits, mask_indices)
+ masked_y_true = y_true[mask_indices]
+ losses = loss_func(
+ logits=masked_logits,
+ labels=tf.one_hot(masked_y_true, depth=num_classes)
+ )
+ masked_kl = tf.gather(kl, mask_indices)
+
+ loss = tf.reduce_mean(losses)
+
+
+ if use_class_uncertainty:
+ loss += tf.reduce_mean(class_uncertainty_losses) * 1.0
+
+
+ if use_VGAE:
+ loss = loss + gae_loss * 1.0 + tf.reduce_mean(masked_kl)*1.0
+
+ return loss
+
+
+def evaluate(logits, mask_indices, show_matrix=False, filter_unseen=True,threshold=None):
+
+ if isinstance(logits, list):
+ logits_list = tf.stack(logits, axis=-1)
+ logits = tf.reduce_mean(logits_list, axis=-1)
+
+ if use_softmax:
+ probs_list = tf.nn.softmax(logits_list, axis=-2)
+ else:
+ probs_list = tf.nn.sigmoid(logits_list)
+ probs = tf.reduce_mean(probs_list, axis=-1)
+ else:
+ probs = logits_to_probs(logits)
+
+ masked_logits = tf.gather(logits, mask_indices)
+ masked_y_pred = tf.argmax(masked_logits, axis=-1)
+ masked_y_true = y_true[mask_indices]
+
+ if filter_unseen:
+ probs = tf.gather(probs, mask_indices)
+ probs = tf.gather_nd(probs, tf.stack([tf.range(masked_logits.shape[0], dtype=tf.int64), masked_y_pred], axis=1))
+ probs = probs.numpy()
+ masked_y_pred = masked_y_pred.numpy()
+ print("mean: ", probs.mean())
+ if threshold is None:
+ threshold = (probs[masked_y_true != unseen_label_index].mean()+probs[masked_y_true == unseen_label_index].mean())/2.0
+ print("auto meanS: ", threshold)
+ # threshold
+ masked_y_pred[probs < threshold] = unseen_label_index
+
+ else:
+ masked_y_pred = masked_y_pred.numpy()
+
+
+ accuracy = accuracy_score(masked_y_true, masked_y_pred)
+ macro_f_score = f1_score(masked_y_true, masked_y_pred, average="macro")
+
+ if show_matrix:
+ print(classification_report(masked_y_true, masked_y_pred))
+ print(confusion_matrix(masked_y_true, masked_y_pred))
+
+ if filter_unseen:
+ return accuracy, macro_f_score, threshold
+ else:
+ return accuracy, macro_f_score
+
+
+optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
+
+results = []
+for step in range(3000):
+
+ with tf.GradientTape() as tape:
+ outputs, kl, penalty = model([graphs, edges], cache=None, training=True)
+ logits = outputs[-1]
+ train_loss = compute_loss(outputs, kl, train_indices) + args.gamma*penalty
+ print(train_loss)
+ vars = tape.watched_variables()
+ grads = tape.gradient(train_loss, vars)
+ optimizer.apply_gradients(zip(grads, vars))
+
+ os.environ["PATH"] += os.pathsep + 'D:/Program Files/software/Graphviz/bin'
+ plot_model(model, to_file='model.png', show_shapes=True)
+
+ if step % 10 == 0:
+
+ train_logits = tf.gather(logits, train_indices)
+ train_probs = logits_to_probs(train_logits)
+
+ train_accuracy, _ = evaluate(logits, train_indices, filter_unseen=False)
+
+ test_results = [model([graphs, edges], cache=None, training=True)
+ for _ in range(uncertain_num_samplings)]
+ outputs_list = [test_result[0] for test_result in test_results]
+ outputs = [
+ tf.reduce_mean(tf.stack([item[i] for item in outputs_list], axis=-1), axis=-1)
+ for i in range(len(outputs_list[0]))
+ ]
+ kl = tf.add_n([test_result[1] for test_result in test_results]) / len(test_results)
+
+ logits = outputs[-1]
+ valid_loss = compute_loss(outputs, kl, valid_indices)
+ valid_accuracy,valid_macro_f_score, threshold = evaluate(logits, valid_indices, filter_unseen=True)
+
+ print(threshold)
+ print('=====')
+ test_loss = compute_loss(outputs, kl, test_indices)
+ test_accuracy, test_macro_f_score, _ = evaluate(logits, test_indices, show_matrix=True, filter_unseen=True,threshold=threshold)
+
+ print(f"step = {step}\n"
+ f"\ttrain_loss = {train_loss}\ttrain_accuracy = {train_accuracy}\n"
+ f"\tvalid_loss = {valid_loss}\tvalid_accuracy = {valid_accuracy}\tvalid_macro_f_score = {valid_macro_f_score}\n"
+ f"\ttest_loss = {test_loss}\ttest_accuracy = {test_accuracy}\ttest_macro_f_score={test_macro_f_score}\n"
+ )
+
+ results.append([test_accuracy, test_macro_f_score])
+ for i, metric_name in enumerate(["accuracy", "f"]):
+ values = np.array(results)[:, i]
+ max_step = np.argmax(values)
+ print(f"max_{metric_name} = {values[max_step]}\tmax_step = {max_step}\t{results[max_step]}")