diff options
| author | lyz <[email protected]> | 2023-06-06 10:55:16 +0400 |
|---|---|---|
| committer | lyz <[email protected]> | 2023-06-06 10:55:16 +0400 |
| commit | cca3fc80042dfa7942cfcf368cf949776367432e (patch) | |
| tree | d10cd0d06cf26c8eb0f9410067442ca7d54b273d /main.py | |
Initial commit
Diffstat (limited to 'main.py')
| -rw-r--r-- | main.py | 281 |
1 files changed, 281 insertions, 0 deletions
@@ -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]}") |
