├── git_figure.PNG ├── requirements.txt ├── gcn_gru ├── read_data │ ├── belief_feature_500.npy │ ├── adj_epinion_500_index.npy │ ├── epinion_node500_alledges.npy │ ├── uncertainty_feature_500.npy │ └── read_data.py ├── initializations.py ├── metrics.py ├── input_data.py ├── optimizer.py ├── GCN_GRU_run.py ├── GCN_GRU_sparse.py ├── layers.py ├── GRU_cell.py ├── preprocessing.py └── model.py ├── LICENSE └── README.md /git_figure.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxj32/GCN-GRU/HEAD/git_figure.PNG -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | scikit-learn 4 | 5 | networkx 6 | tensorflow-gpu 7 | #tensorflow 8 | -------------------------------------------------------------------------------- /gcn_gru/read_data/belief_feature_500.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxj32/GCN-GRU/HEAD/gcn_gru/read_data/belief_feature_500.npy -------------------------------------------------------------------------------- /gcn_gru/read_data/adj_epinion_500_index.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxj32/GCN-GRU/HEAD/gcn_gru/read_data/adj_epinion_500_index.npy -------------------------------------------------------------------------------- /gcn_gru/read_data/epinion_node500_alledges.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxj32/GCN-GRU/HEAD/gcn_gru/read_data/epinion_node500_alledges.npy -------------------------------------------------------------------------------- /gcn_gru/read_data/uncertainty_feature_500.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zxj32/GCN-GRU/HEAD/gcn_gru/read_data/uncertainty_feature_500.npy -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xujiang Zhao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /gcn_gru/initializations.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | 4 | def weight_variable_glorot(input_dim, output_dim, name=""): 5 | """Create a weight variable with Glorot & Bengio (AISTATS 2010) 6 | initialization. 7 | """ 8 | init_range = np.sqrt(6.0 / (input_dim + output_dim)) 9 | # initial = tf.random_uniform([input_dim, output_dim], minval=-init_range, 10 | # maxval=init_range, dtype=tf.float32) 11 | W = tf.get_variable(name=name, shape=[input_dim, output_dim], initializer=tf.random_uniform_initializer(minval=-init_range, 12 | maxval=init_range), dtype=tf.float32) 13 | return W 14 | 15 | 16 | def weight_variable_bisa(output_dim, name=""): 17 | """Create a weight variable with Glorot & Bengio (AISTATS 2010) 18 | initialization. 19 | """ 20 | W = tf.get_variable(name=name, shape=output_dim, initializer=tf.zeros_initializer, dtype=tf.float32) 21 | return W 22 | 23 | 24 | def weight_variable_glorot1(input_dim, output_dim, name=""): 25 | """Create a weight variable with Glorot & Bengio (AISTATS 2010) 26 | initialization. 27 | """ 28 | init_range = np.sqrt(6.0 / (input_dim + output_dim)) 29 | initial = tf.random_uniform([input_dim, output_dim], minval=-init_range, 30 | maxval=init_range, dtype=tf.float32) 31 | return tf.Variable(initial, name=name) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GCN-GRU 2 | 3 | This is a TensorFlow implementation of the GCN-GRU model as described in our paper: 4 | 5 | Xujiang Zhao, Feng Chen, Jin-Hee Cho [Deep Learning for Predicting Dynamic Uncertain Opinions in Network Data], Bigdata (2018) 6 | 7 | GCN-GRU model are end-to-end trainable deep learning models for dynamic uncertain opinions prediction in dynamic network data. 8 | 9 | ![GCN-GRU](git_figure.PNG) 10 | 11 | 12 | ## Installation 13 | 14 | 1. Clone this repository. 15 | ```sh 16 | git clone https://github.com/zxj32/GCN-GRU 17 | cd GCN-GRU 18 | ``` 19 | 20 | 2. Install the dependencies. The code should run with TensorFlow 1.0 and newer. 21 | ```sh 22 | pip install -r requirements.txt # or make install 23 | ``` 24 | 25 | ## Requirements 26 | * TensorFlow (1.0 or later) 27 | * python 2.7 28 | * networkx 29 | * scikit-learn 30 | * scipy 31 | 32 | ## Run the demo 33 | 34 | ```bash 35 | python GCN_GRU_run.py 36 | ``` 37 | If your graph is very large, please use 38 | 39 | ```bash 40 | python GCN_GRU_sparse.py 41 | ``` 42 | ## Data 43 | 44 | In order to use your own data, you have to provide 45 | * an N by N adjacency matrix (N is the number of nodes), and 46 | * an N by L by T ground truth matrix (L is the dimension of label per node, T is time length) 47 | * an N by D by T feature matrix (D is the number of features per node, T is time length) -- optional (if you don't have feature, our model will use the indentity matrix as default feature) 48 | 49 | Have a look at the `generate_train_test_epinion() or generate_train_test_epinion_sparse()` function in `read_data/read_data.py` for an example. 50 | 51 | In this example, we load epinion data with a subgraph 500 nodes. The original datasets can be found here:http://www.trustlet.org/downloaded 52 | 53 | 54 | ## Models 55 | 56 | For now, you can only choose the following model: 57 | * `GCN-GRU`: GCN_GRU_run.py 58 | * `GCN-GRU (sparse)`: GCN_GRU_sparse.py 59 | 60 | I will upload the other baseline models later. 61 | 62 | ## Question 63 | 64 | If you have any question, please feel free to contact me. Email is good for me. 65 | 66 | ## Cite 67 | 68 | Please cite our paper if you use this code in your own work: 69 | 70 | ``` 71 | @inproceedings{zhao2018deep, 72 | title={Deep Learning for Predicting Dynamic Uncertain Opinions in Network Data}, 73 | author={Zhao, Xujiang and Chen, Feng and Cho, Jin-Hee}, 74 | booktitle={2018 IEEE International Conference on Big Data (Big Data)}, 75 | pages={1150--1155}, 76 | year={2018}, 77 | organization={IEEE} 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /gcn_gru/metrics.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | def masked_mse_square(preds, labels, mask): 5 | """Softmax cross-entropy loss with masking.""" 6 | # loss = tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=labels) 7 | # loss = tf.square(preds - labels) 8 | loss = tf.square(preds - labels) 9 | mask = tf.cast(mask, dtype=tf.float32) 10 | mask /= tf.reduce_mean(mask) 11 | loss *= mask 12 | return tf.reduce_mean(loss) 13 | 14 | 15 | def masked_accuracy(preds, labels, mask): 16 | """Accuracy with masking.""" 17 | correct_prediction = tf.equal(tf.argmax(preds, 1), tf.argmax(labels, 1)) 18 | accuracy_all = tf.cast(correct_prediction, tf.float32) 19 | mask = tf.cast(mask, dtype=tf.float32) 20 | mask /= tf.reduce_mean(mask) 21 | accuracy_all *= mask 22 | return tf.reduce_mean(accuracy_all) 23 | 24 | 25 | def masked_mse_abs(preds, labels, mask): 26 | """ MSE with masking.""" 27 | # loss = tf.nn.softmax_cross_entropy_with_logits(logits=preds, labels=labels) 28 | # loss = tf.square(preds - labels) 29 | # preds = tf.reduce_mean(preds, axis=1) 30 | loss = tf.abs(preds - labels) 31 | mask = tf.cast(mask, dtype=tf.float32) 32 | mask /= tf.reduce_mean(mask) 33 | loss *= mask 34 | return tf.reduce_mean(loss) 35 | 36 | 37 | def masked_decode(preds, mask): 38 | """MSE decode with masking.""" 39 | mask = tf.cast(mask, dtype=tf.float32) 40 | loss = mask - preds 41 | mask /= tf.reduce_mean(mask) 42 | loss = loss * mask 43 | return tf.reduce_mean(loss) 44 | 45 | 46 | def masked_decode_sparse(pred, adj): 47 | logits = tf.convert_to_tensor(pred, name="logits") 48 | targets = tf.convert_to_tensor(adj, name="targets") 49 | # targets = tf.reshape(targets, [70317, 70317]) 50 | try: 51 | targets.get_shape().merge_with(logits.get_shape()) 52 | except ValueError: 53 | raise ValueError( 54 | "logits and targets must have the same shape (%s vs %s)" % 55 | (logits.get_shape(), targets.get_shape())) 56 | loss = targets - logits 57 | targets /= tf.reduce_mean(targets) 58 | loss = loss * targets 59 | return tf.reduce_mean(loss) 60 | 61 | 62 | def masked_mae_rnn(preds, labels, mask): 63 | loss = tf.abs(preds - labels) 64 | mask = tf.cast(mask, dtype=tf.float32) 65 | mask /= tf.reduce_mean(mask) 66 | loss *= mask 67 | return tf.reduce_mean(loss) 68 | 69 | 70 | def masked_mse_rnn(preds, labels, mask): 71 | loss = tf.square(preds - labels) 72 | mask = tf.cast(mask, dtype=tf.float32) 73 | mask /= tf.reduce_mean(mask) 74 | loss *= mask 75 | return tf.reduce_mean(loss) -------------------------------------------------------------------------------- /gcn_gru/input_data.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pickle as pkl 3 | import networkx as nx 4 | import scipy.sparse as sp 5 | 6 | 7 | def parse_index_file(filename): 8 | index = [] 9 | for line in open(filename): 10 | index.append(int(line.strip())) 11 | return index 12 | 13 | 14 | def load_data(dataset): 15 | # load the data: x, tx, allx, graph 16 | names = ['x', 'tx', 'allx', 'graph'] 17 | objects = [] 18 | for i in range(len(names)): 19 | objects.append(pkl.load(open("data/ind.{}.{}".format(dataset, names[i])))) 20 | x, tx, allx, graph = tuple(objects) 21 | test_idx_reorder = parse_index_file("data/ind.{}.test.index".format(dataset)) 22 | test_idx_range = np.sort(test_idx_reorder) 23 | 24 | if dataset == 'citeseer': 25 | # Fix citeseer dataset (there are some isolated nodes in the graph) 26 | # Find isolated nodes, add them as zero-vecs into the right position 27 | test_idx_range_full = range(min(test_idx_reorder), max(test_idx_reorder) + 1) 28 | tx_extended = sp.lil_matrix((len(test_idx_range_full), x.shape[1])) 29 | tx_extended[test_idx_range - min(test_idx_range), :] = tx 30 | tx = tx_extended 31 | 32 | features = sp.vstack((allx, tx)).tolil() 33 | features[test_idx_reorder, :] = features[test_idx_range, :] 34 | adj = nx.adjacency_matrix(nx.from_dict_of_lists(graph)) 35 | 36 | return adj, features 37 | 38 | 39 | def load_data_epinion(): 40 | adj = np.load("./traffic_data/epinion_node1000_alledges.npy") 41 | # adj_mask = np.load("./data/adjacency_matrix_dc_milcom.npy") 42 | features = sp.identity(len(adj)) 43 | # adj_mask = np.reshape(adj_mask, [-1]) 44 | adj = sp.csr_matrix(adj) 45 | return adj, features 46 | 47 | def load_data_1(): 48 | adj = np.load("./data/adjacency_matrix_ph_milcom.npy") 49 | # adj_mask = np.load("./data/adjacency_matrix_dc_milcom.npy") 50 | features = sp.identity(len(adj)) 51 | # adj_mask = np.reshape(adj_mask, [-1]) 52 | adj = sp.csr_matrix(adj) 53 | return adj, features 54 | 55 | 56 | def load_data_dc(): 57 | adj = np.load("./data/adjacency_matrix_dc_milcom.npy") 58 | # adj_mask = np.load("./data/adjacency_matrix_dc_milcom.npy") 59 | features = sp.identity(len(adj)) 60 | # adj_mask = np.reshape(adj_mask, [-1]) 61 | adj = sp.csr_matrix(adj) 62 | return adj, features 63 | 64 | def load_data_before(): 65 | adj = np.load("./data/adjacency_matrix_dc_milcom.npy") 66 | # adj_mask = np.load("./data/adjacency_matrix_dc_milcom.npy") 67 | features = sp.identity(len(adj)) 68 | # adj_mask = np.reshape(adj_mask, [-1]) 69 | adj = sp.csr_matrix(adj) 70 | return adj, features 71 | 72 | 73 | def load_data_beijing(): 74 | adj = sp.load_npz("./traffic_data/adj_undirect_beijing_sparse.npz") 75 | # adj = np.load("./traffic_data/adj_undirect_beijing.npy") 76 | # adj_mask = np.load("./traffic_data/adj_undirect_beijing.npy") 77 | # adj_mask = np.reshape(adj_mask, [-1]) 78 | # adj_mask = sp.csr_matrix(adj_mask) 79 | 80 | features = sp.identity(adj.shape[0]) 81 | # adj = sp.csr_matrix(adj) 82 | return adj, features 83 | -------------------------------------------------------------------------------- /gcn_gru/optimizer.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from gcn_gru.metrics import * 3 | 4 | flags = tf.app.flags 5 | FLAGS = flags.FLAGS 6 | 7 | 8 | 9 | class OptimizerRNN(object): 10 | def __init__(self, model, label_b, label_un, mask): 11 | self.cost = 0.0 12 | self.cost_belief = masked_mae_rnn(model.outputs_b, label_b, mask) 13 | self.cost_uncertain = masked_mae_rnn(model.outputs_u, label_un, mask) 14 | 15 | self.optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.learning_rate) # Adam Optimizer 16 | 17 | # Latent loss 18 | self.log_lik = self.cost 19 | 20 | self.cost = self.cost_belief + self.cost_uncertain 21 | self.opt_op = self.optimizer.minimize(self.cost) 22 | 23 | 24 | 25 | class OptimizerRNN_ori2(object): 26 | def __init__(self, model, label_b, label_un, mask): 27 | self.cost = 0.0 28 | self.cost_belief = masked_mae_rnn(model.outputs_b, label_b, mask) 29 | self.cost_belief_s = masked_mse_rnn(model.outputs_b, label_b, mask) 30 | self.cost_uncertain = masked_mae_rnn(model.outputs_u, label_un, mask) 31 | self.cost_uncertain_s = masked_mse_rnn(model.outputs_u, label_un, mask) 32 | self.optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.learning_rate) # Adam Optimizer 33 | 34 | # Latent loss 35 | self.log_lik = self.cost 36 | self.cost = self.cost_belief + self.cost_uncertain 37 | self.opt_op = self.optimizer.minimize(self.cost_belief_s + self.cost_uncertain_s) 38 | 39 | 40 | class OptimizerRNN_ori(object): 41 | def __init__(self, model, label_b, label_un, mask): 42 | self.cost = 0.0 43 | self.cost_belief = masked_mae_rnn(model.outputs_b, label_b, mask) 44 | self.cost_belief_s = masked_mse_rnn(model.outputs_b, label_b, mask) 45 | self.optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.learning_rate) # Adam Optimizer 46 | 47 | # Latent loss 48 | self.log_lik = self.cost 49 | # self.kl = (0.5 / num_nodes) * tf.reduce_mean(tf.reduce_sum(1 + 2 * model.z_log_std - tf.square(model.z_mean) - 50 | # tf.square(tf.exp(model.z_log_std)), 1)) 51 | # self.cost -= self.kl 52 | # self.cost = self.cost_uncertain 53 | self.cost = self.cost_belief 54 | self.opt_op = self.optimizer.minimize(self.cost_belief_s ) 55 | 56 | 57 | class OptimizerGCN_ori(object): 58 | def __init__(self, model, label_b, label_un, mask): 59 | self.cost = 0.0 60 | self.cost_belief = masked_mae_rnn(model.belief, label_b, mask) 61 | self.cost_uncertain = masked_mae_rnn(model.uncertainty, label_un, mask) 62 | self.cost_belief_s = masked_mae_rnn(model.belief, label_b, mask) 63 | self.cost_uncertain_s = masked_mse_rnn(model.uncertainty, label_un, mask) 64 | self.optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.learning_rate) # Adam Optimizer 65 | 66 | # Latent loss 67 | self.log_lik = self.cost 68 | self.cost = self.cost_belief_s + self.cost_uncertain_s 69 | self.opt_op = self.optimizer.minimize(self.cost) 70 | -------------------------------------------------------------------------------- /gcn_gru/GCN_GRU_run.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from __future__ import print_function 3 | 4 | import time 5 | import os 6 | 7 | # Train on CPU (hide GPU) due to memory constraints 8 | os.environ['CUDA_VISIBLE_DEVICES'] = "0" 9 | 10 | import tensorflow as tf 11 | import numpy as np 12 | import scipy.sparse as sp 13 | import random 14 | from sklearn.metrics import roc_auc_score 15 | from sklearn.metrics import average_precision_score 16 | 17 | from gcn_gru.optimizer import OptimizerAE, OptimizerVAE, OptimizerRNN 18 | from gcn_gru.model import GCNModelAE, GCNModelVAE, GCNModelRNN, GCNModelRNN_ori 19 | from gcn_gru.preprocessing import preprocess_graph, construct_feed_dict_rnn, sparse_to_tuple, mask_test_edge_opinion 20 | from gcn_gru.read_data.read_data import generate_train_test_epinion 21 | 22 | # Settings 23 | flags = tf.app.flags 24 | FLAGS = flags.FLAGS 25 | flags.DEFINE_float('learning_rate', 0.005, 'Initial learning rate.') 26 | flags.DEFINE_integer('epochs', 3000, 'Number of epochs to train.') 27 | flags.DEFINE_integer('hidden_units', 10, 'Number of units in hidden layer 1.') 28 | flags.DEFINE_float('dropout', 0.2, 'Dropout rate (1 - keep probability).') 29 | flags.DEFINE_integer('features', 0, 'Whether to use features (1) or not (0).') 30 | flags.DEFINE_float('test_ratio', 0.2, 'test number of dataset.') 31 | flags.DEFINE_float('noise', 0.1, 'noise of synthetic data.') 32 | flags.DEFINE_integer('bias', 0, 'bias.') 33 | flags.DEFINE_integer('node', 500, 'node size.') 34 | 35 | seed = 1 36 | np.random.seed(seed) 37 | tf.set_random_seed(seed) 38 | random.seed(seed) 39 | 40 | print("seed:", seed, "hidden_units:", FLAGS.hidden_units, "dropout:", FLAGS.dropout, "test_ratio:", FLAGS.test_ratio, "noise:", FLAGS.noise, "bias:", FLAGS.bias, "node:", FLAGS.node) 41 | 42 | # adj, label_b, label_u, train_mask, test_mask = generate_train_test_epinion_noise(FLAGS.test_ratio, FLAGS.node, FLAGS.noise) 43 | adj, label_b, label_u, train_mask, test_mask = generate_train_test_epinion(FLAGS.test_ratio, FLAGS.node) 44 | 45 | features = [] 46 | if FLAGS.features == 0: 47 | # features = sp.identity(y_test_belief.shape[0]) # featureless 48 | for i in range(label_b.shape[1]): 49 | features.append(np.identity(adj.shape[0])) 50 | features = np.reshape(features, [1, label_b.shape[1], adj.shape[0] * adj.shape[0]]) 51 | 52 | # Some preprocessing 53 | adj_norm = preprocess_graph(adj) 54 | 55 | # Define placeholders 56 | placeholders = { 57 | 'features': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], adj.shape[0] * adj.shape[0])), 58 | 'adj': tf.sparse_placeholder(tf.float32), 59 | 'dropout': tf.placeholder_with_default(0., shape=()), 60 | 'labels_b': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], label_b.shape[2])), 61 | 'labels_un': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], label_b.shape[2])), 62 | 'labels_mask': tf.placeholder(tf.int32) 63 | } 64 | 65 | num_nodes = adj.shape[0] 66 | 67 | # Create model 68 | 69 | model = GCNModelRNN(placeholders, num_nodes, bias=FLAGS.bias) 70 | 71 | # Optimizer 72 | with tf.name_scope('optimizer'): 73 | opt = OptimizerRNN(model=model, label_b=placeholders['labels_b'], label_un=placeholders['labels_un'], 74 | mask=placeholders['labels_mask']) 75 | 76 | # Initialize session 77 | config = tf.ConfigProto() 78 | config.gpu_options.allow_growth = True 79 | # sess = tf.Session(config=config) 80 | sess = tf.Session() 81 | 82 | for i in range(1): 83 | # seed = i 84 | # np.random.seed(seed) 85 | # tf.set_random_seed(seed) 86 | # random.seed(seed) 87 | adj, label_b, label_u, train_mask, test_mask = generate_train_test_epinion(FLAGS.test_ratio, FLAGS.node) 88 | # Train model 89 | sess.run(tf.global_variables_initializer()) 90 | for epoch in range(FLAGS.epochs): 91 | t = time.time() 92 | # Construct feed dictionary 93 | feed_dict = construct_feed_dict_rnn(adj_norm, features, placeholders, label_b, label_u, train_mask) 94 | feed_dict.update({placeholders['dropout']: FLAGS.dropout}) 95 | outs = sess.run([opt.opt_op, opt.cost, model.outputs_b, model.outputs_u], feed_dict=feed_dict) 96 | print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(outs[1]), "time=", 97 | "{:.5f}".format(time.time() - t)) 98 | print("Optimization Finished!") 99 | 100 | feed_dict = construct_feed_dict_rnn(adj_norm, features, placeholders, label_b, label_u, test_mask) 101 | outs = sess.run([opt.cost, opt.cost, opt.cost_belief, opt.cost_uncertain], feed_dict=feed_dict) 102 | test_cost = outs[1] 103 | print("test cost =", "{:.3f}".format(outs[1]), "belief mae =", "{:.3f}".format(outs[2]), "uncertainty mae =", "{:.3f}".format(outs[3])) 104 | -------------------------------------------------------------------------------- /gcn_gru/GCN_GRU_sparse.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | from __future__ import print_function 3 | 4 | import time 5 | import os 6 | 7 | # Train on CPU (hide GPU) due to memory constraints 8 | os.environ['CUDA_VISIBLE_DEVICES'] = "1" 9 | 10 | import tensorflow as tf 11 | import numpy as np 12 | import scipy.sparse as sp 13 | import random 14 | from sklearn.metrics import roc_auc_score 15 | from sklearn.metrics import average_precision_score 16 | 17 | from gcn_gru.optimizer import OptimizerRNN 18 | from gcn_gru.input_data import load_data, load_data_1 19 | from gcn_gru.model import GCNModelRNN, GCNModelRNN_ori, GCNModelRNN_sparse 20 | from gcn_gru.preprocessing import preprocess_graph, construct_feed_dict_rnn, sparse_to_tuple, construct_feed_dict_rnn_sparse 21 | from gcn_gru.read_data.read_data import generate_train_test_epinion_sparse 22 | 23 | # Settings 24 | flags = tf.app.flags 25 | FLAGS = flags.FLAGS 26 | flags.DEFINE_float('learning_rate', 0.005, 'Initial learning rate.') 27 | flags.DEFINE_integer('epochs', 1000, 'Number of epochs to train.') 28 | flags.DEFINE_integer('hidden_units', 10, 'Number of units in hidden layer 1.') 29 | flags.DEFINE_float('dropout', 0.2, 'Dropout rate (1 - keep probability).') 30 | flags.DEFINE_integer('features', 0, 'Whether to use features (1) or not (0).') 31 | flags.DEFINE_float('test_ratio', 0.2, 'test number of dataset.') 32 | flags.DEFINE_float('noise', 0.1, 'noise of synthetic data.') 33 | flags.DEFINE_integer('bias', 0, 'bias.') 34 | flags.DEFINE_integer('node', 5000, 'node size.') 35 | 36 | seed = 1 37 | np.random.seed(seed) 38 | tf.set_random_seed(seed) 39 | random.seed(seed) 40 | 41 | print("seed:", seed, "hidden_units:", FLAGS.hidden_units, "dropout:", FLAGS.dropout, "learning rate:", FLAGS.learning_rate, "test_ratio:", FLAGS.test_ratio, "noise:", FLAGS.noise, "bias:", FLAGS.bias, "node:", FLAGS.node) 42 | 43 | adj, label_b, label_u, train_mask, test_mask = generate_train_test_epinion_sparse(FLAGS.test_ratio, FLAGS.node) 44 | 45 | features = [] 46 | if FLAGS.features == 0: 47 | # features = sp.identity(y_test_belief.shape[0]) # featureless 48 | # for i in range(label_b.shape[1]): 49 | # features.append(np.identity(adj.shape[0])) 50 | features = np.ones([1, label_b.shape[1], 10]) 51 | 52 | indices = [[x, x] for x in range(adj.shape[0])] 53 | values = np.ones(adj.shape[0]) 54 | 55 | adj_norm = preprocess_graph(adj) 56 | 57 | # Define placeholders 58 | placeholders = { 59 | 'features': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], 10)), 60 | # 'features_rnn': tf.sparse_placeholder(tf.float32), 61 | 'index': tf.placeholder(tf.int64, shape=(adj.shape[0], 2)), 62 | 'value': tf.placeholder(tf.float32, shape=(adj.shape[0])), 63 | 'adj': tf.sparse_placeholder(tf.float32), 64 | 'dropout': tf.placeholder_with_default(0., shape=()), 65 | 'labels_b': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], label_b.shape[2])), 66 | 'labels_un': tf.placeholder(tf.float32, shape=(1, label_b.shape[1], label_b.shape[2])), 67 | 'labels_mask': tf.placeholder(tf.int32) 68 | } 69 | 70 | num_nodes = adj.shape[0] 71 | 72 | # Create model 73 | 74 | model = GCNModelRNN_sparse(placeholders, num_nodes, bias=FLAGS.bias) 75 | 76 | # Optimizer 77 | with tf.name_scope('optimizer'): 78 | opt = OptimizerRNN(model=model, label_b=placeholders['labels_b'], label_un=placeholders['labels_un'], 79 | mask=placeholders['labels_mask']) 80 | 81 | # Initialize session 82 | config = tf.ConfigProto() 83 | config.gpu_options.allow_growth = True 84 | sess = tf.Session(config=config) 85 | # sess = tf.Session() 86 | 87 | for i in range(1): 88 | # seed = i 89 | # np.random.seed(seed) 90 | # tf.set_random_seed(seed) 91 | # random.seed(seed) 92 | # Train model 93 | sess.run(tf.global_variables_initializer()) 94 | feed_dict = construct_feed_dict_rnn_sparse(adj_norm, features, placeholders, label_b, label_u, train_mask, indices, 95 | values) 96 | feed_dict.update({placeholders['dropout']: FLAGS.dropout}) 97 | t1 = time.time() 98 | for epoch in range(FLAGS.epochs): 99 | t = time.time() 100 | outs = sess.run([opt.opt_op, opt.cost, model.outputs_b, model.outputs_u, opt.cost_belief, opt.cost_uncertain], feed_dict=feed_dict) 101 | # Compute loss 102 | print("Epoch:", '%04d' % (epoch + 1), "train_loss=", "{:.5f}".format(outs[1]), "belief mae =", "{:.3f}".format(outs[4]), "uncertainty mae =", "{:.3f}".format(outs[5]), "time=", 103 | "{:.5f}".format(time.time() - t)) 104 | print("Optimization Finished!") 105 | 106 | feed_dict = construct_feed_dict_rnn(adj_norm, features, placeholders, label_b, label_u, test_mask) 107 | outs = sess.run([opt.cost, opt.cost, opt.cost_belief, opt.cost_uncertain], feed_dict=feed_dict) 108 | test_cost = outs[1] 109 | print("test cost =", "{:.3f}".format(outs[1]), "belief mae =", "{:.3f}".format(outs[2]), "uncertainty mae =", "{:.3f}".format(outs[3])) 110 | -------------------------------------------------------------------------------- /gcn_gru/read_data/read_data.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import random 3 | from scipy import sparse 4 | from collections import Counter 5 | 6 | 7 | def add_noise(feat_b, feat_u, test_mask, noise, consis_index): 8 | train_index = [] 9 | conflict_index = [] 10 | noise_num = int(noise * len(feat_b[0])) 11 | 12 | for i in range(len(test_mask)): 13 | train_index_i = [] 14 | test_mask_i = test_mask[i] 15 | for j in range(len(test_mask_i)): 16 | if test_mask_i[j] == False: 17 | train_index_i.append(j) 18 | train_index.append(train_index_i) 19 | 20 | for i in range(len(feat_b)): 21 | consis_index_i = consis_index[i] 22 | train_index_i = train_index[i] 23 | consis_train_index_i = [element for element in train_index_i if element in consis_index_i] 24 | consis_train_index_i = train_index_i 25 | conflict_index_i = random.sample(consis_train_index_i, noise_num) 26 | conflict_index.append(conflict_index_i) 27 | for k in conflict_index_i: 28 | feat_b[i][k] = 1.0 - feat_b[i][k] - feat_u[i][k] 29 | return feat_b 30 | 31 | 32 | def get_mask(num_node, num_test): 33 | test_index = random.sample(range(num_node), num_test) 34 | train_mask = np.ones(num_node, dtype=bool) 35 | test_mask = np.zeros(num_node, dtype=bool) 36 | for i in test_index: 37 | test_mask[i] = True 38 | train_mask[i] = False 39 | return train_mask, test_mask 40 | 41 | def generate_train_test_epinion_noise(test_ratio, node, noise): 42 | adj_n = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_ICDM2018/gae/traffic_data/epinion_node{}_alledges.npy".format(node)) 43 | b_all = np.load("/network/rit/lab/ceashpc/xujiang/eopinion_data/feature/belief_feature_{}.npy".format(node)) 44 | u_all = np.load("/network/rit/lab/ceashpc/xujiang/eopinion_data/feature/uncertainty_feature_{}.npy".format(node)) 45 | consis_index = np.load("/network/rit/lab/ceashpc/xujiang/eopinion_data/feature/consis_index_{}.npy".format(node)) 46 | # consis_index = get_consistent_index(b_all, adj_n) 47 | train_mask = [] 48 | test_mask = [] 49 | num_edge = b_all.shape[1] 50 | test_num = int(test_ratio * num_edge) 51 | for i in range(len(b_all)): 52 | train_mask_i, test_mask_i = get_mask(num_edge, test_num) 53 | train_mask.append(train_mask_i) 54 | test_mask.append(test_mask_i) 55 | b_all = add_noise(b_all, u_all, test_mask, noise, consis_index) 56 | train_feature_b = np.array(b_all) 57 | train_feature_u = np.array(u_all) 58 | train_mask = np.reshape(train_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 59 | test_mask = np.reshape(test_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 60 | train_feature_b = np.reshape(train_feature_b, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 61 | train_feature_u = np.reshape(train_feature_u, [1, train_feature_u.shape[0], train_feature_u.shape[1]]) 62 | 63 | adj = sparse.csr_matrix(adj_n) 64 | return adj, train_feature_b, train_feature_u, train_mask, test_mask 65 | 66 | 67 | def generate_train_test_epinion(test_ratio, node): 68 | adj_n = np.load("read_data/epinion_node{}_alledges.npy".format(node)) 69 | b_all = np.load("read_data/belief_feature_{}.npy".format(node)) 70 | u_all = np.load("read_data/uncertainty_feature_{}.npy".format(node)) 71 | train_mask = [] 72 | test_mask = [] 73 | num_edge = b_all.shape[1] 74 | test_num = int(test_ratio * num_edge) 75 | for i in range(len(b_all)): 76 | train_mask_i, test_mask_i = get_mask(num_edge, test_num) 77 | train_mask.append(train_mask_i) 78 | test_mask.append(test_mask_i) 79 | train_feature_b = np.array(b_all) 80 | train_feature_u = np.array(u_all) 81 | train_mask = np.reshape(train_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 82 | test_mask = np.reshape(test_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 83 | train_feature_b = np.reshape(train_feature_b, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 84 | train_feature_u = np.reshape(train_feature_u, [1, train_feature_u.shape[0], train_feature_u.shape[1]]) 85 | 86 | adj = sparse.csr_matrix(adj_n) 87 | return adj, train_feature_b, train_feature_u, train_mask, test_mask 88 | 89 | def generate_train_test_epinion_noise_sparse(test_ratio, node, noise): 90 | adj_index = np.load("read_data/adj_epinion_{}_index.npy".format(node)) 91 | b_all = np.load("read_data/belief_feature_{}.npy".format(node)) 92 | u_all = np.load("read_data/uncertainty_feature_{}.npy".format(node)) 93 | train_mask = [] 94 | test_mask = [] 95 | num_edge = b_all.shape[1] 96 | test_num = int(test_ratio * num_edge) 97 | for i in range(len(b_all)): 98 | train_mask_i, test_mask_i = get_mask(num_edge, test_num) 99 | train_mask.append(train_mask_i) 100 | test_mask.append(test_mask_i) 101 | train_feature_b = np.array(b_all) 102 | train_feature_u = np.array(u_all) 103 | train_mask = np.reshape(train_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 104 | test_mask = np.reshape(test_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 105 | train_feature_b = np.reshape(train_feature_b, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 106 | train_feature_u = np.reshape(train_feature_u, [1, train_feature_u.shape[0], train_feature_u.shape[1]]) 107 | row = adj_index[:, 0] 108 | col = adj_index[:, 1] 109 | print(np.max(row), np.max(col)) 110 | value = np.ones(len(adj_index)) 111 | adj = sparse.coo_matrix((value, (row, col)), shape=(num_edge, num_edge)) 112 | return adj, train_feature_b, train_feature_u, train_mask, test_mask 113 | 114 | def generate_train_test_epinion_sparse(test_ratio, node): 115 | adj_index = np.load("read_data/adj_epinion_{}_index.npy".format(node)) 116 | b_all = np.load("read_data/belief_feature_{}.npy".format(node)) 117 | u_all = np.load("read_data/uncertainty_feature_{}.npy".format(node)) 118 | train_mask = [] 119 | test_mask = [] 120 | num_edge = b_all.shape[1] 121 | test_num = int(test_ratio * num_edge) 122 | for i in range(len(b_all)): 123 | train_mask_i, test_mask_i = get_mask(num_edge, test_num) 124 | train_mask.append(train_mask_i) 125 | test_mask.append(test_mask_i) 126 | train_feature_b = np.array(b_all) 127 | train_feature_u = np.array(u_all) 128 | train_mask = np.reshape(train_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 129 | test_mask = np.reshape(test_mask, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 130 | train_feature_b = np.reshape(train_feature_b, [1, train_feature_b.shape[0], train_feature_b.shape[1]]) 131 | train_feature_u = np.reshape(train_feature_u, [1, train_feature_u.shape[0], train_feature_u.shape[1]]) 132 | row = adj_index[:, 0] 133 | col = adj_index[:, 1] 134 | print(np.max(row), np.max(col)) 135 | value = np.ones(len(adj_index)) 136 | adj = sparse.coo_matrix((value, (row, col)), shape=(num_edge, num_edge)) 137 | return adj, train_feature_b, train_feature_u, train_mask, test_mask 138 | 139 | -------------------------------------------------------------------------------- /gcn_gru/layers.py: -------------------------------------------------------------------------------- 1 | from gcn_gru.initializations import * 2 | import tensorflow as tf 3 | 4 | flags = tf.app.flags 5 | FLAGS = flags.FLAGS 6 | 7 | # global unique layer ID dictionary for layer name assignment 8 | _LAYER_UIDS = {} 9 | 10 | 11 | def get_layer_uid(layer_name=''): 12 | """Helper function, assigns unique layer IDs 13 | """ 14 | if layer_name not in _LAYER_UIDS: 15 | _LAYER_UIDS[layer_name] = 1 16 | return 1 17 | else: 18 | _LAYER_UIDS[layer_name] += 1 19 | return _LAYER_UIDS[layer_name] 20 | 21 | 22 | def dropout_sparse(x, keep_prob, num_nonzero_elems): 23 | """Dropout for sparse tensors. Currently fails for very large sparse tensors (>1M elements) 24 | """ 25 | noise_shape = [num_nonzero_elems] 26 | random_tensor = keep_prob 27 | random_tensor += tf.random_uniform(noise_shape) 28 | dropout_mask = tf.cast(tf.floor(random_tensor), dtype=tf.bool) 29 | pre_out = tf.sparse_retain(x, dropout_mask) 30 | return pre_out * (1. / keep_prob) 31 | 32 | 33 | class Layer(object): 34 | """Base layer class. Defines basic API for all layer objects. 35 | 36 | # Properties 37 | name: String, defines the variable scope of the layer. 38 | 39 | # Methods 40 | _call(inputs): Defines computation graph of layer 41 | (i.e. takes input, returns output) 42 | __call__(inputs): Wrapper for _call() 43 | """ 44 | 45 | def __init__(self, **kwargs): 46 | allowed_kwargs = {'name', 'logging'} 47 | for kwarg in kwargs.keys(): 48 | assert kwarg in allowed_kwargs, 'Invalid keyword argument: ' + kwarg 49 | name = kwargs.get('name') 50 | if not name: 51 | layer = self.__class__.__name__.lower() 52 | name = layer + '_' + str(get_layer_uid(layer)) 53 | self.name = name 54 | self.vars = {} 55 | logging = kwargs.get('logging', False) 56 | self.logging = logging 57 | self.issparse = False 58 | 59 | def _call(self, inputs): 60 | return inputs 61 | 62 | def __call__(self, inputs): 63 | with tf.name_scope(self.name): 64 | outputs = self._call(inputs) 65 | return outputs 66 | 67 | 68 | class GraphConvolution_saprse(Layer): 69 | """Basic graph convolution layer for undirected graph without edge labels.""" 70 | 71 | def __init__(self, input_dim, output_dim, adj, dropout, non_zero, act=tf.nn.sigmoid, bias=False, **kwargs): 72 | super(GraphConvolution_saprse, self).__init__(**kwargs) 73 | self.bias = bias 74 | with tf.variable_scope(self.name + '_vars'): 75 | self.vars['weights'] = weight_variable_glorot(input_dim, output_dim, name="weights") 76 | if self.bias: 77 | self.vars['bias'] = weight_variable_bisa([output_dim], name='bias') 78 | self.dropout = dropout 79 | self.num_features_nonzero = non_zero 80 | self.adj = adj 81 | self.act = act 82 | 83 | def _call(self, inputs): 84 | x = inputs 85 | # x = tf.nn.dropout(x, 1 - self.dropout) 86 | x = dropout_sparse(x, 1 - self.dropout, self.num_features_nonzero) 87 | # x = tf.matmul(x, self.vars['weights']) 88 | x = tf.sparse_tensor_dense_matmul(x, self.vars['weights']) 89 | x = tf.sparse_tensor_dense_matmul(self.adj, x) 90 | outputs = x 91 | # bias 92 | if self.bias: 93 | outputs += self.vars['bias'] 94 | return self.act(outputs) 95 | 96 | 97 | class GraphConvolution(Layer): 98 | """Basic graph convolution layer for undirected graph without edge labels.""" 99 | 100 | def __init__(self, input_dim, output_dim, adj, dropout=0., act=tf.nn.sigmoid, bias=False, **kwargs): 101 | super(GraphConvolution, self).__init__(**kwargs) 102 | self.bias = bias 103 | with tf.variable_scope(self.name + '_vars'): 104 | self.vars['weights'] = weight_variable_glorot(input_dim, output_dim, name="weights") 105 | if self.bias: 106 | self.vars['bias'] = weight_variable_bisa([output_dim], name='bias') 107 | self.dropout = dropout 108 | self.adj = adj 109 | self.act = act 110 | 111 | def _call(self, inputs): 112 | x = inputs 113 | x = tf.nn.dropout(x, 1 - self.dropout) 114 | x = tf.matmul(x, self.vars['weights']) 115 | # x = tf.sparse_tensor_dense_matmul(x, self.vars['weights']) 116 | x = tf.sparse_tensor_dense_matmul(self.adj, x) 117 | outputs = x 118 | # bias 119 | if self.bias: 120 | outputs += self.vars['bias'] 121 | return self.act(outputs) 122 | 123 | class Graph_matual(Layer): 124 | """Basic graph convolution layer for undirected graph without edge labels.""" 125 | 126 | def __init__(self, input_dim, output_dim, adj, dropout=0., act=tf.nn.sigmoid, bias=False, **kwargs): 127 | super(Graph_matual, self).__init__(**kwargs) 128 | self.bias = bias 129 | with tf.variable_scope(self.name + '_vars'): 130 | self.vars['weights'] = weight_variable_glorot(input_dim, output_dim, name="weights") 131 | if self.bias: 132 | self.vars['bias'] = weight_variable_bisa([output_dim], name='bias') 133 | self.dropout = dropout 134 | self.adj = adj 135 | self.act = act 136 | 137 | def _call(self, inputs): 138 | x = inputs 139 | x = tf.nn.dropout(x, 1 - self.dropout) 140 | x = tf.matmul(x, self.vars['weights']) 141 | outputs = x 142 | # bias 143 | if self.bias: 144 | outputs += self.vars['bias'] 145 | return self.act(outputs) 146 | 147 | 148 | class GraphConvolutionSparse(Layer): 149 | """Graph convolution layer for sparse inputs.""" 150 | 151 | def __init__(self, input_dim, output_dim, adj, features_nonzero, dropout=0., act=tf.nn.relu, **kwargs): 152 | super(GraphConvolutionSparse, self).__init__(**kwargs) 153 | with tf.variable_scope(self.name + '_vars'): 154 | self.vars['weights'] = weight_variable_glorot(input_dim, output_dim, name="weights") 155 | self.dropout = dropout 156 | self.adj = adj 157 | self.act = act 158 | self.issparse = True 159 | self.features_nonzero = features_nonzero 160 | 161 | def _call(self, inputs): 162 | x = inputs 163 | x = dropout_sparse(x, 1 - self.dropout, self.features_nonzero) 164 | x = tf.sparse_tensor_dense_matmul(x, self.vars['weights']) 165 | x = tf.sparse_tensor_dense_matmul(self.adj, x) 166 | outputs = self.act(x) 167 | return outputs 168 | 169 | 170 | class InnerProductDecoder(Layer): 171 | """Decoder model layer for link prediction.""" 172 | 173 | def __init__(self, input_dim, dropout=0., act=tf.nn.sigmoid, **kwargs): 174 | super(InnerProductDecoder, self).__init__(**kwargs) 175 | self.dropout = dropout 176 | self.act = act 177 | 178 | def _call(self, inputs): 179 | inputs = tf.nn.dropout(inputs, 1 - self.dropout) 180 | x = tf.transpose(inputs) 181 | x = tf.matmul(inputs, x) 182 | x = tf.reshape(x, [-1]) 183 | outputs = self.act(x) 184 | return outputs 185 | 186 | 187 | class InnerProductDecoder_Opinion(Layer): 188 | """Decoder model layer for link prediction.""" 189 | 190 | def __init__(self, input_dim, dropout=0., act=tf.nn.sigmoid, **kwargs): 191 | super(InnerProductDecoder_Opinion, self).__init__(**kwargs) 192 | self.dropout = dropout 193 | self.act = act 194 | 195 | def _call(self, inputs): 196 | inputs = tf.nn.dropout(inputs, 1 - self.dropout) 197 | x = tf.transpose(inputs) 198 | x = tf.matmul(inputs, x) 199 | x = tf.reshape(x, [-1]) 200 | outputs = self.act(x) 201 | return outputs 202 | -------------------------------------------------------------------------------- /gcn_gru/GRU_cell.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import numpy as np 6 | import tensorflow as tf 7 | 8 | from tensorflow.contrib.rnn import RNNCell 9 | 10 | from tensorflow.python.platform import tf_logging as logging 11 | from gcn_gru.layers import GraphConvolution, Graph_matual, GraphConvolution_saprse 12 | 13 | 14 | class GCNGRUCell_sparse(RNNCell): 15 | """Graph Convolution Gated Recurrent Unit cell. 16 | """ 17 | 18 | def call(self, inputs, **kwargs): 19 | pass 20 | 21 | def _compute_output_shape(self, input_shape): 22 | pass 23 | 24 | def __init__(self, num_units, adj_mx, dropout, num_nodes, index, value, bias, input_size=None, reuse=None): 25 | """ 26 | :param num_units: 27 | :param adj_mx: 28 | :param num_nodes: 29 | :param input_size: 30 | :param reuse: 31 | """ 32 | super(GCNGRUCell_sparse, self).__init__(_reuse=reuse) 33 | if input_size is not None: 34 | logging.warn("%s: The input_size parameter is deprecated.", self) 35 | self._num_nodes = num_nodes 36 | self._num_units = num_units 37 | self.adj = adj_mx 38 | self.dropout = dropout 39 | self.logging = logging 40 | self.bias = bias 41 | # self.index = index 42 | # self.value = value 43 | self.input_rnn = tf.SparseTensor(index, value, [num_nodes, num_nodes]) 44 | 45 | 46 | @property 47 | def state_size(self): 48 | return self._num_nodes * self._num_units 49 | 50 | @property 51 | def output_size(self): 52 | output_size = self._num_nodes * self._num_units 53 | return output_size 54 | 55 | def __call__(self, inputs, state, scope=None): 56 | """Gated recurrent unit (GRU) with Graph Convolution. 57 | :param inputs: (B, num_nodes * input_dim) 58 | 59 | :return 60 | - Output: A `2-D` tensor with shape `[batch_size x self.output_size]`. 61 | - New state: Either a single `2-D` tensor, or a tuple of tensors matching 62 | the arity and shapes of `state` 63 | """ 64 | with tf.variable_scope(scope or "dcgru_cell"): 65 | # inputs = tf.ones([self._num_nodes, self._num_nodes]) 66 | # x_shape = tf.concat([inputs, state], axis=1) 67 | # input_shape = x_shape.get_shape().as_list() 68 | # input_rnn = tf.SparseTensor(self.index, self.value, [self._num_nodes, self._num_nodes]) 69 | state = tf.reshape(state, [self._num_nodes, -1]) 70 | state_shape = state.get_shape().as_list() 71 | input_dim = state_shape[1] + self._num_nodes 72 | 73 | zero = tf.constant(0, dtype=tf.float32) 74 | where = tf.not_equal(state, zero) 75 | indices = tf.where(where) 76 | values = tf.gather_nd(state, indices) 77 | sparse_state = tf.SparseTensor(indices, values, state.shape) 78 | x1 = tf.sparse_concat(sp_inputs=[self.input_rnn, sparse_state], axis=1) 79 | non_zeros_feat = tf.size(x1.values) 80 | with tf.variable_scope("gates"): # Reset gate 81 | # We start with bias of 1.0 to not reset and not update. 82 | r = GraphConvolution_saprse(input_dim=input_dim, 83 | output_dim=self._num_units, 84 | adj=self.adj, 85 | act=tf.nn.sigmoid, 86 | dropout=self.dropout, 87 | non_zero = non_zeros_feat, 88 | bias=self.bias, 89 | logging=self.logging)(x1) 90 | 91 | with tf.variable_scope("gates"): # Update gate 92 | u = GraphConvolution_saprse(input_dim=input_dim, 93 | output_dim=self._num_units, 94 | adj=self.adj, 95 | act=tf.nn.sigmoid, 96 | dropout=self.dropout, 97 | non_zero=non_zeros_feat, 98 | bias=self.bias, 99 | logging=self.logging)(x1) 100 | 101 | with tf.variable_scope("candidate"): 102 | state_r = r * state 103 | where_r = tf.not_equal(state_r, zero) 104 | indices_r = tf.where(where_r) 105 | values_r = tf.gather_nd(state_r, indices_r) 106 | sparse_state_r = tf.SparseTensor(indices_r, values_r, state_r.shape) 107 | x2 = tf.sparse_concat(sp_inputs=[self.input_rnn, sparse_state_r], axis=1) 108 | 109 | c = GraphConvolution_saprse(input_dim=input_dim, 110 | output_dim=self._num_units, 111 | adj=self.adj, 112 | act=tf.nn.sigmoid, 113 | dropout=self.dropout, 114 | non_zero=non_zeros_feat, 115 | bias=self.bias, 116 | logging=self.logging)(x2) 117 | 118 | h = u * state + (1 - u) * c 119 | h = tf.reshape(h, [1, -1]) 120 | output = new_state = h 121 | return output, new_state 122 | 123 | 124 | class GRUCell_ori(RNNCell): 125 | """Graph Convolution Gated Recurrent Unit cell. 126 | """ 127 | 128 | def call(self, inputs, **kwargs): 129 | pass 130 | 131 | def _compute_output_shape(self, input_shape): 132 | pass 133 | 134 | def __init__(self, num_units, adj_mx, dropout, num_nodes, bias, input_size=None, reuse=None): 135 | """ 136 | :param num_units: 137 | :param adj_mx: 138 | :param num_nodes: 139 | :param input_size: 140 | :param reuse: 141 | """ 142 | super(GRUCell_ori, self).__init__(_reuse=reuse) 143 | if input_size is not None: 144 | logging.warn("%s: The input_size parameter is deprecated.", self) 145 | self._num_nodes = num_nodes 146 | self._num_units = num_units 147 | self.adj = adj_mx 148 | self.dropout = dropout 149 | self.logging = logging 150 | self.bias = bias 151 | 152 | @property 153 | def state_size(self): 154 | return self._num_nodes * self._num_units 155 | 156 | @property 157 | def output_size(self): 158 | output_size = self._num_nodes * self._num_units 159 | return output_size 160 | 161 | def __call__(self, inputs, state, scope=None): 162 | """Gated recurrent unit (GRU) with Graph Convolution. 163 | :param inputs: (B, num_nodes * input_dim) 164 | 165 | :return 166 | - Output: A `2-D` tensor with shape `[batch_size x self.output_size]`. 167 | - New state: Either a single `2-D` tensor, or a tuple of tensors matching 168 | the arity and shapes of `state` 169 | """ 170 | with tf.variable_scope(scope or "dcgru_cell"): 171 | inputs = tf.reshape(inputs, [self._num_nodes, -1]) 172 | state = tf.reshape(state, [self._num_nodes, -1]) 173 | x1 = tf.concat([inputs, state], axis=1) 174 | input_shape = x1.get_shape().as_list() 175 | with tf.variable_scope("gates"): # Reset gate 176 | # We start with bias of 1.0 to not reset and not update. 177 | r = Graph_matual(input_dim=input_shape[1], 178 | output_dim=self._num_units, 179 | adj=self.adj, 180 | act=tf.nn.sigmoid, 181 | dropout=self.dropout, 182 | bias=self.bias, 183 | logging=self.logging)(x1) 184 | 185 | with tf.variable_scope("gates"): # Update gate 186 | u = Graph_matual(input_dim=input_shape[1], 187 | output_dim=self._num_units, 188 | adj=self.adj, 189 | act=tf.nn.sigmoid, 190 | dropout=self.dropout, 191 | bias=self.bias, 192 | logging=self.logging)(x1) 193 | 194 | with tf.variable_scope("candidate"): 195 | x2 = tf.concat([inputs, r * state], axis=1) 196 | c = Graph_matual(input_dim=input_shape[1], 197 | output_dim=self._num_units, 198 | adj=self.adj, 199 | act=tf.nn.sigmoid, 200 | dropout=self.dropout, 201 | bias=self.bias, 202 | logging=self.logging)(x2) 203 | 204 | h = u * state + (1 - u) * c 205 | h = tf.reshape(h, [1, -1]) 206 | output = new_state = h 207 | return output, new_state 208 | 209 | 210 | class GCNGRUCell(RNNCell): 211 | """Graph Convolution Gated Recurrent Unit cell. 212 | """ 213 | 214 | def call(self, inputs, **kwargs): 215 | pass 216 | 217 | def _compute_output_shape(self, input_shape): 218 | pass 219 | 220 | def __init__(self, num_units, adj_mx, dropout, num_nodes, bias, input_size=None, reuse=None): 221 | """ 222 | :param num_units: 223 | :param adj_mx: 224 | :param num_nodes: 225 | :param input_size: 226 | :param reuse: 227 | """ 228 | super(GCNGRUCell, self).__init__(_reuse=reuse) 229 | if input_size is not None: 230 | logging.warn("%s: The input_size parameter is deprecated.", self) 231 | self._num_nodes = num_nodes 232 | self._num_units = num_units 233 | self.adj = adj_mx 234 | self.dropout = dropout 235 | self.logging = logging 236 | self.bias = bias 237 | 238 | @property 239 | def state_size(self): 240 | return self._num_nodes * self._num_units 241 | 242 | @property 243 | def output_size(self): 244 | output_size = self._num_nodes * self._num_units 245 | return output_size 246 | 247 | def __call__(self, inputs, state, scope=None): 248 | """Gated recurrent unit (GRU) with Graph Convolution. 249 | :param inputs: (B, num_nodes * input_dim) 250 | 251 | :return 252 | - Output: A `2-D` tensor with shape `[batch_size x self.output_size]`. 253 | - New state: Either a single `2-D` tensor, or a tuple of tensors matching 254 | the arity and shapes of `state` 255 | """ 256 | with tf.variable_scope(scope or "dcgru_cell"): 257 | inputs = tf.reshape(inputs, [self._num_nodes, -1]) 258 | state = tf.reshape(state, [self._num_nodes, -1]) 259 | x1 = tf.concat([inputs, state], axis=1) 260 | input_shape = x1.get_shape().as_list() 261 | with tf.variable_scope("gates"): # Reset gate 262 | # We start with bias of 1.0 to not reset and not update. 263 | r = GraphConvolution(input_dim=input_shape[1], 264 | output_dim=self._num_units, 265 | adj=self.adj, 266 | act=tf.nn.sigmoid, 267 | dropout=self.dropout, 268 | bias=self.bias, 269 | logging=self.logging)(x1) 270 | 271 | with tf.variable_scope("gates"): # Update gate 272 | u = GraphConvolution(input_dim=input_shape[1], 273 | output_dim=self._num_units, 274 | adj=self.adj, 275 | act=tf.nn.sigmoid, 276 | dropout=self.dropout, 277 | bias=self.bias, 278 | logging=self.logging)(x1) 279 | 280 | with tf.variable_scope("candidate"): 281 | x2 = tf.concat([inputs, r * state], axis=1) 282 | c = GraphConvolution(input_dim=input_shape[1], 283 | output_dim=self._num_units, 284 | adj=self.adj, 285 | act=tf.nn.sigmoid, 286 | dropout=self.dropout, 287 | bias=self.bias, 288 | logging=self.logging)(x2) 289 | 290 | h = u * state + (1 - u) * c 291 | h = tf.reshape(h, [1, -1]) 292 | output = new_state = h 293 | return output, new_state -------------------------------------------------------------------------------- /gcn_gru/preprocessing.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | import random 4 | 5 | def sparse_to_tuple(sparse_mx): 6 | if not sp.isspmatrix_coo(sparse_mx): 7 | sparse_mx = sparse_mx.tocoo() 8 | coords = np.vstack((sparse_mx.row, sparse_mx.col)).transpose() 9 | values = sparse_mx.data 10 | shape = sparse_mx.shape 11 | return coords, values, shape 12 | 13 | 14 | def preprocess_graph(adj): 15 | adj = sp.coo_matrix(adj) 16 | adj_ = adj + sp.eye(adj.shape[0]) 17 | rowsum = np.array(adj_.sum(1)) 18 | degree_mat_inv_sqrt = sp.diags(np.power(rowsum, -0.5).flatten()) 19 | adj_normalized = adj_.dot(degree_mat_inv_sqrt).transpose().dot(degree_mat_inv_sqrt).tocoo() 20 | return sparse_to_tuple(adj_normalized) 21 | 22 | 23 | def construct_feed_dict(adj_normalized, adj, features, placeholders, labels_b, label_un, labels_mask, omega, alpha_0, beta_0): 24 | # construct feed dictionary 25 | feed_dict = dict() 26 | feed_dict.update({placeholders['features']: features}) 27 | feed_dict.update({placeholders['adj']: adj_normalized}) 28 | feed_dict.update({placeholders['adj_orig']: adj}) 29 | feed_dict.update({placeholders['labels_b']: labels_b}) 30 | feed_dict.update({placeholders['labels_un']: label_un}) 31 | feed_dict.update({placeholders['labels_mask']: labels_mask}) 32 | feed_dict.update({placeholders['alpha_0']: alpha_0}) 33 | feed_dict.update({placeholders['beta_0']: beta_0}) 34 | feed_dict.update({placeholders['omega_t']: omega}) 35 | return feed_dict 36 | 37 | 38 | def construct_feed_dict_rnn_sparse(adj_normalized, features, placeholders, labels_b, label_un, labels_mask, index, value): 39 | # construct feed dictionary 40 | feed_dict = dict() 41 | feed_dict.update({placeholders['features']: features}) 42 | feed_dict.update({placeholders['adj']: adj_normalized}) 43 | feed_dict.update({placeholders['labels_b']: labels_b}) 44 | feed_dict.update({placeholders['labels_un']: label_un}) 45 | feed_dict.update({placeholders['labels_mask']: labels_mask}) 46 | feed_dict.update({placeholders['index']: index}) 47 | feed_dict.update({placeholders['value']: value}) 48 | return feed_dict 49 | 50 | 51 | def construct_feed_dict_rnn(adj_normalized, features, placeholders, labels_b, label_un, labels_mask): 52 | # construct feed dictionary 53 | feed_dict = dict() 54 | feed_dict.update({placeholders['features']: features}) 55 | feed_dict.update({placeholders['adj']: adj_normalized}) 56 | feed_dict.update({placeholders['labels_b']: labels_b}) 57 | feed_dict.update({placeholders['labels_un']: label_un}) 58 | feed_dict.update({placeholders['labels_mask']: labels_mask}) 59 | return feed_dict 60 | 61 | 62 | def construct_feed_dict_gcnori(adj_normalized, features_b, feature_u, placeholders, labels_b, label_un, labels_mask): 63 | # construct feed dictionary 64 | feed_dict = dict() 65 | feed_dict.update({placeholders['features']: features_b}) 66 | feed_dict.update({placeholders['features_u']: feature_u}) 67 | feed_dict.update({placeholders['adj']: adj_normalized}) 68 | feed_dict.update({placeholders['labels_b']: labels_b}) 69 | feed_dict.update({placeholders['labels_un']: label_un}) 70 | feed_dict.update({placeholders['labels_mask']: labels_mask}) 71 | return feed_dict 72 | 73 | def mask_test_edges(adj): 74 | # Function to build test set with 10% positive links 75 | # NOTE: Splits are randomized and results might slightly deviate from reported numbers in the paper. 76 | # TODO: Clean up. 77 | 78 | # Remove diagonal elements 79 | adj = adj - sp.dia_matrix((adj.diagonal()[np.newaxis, :], [0]), shape=adj.shape) 80 | adj.eliminate_zeros() 81 | # Check that diag is zero: 82 | assert np.diag(adj.todense()).sum() == 0 83 | 84 | adj_triu = sp.triu(adj) 85 | adj_tuple = sparse_to_tuple(adj_triu) 86 | edges = adj_tuple[0] 87 | edges_all = sparse_to_tuple(adj)[0] 88 | num_test = int(np.floor(edges.shape[0] / 10.)) 89 | num_val = int(np.floor(edges.shape[0] / 20.)) 90 | 91 | all_edge_idx = range(edges.shape[0]) 92 | np.random.shuffle(all_edge_idx) 93 | val_edge_idx = all_edge_idx[:num_val] 94 | test_edge_idx = all_edge_idx[num_val:(num_val + num_test)] 95 | test_edges = edges[test_edge_idx] 96 | val_edges = edges[val_edge_idx] 97 | train_edges = np.delete(edges, np.hstack([test_edge_idx, val_edge_idx]), axis=0) 98 | 99 | def ismember(a, b, tol=5): 100 | rows_close = np.all(np.round(a - b[:, None], tol) == 0, axis=-1) 101 | return np.any(rows_close) 102 | 103 | test_edges_false = [] 104 | while len(test_edges_false) < len(test_edges): 105 | idx_i = np.random.randint(0, adj.shape[0]) 106 | idx_j = np.random.randint(0, adj.shape[0]) 107 | if idx_i == idx_j: 108 | continue 109 | if ismember([idx_i, idx_j], edges_all): 110 | continue 111 | if test_edges_false: 112 | if ismember([idx_j, idx_i], np.array(test_edges_false)): 113 | continue 114 | if ismember([idx_i, idx_j], np.array(test_edges_false)): 115 | continue 116 | test_edges_false.append([idx_i, idx_j]) 117 | 118 | val_edges_false = [] 119 | while len(val_edges_false) < len(val_edges): 120 | idx_i = np.random.randint(0, adj.shape[0]) 121 | idx_j = np.random.randint(0, adj.shape[0]) 122 | if idx_i == idx_j: 123 | continue 124 | if ismember([idx_i, idx_j], train_edges): 125 | continue 126 | if ismember([idx_j, idx_i], train_edges): 127 | continue 128 | if ismember([idx_i, idx_j], val_edges): 129 | continue 130 | if ismember([idx_j, idx_i], val_edges): 131 | continue 132 | if val_edges_false: 133 | if ismember([idx_j, idx_i], np.array(val_edges_false)): 134 | continue 135 | if ismember([idx_i, idx_j], np.array(val_edges_false)): 136 | continue 137 | val_edges_false.append([idx_i, idx_j]) 138 | 139 | assert ~ismember(test_edges_false, edges_all) 140 | assert ~ismember(val_edges_false, edges_all) 141 | assert ~ismember(val_edges, train_edges) 142 | assert ~ismember(test_edges, train_edges) 143 | assert ~ismember(val_edges, test_edges) 144 | 145 | data = np.ones(train_edges.shape[0]) 146 | 147 | # Re-build adj matrix 148 | adj_train = sp.csr_matrix((data, (train_edges[:, 0], train_edges[:, 1])), shape=adj.shape) 149 | adj_train = adj_train + adj_train.T 150 | 151 | # NOTE: these edge lists only contain single direction of edge! 152 | return adj_train, train_edges, val_edges, val_edges_false, test_edges, test_edges_false 153 | 154 | 155 | def get_omega(b, u): 156 | W = 2.0 157 | a = 0.5 158 | d = 1.0 - b - u 159 | r = W * b / u 160 | s = W * d / u 161 | alpha = r + W * a 162 | beta = s + W * (1.0 - a) 163 | a0 = np.mean(alpha) * 1.0 164 | b0 = np.mean(beta) * 1.0 165 | # a0 = 2.0 166 | # b0 = 5.0 167 | omega = alpha / (alpha + beta) 168 | return omega, a0, b0 169 | 170 | 171 | def get_omega_train(b, u, mask): 172 | W = 2.0 173 | a = 0.5 174 | d = 1.0 - b - u 175 | r = W * b / u 176 | s = W * d / u 177 | alpha = r + W * a 178 | beta = s + W * (1.0 - a) 179 | mask = np.array(mask, dtype=float) 180 | mask /= np.mean(mask) 181 | alpha *= mask 182 | beta *= mask 183 | a0 = np.mean(alpha) * 0.5 184 | b0 = np.mean(beta) * 0.5 185 | # a0 = 2 186 | # b0 = 9 187 | omega = alpha / (alpha + beta) 188 | return a0, b0 189 | 190 | def mask_test_edge_opinion(test_rat, index): 191 | b_all = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/traffic_data/pa_belief_T38_0.8.npy") 192 | u_all = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/traffic_data/pa_uncertain_T38_0.8.npy") 193 | # belief, uncertain = rb_data.get_dc_data() 194 | belief = b_all[index] 195 | uncertain = u_all[index] 196 | belief = np.reshape(belief, [len(belief), 1]) 197 | uncertain = np.reshape(uncertain, [len(uncertain), 1]) 198 | omega, a0, b0 = get_omega(belief, uncertain) 199 | random.seed(132) 200 | test_num = int(test_rat * len(belief)) 201 | test_index = random.sample(range(len(belief)), test_num) 202 | train_mask = np.zeros_like(belief, dtype=bool) 203 | test_mask = np.zeros_like(belief, dtype=bool) 204 | y_train_belief = np.zeros_like(belief) 205 | y_test_belief = np.zeros_like(belief) 206 | y_train_un = np.zeros_like(belief) 207 | y_test_un = np.zeros_like(belief) 208 | for i in range(len(test_mask)): 209 | if i in test_index: 210 | y_test_belief[i] = belief[i] 211 | y_test_un[i] = uncertain[i] 212 | test_mask[i] = True 213 | else: 214 | y_train_belief[i] = belief[i] 215 | y_train_un[i] = uncertain[i] 216 | train_mask[i] = True 217 | # a1, b1 = get_omega_train(belief, uncertain, train_mask) 218 | return y_train_belief, y_test_belief, y_train_un, y_test_un, train_mask, test_mask, omega, a0, b0 219 | 220 | 221 | def mask_test_edge_epinion(test_rat, T): 222 | # b_all = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/traffic_data/pa_belief_T38_0.8.npy") 223 | # u_all = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/traffic_data/pa_uncertain_T38_0.8.npy") 224 | # # belief, uncertain = rb_data.get_dc_data() 225 | # belief = b_all[index] 226 | # uncertain = u_all[index] 227 | belief, uncertain, test_index = rb_data.get_epinion_data(T) 228 | 229 | belief = np.reshape(belief, [len(belief), 1]) 230 | uncertain = np.reshape(uncertain, [len(uncertain), 1]) 231 | omega, a0, b0 = get_omega(belief, uncertain) 232 | # random.seed(132) 233 | # test_num = int(test_rat * len(belief)) 234 | # test_index = random.sample(range(len(belief)), test_num) 235 | train_mask = np.zeros_like(belief, dtype=bool) 236 | test_mask = np.zeros_like(belief, dtype=bool) 237 | y_train_belief = np.zeros_like(belief) 238 | y_test_belief = np.zeros_like(belief) 239 | y_train_un = np.zeros_like(belief) 240 | y_test_un = np.zeros_like(belief) 241 | for i in range(len(test_mask)): 242 | if i in test_index: 243 | y_test_belief[i] = belief[i] 244 | y_test_un[i] = uncertain[i] 245 | test_mask[i] = True 246 | else: 247 | y_train_belief[i] = belief[i] 248 | y_train_un[i] = uncertain[i] 249 | train_mask[i] = True 250 | return y_train_belief, y_test_belief, y_train_un, y_test_un, train_mask, test_mask, omega, a0, b0 251 | 252 | def mask_test_edge_opinion_beijing(test_ratio): 253 | # belief = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/synthetic_belief_noise10.npy") 254 | # uncertain = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/synthetic_uncertain_noise10.npy") 255 | # _, belief = generate_synthetic_belief2(500, noise) 256 | # _, uncertain = generate_synthetic_uncertain2(500, noise) 257 | belief = np.load("./traffic_data/belief_undirect_beijing.npy") 258 | uncertain = np.load("./traffic_data/uncertain_undirect_beijing.npy") 259 | belief = np.reshape(belief, [len(belief), 1]) 260 | uncertain = np.reshape(uncertain, [len(uncertain), 1]) 261 | omega = get_omega(belief, uncertain) 262 | random.seed(132) 263 | test_index = random.sample(range(len(belief)), int(len(belief) * test_ratio)) 264 | train_mask = np.zeros_like(belief, dtype=bool) 265 | test_mask = np.zeros_like(belief, dtype=bool) 266 | y_train_belief = np.zeros_like(belief) 267 | y_test_belief = np.zeros_like(belief) 268 | y_train_un = np.zeros_like(belief) 269 | y_test_un = np.zeros_like(belief) 270 | for i in range(len(test_mask)): 271 | if i in test_index: 272 | y_test_belief[i] = belief[i] 273 | y_test_un[i] = uncertain[i] 274 | test_mask[i] = True 275 | else: 276 | y_train_belief[i] = belief[i] 277 | y_train_un[i] = uncertain[i] 278 | train_mask[i] = True 279 | return y_train_belief, y_test_belief, y_train_un, y_test_un, train_mask, test_mask, omega 280 | 281 | def mask_test_edge_opinion_f(test_num, noise): 282 | # belief = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/synthetic_belief_noise10.npy") 283 | # uncertain = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/synthetic_uncertain_noise10.npy") 284 | _, belief = generate_synthetic_belief2(500, noise) 285 | _, uncertain = generate_synthetic_uncertain2(500, noise) 286 | features = np.zeros([len(belief), 2]) 287 | features[:, 0] = belief 288 | features[:, 1] = uncertain 289 | belief = np.reshape(belief, [len(belief), 1]) 290 | uncertain = np.reshape(uncertain, [len(uncertain), 1]) 291 | omega = get_omega(belief, uncertain) 292 | random.seed(132) 293 | test_index = random.sample(range(len(belief)), test_num) 294 | train_mask = np.zeros_like(belief, dtype=bool) 295 | test_mask = np.zeros_like(belief, dtype=bool) 296 | y_train_belief = np.zeros_like(belief) 297 | y_test_belief = np.zeros_like(belief) 298 | y_train_un = np.zeros_like(belief) 299 | y_test_un = np.zeros_like(belief) 300 | for i in range(len(test_mask)): 301 | if i in test_index: 302 | features[i][0] = 0.0 303 | features[i][1] = 0.0 304 | y_test_belief[i] = belief[i] 305 | y_test_un[i] = uncertain[i] 306 | test_mask[i] = True 307 | else: 308 | y_train_belief[i] = belief[i] 309 | y_train_un[i] = uncertain[i] 310 | train_mask[i] = True 311 | features = sparse.csr_matrix(features) 312 | return y_train_belief, y_test_belief, y_train_un, y_test_un, train_mask, test_mask, omega, features 313 | 314 | if __name__ == '__main__': 315 | y_train_belief, y_test_belief, y_train_un, y_test_un, train_mask, test_mask, omega = mask_test_edge_opinion_beijing(0.4) 316 | b = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/tem_b.npy") 317 | u = np.load("/network/rit/lab/ceashpc/xujiang/project/GAE_TEST/gae/data/tem_u.npy") 318 | eb =[] 319 | eu=[] 320 | for i in range(len(b)): 321 | if test_mask[i]: 322 | error_b = np.abs(b[i]-y_test_belief[i]) 323 | error_u = np.abs(u[i] - y_test_un[i]) 324 | eb.append(error_b) 325 | eu.append(error_u) 326 | ebm = np.mean(eb) 327 | eum = np.mean(eu) 328 | 329 | print(1) -------------------------------------------------------------------------------- /gcn_gru/model.py: -------------------------------------------------------------------------------- 1 | from gcn_gru.layers import GraphConvolution, InnerProductDecoder, InnerProductDecoder_Opinion, GraphConvolutionSparse, \ 2 | GraphConvolution_saprse 3 | import tensorflow as tf 4 | from gcn_gru.GRU_cell import GCNGRUCell, GRUCell_ori, GCNGRUCell_sparse 5 | 6 | flags = tf.app.flags 7 | FLAGS = flags.FLAGS 8 | 9 | 10 | class Model(object): 11 | def __init__(self, **kwargs): 12 | allowed_kwargs = {'name', 'logging'} 13 | for kwarg in kwargs.keys(): 14 | assert kwarg in allowed_kwargs, 'Invalid keyword argument: ' + kwarg 15 | 16 | for kwarg in kwargs.keys(): 17 | assert kwarg in allowed_kwargs, 'Invalid keyword argument: ' + kwarg 18 | name = kwargs.get('name') 19 | if not name: 20 | name = self.__class__.__name__.lower() 21 | self.name = name 22 | 23 | logging = kwargs.get('logging', False) 24 | self.logging = logging 25 | 26 | self.vars = {} 27 | 28 | def _build(self): 29 | raise NotImplementedError 30 | 31 | def build(self): 32 | """ Wrapper for _build() """ 33 | with tf.variable_scope(self.name): 34 | self._build() 35 | variables = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope=self.name) 36 | self.vars = {var.name: var for var in variables} 37 | 38 | def fit(self): 39 | pass 40 | 41 | def predict(self): 42 | pass 43 | 44 | 45 | class GCNModelAE(Model): 46 | def __init__(self, placeholders, num_features, features_nonzero, **kwargs): 47 | super(GCNModelAE, self).__init__(**kwargs) 48 | 49 | self.inputs = placeholders['features'] 50 | self.input_dim = num_features 51 | self.features_nonzero = features_nonzero 52 | self.adj = placeholders['adj'] 53 | self.dropout = placeholders['dropout'] 54 | self.build() 55 | 56 | def _build(self): 57 | self.hidden1 = GraphConvolutionSparse(input_dim=self.input_dim, 58 | output_dim=FLAGS.hidden1, 59 | adj=self.adj, 60 | features_nonzero=self.features_nonzero, 61 | act=tf.nn.relu, 62 | dropout=self.dropout, 63 | logging=self.logging)(self.inputs) 64 | 65 | self.embeddings = GraphConvolution(input_dim=FLAGS.hidden1, 66 | output_dim=FLAGS.hidden2, 67 | adj=self.adj, 68 | act=lambda x: x, 69 | dropout=self.dropout, 70 | logging=self.logging)(self.hidden1) 71 | 72 | self.z_mean = self.embeddings 73 | 74 | self.reconstructions = InnerProductDecoder(input_dim=FLAGS.hidden2, 75 | act=lambda x: x, 76 | logging=self.logging)(self.embeddings) 77 | 78 | 79 | class GCNModelVAE(Model): 80 | def __init__(self, placeholders, num_features, num_nodes, features_nonzero, **kwargs): 81 | super(GCNModelVAE, self).__init__(**kwargs) 82 | 83 | self.inputs = placeholders['features'] 84 | self.input_dim = num_features 85 | self.features_nonzero = features_nonzero 86 | self.n_samples = num_nodes 87 | self.adj = placeholders['adj'] 88 | self.dropout = placeholders['dropout'] 89 | self.label_b = placeholders['labels_b'] 90 | self.label_un = placeholders['labels_un'] 91 | self.mask = placeholders['labels_mask'] 92 | self.alpha_0 = placeholders['alpha_0'] 93 | self.beta_0 = placeholders['beta_0'] 94 | self.m = FLAGS.KL_m 95 | self.build() 96 | 97 | def _build(self): 98 | self.hidden1 = GraphConvolutionSparse(input_dim=self.input_dim, 99 | output_dim=FLAGS.hidden1, 100 | adj=self.adj, 101 | features_nonzero=self.features_nonzero, 102 | act=tf.nn.relu, 103 | dropout=self.dropout, 104 | logging=self.logging)(self.inputs) 105 | 106 | self.belief = GraphConvolution(input_dim=FLAGS.hidden1, 107 | output_dim=FLAGS.hidden2, 108 | adj=self.adj, 109 | act=tf.nn.sigmoid, 110 | dropout=self.dropout, 111 | logging=self.logging)(self.hidden1) 112 | 113 | self.uncertain = GraphConvolution(input_dim=FLAGS.hidden1, 114 | output_dim=FLAGS.hidden2, 115 | adj=self.adj, 116 | act=tf.nn.sigmoid, 117 | dropout=self.dropout, 118 | logging=self.logging)(self.hidden1) 119 | # decode define 120 | self.b = tf.minimum(self.belief + 0.0000001, 0.999999) 121 | self.u = tf.minimum(self.uncertain + 0.0000001, 0.999999) 122 | self.W = 2.0 123 | self.r = self.W * self.b / self.u + 0.0000001 124 | self.d = tf.minimum(tf.nn.relu(1 - self.b - self.u) + 0.0000001, 0.999999) 125 | self.s = self.W * self.d / self.u + 0.0000001 126 | self.a = 0.5 127 | self.alpha = self.r + self.W * self.a + 0.0000001 128 | self.beta = self.s + self.W * (1 - self.a) + 0.0000001 129 | self.uni = tf.random_uniform([self.n_samples, FLAGS.hidden2], 0.001, 0.999) 130 | self.z_n_b = tf.minimum((1.0 - tf.pow(self.uni, tf.reciprocal(self.beta)) + 0.0000001), 0.999999) 131 | self.z_n = tf.minimum(tf.pow(self.z_n_b, tf.reciprocal(self.alpha)) + 0.0000001, 0.999999) 132 | self.z = tf.distributions.Normal(loc=0.0, scale=1.0).quantile(self.z_n) 133 | # self.z = self.z_mean + tf.random_normal([self.n_samples, FLAGS.hidden2]) * tf.exp(self.z_log_std) 134 | self.reconstructions = InnerProductDecoder_Opinion(input_dim=FLAGS.hidden2, 135 | act=tf.nn.sigmoid, 136 | logging=self.logging)(self.z) 137 | # KL-divergence 138 | self.digmma_beta = tf.digamma(self.beta) 139 | self.kl_1 = (1.0 - self.alpha_0 / self.alpha) * ( 140 | -0.5772 - self.digmma_beta - tf.reciprocal(self.beta)) + tf.log(self.alpha * self.beta) + tf.lbeta( 141 | [self.alpha_0, self.beta_0]) - 1.0 + tf.reciprocal(self.beta) 142 | self.kl_2 = 0.0 143 | for m in range(1, self.m + 1): 144 | self.kl_2 += tf.reciprocal(m + self.alpha * self.beta) * tf.exp( 145 | tf.lbeta(tf.stack([m / self.alpha, self.beta], axis=2))) 146 | self.kl_d = self.kl_1 + self.beta * (self.beta_0 - 1.0) * self.kl_2 147 | # omege 148 | self.omega = self.alpha / (self.alpha + self.beta) 149 | 150 | 151 | class GCNModel_ori(Model): 152 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 153 | super(GCNModel_ori, self).__init__(**kwargs) 154 | 155 | self.inputs = placeholders['features'] 156 | self.n_samples = num_nodes 157 | self.hidden_units = FLAGS.hidden_units 158 | self.adj = placeholders['adj'] 159 | self.dropout = placeholders['dropout'] 160 | self.bias = bool(bias) 161 | self.build() 162 | 163 | def _build(self): 164 | self.hidden1 = GraphConvolution(input_dim=self.n_samples, 165 | output_dim=10, 166 | adj=self.adj, 167 | act=tf.nn.relu, 168 | dropout=self.dropout, 169 | logging=self.logging)(self.inputs) 170 | 171 | self.belief = GraphConvolution(input_dim=10, 172 | output_dim=1, 173 | adj=self.adj, 174 | act=tf.nn.sigmoid, 175 | dropout=self.dropout, 176 | logging=self.logging)(self.hidden1) 177 | 178 | self.hidden2 = GraphConvolution(input_dim=self.n_samples, 179 | output_dim=10, 180 | adj=self.adj, 181 | act=tf.nn.relu, 182 | dropout=self.dropout, 183 | logging=self.logging)(self.inputs) 184 | 185 | self.uncertainty = GraphConvolution(input_dim=10, 186 | output_dim=1, 187 | adj=self.adj, 188 | act=tf.nn.sigmoid, 189 | dropout=self.dropout, 190 | logging=self.logging)(self.hidden2) 191 | 192 | 193 | class GCNModel_ori3(Model): 194 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 195 | super(GCNModel_ori3, self).__init__(**kwargs) 196 | 197 | self.index = placeholders['index'] 198 | self.value = placeholders['value'] 199 | self.inputs = tf.SparseTensor(self.index, self.value, [num_nodes, num_nodes]) 200 | self.n_samples = num_nodes 201 | self.hidden_units = FLAGS.hidden_units 202 | self.adj = placeholders['adj'] 203 | self.dropout = placeholders['dropout'] 204 | self.bias = bool(bias) 205 | self.build() 206 | 207 | def _build(self): 208 | non_zeros_feat = tf.size(self.inputs.values) 209 | self.hidden1 = GraphConvolution_saprse(input_dim=self.n_samples, 210 | output_dim=10, 211 | adj=self.adj, 212 | act=tf.nn.relu, 213 | dropout=self.dropout, 214 | non_zero=non_zeros_feat, 215 | logging=self.logging)(self.inputs) 216 | 217 | self.belief = GraphConvolution(input_dim=10, 218 | output_dim=1, 219 | adj=self.adj, 220 | act=tf.nn.sigmoid, 221 | dropout=self.dropout, 222 | logging=self.logging)(self.hidden1) 223 | 224 | self.hidden2 = GraphConvolution_saprse(input_dim=self.n_samples, 225 | output_dim=10, 226 | adj=self.adj, 227 | act=tf.nn.relu, 228 | dropout=self.dropout, 229 | non_zero=non_zeros_feat, 230 | logging=self.logging)(self.inputs) 231 | 232 | self.uncertainty = GraphConvolution(input_dim=10, 233 | output_dim=1, 234 | adj=self.adj, 235 | act=tf.nn.sigmoid, 236 | dropout=self.dropout, 237 | logging=self.logging)(self.hidden2) 238 | 239 | 240 | class GCNModel_ori2(Model): 241 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 242 | super(GCNModel_ori2, self).__init__(**kwargs) 243 | 244 | self.inputs = placeholders['features'] 245 | self.inouts_u = placeholders['features_u'] 246 | self.n_samples = num_nodes 247 | self.hidden_units = FLAGS.hidden_units 248 | self.adj = placeholders['adj'] 249 | self.dropout = placeholders['dropout'] 250 | self.bias = bool(bias) 251 | self.build() 252 | 253 | def _build(self): 254 | self.hidden1 = GraphConvolution(input_dim=1, 255 | output_dim=10, 256 | adj=self.adj, 257 | act=tf.nn.relu, 258 | dropout=self.dropout, 259 | logging=self.logging)(self.inputs) 260 | 261 | self.belief = GraphConvolution(input_dim=10, 262 | output_dim=1, 263 | adj=self.adj, 264 | act=tf.nn.sigmoid, 265 | dropout=self.dropout, 266 | logging=self.logging)(self.hidden1) 267 | 268 | self.hidden2 = GraphConvolution(input_dim=1, 269 | output_dim=10, 270 | adj=self.adj, 271 | act=tf.nn.relu, 272 | dropout=self.dropout, 273 | logging=self.logging)(self.inouts_u) 274 | 275 | self.uncertainty = GraphConvolution(input_dim=10, 276 | output_dim=1, 277 | adj=self.adj, 278 | act=tf.nn.sigmoid, 279 | dropout=self.dropout, 280 | logging=self.logging)(self.hidden2) 281 | 282 | 283 | class GCNModel_ori_spam(Model): 284 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 285 | super(GCNModel_ori_spam, self).__init__(**kwargs) 286 | 287 | self.inputs = placeholders['features'] 288 | self.inouts_u = placeholders['features_u'] 289 | self.n_samples = num_nodes 290 | self.hidden_units = FLAGS.hidden_units 291 | self.adj = placeholders['adj'] 292 | self.dropout = placeholders['dropout'] 293 | self.bias = bool(bias) 294 | self.build() 295 | 296 | def _build(self): 297 | self.belief = GraphConvolution(input_dim=1, 298 | output_dim=1, 299 | adj=self.adj, 300 | act=tf.nn.relu, 301 | dropout=self.dropout, 302 | logging=self.logging)(self.inputs) 303 | 304 | self.uncertainty = GraphConvolution(input_dim=1, 305 | output_dim=1, 306 | adj=self.adj, 307 | act=tf.nn.relu, 308 | dropout=self.dropout, 309 | logging=self.logging)(self.inouts_u) 310 | 311 | 312 | class GCNModelRNN_sparse(Model): 313 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 314 | super(GCNModelRNN_sparse, self).__init__(**kwargs) 315 | 316 | self.inputs = placeholders['features'] 317 | # self.input_rnn = placeholders['features_rnn'] 318 | self.n_samples = num_nodes 319 | self.hidden_units = FLAGS.hidden_units 320 | self.adj = placeholders['adj'] 321 | self.dropout = placeholders['dropout'] 322 | self.bias = bool(bias) 323 | self.index = placeholders['index'] 324 | self.value = placeholders['value'] 325 | self.build() 326 | 327 | def _build(self): 328 | self.cell_1 = GCNGRUCell_sparse(num_units=self.hidden_units, adj_mx=self.adj, num_nodes=self.n_samples, 329 | dropout=self.dropout, bias=self.bias, index=self.index, value=self.value) 330 | self.cell_2 = GCNGRUCell_sparse(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 331 | bias=self.bias, index=self.index, value=self.value) 332 | self.cell_3 = GCNGRUCell_sparse(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 333 | bias=self.bias, index=self.index, value=self.value) 334 | self.cell_b = [self.cell_1, self.cell_2] 335 | self.cell_u = [self.cell_1, self.cell_3] 336 | self.cell_multi_b = tf.nn.rnn_cell.MultiRNNCell(self.cell_b, state_is_tuple=True) 337 | self.cell_multi_u = tf.nn.rnn_cell.MultiRNNCell(self.cell_u, state_is_tuple=True) 338 | 339 | self.initial_state = self.cell_multi_b.zero_state(1, tf.float32) 340 | 341 | self.outputs_b, _ = tf.nn.dynamic_rnn(self.cell_multi_b, self.inputs, initial_state=self.initial_state) 342 | self.outputs_u, _ = tf.nn.dynamic_rnn(self.cell_multi_u, self.inputs, initial_state=self.initial_state) 343 | 344 | 345 | class GCNModelRNN(Model): 346 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 347 | super(GCNModelRNN, self).__init__(**kwargs) 348 | 349 | self.inputs = placeholders['features'] 350 | self.n_samples = num_nodes 351 | self.hidden_units = FLAGS.hidden_units 352 | self.adj = placeholders['adj'] 353 | self.dropout = placeholders['dropout'] 354 | self.bias = bool(bias) 355 | self.build() 356 | 357 | def _build(self): 358 | self.cell_1 = GCNGRUCell(num_units=self.hidden_units, adj_mx=self.adj, num_nodes=self.n_samples, 359 | dropout=self.dropout, bias=self.bias) 360 | self.cell_2 = GCNGRUCell(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 361 | bias=self.bias) 362 | self.cell_3 = GCNGRUCell(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 363 | bias=self.bias) 364 | self.cell_b = [self.cell_1, self.cell_2] 365 | self.cell_u = [self.cell_1, self.cell_3] 366 | self.cell_multi_b = tf.nn.rnn_cell.MultiRNNCell(self.cell_b, state_is_tuple=True) 367 | self.cell_multi_u = tf.nn.rnn_cell.MultiRNNCell(self.cell_u, state_is_tuple=True) 368 | 369 | self.initial_state = self.cell_multi_b.zero_state(1, tf.float32) 370 | 371 | self.outputs_b, _ = tf.nn.dynamic_rnn(self.cell_multi_b, self.inputs, initial_state=self.initial_state) 372 | self.outputs_u, _ = tf.nn.dynamic_rnn(self.cell_multi_u, self.inputs, initial_state=self.initial_state) 373 | 374 | 375 | class GCNModelRNN_ori(Model): 376 | def __init__(self, placeholders, num_nodes, bias, **kwargs): 377 | super(GCNModelRNN_ori, self).__init__(**kwargs) 378 | 379 | self.inputs = placeholders['features'] 380 | self.n_samples = num_nodes 381 | self.hidden_units = FLAGS.hidden_units 382 | self.adj = placeholders['adj'] 383 | self.dropout = placeholders['dropout'] 384 | self.bias = bool(bias) 385 | self.build() 386 | 387 | def _build(self): 388 | self.cell_1 = GRUCell_ori(num_units=self.hidden_units, adj_mx=self.adj, num_nodes=self.n_samples, 389 | dropout=self.dropout, bias=self.bias) 390 | self.cell_4 = GRUCell_ori(num_units=self.hidden_units, adj_mx=self.adj, num_nodes=self.n_samples, 391 | dropout=self.dropout, bias=self.bias) 392 | self.cell_2 = GRUCell_ori(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 393 | bias=self.bias) 394 | self.cell_3 = GRUCell_ori(num_units=1, adj_mx=self.adj, num_nodes=self.n_samples, dropout=self.dropout, 395 | bias=self.bias) 396 | self.cell_b = [self.cell_1, self.cell_2] 397 | self.cell_u = [self.cell_4, self.cell_3] 398 | self.cell_multi_b = tf.nn.rnn_cell.MultiRNNCell(self.cell_b, state_is_tuple=True) 399 | self.cell_multi_u = tf.nn.rnn_cell.MultiRNNCell(self.cell_u, state_is_tuple=True) 400 | 401 | self.initial_state = self.cell_multi_b.zero_state(1, tf.float32) 402 | 403 | self.outputs_b, _ = tf.nn.dynamic_rnn(self.cell_multi_b, self.inputs, initial_state=self.initial_state) 404 | self.outputs_u, _ = tf.nn.dynamic_rnn(self.cell_multi_u, self.inputs, initial_state=self.initial_state) 405 | 406 | 407 | class GCNModelRNN_ori1(Model): 408 | def __init__(self, placeholders, num_nodes, **kwargs): 409 | super(GCNModelRNN_ori1, self).__init__(**kwargs) 410 | 411 | self.inputs = placeholders['features'] 412 | self.n_samples = num_nodes 413 | self.adj = placeholders['adj'] 414 | self.dropout = placeholders['dropout'] 415 | self.build() 416 | 417 | def _build(self): 418 | # self.cell_1 = tf.nn.rnn_cell.GRUCell(num_units=16) 419 | # self.cell_2 = tf.nn.rnn_cell.GRUCell(num_units=1) 420 | # self.cell_3 = tf.nn.rnn_cell.GRUCell(num_units=1) 421 | # self.cell_b = [self.cell_1, self. cell_2] 422 | # self.cell_u = [self.cell_1, self.cell_3] 423 | # with tf.variable_scope("belief"): 424 | # self.cell_b = [tf.nn.rnn_cell.GRUCell(size) for size in [self.n_samples]] 425 | self.cell_b = tf.nn.rnn_cell.GRUCell(self.n_samples) 426 | # with tf.variable_scope("uncertainty"): 427 | # self.cell_u = [tf.nn.rnn_cell.GRUCell(size) for size in [10, 1]] 428 | self.cell_multi_b = tf.nn.rnn_cell.MultiRNNCell(self.cell_b, state_is_tuple=True) 429 | # self.cell_multi_u = tf.nn.rnn_cell.MultiRNNCell(self.cell_u, state_is_tuple=True) 430 | 431 | self.initial_state = self.cell_multi_b.zero_state(1, tf.float32) 432 | 433 | self.outputs_b, _ = tf.nn.dynamic_rnn(self.cell_multi_b, self.inputs, initial_state=self.initial_state) 434 | # self.outputs_u, _ = tf.nn.dynamic_rnn(self.cell_multi_u, self.inputs, initial_state=self.initial_state) 435 | 436 | 437 | class GCNModelRNN_ori2(Model): 438 | def __init__(self, placeholders, num_nodes, **kwargs): 439 | super(GCNModelRNN_ori2, self).__init__(**kwargs) 440 | 441 | self.inputs = placeholders['features'] 442 | self.n_samples = num_nodes 443 | self.adj = placeholders['adj'] 444 | self.dropout = placeholders['dropout'] 445 | self.build() 446 | 447 | def _build(self): 448 | # self.cell_1 = tf.nn.rnn_cell.GRUCell(num_units=16) 449 | # self.cell_2 = tf.nn.rnn_cell.GRUCell(num_units=1) 450 | # self.cell_3 = tf.nn.rnn_cell.GRUCell(num_units=1) 451 | # self.cell_b = [self.cell_1, self. cell_2] 452 | # self.cell_u = [self.cell_1, self.cell_3] 453 | # with tf.variable_scope("belief"): 454 | # self.cell_b = [tf.nn.rnn_cell.GRUCell(size) for size in [self.n_samples]] 455 | self.cell_b = tf.nn.rnn_cell.GRUCell(self.n_samples) 456 | # with tf.variable_scope("uncertainty"): 457 | # self.cell_u = [tf.nn.rnn_cell.GRUCell(size) for size in [10, 1]] 458 | # self.cell_multi_u = tf.nn.rnn_cell.MultiRNNCell(self.cell_u, state_is_tuple=True) 459 | 460 | self.initial_state = self.cell_b.zero_state(1, tf.float32) 461 | 462 | self.outputs_b, _ = tf.nn.dynamic_rnn(self.cell_b, self.inputs, initial_state=self.initial_state) 463 | # self.outputs_u, _ = tf.nn.dynamic_rnn(self.cell_multi_u, self.inputs, initial_state=self.initial_state) 464 | --------------------------------------------------------------------------------