From ad128707a8472e81a88ad6556699639ba7351e78 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 7 Aug 2019 16:59:40 +1000 Subject: [PATCH 01/82] add space --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 4ea9305e2..0f8c4fe20 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,4 @@ pytest==3.9.3 pytest-benchmark>=3.1 pytest-cov>=2.6.0 coveralls>=1.5.1 + From ace4fec29121c894cddf167e76b45885ac8994da Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 7 Aug 2019 18:06:49 +1000 Subject: [PATCH 02/82] Add the definition of the attri2vecLinkGenerator, which helps generate a batch of (feature of target node, index of context node, label of node pair) pairs per iteration, for training the attri2vec model --- stellargraph/mapper/link_mappers.py | 125 ++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 6 deletions(-) mode change 100644 => 100755 stellargraph/mapper/link_mappers.py diff --git a/stellargraph/mapper/link_mappers.py b/stellargraph/mapper/link_mappers.py old mode 100644 new mode 100755 index 06f19b3fd..5b086cda3 --- a/stellargraph/mapper/link_mappers.py +++ b/stellargraph/mapper/link_mappers.py @@ -24,6 +24,7 @@ "OnDemandLinkSequence", "GraphSAGELinkGenerator", "HinSAGELinkGenerator", + "attri2vecLinkGenerator" ] import random @@ -178,7 +179,7 @@ class OnDemandLinkSequence(Sequence): :class:`GraphSAGELinkGenerator` ` . Args: - generator: An instance of :class:`GraphSAGELinkGenerator`. + generator: An instance of :class:`GraphSAGELinkGenerator` or 'attri2vecLink Generator'. sampler: An instance of :class:`UnsupervisedSampler` that encapsulates the neighbourhood sampling of a graph. The generator method of this class returns `batch_size` of positive and negative samples on demand. """ @@ -205,11 +206,18 @@ def __init__(self, generator, walker): * self.walker.number_of_walks ) # an estimate of the upper bound on how many samples are generated in each epoch - print( - "Running GraphSAGELinkGenerator with an estimated {} batches generated on the fly per epoch.".format( - round(self.data_size / self.generator.batch_size) - ) - ) + if isinstance(self.generator, GraphSAGELinkGenerator): + print( + "Running GraphSAGELinkGenerator with an estimated {} batches generated on the fly per epoch.".format( + round(self.data_size / self.generator.batch_size) + ) + ) + else: + print( + "Running attri2vecLinkGenerator with an estimated {} batches generated on the fly per epoch.".format( + round(self.data_size / self.generator.batch_size) + ) + ) self._gen = self.walker.generator( self.generator.batch_size @@ -607,3 +615,108 @@ def flow(self, link_ids, targets=None, shuffle=False): ) return LinkSequence(self, link_ids, targets, shuffle) + +class attri2vecLinkGenerator: + """ + A data generator for link prediction with Homogeneous attri2vec models + + At minimum, supply the StellarGraph the batch size. + + The supplied graph should be a StellarGraph object that is ready for + machine learning. Currently the model requires node features for all + nodes in the graph. + + Use the :meth:`.flow` method supplying the nodes and (optionally) targets, + or an UnsupervisedSampler instance that generates node samples on demand, + to get an object that can be used as a Keras data generator. + + Example:: + + G_generator = attri2vecLinkGenerator(G, 50) + train_data_gen = G_generator.flow(edge_ids) + + Args: + G (StellarGraph): A machine-learning ready graph. + batch_size (int): Size of batch of links to return. + num_samples: for compatibility with GraphSAGE + seed (int or str), optional: Random seed for the sampling methods. + name, optional: Name of generator + """ + + def __init__(self, G, batch_size, num_samples=[1,1], seed=None, name=None): + if not isinstance(G, StellarGraphBase): + raise TypeError("Graph must be a StellarGraph object.") + + G.check_graph_for_ml(features=True) + + self.graph = G + self.num_samples = num_samples + self.batch_size = batch_size + self.name = name + + # We need a schema for compatibility with HinSAGE + self.schema = G.create_graph_schema(create_type_maps=True) + + # The sampler used to generate random samples of neighbours + #self.sampler = SampledBreadthFirstWalk(G, graph_schema=self.schema, seed=seed) + + def sample_features(self, head_links, sampling_schema): + """ + Sample content features of the target nodes and the ids of the context nodes + and return these as a list of feature arrays for the attri2vec algorithm. + + Args: + head_links: An iterable of edges to perform sampling for. + sampling_schema: The sampling schema for the model, for compatibility + with GraphSAGE and HinSAGE + + Returns: + a list of feaure arrys, with each element being the feature of a + target node and the id of the corresponding context node + """ + + target_ids = [head_link[0] for head_link in head_links] + context_ids = [head_link[1] for head_link in head_links] + target_feats = self.graph.get_feature_for_nodes(target_ids) + batch_feats = [target_feats, np.array(context_ids)] + + return batch_feats + + def flow(self, link_ids, targets=None, shuffle=False): + """ + Creates a generator/sequence object for training or evaluation + with the supplied edge IDs and numeric targets. + + The edge IDs are the edges to train or inference on. They are + expected to by tuples of (source_id, destination_id). + + The targets are an array of numeric targets corresponding to the + supplied link_ids to be used by the downstream task. They should + be given in the same order as the list of link IDs. + If they are not specified (for example, for use in prediction), + the targets will not be available to the downsteam task. + + Note that the shuffle argument should be True for training and + False for prediction. + + Args: + link_ids (list or UnsupervisedSampler): an iterable of (src_id, dst_id) tuples + specifying the edges or an UnsupervisedSampler object that has a generator + method to generate samples on the fly. + targets (optional, array): a 2D array of numeric targets with shape + `(len(link_ids), target_size)` + shuffle (optional, bool): If True the node_ids will be shuffled at each + epoch, if False the node_ids will be processed in order. + + Returns: + An OnDemandLinkSequence object to use with the attri2vec model. + """ + # Pass sampler to on-demand link sequence generation + if isinstance(link_ids, UnsupervisedSampler): + return OnDemandLinkSequence(self, link_ids) + + else: + raise TypeError( + "Argument to .flow not recognised. " + "Please pass a list of samples or a UnsupervisedSampler object." + ) From 8df75763855a7459beb266bb32ed09ada40b636c Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 7 Aug 2019 18:10:24 +1000 Subject: [PATCH 03/82] Add the implementation of attri2vec, and investigate its performance on out-of-sample node link prediction. --- .../stellargraph-attri2vec-DBLP.ipynb | 769 ++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 demos/embeddings/stellargraph-attri2vec-DBLP.ipynb diff --git a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb new file mode 100644 index 000000000..8abfad166 --- /dev/null +++ b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb @@ -0,0 +1,769 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Infer Representations for Out-of-sample Nodes Through attri2vec" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the python implementation of the attri2vec algorithm outlined in paper ***[Attributed Network Embedding Via Subspace Discovery](https://arxiv.org/abs/1901.04095)*** D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. The implementation uses the stellargraph libraries.\n", + "\n", + "## Dataset\n", + "This demo uses a DBLP citation network, a subgraph extracted from [DBLP-Citation-network V3](https://aminer.org/citation). To form this subgraph, papers from four subjects are extracted according to their venue information: *Database, Data Mining, Artificial Intelligence and Computer Vision*, and papers with no citations are removed. The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. By ignoring the citation direction, we take the DBLP subgraph as an undirected network.\n", + "\n", + "As papers in DBLP are attached with publication year, the DBLP network with the dynamic property can be used to study the problem of out-of-sample node representation learning. From the DBLP network, we construct four in-sample subgraphs using papers published before 2006, 2007, 2008 and 2009, and denote the four subgraphs as DBLP2006, DBLP2007, DBLP2008, and DBLP2009. For each subgraph, the remaining papers are taken as out-of-sample nodes. We consider the case where new coming nodes have no links. We predict the links of out-of-sample nodes using the learned out-of-sample node representations and compare its performance with the node content feature baseline.\n", + "\n", + "\n", + "\n", + "## attri2vec\n", + "\n", + "For networks attached with node content attributes, attri2vec infers node representations by discovering a latent node attribute subspace that respects network structure in a more consistent way. To transform network nodes from the original attribute space into the targeted subspace, a non-linear mapping is used. To make the mapped images respect structural similarity, [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec) learning mechanism is used to make nodes sharing similar random walk context nodes represented closely in the subspace. Following [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec), attri2vec learns node representations by maximizing the occurrence probability of context nodes conditioned on the representation of the target nodes. The probability is modelled by Softmax and negative sampling is used to speed up its calculation. This makes attri2vec equivalent to predict whether a node occurs in the given target node's context in random walks with the representation of the target node, by minimizing the cross-entropy loss. \n", + "\n", + "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes. Unlike the embeddings learned by DeepWalk/node2vec, the mapping is inductive. Different from the mapping generated by GraphSAGE, the mapping only performs on node content attributes and does not rely on any link information, which makes it possible to construct representations for new coming nodes having few or no link information from their content attributes.\n", + "\n", + "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameters used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)`, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", + "\n", + "The entire model is trained end-to-end by minimizing the loss function of choice (e.g., binary cross-entropy between predicted node pair labels and true link labels) using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' links generated on demand and fed into the model.\n", + "\n", + "In this demo, we first train the attri2vec model on the in-sample subgraph and obtain a mapping function from node attributes to node representations, then apply the mapping function to the content attributes of out-of-sample nodes and obtain the representations of out-of-sample nodes. We evaluate the quality of inferred out-of-sample node representations by using it to predict the links of out-of-sample nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using TensorFlow backend.\n" + ] + } + ], + "source": [ + "import networkx as nx\n", + "import pandas as pd\n", + "import numpy as np\n", + "import os\n", + "import random\n", + "\n", + "import stellargraph as sg\n", + "from stellargraph.data import UniformRandomWalk\n", + "from stellargraph.data import UnsupervisedSampler\n", + "from stellargraph.mapper import attri2vecLinkGenerator\n", + "\n", + "import keras \n", + "from keras.utils import Sequence\n", + "from keras.models import Model\n", + "from keras.layers import Input, Dense, Reshape, merge\n", + "from keras.layers.embeddings import Embedding\n", + "\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import accuracy_score\n", + "from sklearn.metrics import roc_auc_score" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading DBLP network data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dataset used in this demo can be downloaded from https://www.kaggle.com/daozhang/dblp-subgraph.\n", + "The following is the description of the dataset:\n", + "\n", + "> The content.txt file contains descriptions of the papers in the following format:\n", + "\n", + " \t\t \n", + " \n", + "> The first entry in each line contains the unique integer ID (ranging from 0 to 18,447) of the paper followed by > binary values indicating whether each word in the vocabulary is present (indicated by 1) or absent (indicated by 0) in the paper. Finally, the last two entries in the line are the class label and the publication year of the paper.\n", + "> The edgeList.txt file contains the citation relations. Each line describes a link in the following format:\n", + "\t\t\n", + " \n", + " \n", + "> Each line contains two paper IDs, with paper2 citing paper1 or paper1 citing paper2.\n", + "\n", + "\n", + "Download and unzip the dblp-subgraph.zip file to a location on your computer and set the `data_dir` variable to\n", + "point to the location of the dataset (the \"DBLP\" directory containing \"content.txt\" and \"edgeList.txt\")." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = \"~/data/DBLP\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the graph from the edgelist." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "edgelist = pd.read_csv(os.path.join(data_dir, \"edgeList.txt\"), sep='\\t', header=None, names=[\"source\", \"target\"])\n", + "edgelist[\"label\"] = \"cites\" # set the edge type" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load paper content features, subjects and publishing years." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "feature_names = [\"w_{}\".format(ii) for ii in range(2476)]\n", + "node_column_names = feature_names + [\"subject\", \"year\"]\n", + "node_data = pd.read_csv(os.path.join(data_dir, \"content.txt\"), sep='\\t', header=None, names=node_column_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get DBLP Subgraph \n", + "### with papers published before a threshold year" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the edge list connecting in-sample nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "year_thresh = 2006 # the threshold year for in-sample and out-of-sample set split, which can be 2007, 2008 and 2009\n", + "subgraph_edgelist = []\n", + "for ii in range(len(edgelist)):\n", + " source_index = edgelist[\"source\"][ii]\n", + " target_index = edgelist[\"target\"][ii]\n", + " source_year = int(node_data[\"year\"][source_index])\n", + " target_year = int(node_data[\"year\"][target_index])\n", + " if source_year < year_thresh and target_year < year_thresh:\n", + " subgraph_edgelist.append([source_index, target_index])\n", + "subgraph_edgelist = pd.DataFrame(np.array(subgraph_edgelist), columns=[\"source\", \"target\"])\n", + "subgraph_edgelist[\"label\"] = \"cites\" # set the edge type" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the network from the selected edge list." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "Gnx = nx.from_pandas_edgelist(subgraph_edgelist, edge_attr=\"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify node types." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "nx.set_node_attributes(Gnx, \"paper\", \"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get in-sample node features." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "subgraph_node_data = node_data[node_data[\"year\"]<2006]\n", + "subgraph_node_features = subgraph_node_data[feature_names]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Stellargraph with node features." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "G = sg.StellarGraph(Gnx, node_features=subgraph_node_features)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StellarGraph: Undirected multigraph\n", + " Nodes: 11776, Edges: 28937\n", + "\n", + " Node types:\n", + " paper: [11776]\n", + " Edge types: paper-cites->paper\n", + "\n", + " Edge types:\n", + " paper-cites->paper: [28937]\n", + "\n" + ] + } + ], + "source": [ + "print(G.info())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train attri2vec on the DBLP Subgraph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify the other optional parameter values: root nodes, the number of walks to take per node, the length of each walk, and random seed." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "nodes = list(G.nodes())\n", + "number_of_walks = 1\n", + "length = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the UnsupervisedSampler instance with the relevant parameters passed to it." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "unsupervised_samples = UnsupervisedSampler(G, nodes=nodes, length=length, number_of_walks=number_of_walks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the batch size and the number of epochs. " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 50\n", + "epochs = 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define the attri2vec training generator, which generates a batch of (feature of target node, index of context node, label of node pair) pairs per iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running attri2vecLinkGenerator with an estimated 2355 batches generated on the fly per epoch.\n" + ] + } + ], + "source": [ + "train_gen = attri2vecLinkGenerator(G, batch_size).flow(unsupervised_samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following is the keras implementation of attri2vec. The objective attri2vec is equivalent to minimize the cross-entropy loss for predicting the context nodes with target nodes, with the predicted output being the dot product of the \"input embedding\" of target nodes and the \"output embedding\" of target nodes, followed by a sigmoid activation. The \"input embedding\", the objective node representation, is constructed from node content features through a linear transformation followed by a sigmoid activation. The \"out embedding\" is a look-up table for each context node." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0807 17:47:53.407229 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", + "\n", + "W0807 17:47:53.423400 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", + "\n", + "W0807 17:47:53.428951 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", + "\n", + "W0807 17:47:53.504508 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", + "\n", + "W0807 17:47:53.510684 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", + "\n", + "W0807 17:47:53.517368 140736734368704 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" + ] + } + ], + "source": [ + "embedding_size = 256 # set the embedding dimension to 256.\n", + "input_target = Input((G.node_feature_sizes()[\"paper\"],)) # define the input for target nodes as node content features \n", + "input_context = Input((1,)) # define the input for context nodes as node ids\n", + "\n", + "target = Dense(embedding_size, activation='sigmoid')(input_target) # get \"input embedding\" for the target node\n", + "target = Reshape((embedding_size, 1))(target) \n", + "out_embedding = Embedding(len(node_data), embedding_size, input_length=1, name='out_embedding')\n", + "context = out_embedding(input_context) # get the \"output embedding\" for the context node\n", + "context = Reshape((embedding_size, 1))(context)\n", + "\n", + "# perform dot product between the \"input embedding\" and the \"output embedding\"\n", + "dot_product = keras.layers.dot([target, context], axes = 1, normalize=False) \n", + "dot_product = Reshape((1,))(dot_product) \n", + "\n", + "output = Dense(1, activation='sigmoid')(dot_product) # get the predicted output\n", + "\n", + "model = Model(inputs=[input_target, input_context], outputs=output)\n", + "model.compile(\n", + " optimizer=keras.optimizers.Adam(lr=1e-3),\n", + " loss=keras.losses.binary_crossentropy,\n", + " metrics=[keras.metrics.binary_accuracy],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Train the model." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0807 17:47:56.943290 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/4\n", + "2356/2356 [==============================] - 136s 58ms/step - loss: 0.7146 - binary_accuracy: 0.5173\n", + "Epoch 2/4\n", + "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6876 - binary_accuracy: 0.5374\n", + "Epoch 3/4\n", + "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6759 - binary_accuracy: 0.5468\n", + "Epoch 4/4\n", + "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6571 - binary_accuracy: 0.5578\n" + ] + } + ], + "source": [ + "history = model.fit_generator(\n", + " train_gen,\n", + " epochs=epochs,\n", + " verbose=1,\n", + " use_multiprocessing=False,\n", + " workers=0,\n", + " shuffle=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Predicting links of out-of-sample nodes with the learned attri2vec model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the node embeddings, for both in-sample and out-of-sample nodes, by applying the learned mapping function to node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "embedding_model = Model(inputs = input_target, outputs = Reshape((embedding_size,))(target))\n", + "node_embeddings = embedding_model.predict(node_data[feature_names].values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the positive and negative edges for in-sample nodes and out-of-sample nodes. The edges of the in-sample nodes only include the edges between in-sample nodes, and the edges of out-of-sample nodes are referred to all the edges linked to out-of-sample nodes, including the edges connecting in-sample and out-of-sample edges." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "year_thresh = 2006\n", + "in_sample_edges = []\n", + "out_of_sample_edges = []\n", + "for ii in range(len(edgelist)):\n", + " source_index = edgelist[\"source\"][ii]\n", + " target_index = edgelist[\"target\"][ii]\n", + " if source_index > target_index: # neglect edge direction for the undirected graph\n", + " continue\n", + " source_year = int(node_data[\"year\"][source_index])\n", + " target_year = int(node_data[\"year\"][target_index])\n", + " if source_year < year_thresh and target_year < year_thresh:\n", + " in_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", + " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", + " in_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative node\n", + " else:\n", + " out_of_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", + " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", + " out_of_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative node\n", + "in_sample_edges = np.array(in_sample_edges)\n", + "out_of_sample_edges = np.array(out_of_sample_edges)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the edge features from the learned node representations with l2 normed difference, where edge features are the element-wise square of the difference between the embeddings of two head nodes. Other strategy like element-wise product can also be used to construct edge features." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "in_sample_edge_feat_from_emb = (node_embeddings[in_sample_edges[:,0]]-node_embeddings[in_sample_edges[:,1]])**2\n", + "out_of_sample_edge_feat_from_emb = (node_embeddings[out_of_sample_edges[:,0]]-node_embeddings[out_of_sample_edges[:,1]])**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Train the Logistic Regression classifier from in-sample edges with the edge features constructed from attri2vec embeddings. " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", + " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", + " multi_class='auto', n_jobs=None, penalty='l2',\n", + " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", + " warm_start=False)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clf_edge_pred_from_emb = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", + "clf_edge_pred_from_emb.fit(in_sample_edge_feat_from_emb, in_sample_edges[:,2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predict the edge existence probability with the trained Logistic Regression classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "edge_pred_from_emb = clf_edge_pred_from_emb.predict_proba(out_of_sample_edge_feat_from_emb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the positive class index of `edge_pred_from_emb`." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "if clf_edge_pred_from_emb.classes_[0] == 1:\n", + " positive_class_index = 0\n", + "else:\n", + " positive_class_index = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluate the AUC score for the prediction with attri2vec embeddings." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.736614362152765" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_emb[:,positive_class_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the baseline, we also investigate the performance of node content features in predicting the edges of out-of-sample nodes. Firstly, we construct edge features from node content features with the same strategy." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "in_sample_edge_rep_from_feat = (node_data[feature_names].values[in_sample_edges[:,0]]-node_data[feature_names].values[in_sample_edges[:,1]])**2\n", + "out_of_sample_edge_rep_from_feat = (node_data[feature_names].values[out_of_sample_edges[:,0]]-node_data[feature_names].values[out_of_sample_edges[:,1]])**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we train the Logistic Regression classifier from in-sample edges with the edge features constructed from node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", + " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", + " multi_class='auto', n_jobs=None, penalty='l2',\n", + " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", + " warm_start=False)" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clf_edge_pred_from_feat = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", + "clf_edge_pred_from_feat.fit(in_sample_edge_rep_from_feat, in_sample_edges[:,2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predict the edge existence probability with the trained Logistic Regression classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "edge_pred_from_feat = clf_edge_pred_from_feat.predict_proba(out_of_sample_edge_rep_from_feat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get positive class index of `clf_edge_pred_from_feat`." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "if clf_edge_pred_from_feat.classes_[0] == 1:\n", + " positive_class_index = 0\n", + "else:\n", + " positive_class_index = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluate the AUC score for the prediction with node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.6651658318918301" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_feat[:,positive_class_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "attri2vec performs much better than node content features in predicting the links of out-of-sample nodes." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 46a77dd4429925479d08229872e1a797794586c5 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 12:52:25 +1000 Subject: [PATCH 04/82] reformat link_mappers.py with black --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 1 + demos/.DS_Store | Bin 0 -> 6148 bytes requirements.txt | 1 - stellargraph/.DS_Store | Bin 0 -> 6148 bytes stellargraph/mapper/link_mappers.py | 24 +++++++++++------------- 6 files changed, 12 insertions(+), 14 deletions(-) create mode 100644 .DS_Store create mode 100644 demos/.DS_Store create mode 100644 stellargraph/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a7c5630e292e8a22ff249f7a06d0ea30027f092a GIT binary patch literal 6148 zcmeHK%}&BV5T1pi#h=K*M2>s$#sLDz$)rI%cr(H1K@GGifhMI(Xpv~e^fmO2d;(v` z*&j?1xp*+9*=c6K*`L|Xe97)~0D!b-ZVjLW046F&V+WfbgwJzblbjkc5Q*3$bmrm2 z@tL!>Ru5<+kqYsl zI}Lmm3~`iu>_G?-hVSEN!xV<7HcViYddf0I#m0cY5woOEV^$eZ7slMpYJfT}&46a$ z*9`FYfueG>6ebeI(}9gB0TB6bgb=iOEx~=LLQ7#H5ob_{bVZb|M3opsy5l%i>nw$d zMClGh6(2;MOjLzJ#Ob&{70ZEG5_PK?&;F|J-O~(c1~SC}F*@B& z8$(jLbuBoaYbk0Ul?z{&NE9yEsB|n0o{Gz;LU4|91JP2LNW>8o{Uab~(2Zu`PZ{_G DyGxoe literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index 96931b78f..08e33bc8b 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ demos/graphsage-test/log # Vim session Session.vim +*.txt diff --git a/demos/.DS_Store b/demos/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e03e0ae2fe6fa4a57617c72c9464fc7a55199887 GIT binary patch literal 6148 zcmeHKPfG$p6n~>uYY}+}@;H}n9uzfC!D4pk78rG?&|Ow^L3hPnlQLt!Mt!3`L0_l$ zW=2u8QxGBV!JFTk_h*Lr?J|D=K-9-x2_Odm7Aj#Xi_He1IO&?CjE7LDF+A|VhXA?| zt!1<0KQchyZXY@@02kY(@8?dUq1z8#jDNbrz8}TK;+IIJGdsI`RyJ#853R>$FPt=E zCmu(2XLPT6zSnV$eG`WLh3&YverM9k9bbe&?D#=vw3PmE=LcRmsfXjhi_|#RPTa#< zHBl>x*gXfp&>+J1aGc53DRB~i+4j*W2 zTQZ5z7($n$Uz$AIV4_i%gHSW$IA&&HUMND%j((}q zLD(9(Wd@jmRR+?!o1^pp^5^&eY7zIC0cK#U7!a98vr)$-nX`3madg&7)HW&!ud6b;-k1AofEH@Nsy*Z=?k literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt index 0f8c4fe20..4ea9305e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,4 +14,3 @@ pytest==3.9.3 pytest-benchmark>=3.1 pytest-cov>=2.6.0 coveralls>=1.5.1 - diff --git a/stellargraph/.DS_Store b/stellargraph/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..79bde8f3936a96fe721af05b76d9e85f538a6d49 GIT binary patch literal 6148 zcmeHK%}T>S5Z-N5O%*W*!5;VGt%sJh_9TQ@58i}`9#qZMLI|5vw~dg75K=)YDm&18BXpkXid4ji0*Kijv6Cee zCy1PtwQ@i*AQ||74A8qm66BN^NUft=HB1o_c4EqRdL| zbefoUe8YOa>p8-{jH2Mvww){A%LdxPX%wcmAA0e^^4n`abfe6SrlFg#eJ<>D1itK` zf!4@#UGFxD-su)ilJ|P8Ch6$MMWL#PN9~jI;du6#KNZg}oK*}@5R-j@b9e<~A;bqO z4udGXhf(UWg~ky41im#6e<{c>1k7oYxM>WC3#0CCTHrEX$$(_wR|e?&KtL%P0!xnU z>41in0D$y2f(h8PmY_aFpdqm22s0p-Fb%wx_BX>tw6dzcej75cl z+3B!9VapLVILcNsAQ@O@pvt=%&HraV*Z<2-vL_jk46GFcSm|4R6G9TXbtO2OYYFHO rlnPx}a%3*hh;+;hnu;5sOkj>s1JDpya)c2O`6Iw+kd0*EPZ{_C2;P+@ literal 0 HcmV?d00001 diff --git a/stellargraph/mapper/link_mappers.py b/stellargraph/mapper/link_mappers.py index 5b086cda3..a791fac85 100755 --- a/stellargraph/mapper/link_mappers.py +++ b/stellargraph/mapper/link_mappers.py @@ -24,7 +24,7 @@ "OnDemandLinkSequence", "GraphSAGELinkGenerator", "HinSAGELinkGenerator", - "attri2vecLinkGenerator" + "attri2vecLinkGenerator", ] import random @@ -208,16 +208,16 @@ def __init__(self, generator, walker): if isinstance(self.generator, GraphSAGELinkGenerator): print( - "Running GraphSAGELinkGenerator with an estimated {} batches generated on the fly per epoch.".format( - round(self.data_size / self.generator.batch_size) - ) - ) + "Running GraphSAGELinkGenerator with an estimated {} batches generated on the fly per epoch.".format( + round(self.data_size / self.generator.batch_size) + ) + ) else: print( - "Running attri2vecLinkGenerator with an estimated {} batches generated on the fly per epoch.".format( - round(self.data_size / self.generator.batch_size) - ) - ) + "Running attri2vecLinkGenerator with an estimated {} batches generated on the fly per epoch.".format( + round(self.data_size / self.generator.batch_size) + ) + ) self._gen = self.walker.generator( self.generator.batch_size @@ -616,6 +616,7 @@ def flow(self, link_ids, targets=None, shuffle=False): return LinkSequence(self, link_ids, targets, shuffle) + class attri2vecLinkGenerator: """ A data generator for link prediction with Homogeneous attri2vec models @@ -643,7 +644,7 @@ class attri2vecLinkGenerator: name, optional: Name of generator """ - def __init__(self, G, batch_size, num_samples=[1,1], seed=None, name=None): + def __init__(self, G, batch_size, num_samples=[1, 1], seed=None, name=None): if not isinstance(G, StellarGraphBase): raise TypeError("Graph must be a StellarGraph object.") @@ -657,9 +658,6 @@ def __init__(self, G, batch_size, num_samples=[1,1], seed=None, name=None): # We need a schema for compatibility with HinSAGE self.schema = G.create_graph_schema(create_type_maps=True) - # The sampler used to generate random samples of neighbours - #self.sampler = SampledBreadthFirstWalk(G, graph_schema=self.schema, seed=seed) - def sample_features(self, head_links, sampling_schema): """ Sample content features of the target nodes and the ids of the context nodes From 189a6122aece4b9d3fe9090ee6f213a9dafe5355 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:03:10 +1000 Subject: [PATCH 05/82] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 08e33bc8b..96931b78f 100644 --- a/.gitignore +++ b/.gitignore @@ -117,4 +117,3 @@ demos/graphsage-test/log # Vim session Session.vim -*.txt From 158f32b6719b046bd3e02507b73f4716a953a630 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:09:43 +1000 Subject: [PATCH 06/82] Delete .DS_Store --- stellargraph/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 stellargraph/.DS_Store diff --git a/stellargraph/.DS_Store b/stellargraph/.DS_Store deleted file mode 100644 index 79bde8f3936a96fe721af05b76d9e85f538a6d49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-N5O%*W*!5;VGt%sJh_9TQ@58i}`9#qZMLI|5vw~dg75K=)YDm&18BXpkXid4ji0*Kijv6Cee zCy1PtwQ@i*AQ||74A8qm66BN^NUft=HB1o_c4EqRdL| zbefoUe8YOa>p8-{jH2Mvww){A%LdxPX%wcmAA0e^^4n`abfe6SrlFg#eJ<>D1itK` zf!4@#UGFxD-su)ilJ|P8Ch6$MMWL#PN9~jI;du6#KNZg}oK*}@5R-j@b9e<~A;bqO z4udGXhf(UWg~ky41im#6e<{c>1k7oYxM>WC3#0CCTHrEX$$(_wR|e?&KtL%P0!xnU z>41in0D$y2f(h8PmY_aFpdqm22s0p-Fb%wx_BX>tw6dzcej75cl z+3B!9VapLVILcNsAQ@O@pvt=%&HraV*Z<2-vL_jk46GFcSm|4R6G9TXbtO2OYYFHO rlnPx}a%3*hh;+;hnu;5sOkj>s1JDpya)c2O`6Iw+kd0*EPZ{_C2;P+@ From 1c24d09321e9fadabf0579b43feeeca0f8c1f253 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:11:23 +1000 Subject: [PATCH 07/82] Delete .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index a7c5630e292e8a22ff249f7a06d0ea30027f092a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}&BV5T1pi#h=K*M2>s$#sLDz$)rI%cr(H1K@GGifhMI(Xpv~e^fmO2d;(v` z*&j?1xp*+9*=c6K*`L|Xe97)~0D!b-ZVjLW046F&V+WfbgwJzblbjkc5Q*3$bmrm2 z@tL!>Ru5<+kqYsl zI}Lmm3~`iu>_G?-hVSEN!xV<7HcViYddf0I#m0cY5woOEV^$eZ7slMpYJfT}&46a$ z*9`FYfueG>6ebeI(}9gB0TB6bgb=iOEx~=LLQ7#H5ob_{bVZb|M3opsy5l%i>nw$d zMClGh6(2;MOjLzJ#Ob&{70ZEG5_PK?&;F|J-O~(c1~SC}F*@B& z8$(jLbuBoaYbk0Ul?z{&NE9yEsB|n0o{Gz;LU4|91JP2LNW>8o{Uab~(2Zu`PZ{_G DyGxoe From c53a5cd2f7bd9ebc1067466f55b0bd57097a32e6 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:11:51 +1000 Subject: [PATCH 08/82] Delete .DS_Store --- demos/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 demos/.DS_Store diff --git a/demos/.DS_Store b/demos/.DS_Store deleted file mode 100644 index e03e0ae2fe6fa4a57617c72c9464fc7a55199887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKPfG$p6n~>uYY}+}@;H}n9uzfC!D4pk78rG?&|Ow^L3hPnlQLt!Mt!3`L0_l$ zW=2u8QxGBV!JFTk_h*Lr?J|D=K-9-x2_Odm7Aj#Xi_He1IO&?CjE7LDF+A|VhXA?| zt!1<0KQchyZXY@@02kY(@8?dUq1z8#jDNbrz8}TK;+IIJGdsI`RyJ#853R>$FPt=E zCmu(2XLPT6zSnV$eG`WLh3&YverM9k9bbe&?D#=vw3PmE=LcRmsfXjhi_|#RPTa#< zHBl>x*gXfp&>+J1aGc53DRB~i+4j*W2 zTQZ5z7($n$Uz$AIV4_i%gHSW$IA&&HUMND%j((}q zLD(9(Wd@jmRR+?!o1^pp^5^&eY7zIC0cK#U7!a98vr)$-nX`3madg&7)HW&!ud6b;-k1AofEH@Nsy*Z=?k From 4517c9f9748aecb33cf54b58d5c03289934471b0 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:33:24 +1000 Subject: [PATCH 09/82] Update README.md --- demos/embeddings/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/demos/embeddings/README.md b/demos/embeddings/README.md index db2c667f7..7f8544371 100644 --- a/demos/embeddings/README.md +++ b/demos/embeddings/README.md @@ -4,11 +4,13 @@ This folder contains three [Jupyter](http://jupyter.org/) python notebooks demon **Node2Vec** and **Metapath2Vec** notebooks demonstrate the combined use of `stellargraph` and `Gensim` [4] libraries for representation learning on homogeneous and heterogeneous graphs. **Unsupervised GraphSAGE** notebook demonstrates the use of `Stellargraph` library's GraphSAGE implementation for unsupervised learning of node embeddings for homogeneous graphs with node features. +**attri2vec** notebook demonstrates the implementation of attri2vec with the `Stellargraph` library for unsupervised inductive learning of node embeddings for homogeneous graphs with node features, and the evaluation for its ablity to infer the representations of out-of-sample nodes with the out-of-sample node link prediction task. The notebooks demonstrate the following algorithms. - `stellargraph-node2vec.ipynb` The **Node2Vec** algorithm [1] for representation learning on homogeneous graphs - `stellargraph-metapath2vec.ipynb` The **Metapath2Vec** algorithm [2] for representation learning on heterogeneous graphs. - `embeddings-unsupervised-graphsage-cora.ipynb` The **Unsupervised GraphSAGE** algorithm [5] for representation learning on homogeneous graphs with node features. +- `stellargraph-attri2vec-DBLP.ipynb` The **attri2vec** algorithm [6] for representation learning on homogeneous graphs with node features. All examples demonstrate how to calculate embedding vectors for a graph's nodes in just a few lines of Python code. The learned node representations can be used in numerous downstream tasks such as node attribute inference, link @@ -32,3 +34,5 @@ G. S. Corrado, and J. Dean. In Advances in Neural Information Processing System **5.** Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) + +**6.** Attributed Network Embedding Via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) From 947c843879eb4811e2c51a68483d7aa691e9a2b9 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:33:46 +1000 Subject: [PATCH 10/82] Update README.md --- demos/embeddings/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/embeddings/README.md b/demos/embeddings/README.md index 7f8544371..b62eb6a0a 100644 --- a/demos/embeddings/README.md +++ b/demos/embeddings/README.md @@ -35,4 +35,4 @@ G. S. Corrado, and J. Dean. In Advances in Neural Information Processing System **5.** Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) -**6.** Attributed Network Embedding Via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) +**6.** Attributed Network Embedding via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) From a37f67c3cc723b8b0c25e007f32fb70b77a4f0c9 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 8 Aug 2019 13:34:56 +1000 Subject: [PATCH 11/82] Update README.md --- demos/embeddings/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/embeddings/README.md b/demos/embeddings/README.md index b62eb6a0a..18f4aa190 100644 --- a/demos/embeddings/README.md +++ b/demos/embeddings/README.md @@ -4,7 +4,7 @@ This folder contains three [Jupyter](http://jupyter.org/) python notebooks demon **Node2Vec** and **Metapath2Vec** notebooks demonstrate the combined use of `stellargraph` and `Gensim` [4] libraries for representation learning on homogeneous and heterogeneous graphs. **Unsupervised GraphSAGE** notebook demonstrates the use of `Stellargraph` library's GraphSAGE implementation for unsupervised learning of node embeddings for homogeneous graphs with node features. -**attri2vec** notebook demonstrates the implementation of attri2vec with the `Stellargraph` library for unsupervised inductive learning of node embeddings for homogeneous graphs with node features, and the evaluation for its ablity to infer the representations of out-of-sample nodes with the out-of-sample node link prediction task. +**attri2vec** notebook demonstrates the implementation of attri2vec with the `Stellargraph` library for unsupervised inductive learning of node embeddings for homogeneous graphs with node features, and the evaluation for its ability to infer the representations of out-of-sample nodes with the out-of-sample node link prediction task. The notebooks demonstrate the following algorithms. - `stellargraph-node2vec.ipynb` The **Node2Vec** algorithm [1] for representation learning on homogeneous graphs From 50ccc0cf7cfa25cb68f45c22459ef08cebcec483 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:08:58 +1000 Subject: [PATCH 12/82] rewrite the attri2vec demo by using the Attri2Vec model, Attri2VecNodeGenerator and Attri2VecLinkGenerator --- .../stellargraph-attri2vec-DBLP.ipynb | 342 +++++++++++++----- 1 file changed, 256 insertions(+), 86 deletions(-) diff --git a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb index 8abfad166..47aefb365 100644 --- a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb +++ b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Infer Representations for Out-of-sample Nodes Through attri2vec" + "# Inferring Representations for Out-of-sample Nodes Through attri2vec" ] }, { @@ -26,9 +26,9 @@ "\n", "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes. Unlike the embeddings learned by DeepWalk/node2vec, the mapping is inductive. Different from the mapping generated by GraphSAGE, the mapping only performs on node content attributes and does not rely on any link information, which makes it possible to construct representations for new coming nodes having few or no link information from their content attributes.\n", "\n", - "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameters used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)`, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", + "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameter vector used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)` pair, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", "\n", - "The entire model is trained end-to-end by minimizing the loss function of choice (e.g., binary cross-entropy between predicted node pair labels and true link labels) using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' links generated on demand and fed into the model.\n", + "The entire model is trained end-to-end by minimizing the binary cross-entropy loss function with regards to predicted node pair labels and true node pair labels, using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' node pairs generated on demand and fed into the model.\n", "\n", "In this demo, we first train the attri2vec model on the in-sample subgraph and obtain a mapping function from node attributes to node representations, then apply the mapping function to the content attributes of out-of-sample nodes and obtain the representations of out-of-sample nodes. We evaluate the quality of inferred out-of-sample node representations by using it to predict the links of out-of-sample nodes." ] @@ -56,16 +56,13 @@ "import stellargraph as sg\n", "from stellargraph.data import UniformRandomWalk\n", "from stellargraph.data import UnsupervisedSampler\n", - "from stellargraph.mapper import attri2vecLinkGenerator\n", + "from stellargraph.mapper import Attri2VecLinkGenerator\n", + "from stellargraph.mapper.node_mappers import Attri2VecNodeGenerator\n", + "from stellargraph.layer import Attri2Vec, link_classification\n", "\n", - "import keras \n", - "from keras.utils import Sequence\n", - "from keras.models import Model\n", - "from keras.layers import Input, Dense, Reshape, merge\n", - "from keras.layers.embeddings import Embedding\n", + "import keras\n", "\n", "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.metrics import accuracy_score\n", "from sklearn.metrics import roc_auc_score" ] }, @@ -87,7 +84,7 @@ "\n", " \t\t \n", " \n", - "> The first entry in each line contains the unique integer ID (ranging from 0 to 18,447) of the paper followed by > binary values indicating whether each word in the vocabulary is present (indicated by 1) or absent (indicated by 0) in the paper. Finally, the last two entries in the line are the class label and the publication year of the paper.\n", + "> The first entry in each line contains the unique integer ID (ranging from 0 to 18,447) of the paper followed by binary values indicating whether each word in the vocabulary is present (indicated by 1) or absent (indicated by 0) in the paper. Finally, the last two entries in the line are the class label and the publication year of the paper.\n", "> The edgeList.txt file contains the citation relations. Each line describes a link in the following format:\n", "\t\t\n", " \n", @@ -143,6 +140,96 @@ "node_data = pd.read_csv(os.path.join(data_dir, \"content.txt\"), sep='\\t', header=None, names=node_column_names)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the whole graph from edge list." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "G_all_nx = nx.from_pandas_edgelist(edgelist, edge_attr=\"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify node types." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "nx.set_node_attributes(G_all_nx, \"paper\", \"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get node features." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "all_node_features = node_data[feature_names]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Stellargraph with node features." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "G_all = sg.StellarGraph(G_all_nx, node_features=all_node_features)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StellarGraph: Undirected multigraph\n", + " Nodes: 18448, Edges: 45611\n", + "\n", + " Node types:\n", + " paper: [18448]\n", + " Edge types: paper-cites->paper\n", + "\n", + " Edge types:\n", + " paper-cites->paper: [45611]\n", + "\n" + ] + } + ], + "source": [ + "print(G_all.info())" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -160,7 +247,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -186,11 +273,11 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ - "Gnx = nx.from_pandas_edgelist(subgraph_edgelist, edge_attr=\"label\")" + "G_sub_nx = nx.from_pandas_edgelist(subgraph_edgelist, edge_attr=\"label\")" ] }, { @@ -202,11 +289,11 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ - "nx.set_node_attributes(Gnx, \"paper\", \"label\")" + "nx.set_node_attributes(G_sub_nx, \"paper\", \"label\")" ] }, { @@ -218,7 +305,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -235,16 +322,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ - "G = sg.StellarGraph(Gnx, node_features=subgraph_node_features)" + "G_sub = sg.StellarGraph(G_sub_nx, node_features=subgraph_node_features)" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -265,7 +352,7 @@ } ], "source": [ - "print(G.info())" + "print(G_sub.info())" ] }, { @@ -284,12 +371,12 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ - "nodes = list(G.nodes())\n", - "number_of_walks = 1\n", + "nodes = list(G_sub.nodes())\n", + "number_of_walks = 2\n", "length = 5" ] }, @@ -302,11 +389,11 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ - "unsupervised_samples = UnsupervisedSampler(G, nodes=nodes, length=length, number_of_walks=number_of_walks)" + "unsupervised_samples = UnsupervisedSampler(G_sub, nodes=nodes, length=length, number_of_walks=number_of_walks)" ] }, { @@ -318,7 +405,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -330,36 +417,38 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Define the attri2vec training generator, which generates a batch of (feature of target node, index of context node, label of node pair) pairs per iteration." + "Define an attri2vec training generator, which generates a batch of (feature of target node, index of context node, label of node pair) pairs per iteration." ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Running attri2vecLinkGenerator with an estimated 2355 batches generated on the fly per epoch.\n" + "Running Attri2VecLinkGenerator with an estimated 4710 batches generated on the fly per epoch.\n" ] } ], "source": [ - "train_gen = attri2vecLinkGenerator(G, batch_size).flow(unsupervised_samples)" + "train_gen = Attri2VecLinkGenerator(G_sub, batch_size).flow(unsupervised_samples)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The following is the keras implementation of attri2vec. The objective attri2vec is equivalent to minimize the cross-entropy loss for predicting the context nodes with target nodes, with the predicted output being the dot product of the \"input embedding\" of target nodes and the \"output embedding\" of target nodes, followed by a sigmoid activation. The \"input embedding\", the objective node representation, is constructed from node content features through a linear transformation followed by a sigmoid activation. The \"out embedding\" is a look-up table for each context node." + "Building the model: a 1-hidden-layer node representation ('input embedding') of the `target` node and the parameter vector ('output embedding') for predicting the existence of `context node` for each `(target context)` pair, with a link classification layer performed on the dot product of the 'input embedding' of the `target` node and the 'output embedding' of the `context` node.\n", + "\n", + "Attri2Vec part of the model, with a 128-dimenssion hidden layer, no bias term, no dropout and no normalization. (Dropout can be switched on by specifying a positive dropout rate, 0 < dropout < 1 and normalization can be set to 'l2'). " ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -367,40 +456,94 @@ "output_type": "stream", "text": [ "WARNING: Logging before flag parsing goes to stderr.\n", - "W0807 17:47:53.407229 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", - "\n", - "W0807 17:47:53.423400 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", - "\n", - "W0807 17:47:53.428951 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", + "W0821 16:57:15.264071 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", + "\n" + ] + } + ], + "source": [ + "layer_sizes = [128]\n", + "attri2vec = Attri2Vec(\n", + " layer_sizes=layer_sizes, generator=train_gen, bias=False, dropout=0.0, normalize=\"None\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0821 16:57:18.045172 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", "\n", - "W0807 17:47:53.504508 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", + "W0821 16:57:18.051191 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", + "\n" + ] + } + ], + "source": [ + "# Build the model and expose input and output sockets of attri2vec, for node pair inputs:\n", + "x_inp, x_out = attri2vec.build()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the link_classification function to generate the prediction, with the 'ip' edge embedding generation method and the 'sigmoid' activation, which actually performs the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node followed by a sigmoid activation. " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "link_classification: using 'ip' method to combine node embeddings into edge embeddings\n" + ] + } + ], + "source": [ + "prediction = link_classification(\n", + " output_dim=1, output_act=\"sigmoid\", edge_embedding_method='ip'\n", + ")(x_out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Stack the Attri2Vec encoder and prediction layer into a Keras model, and specify the loss." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0821 16:57:23.894735 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", "\n", - "W0807 17:47:53.510684 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", + "W0821 16:57:23.901146 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", "\n", - "W0807 17:47:53.517368 140736734368704 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "W0821 16:57:23.909626 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" ] } ], "source": [ - "embedding_size = 256 # set the embedding dimension to 256.\n", - "input_target = Input((G.node_feature_sizes()[\"paper\"],)) # define the input for target nodes as node content features \n", - "input_context = Input((1,)) # define the input for context nodes as node ids\n", - "\n", - "target = Dense(embedding_size, activation='sigmoid')(input_target) # get \"input embedding\" for the target node\n", - "target = Reshape((embedding_size, 1))(target) \n", - "out_embedding = Embedding(len(node_data), embedding_size, input_length=1, name='out_embedding')\n", - "context = out_embedding(input_context) # get the \"output embedding\" for the context node\n", - "context = Reshape((embedding_size, 1))(context)\n", + "model = keras.Model(inputs=x_inp, outputs=prediction)\n", "\n", - "# perform dot product between the \"input embedding\" and the \"output embedding\"\n", - "dot_product = keras.layers.dot([target, context], axes = 1, normalize=False) \n", - "dot_product = Reshape((1,))(dot_product) \n", - "\n", - "output = Dense(1, activation='sigmoid')(dot_product) # get the predicted output\n", - "\n", - "model = Model(inputs=[input_target, input_context], outputs=output)\n", "model.compile(\n", " optimizer=keras.optimizers.Adam(lr=1e-3),\n", " loss=keras.losses.binary_crossentropy,\n", @@ -417,7 +560,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 24, "metadata": { "scrolled": true }, @@ -426,7 +569,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0807 17:47:56.943290 140736734368704 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", + "W0821 16:57:27.992636 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", "\n" ] }, @@ -435,13 +578,13 @@ "output_type": "stream", "text": [ "Epoch 1/4\n", - "2356/2356 [==============================] - 136s 58ms/step - loss: 0.7146 - binary_accuracy: 0.5173\n", + "4711/4711 [==============================] - 93s 20ms/step - loss: 0.6506 - binary_accuracy: 0.6515\n", "Epoch 2/4\n", - "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6876 - binary_accuracy: 0.5374\n", + "4711/4711 [==============================] - 94s 20ms/step - loss: 0.5718 - binary_accuracy: 0.6775\n", "Epoch 3/4\n", - "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6759 - binary_accuracy: 0.5468\n", + "4711/4711 [==============================] - 95s 20ms/step - loss: 0.4567 - binary_accuracy: 0.7736\n", "Epoch 4/4\n", - "2356/2356 [==============================] - 136s 58ms/step - loss: 0.6571 - binary_accuracy: 0.5578\n" + "4711/4711 [==============================] - 94s 20ms/step - loss: 0.2897 - binary_accuracy: 0.8791\n" ] } ], @@ -450,8 +593,8 @@ " train_gen,\n", " epochs=epochs,\n", " verbose=1,\n", - " use_multiprocessing=False,\n", - " workers=0,\n", + " use_multiprocessing=True,\n", + " workers=4,\n", " shuffle=True,\n", ")" ] @@ -467,17 +610,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Get the node embeddings, for both in-sample and out-of-sample nodes, by applying the learned mapping function to node content features." + "Build the node based model for predicting node representations from node content attributes with the learned parameters. Below a Keras model is constructed, with x_inp[0] as input and x_out[0] as output. Note that this model's weights are the same as those of the corresponding node encoder in the previously trained node pair classifier." ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ - "embedding_model = Model(inputs = input_target, outputs = Reshape((embedding_size,))(target))\n", - "node_embeddings = embedding_model.predict(node_data[feature_names].values)" + "x_inp_src = x_inp[0]\n", + "x_out_src = x_out[0]\n", + "embedding_model = keras.Model(inputs=x_inp_src, outputs=x_out_src)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the node embeddings, for both in-sample and out-of-sample nodes, by applying the learned mapping function to node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "369/369 [==============================] - 1s 2ms/step\n" + ] + } + ], + "source": [ + "node_ids = node_data.index\n", + "node_gen = Attri2VecNodeGenerator(G_all, batch_size).flow(node_ids)\n", + "node_embeddings = embedding_model.predict_generator(node_gen, workers=4, verbose=1)" ] }, { @@ -489,7 +659,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -524,7 +694,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -541,7 +711,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -554,7 +724,7 @@ " warm_start=False)" ] }, - "execution_count": 20, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } @@ -573,7 +743,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -589,7 +759,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 31, "metadata": {}, "outputs": [], "source": [ @@ -608,16 +778,16 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.736614362152765" + "0.8109590038749268" ] }, - "execution_count": 23, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -635,7 +805,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ @@ -652,7 +822,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 34, "metadata": {}, "outputs": [ { @@ -665,7 +835,7 @@ " warm_start=False)" ] }, - "execution_count": 25, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -684,7 +854,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 35, "metadata": {}, "outputs": [], "source": [ @@ -700,7 +870,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -719,16 +889,16 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.6651658318918301" + "0.6638026335702683" ] }, - "execution_count": 28, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } From fb7ce3694e1bc8b9490f31d09692b51737c00d16 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:10:48 +1000 Subject: [PATCH 13/82] Add the module to define Attri2Vec class --- stellargraph/layer/attri2vec.py | 212 ++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 stellargraph/layer/attri2vec.py diff --git a/stellargraph/layer/attri2vec.py b/stellargraph/layer/attri2vec.py new file mode 100644 index 000000000..ec4774357 --- /dev/null +++ b/stellargraph/layer/attri2vec.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2018 Data61, CSIRO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +""" +attri2vec + +""" +__all__ = ["Attri2Vec"] + +from keras import Input +from keras import backend as K +from keras.layers import Input, Dense, Lambda, Dropout, Reshape +from keras.layers.embeddings import Embedding +import warnings + + +class Attri2Vec: + """ + Implementation of the attri2vec algorithm of Zhang et al. with Keras layers. + see: https://arxiv.org/abs/1901.04095 + + The model minimally requires specification of the layer sizes as a list of ints + corresponding to the feature dimensions for each hidden layer and a generator object. + + Args: + layer_sizes (list): Hidden feature dimensions for each layer + generator (Sequence): A NodeSequence or LinkSequence. + input_dim (int): The dimensions of the node features used as input to the model. + node_num (int): The number of nodes in the given graph. + bias (bool): If True a bias vector is learnt for each layer in the attri2vec model, default to False. + dropout (float): The dropout supplied to each layer in the attri2vec model, default to 0.0. + normalize (str or None): The normalization used after each layer, default to None. + + """ + + def __init__( + self, + layer_sizes, + generator=None, + input_dim=None, + node_num=None, + bias=False, + dropout=0.0, + normalize=None, + ): + + if normalize == "l2": + self._normalization = Lambda(lambda x: K.l2_normalize(x, axis=-1)) + + elif normalize is None or normalize == "none" or normalize == "None": + self._normalization = Lambda(lambda x: x) + + else: + raise ValueError( + "Normalization should be either 'l2' or 'none'; received '{}'".format( + normalize + ) + ) + + # Get the input_dim and node_num from the generator if it is given + # Use both the schema and head node type from the generator + self.generator = generator + if generator is not None: + feature_sizes = generator.generator.graph.node_feature_sizes() + if len(feature_sizes) > 1: + raise RuntimeError( + "Attri2Vec called on graph with more than one node type." + ) + + self.input_feature_size = feature_sizes.popitem()[1] + self.input_node_num = generator.generator.graph.number_of_nodes() + + elif input_dim is not None and node_num is not None: + self.input_feature_size = input_dim + self.input_node_num = node_num + + else: + raise RuntimeError( + "If generator is not provided, input_dim and node_num must be specified." + ) + + # Model parameters + self.n_layers = len(layer_sizes) + self.bias = bias + self.dropout = dropout + self.activation = "sigmoid" # the activation fuction used in hidden layers + self.initializer = ( + "glorot_uniform" + ) # the initializer for the weights to construct hidden layers + + # Feature dimensions for each layer + self.dims = [self.input_feature_size] + layer_sizes + + def __call__(self, xin): + """ + Construct node representations from node attributes through deep neural network + + Args: + xin (Keras Tensor): Batch input features + + Returns: + Output tensor + """ + # Form Attri2Vec layers iteratively + h_layer = xin + for layer in range(0, self.n_layers): + h_layer = Dropout(self.dropout)(h_layer) + h_layer = Dense( + self.dims[layer + 1], + activation=self.activation, + kernel_initializer=self.initializer, + use_bias=self.bias, + )(h_layer) + h_layer = self._normalization(h_layer) + + return h_layer + + def node_model(self): + """ + Builds a Attri2Vec model for node prediction + + Returns: + tuple: (x_inp, x_out) where ``x_inp`` is a Keras input tensor + for the Attri2Vec model and ``x_out`` is the Keras tensor + for the Attri2Vec model output. + + """ + # Create tensor inputs + x_inp = Input(shape=(self.input_feature_size,)) + + # Output from Attri2Vec model + x_out = self(x_inp) + + return x_inp, x_out + + def link_model(self): + """ + Builds a Attri2Vec model for link or node pair prediction + + Returns: + tuple: (x_inp, x_out) where ``x_inp`` is a list of Keras input tensors for (src, dst) nodes in the node pairs + and ``x_out`` is a list of output tensors for (src, dst) nodes in the node pairs + + """ + # Expose input and output sockets of the model, for source node: + x_inp_src, x_out_src = self.node_model() + + # Expose input and out sockets of the model, for target node: + x_inp_dst = Input(shape=(1,)) + output_embedding = Embedding( + self.input_node_num, + self.dims[self.n_layers], + input_length=1, + name="output_embedding", + ) + x_out_dst = output_embedding(x_inp_dst) + x_out_dst = Reshape((self.dims[self.n_layers],))(x_out_dst) + + x_inp = [x_inp_src, x_inp_dst] + x_out = [x_out_src, x_out_dst] + return x_inp, x_out + + def build(self): + """ + Builds a Attri2Vec model for node or link/node pair prediction, depending on the generator used to construct + the model (whether it is a node or link/node pair generator). + + Returns: + tuple: (x_inp, x_out), where ``x_inp`` contains Keras input tensor(s) + for the specified Attri2Vec model (either node or link/node pair model) and ``x_out`` contains + model output tensor(s) of shape (batch_size, layer_sizes[-1]) + + """ + if self.generator is not None and hasattr(self.generator, "_sampling_schema"): + if len(self.generator._sampling_schema) == 1: + return self.node_model() + elif len(self.generator._sampling_schema) == 2: + return self.link_model() + else: + raise RuntimeError( + "The generator used for model creation is neither a node nor a link generator, " + "unable to figure out how to build the model. Consider using node_model or " + "link_model method explicitly to build node or link prediction model, respectively." + ) + else: + raise RuntimeError( + "Suitable generator is not provided at model creation time, unable to figure out how to build the model. " + "Consider either providing a generator, or using node_model or link_model method explicitly to build node or " + "link prediction model, respectively." + ) + + def default_model(self, flatten_output=True): + warnings.warn( + "The .default_model() method will be deprecated in future versions. " + "Please use .build() method instead.", + PendingDeprecationWarning, + ) + return self.build() From 094650e713b2ad7f726f10aa2ccf90759ea7c0dc Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:12:43 +1000 Subject: [PATCH 14/82] Add the definition of the class: Attri2VecLinkGenerator --- stellargraph/mapper/link_mappers.py | 49 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/stellargraph/mapper/link_mappers.py b/stellargraph/mapper/link_mappers.py index a791fac85..1f3e5b750 100755 --- a/stellargraph/mapper/link_mappers.py +++ b/stellargraph/mapper/link_mappers.py @@ -16,7 +16,7 @@ """ Generators that create batches of data from a machine-learnign ready graph -for link prediction/link attribute inference problems using GraphSAGE and HinSAGE. +for link prediction/link attribute inference problems using GraphSAGE, HinSAGE and Attri2Vec. """ __all__ = [ @@ -24,7 +24,7 @@ "OnDemandLinkSequence", "GraphSAGELinkGenerator", "HinSAGELinkGenerator", - "attri2vecLinkGenerator", + "Attri2VecLinkGenerator", ] import random @@ -56,11 +56,12 @@ class LinkSequence(Sequence): :meth:`keras.Model.evaluate_generator`, and :meth:`keras.Model.predict_generator` This class generates data samples for link inference models and should be created using the :meth:`flow` method of - :class:`GraphSAGELinkGenerator` or :class:`HinSAGELinkGenerator` . + :class:`GraphSAGELinkGenerator` or :class:`HinSAGELinkGenerator` or :class:`Attri2VecLinkGenerator`. Args: - generator: An instance of :class:`GraphSAGELinkGenerator` or :class:`HinSAGELinkGenerator`. + generator: An instance of :class:`GraphSAGELinkGenerator` or :class:`HinSAGELinkGenerator` or + :class:`Attri2VecLinkGenerator`. ids (list or iterable): Link IDs to batch, each link id being a tuple of (src, dst) node ids. - (The graph nodes must have a "feature" attribute that is used as input to the GraphSAGE model.) + (The graph nodes must have a "feature" attribute that is used as input to the GraphSAGE/Attri2Vec model.) These are the links that are to be used to train or inference, and the embeddings calculated for these links via a binary operator applied to their source and destination nodes, are passed to the downstream task of link prediction or link attribute inference. @@ -176,10 +177,10 @@ class OnDemandLinkSequence(Sequence): This class generates data samples for link inference models and should be created using the :meth:`flow` method of - :class:`GraphSAGELinkGenerator` ` . + :class:`GraphSAGELinkGenerator` or :class:`Attri2VecLinkGenerator`. Args: - generator: An instance of :class:`GraphSAGELinkGenerator` or 'attri2vecLink Generator'. + generator: An instance of :class:`GraphSAGELinkGenerator` or 'Attri2VecLinkGenerator'. sampler: An instance of :class:`UnsupervisedSampler` that encapsulates the neighbourhood sampling of a graph. The generator method of this class returns `batch_size` of positive and negative samples on demand. """ @@ -214,7 +215,7 @@ def __init__(self, generator, walker): ) else: print( - "Running attri2vecLinkGenerator with an estimated {} batches generated on the fly per epoch.".format( + "Running Attri2VecLinkGenerator with an estimated {} batches generated on the fly per epoch.".format( round(self.data_size / self.generator.batch_size) ) ) @@ -617,11 +618,11 @@ def flow(self, link_ids, targets=None, shuffle=False): return LinkSequence(self, link_ids, targets, shuffle) -class attri2vecLinkGenerator: +class Attri2VecLinkGenerator: """ - A data generator for link prediction with Homogeneous attri2vec models + A data generator for link/node pair prediction with attri2vec models - At minimum, supply the StellarGraph the batch size. + At minimum, supply the StellarGraph and the batch size. The supplied graph should be a StellarGraph object that is ready for machine learning. Currently the model requires node features for all @@ -633,25 +634,23 @@ class attri2vecLinkGenerator: Example:: - G_generator = attri2vecLinkGenerator(G, 50) + G_generator = Attri2VecLinkGenerator(G, 50) train_data_gen = G_generator.flow(edge_ids) Args: G (StellarGraph): A machine-learning ready graph. batch_size (int): Size of batch of links to return. - num_samples: for compatibility with GraphSAGE - seed (int or str), optional: Random seed for the sampling methods. - name, optional: Name of generator + name, optional: Name of generator. """ - def __init__(self, G, batch_size, num_samples=[1, 1], seed=None, name=None): + def __init__(self, G, batch_size, name=None): if not isinstance(G, StellarGraphBase): raise TypeError("Graph must be a StellarGraph object.") G.check_graph_for_ml(features=True) self.graph = G - self.num_samples = num_samples + self.num_samples = [0] # for compatibility with GraphSAGE self.batch_size = batch_size self.name = name @@ -665,16 +664,16 @@ def sample_features(self, head_links, sampling_schema): Args: head_links: An iterable of edges to perform sampling for. - sampling_schema: The sampling schema for the model, for compatibility - with GraphSAGE and HinSAGE + sampling_schema: The sampling schema for the model, for compatibility with GraphSAGE and HinSAGE. Returns: - a list of feaure arrys, with each element being the feature of a - target node and the id of the corresponding context node + A list of feaure arrys, with each element being the feature of a + target node and the id of the corresponding context node. """ + all_nodes = list(self.graph.nodes()) target_ids = [head_link[0] for head_link in head_links] - context_ids = [head_link[1] for head_link in head_links] + context_ids = [all_nodes.index(head_link[1]) for head_link in head_links] target_feats = self.graph.get_feature_for_nodes(target_ids) batch_feats = [target_feats, np.array(context_ids)] @@ -702,7 +701,7 @@ def flow(self, link_ids, targets=None, shuffle=False): specifying the edges or an UnsupervisedSampler object that has a generator method to generate samples on the fly. targets (optional, array): a 2D array of numeric targets with shape - `(len(link_ids), target_size)` + `(len(link_ids), target_size)`. shuffle (optional, bool): If True the node_ids will be shuffled at each epoch, if False the node_ids will be processed in order. @@ -713,6 +712,10 @@ def flow(self, link_ids, targets=None, shuffle=False): if isinstance(link_ids, UnsupervisedSampler): return OnDemandLinkSequence(self, link_ids) + # Otherwise pass iterable to standard LinkSequence + elif isinstance(link_ids, collections.Iterable): + return LinkSequence(self, link_ids, targets, shuffle) + else: raise TypeError( "Argument to .flow not recognised. " From b9a81c976250eb9712fe42bae907217a980d55c5 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:13:14 +1000 Subject: [PATCH 15/82] Add the definition of the class: Attri2VecNodeGenerator --- stellargraph/mapper/node_mappers.py | 142 ++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 9 deletions(-) mode change 100644 => 100755 stellargraph/mapper/node_mappers.py diff --git a/stellargraph/mapper/node_mappers.py b/stellargraph/mapper/node_mappers.py old mode 100644 new mode 100755 index 1e9518b9c..b94fc0db4 --- a/stellargraph/mapper/node_mappers.py +++ b/stellargraph/mapper/node_mappers.py @@ -22,6 +22,7 @@ "NodeSequence", "GraphSAGENodeGenerator", "HinSAGENodeGenerator", + "Attri2VecNodeGenerator", "FullBatchNodeGenerator", "FullBatchNodeSequence", "SparseFullBatchNodeSequence", @@ -54,17 +55,22 @@ class NodeSequence(Sequence): This class generated data samples for node inference models and should be created using the `.flow(...)` method of - :class:`GraphSAGENodeGenerator` or :class:`HinSAGENodeGenerator`. - - These Generators are classes that capture the graph structure - and the feature vectors of each node. These generator classes - are used within the NodeSequence to generate samples of k-hop - neighbourhoods in the graph and to return to this class the - features from the sampled neighbourhoods. + :class:`GraphSAGENodeGenerator` or :class:`HinSAGENodeGenerator` + or :class:`Attri2vecNodeGenerator`. + + GraphSAGENodeGenerator and HinSAGENodeGenerator are classes that + capture the graph structure and the feature vectors of each node. + These generator classes are used within the NodeSequence to generate + samples of k-hop neighbourhoods in the graph and to return to this + class the features from the sampled neighbourhoods. + + Attri2VecNodeGenerator is the class that captures node feature vectors + of each node. Args: - generator: GraphSAGENodeGenerator or HinSAGENodeGenerator - The generator object containing the graph information. + generator: GraphSAGENodeGenerator or HinSAGENodeGenerator or + Attri2VecNodeGenerator. The generator object containing the + graph information. ids: list A list of the node_ids to be used as head-nodes in the downstream task. @@ -508,6 +514,124 @@ def flow_from_dataframe(self, node_targets, shuffle=False): ) +class Attri2VecNodeGenerator: + """ + A data generator for node prediction with attri2vec models + + At minimum, supply the StellarGraph and the batch size. + + The supplied graph should be a StellarGraph object that is ready for + machine learning. Currently the model requires node features for all + nodes in the graph. + + Use the :meth:`flow` method supplying the nodes and (optionally) targets + to get an object that can be used as a Keras data generator. + + Example:: + + G_generator = Attri2VecNodeGenerator(G, 50) + train_data_gen = G_generator.flow(train_node_ids, train_node_labels) + test_data_gen = G_generator.flow(test_node_ids) + + Args: + G (StellarGraph): The machine-learning ready graph. + batch_size (int): Size of batch to return. + name (str or None): Name of the generator (optional). + """ + + def __init__(self, G, batch_size, name=None): + if not isinstance(G, StellarGraphBase): + raise TypeError("Graph must be a StellarGraph object.") + + self.graph = G + self.num_samples = [0] # for compatibility with GraphSAGE + self.batch_size = batch_size + self.name = name + + # Check if the graph has features + G.check_graph_for_ml() + + # We need a schema for compatibility with HinSAGE + self.schema = G.create_graph_schema(create_type_maps=True) + + # Check that there is only a single node type for Attri2Vec + if len(self.schema.node_types) > 1: + print( + "Warning: running homogeneous Attri2Vec on a graph with multiple node types" + ) + + def sample_features(self, head_nodes, sampling_schema): + """ + Sample content features of the head nodes, and return these as a list of feature + arrays for the attri2vec algorithm. + + Args: + head_nodes: An iterable of head nodes to perform sampling on. + sampling_schema: The sampling schema for the model, for compatibility with GraphSAGE and HinSAGE. + + Returns: + A list of feaure arrys, with each element being the feature of a + head node. + """ + + batch_feats = self.graph.get_feature_for_nodes(head_nodes) + return batch_feats + + def flow(self, node_ids, targets=None, shuffle=False): + """ + Creates a generator/sequence object for training or evaluation + with the supplied node ids and numeric targets. + + The node IDs are the nodes to train or inference on: the embeddings + calculated for these nodes are passed to the downstream task. These + are a subset of the nodes in the graph. + + The targets are an array of numeric targets corresponding to the + supplied node_ids to be used by the downstream task. They should + be given in the same order as the list of node IDs. + If they are not specified (for example, for use in prediction), + the targets will not be available to the downsteam task. + + Note that the shuffle argument should be True for training and + False for prediction. + + Args: + node_ids: an iterable of node IDs. + targets: a 2D array of numeric targets with shape + `(len(node_ids), target_size)`. + shuffle (bool): If True the node_ids will be shuffled at each + epoch, if False the node_ids will be processed in order. + + Returns: + A NodeSequence object to use with the Attri2Vec model + in Keras methods ``fit_generator``, ``evaluate_generator``, + and ``predict_generator``. + + """ + return NodeSequence(self, node_ids, targets, shuffle=shuffle) + + def flow_from_dataframe(self, node_targets, shuffle=False): + """ + Creates a generator/sequence object for training or evaluation + with the supplied node ids and numeric targets. + + Args: + node_targets: a Pandas DataFrame of numeric targets indexed + by the node ID for that target. + shuffle (bool): If True the node_ids will be shuffled at each + epoch, if False the node_ids will be processed in order. + + Returns: + A NodeSequence object to use with the Attri2Vec model + in Keras methods ``fit_generator``, ``evaluate_generator``, + and ``predict_generator``. + + """ + return NodeSequence( + self, node_targets.index, node_targets.values, shuffle=shuffle + ) + + class SparseFullBatchNodeSequence(Sequence): """ Keras-compatible data generator for for node inference models From 04dbc46b3ed587848263bec4b0e65da998d22dc6 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:14:55 +1000 Subject: [PATCH 16/82] Add the test for Attri2VecNodeGenerator --- tests/mapper/test_node_mappers.py | 153 ++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) mode change 100644 => 100755 tests/mapper/test_node_mappers.py diff --git a/tests/mapper/test_node_mappers.py b/tests/mapper/test_node_mappers.py old mode 100644 new mode 100755 index 39c66dc24..9002bf32b --- a/tests/mapper/test_node_mappers.py +++ b/tests/mapper/test_node_mappers.py @@ -682,6 +682,159 @@ def test_hinnodemapper_no_neighbors(): assert np.all(batch_feats[3][:, 0, 0] == np.array([12, 0, 0])) +def test_attri2vec_nodemapper_constructor_nx(): + """ + Attri2VecNodeGenerator requires a StellarGraph object + """ + G = nx.Graph() + G.add_nodes_from(range(4)) + + with pytest.raises(TypeError): + Attri2VecNodeGenerator(G, batch_size=2) + + +def test_attri2vec_nodemapper_constructor_no_feats(): + """ + Attri2VecNodeGenerator requires the graph to have features + """ + + G = example_graph_1() + with pytest.raises(RuntimeError): + Attri2VecNodeGenerator(G, batch_size=2) + + +def test_attri2vec_nodemapper_constructor(): + n_feat = 4 + + G = example_graph_1(feature_size=n_feat) + + generator = Attri2VecNodeGenerator(G, batch_size=2) + + mapper = generator.flow(list(G)) + + assert generator.batch_size == 2 + assert mapper.data_size == 4 + assert len(mapper.ids) == 4 + + +def test_attri2vec_nodemapper_1(): + n_feat = 4 + n_batch = 2 + + # test graph + G1 = example_graph_1(n_feat) + + mapper1 = Attri2VecNodeGenerator(G1, batch_size=n_batch).flow(G1.nodes()) + assert len(mapper1) == 2 + + G2 = example_graph_2(n_feat) + + mapper2 = Attri2VecNodeGenerator(G2, batch_size=n_batch).flow(G2.nodes()) + assert len(mapper2) == 3 + + for mapper in [mapper1, mapper2]: + for ii in range(2): + nf, nl = mapper[ii] + assert nf.shape == (n_batch, n_feat) + assert nl is None + + # Check beyond the graph lengh + with pytest.raises(IndexError): + nf, nl = mapper1[len(mapper1)] + + # Check the last batch + nf, nl = mapper2[len(mapper2) - 1] + assert nf.shape == (1, n_feat) + + # This will fail as the nodes are not in the graph + with pytest.raises(KeyError): + Attri2VecNodeGenerator(G1, batch_size=2).flow(["A", "B"]) + + +def test_attri2vec_nodemapper_shuffle(): + n_feat = 1 + n_batch = 2 + + G = example_graph_2(feature_size=n_feat) + nodes = list(G.nodes()) + + # With shuffle + random.seed(15) + mapper = Attri2VecNodeGenerator(G, batch_size=n_batch).flow( + nodes, nodes, shuffle=True + ) + + expected_node_batches = [[5, 4], [3, 1], [2]] + assert len(mapper) == 3 + for ii in range(len(mapper)): + nf, nl = mapper[ii] + assert all(np.ravel(nf) == expected_node_batches[ii]) + assert all(np.array(nl) == expected_node_batches[ii]) + + # This should re-shuffle the IDs + mapper.on_epoch_end() + expected_node_batches = [[4, 3], [1, 5], [2]] + assert len(mapper) == 3 + for ii in range(len(mapper)): + nf, nl = mapper[ii] + assert all(np.ravel(nf) == expected_node_batches[ii]) + assert all(np.array(nl) == expected_node_batches[ii]) + + # With no shuffle + mapper = Attri2VecNodeGenerator(G, batch_size=n_batch).flow( + nodes, nodes, shuffle=False + ) + expected_node_batches = [[1, 2], [3, 4], [5]] + assert len(mapper) == 3 + for ii in range(len(mapper)): + nf, nl = mapper[ii] + assert all(np.ravel(nf) == expected_node_batches[ii]) + assert all(np.array(nl) == expected_node_batches[ii]) + + +def test_attri2vec_nodemapper_with_labels(): + n_feat = 4 + n_batch = 2 + + # test graph + G2 = example_graph_2(n_feat) + nodes = list(G2) + labels = [n * 2 for n in nodes] + + gen = Attri2VecNodeGenerator(G2, batch_size=n_batch).flow(nodes, labels) + assert len(gen) == 3 + + for ii in range(3): + nf, nl = gen[ii] + + # Check sizes - note batch sizes are (2,2,1) for each iteration + assert nf.shape[1:] == (n_feat,) + + # Check labels + assert all(int(a) == int(2 * b) for a, b in zip(nl, nf[:, 0])) + + # Check beyond the graph lengh + with pytest.raises(IndexError): + nf, nl = gen[len(gen)] + + +def test_attri2vec_nodemapper_incorrect_targets(): + """ + Tests checks on target shape + """ + n_feat = 4 + n_batch = 2 + + # test graph + G = example_graph_1(feature_size=n_feat) + + with pytest.raises(TypeError): + Attri2VecNodeGenerator(G, batch_size=n_batch).flow(list(G), 1) + + with pytest.raises(ValueError): + Attri2VecNodeGenerator(G, batch_size=n_batch).flow(list(G), targets=[]) + + def create_graph_features(): G = nx.Graph() G.add_nodes_from(["a", "b", "c"]) From 3e906417312a6e5e539ccedfe9dd04218f0b1557 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:15:17 +1000 Subject: [PATCH 17/82] Add test for Attri2VecLinkGenerator --- tests/mapper/test_link_mappers.py | 151 ++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) mode change 100644 => 100755 tests/mapper/test_link_mappers.py diff --git a/tests/mapper/test_link_mappers.py b/tests/mapper/test_link_mappers.py old mode 100644 new mode 100755 index 7a033a623..b4a428f11 --- a/tests/mapper/test_link_mappers.py +++ b/tests/mapper/test_link_mappers.py @@ -695,3 +695,154 @@ def test_HinSAGELinkGenerator_isolates(self): # With two isolates, all features are zero assert all(pytest.approx(0) == x for x in ne[2:]) + + +class Test_Attri2VecLinkGenerator: + """ + Tests of Attri2VecLinkGenerator class + """ + + n_feat = 4 + batch_size = 2 + + def test_LinkMapper_constructor(self): + + G = example_Graph_1(self.n_feat) + edge_labels = [0] * G.number_of_edges() + + generator = Attri2VecLinkGenerator(G, batch_size=self.batch_size) + mapper = generator.flow(G.edges(), edge_labels) + assert generator.batch_size == self.batch_size + assert mapper.data_size == G.number_of_edges() + assert len(mapper.ids) == G.number_of_edges() + + G = example_DiGraph_1(self.n_feat) + edge_labels = [0] * G.number_of_edges() + generator = Attri2VecLinkGenerator(G, batch_size=self.batch_size) + mapper = generator.flow(G.edges(), edge_labels) + assert generator.batch_size == self.batch_size + assert mapper.data_size == G.number_of_edges() + assert len(mapper.ids) == G.number_of_edges() + + def test_Attri2VecLinkGenerator_1(self): + + G = example_Graph_2(self.n_feat) + data_size = G.number_of_edges() + edge_labels = [0] * data_size + + mapper = Attri2VecLinkGenerator(G, batch_size=self.batch_size).flow( + G.edges(), edge_labels + ) + + assert len(mapper) == 2 + + for batch in range(len(mapper)): + nf, nl = mapper[batch] + assert len(nf) == 2 + assert nf[0].shape == (min(self.batch_size, data_size), self.n_feat) + assert nf[1].shape == (min(self.batch_size, data_size),) + assert len(nl) == min(self.batch_size, data_size) + assert all(nl == 0) + + with pytest.raises(IndexError): + nf, nl = mapper[2] + + def test_Attri2VecLinkGenerator_shuffle(self): + def test_edge_consistency(shuffle): + G = example_Graph_2(1) + edges = list(G.edges()) + nodes = list(G.nodes()) + edge_labels = list(range(len(edges))) + + mapper = Attri2VecLinkGenerator(G, batch_size=2).flow( + edges, edge_labels, shuffle=shuffle + ) + + assert len(mapper) == 2 + + for batch in range(len(mapper)): + nf, nl = mapper[batch] + e1 = edges[nl[0]] + e2 = edges[nl[1]] + assert nf[0][0, 0] == e1[0] + assert nf[1][0] == nodes.index(e1[1]) + assert nf[0][1, 0] == e2[0] + assert nf[1][1] == nodes.index(e2[1]) + + test_edge_consistency(True) + test_edge_consistency(False) + + def test_Attri2VecLinkGenerator_not_Stellargraph(self): + G = nx.Graph() + elist = [(1, 2), (2, 3), (1, 4), (3, 2)] + G.add_edges_from(elist) + + # Add example features + for v in G.nodes(): + G.node[v]["feature"] = np.ones(1) + + with pytest.raises(TypeError): + Attri2VecLinkGenerator(G, batch_size=self.batch_size) + + def test_Attri2VecLinkGenerator_no_targets(self): + """ + This tests link generator's iterator for prediction, i.e., without targets provided + """ + G = example_Graph_2(self.n_feat) + gen = Attri2VecLinkGenerator(G, batch_size=self.batch_size).flow(G.edges()) + for i in range(len(gen)): + assert gen[i][1] is None + + def test_Attri2VecLinkGenerator_unsupervisedSampler_flow(self): + """ + This tests link generator's initialization for on demand link generation i.e. there is no pregenerated list of samples provided to it. + """ + n_feat = 4 + n_batch = 2 + + # test graph + G = example_graph_random( + feature_size=n_feat, n_nodes=6, n_isolates=2, n_edges=10 + ) + + unsupervisedSamples = UnsupervisedSampler(G, nodes=G.nodes) + + gen = Attri2VecLinkGenerator(G, batch_size=n_batch).flow(unsupervisedSamples) + + # The flow method is not passed UnsupervisedSampler object or a list of samples is not passed + with pytest.raises(TypeError): + gen = Attri2VecLinkGenerator(G, batch_size=n_batch).flow( + "not_a_list_of_samples_or_a_sample_generator" + ) + + # The flow method is not passed nothing + with pytest.raises(TypeError): + gen = Attri2VecLinkGenerator(G, batch_size=n_batch).flow() + + def test_Attri2VecLinkGenerator_unsupervisedSampler_sample_generation(self): + + G = example_Graph_2(self.n_feat) + + unsupervisedSamples = UnsupervisedSampler(G) + + mapper = Attri2VecLinkGenerator(G, batch_size=self.batch_size).flow( + unsupervisedSamples + ) + + assert mapper.data_size == 16 + assert self.batch_size == 2 + assert len(mapper) == 8 + + for batch in range(len(mapper)): + nf, nl = mapper[batch] + + assert len(nf) == 2 + assert len(set(mapper.head_node_types)) == 1 + + assert nf[0].shape == (min(self.batch_size, mapper.data_size), self.n_feat) + assert nf[1].shape == (min(self.batch_size, mapper.data_size),) + assert len(nl) == min(self.batch_size, mapper.data_size) + assert sorted(nl) == [0, 1] + + with pytest.raises(IndexError): + nf, nl = mapper[8] From 1a8a981891b07e966fc1fc93af887137025e4929 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:16:15 +1000 Subject: [PATCH 18/82] Add tests for Attri2Vec class --- tests/layer/test_attri2vec.py | 138 ++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tests/layer/test_attri2vec.py diff --git a/tests/layer/test_attri2vec.py b/tests/layer/test_attri2vec.py new file mode 100644 index 000000000..84d188219 --- /dev/null +++ b/tests/layer/test_attri2vec.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2018 Data61, CSIRO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +""" +Attri2Vec tests + +""" +from stellargraph.core.graph import StellarGraph +from stellargraph.mapper.node_mappers import Attri2VecNodeGenerator +from stellargraph.layer.attri2vec import * + +import keras +import numpy as np +import networkx as nx +import pytest + +from keras.engine import saving + + +def example_graph_1(feature_size=None): + G = nx.Graph() + elist = [(1, 2), (2, 3), (1, 4), (3, 2)] + G.add_nodes_from([1, 2, 3, 4], label="default") + G.add_edges_from(elist, label="default") + + # Add example features + if feature_size is not None: + for v in G.nodes(): + G.node[v]["feature"] = np.ones(feature_size) + return StellarGraph(G, node_features="feature") + + else: + return StellarGraph(G) + + +def test_attri2vec_constructor(): + attri2vec = Attri2Vec(layer_sizes=[4], input_dim=2, node_num=4, normalize="l2") + assert attri2vec.dims == [2, 4] + assert attri2vec.input_node_num == 4 + assert attri2vec.n_layers == 1 + assert attri2vec.bias == False + + # Check incorrect normalization flag + with pytest.raises(ValueError): + Attri2Vec(layer_sizes=[4], input_dim=2, node_num=4, normalize=lambda x: x) + + with pytest.raises(ValueError): + Attri2Vec(layer_sizes=[4], input_dim=2, node_num=4, normalize="unknown") + + # Check requirement for generator or input_dim and node_num + with pytest.raises(RuntimeError): + Attri2Vec(layer_sizes=[4]) + + # Construction from generator + G = example_graph_1(feature_size=3) + gen = Attri2VecNodeGenerator(G, batch_size=2).flow([1, 2]) + attri2vec = Attri2Vec(layer_sizes=[4, 8], generator=gen, bias=True) + + assert attri2vec.dims == [3, 4, 8] + assert attri2vec.input_node_num == 4 + assert attri2vec.n_layers == 2 + assert attri2vec.bias + + +def test_attri2vec_apply(): + attri2vec = Attri2Vec( + layer_sizes=[4], bias=False, input_dim=2, node_num=4, normalize=None + ) + + inp = keras.Input(shape=(1, 2)) + out = attri2vec(inp) + model = keras.Model(inputs=inp, outputs=out) + + +def test_attri2vec_apply_1(): + attri2vec = Attri2Vec( + layer_sizes=[2, 2, 2], bias=False, input_dim=2, node_num=4, normalize=None + ) + attri2vec.activation = "linear" + attri2vec.initializer = "ones" + + inp = keras.Input(shape=(2,)) + out = attri2vec(inp) + model = keras.Model(inputs=inp, outputs=out) + + x = np.array([[1, 2]]) + expected = np.array([[12, 12]]) + + actual = model.predict(x) + assert expected == pytest.approx(actual) + + # Use the node model: + xinp, xout = attri2vec.node_model() + model2 = keras.Model(inputs=xinp, outputs=xout) + assert pytest.approx(expected) == model2.predict(x) + + +def test_attri2vec_serialize(): + attri2vec = Attri2Vec( + layer_sizes=[4], bias=False, input_dim=2, node_num=4, normalize=None + ) + attri2vec.activation = "linear" + attri2vec.initializer = "ones" + + inp = keras.Input(shape=(2,)) + out = attri2vec(inp) + model = keras.Model(inputs=inp, outputs=out) + + # Save model + model_json = model.to_json() + + # Set all weights to one + model_weights = [np.ones_like(w) for w in model.get_weights()] + + # Load model from json & set all weights + model2 = keras.models.model_from_json(model_json) + model2.set_weights(model_weights) + + # Test loaded model + x = np.array([[1, 2]]) + expected = np.array([[3, 3, 3, 3]]) + + actual = model2.predict(x) + assert expected == pytest.approx(actual) From 4085790f643df36836be68240d3a0dafe93adc4a Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:17:46 +1000 Subject: [PATCH 19/82] Add the Attri2Vec, Attri2VecNodeGenerator and Attri2VecLinkGenerator to api --- docs/api.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) mode change 100644 => 100755 docs/api.txt diff --git a/docs/api.txt b/docs/api.txt old mode 100644 new mode 100755 index c206b3efc..2479042df --- a/docs/api.txt +++ b/docs/api.txt @@ -19,7 +19,7 @@ Generators ----------- .. automodule:: stellargraph.mapper - :members: FullBatchNodeGenerator, GraphSAGENodeGenerator, GraphSAGELinkGenerator, HinSAGENodeGenerator, HinSAGELinkGenerator + :members: FullBatchNodeGenerator, GraphSAGENodeGenerator, GraphSAGELinkGenerator, HinSAGENodeGenerator, HinSAGELinkGenerator, Attri2VecNodeGenerator, Attri2VecLinkGenerator GraphSAGE model @@ -36,6 +36,13 @@ HinSAGE model :members: HinSAGE, MeanHinAggregator +Attri2Vec model +---------------- + +.. automodule:: stellargraph.layer.attri2vec + :members: Attri2Vec + + GCN model ------------- From 37ce44df007c65892a1ef0c453294937cf955325 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:20:18 +1000 Subject: [PATCH 20/82] Add attri2vec module to the stellargraph/layer/__init__.py file --- stellargraph/layer/__init__.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 stellargraph/layer/__init__.py diff --git a/stellargraph/layer/__init__.py b/stellargraph/layer/__init__.py old mode 100644 new mode 100755 index 87926b106..228c7ce0b --- a/stellargraph/layer/__init__.py +++ b/stellargraph/layer/__init__.py @@ -27,5 +27,6 @@ from .graph_attention import * from .link_inference import * from .gcn import * +from .attri2vec import * from .misc import SqueezedSparseConversion from .preprocessing_layer import GraphPreProcessingLayer From 208835e60368a2908d32ef23f9e3fd04aeab2a43 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 21 Aug 2019 17:33:54 +1000 Subject: [PATCH 21/82] rerun the attri2vec demo --- .../stellargraph-attri2vec-DBLP.ipynb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb index 47aefb365..52bd0b6ba 100644 --- a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb +++ b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb @@ -456,7 +456,7 @@ "output_type": "stream", "text": [ "WARNING: Logging before flag parsing goes to stderr.\n", - "W0821 16:57:15.264071 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", + "W0821 17:24:39.472835 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", "\n" ] } @@ -477,9 +477,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 16:57:18.045172 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", + "W0821 17:24:40.300625 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", "\n", - "W0821 16:57:18.051191 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", + "W0821 17:24:40.306243 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", "\n" ] } @@ -531,11 +531,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 16:57:23.894735 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", + "W0821 17:24:43.567921 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", "\n", - "W0821 16:57:23.901146 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", + "W0821 17:24:43.574287 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", "\n", - "W0821 16:57:23.909626 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "W0821 17:24:43.582134 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" ] @@ -569,7 +569,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 16:57:27.992636 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", + "W0821 17:24:45.546332 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", "\n" ] }, @@ -578,13 +578,13 @@ "output_type": "stream", "text": [ "Epoch 1/4\n", - "4711/4711 [==============================] - 93s 20ms/step - loss: 0.6506 - binary_accuracy: 0.6515\n", + "4711/4711 [==============================] - 92s 20ms/step - loss: 0.6903 - binary_accuracy: 0.6251\n", "Epoch 2/4\n", - "4711/4711 [==============================] - 94s 20ms/step - loss: 0.5718 - binary_accuracy: 0.6775\n", + "4711/4711 [==============================] - 93s 20ms/step - loss: 0.6135 - binary_accuracy: 0.6346\n", "Epoch 3/4\n", - "4711/4711 [==============================] - 95s 20ms/step - loss: 0.4567 - binary_accuracy: 0.7736\n", + "4711/4711 [==============================] - 93s 20ms/step - loss: 0.5289 - binary_accuracy: 0.7100\n", "Epoch 4/4\n", - "4711/4711 [==============================] - 94s 20ms/step - loss: 0.2897 - binary_accuracy: 0.8791\n" + "4711/4711 [==============================] - 94s 20ms/step - loss: 0.3581 - binary_accuracy: 0.8372\n" ] } ], @@ -784,7 +784,7 @@ { "data": { "text/plain": [ - "0.8109590038749268" + "0.7857757735930484" ] }, "execution_count": 32, @@ -895,7 +895,7 @@ { "data": { "text/plain": [ - "0.6638026335702683" + "0.6631950060001668" ] }, "execution_count": 37, From 6179a3adc08bffe76ec74074b0b02c828d637940 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Thu, 22 Aug 2019 10:52:27 +1000 Subject: [PATCH 22/82] update the attri2vec demo by fixing some typos --- .../stellargraph-attri2vec-DBLP.ipynb | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb index 52bd0b6ba..618865352 100644 --- a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb +++ b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb @@ -56,8 +56,7 @@ "import stellargraph as sg\n", "from stellargraph.data import UniformRandomWalk\n", "from stellargraph.data import UnsupervisedSampler\n", - "from stellargraph.mapper import Attri2VecLinkGenerator\n", - "from stellargraph.mapper.node_mappers import Attri2VecNodeGenerator\n", + "from stellargraph.mapper import Attri2VecLinkGenerator, Attri2VecNodeGenerator\n", "from stellargraph.layer import Attri2Vec, link_classification\n", "\n", "import keras\n", @@ -456,7 +455,7 @@ "output_type": "stream", "text": [ "WARNING: Logging before flag parsing goes to stderr.\n", - "W0821 17:24:39.472835 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", + "W0822 10:43:54.482249 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", "\n" ] } @@ -477,9 +476,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 17:24:40.300625 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", + "W0822 10:43:56.449973 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", "\n", - "W0821 17:24:40.306243 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", + "W0822 10:43:56.455691 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", "\n" ] } @@ -531,11 +530,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 17:24:43.567921 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", + "W0822 10:44:02.083713 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", "\n", - "W0821 17:24:43.574287 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", + "W0822 10:44:02.091721 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", "\n", - "W0821 17:24:43.582134 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "W0822 10:44:02.102672 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" ] @@ -569,7 +568,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "W0821 17:24:45.546332 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", + "W0822 10:44:04.704549 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", "\n" ] }, @@ -578,13 +577,13 @@ "output_type": "stream", "text": [ "Epoch 1/4\n", - "4711/4711 [==============================] - 92s 20ms/step - loss: 0.6903 - binary_accuracy: 0.6251\n", + "4711/4711 [==============================] - 89s 19ms/step - loss: 0.6678 - binary_accuracy: 0.6432\n", "Epoch 2/4\n", - "4711/4711 [==============================] - 93s 20ms/step - loss: 0.6135 - binary_accuracy: 0.6346\n", + "4711/4711 [==============================] - 92s 19ms/step - loss: 0.5859 - binary_accuracy: 0.6642\n", "Epoch 3/4\n", - "4711/4711 [==============================] - 93s 20ms/step - loss: 0.5289 - binary_accuracy: 0.7100\n", + "4711/4711 [==============================] - 91s 19ms/step - loss: 0.4810 - binary_accuracy: 0.7541\n", "Epoch 4/4\n", - "4711/4711 [==============================] - 94s 20ms/step - loss: 0.3581 - binary_accuracy: 0.8372\n" + "4711/4711 [==============================] - 93s 20ms/step - loss: 0.3283 - binary_accuracy: 0.8544\n" ] } ], @@ -676,11 +675,11 @@ " if source_year < year_thresh and target_year < year_thresh:\n", " in_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", - " in_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative node\n", + " in_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", " else:\n", " out_of_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", - " out_of_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative node\n", + " out_of_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", "in_sample_edges = np.array(in_sample_edges)\n", "out_of_sample_edges = np.array(out_of_sample_edges)" ] @@ -784,7 +783,7 @@ { "data": { "text/plain": [ - "0.7857757735930484" + "0.798202033278801" ] }, "execution_count": 32, @@ -895,7 +894,7 @@ { "data": { "text/plain": [ - "0.6631950060001668" + "0.6638897794650095" ] }, "execution_count": 37, From f959e65469f05ab8e620be732ae7f0d56c266ae1 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 10:57:25 +1000 Subject: [PATCH 23/82] code update --- tests/mapper/test_link_mappers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/mapper/test_link_mappers.py b/tests/mapper/test_link_mappers.py index b4a428f11..8442cd088 100755 --- a/tests/mapper/test_link_mappers.py +++ b/tests/mapper/test_link_mappers.py @@ -837,7 +837,6 @@ def test_Attri2VecLinkGenerator_unsupervisedSampler_sample_generation(self): nf, nl = mapper[batch] assert len(nf) == 2 - assert len(set(mapper.head_node_types)) == 1 assert nf[0].shape == (min(self.batch_size, mapper.data_size), self.n_feat) assert nf[1].shape == (min(self.batch_size, mapper.data_size),) From 36a7cd8b2ca384e153687a1ce0298ae527ebc466 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 10:57:46 +1000 Subject: [PATCH 24/82] code update --- tests/layer/test_attri2vec.py | 68 ++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/tests/layer/test_attri2vec.py b/tests/layer/test_attri2vec.py index 84d188219..0701128a6 100644 --- a/tests/layer/test_attri2vec.py +++ b/tests/layer/test_attri2vec.py @@ -23,13 +23,11 @@ from stellargraph.mapper.node_mappers import Attri2VecNodeGenerator from stellargraph.layer.attri2vec import * -import keras +from tensorflow import keras import numpy as np import networkx as nx import pytest -from keras.engine import saving - def example_graph_1(feature_size=None): G = nx.Graph() @@ -78,43 +76,65 @@ def test_attri2vec_constructor(): def test_attri2vec_apply(): attri2vec = Attri2Vec( - layer_sizes=[4], bias=False, input_dim=2, node_num=4, normalize=None - ) - - inp = keras.Input(shape=(1, 2)) - out = attri2vec(inp) - model = keras.Model(inputs=inp, outputs=out) - - -def test_attri2vec_apply_1(): - attri2vec = Attri2Vec( - layer_sizes=[2, 2, 2], bias=False, input_dim=2, node_num=4, normalize=None + layer_sizes=[2, 2, 2], + bias=False, + input_dim=2, + node_num=4, + activation="linear", + normalize=None, ) - attri2vec.activation = "linear" - attri2vec.initializer = "ones" - - inp = keras.Input(shape=(2,)) - out = attri2vec(inp) - model = keras.Model(inputs=inp, outputs=out) x = np.array([[1, 2]]) expected = np.array([[12, 12]]) - actual = model.predict(x) + inp = keras.Input(shape=(2,)) + out = attri2vec(inp) + model1 = keras.Model(inputs=inp, outputs=out) + model_weights1 = [np.ones_like(w) for w in model1.get_weights()] + model1.set_weights(model_weights1) + actual = model1.predict(x) assert expected == pytest.approx(actual) # Use the node model: xinp, xout = attri2vec.node_model() model2 = keras.Model(inputs=xinp, outputs=xout) + model_weights2 = [np.ones_like(w) for w in model2.get_weights()] + model2.set_weights(model_weights2) assert pytest.approx(expected) == model2.predict(x) + x1 = np.array([[3, 1]]) + x2 = np.array([[2]]) + y1 = np.array([[16, 16]]) + y2 = np.array([[1, 1]]) + + # Test the build function: + xinp, xout = attri2vec.build() + model3 = keras.Model(inputs=xinp, outputs=xout) + model_weights3 = [np.ones_like(w) for w in model3.get_weights()] + model3.set_weights(model_weights3) + actual = model3.predict([x1, x2]) + assert pytest.approx(y1) == actual[0] + assert pytest.approx(y2) == actual[1] + + # Use the link model: + xinp, xout = attri2vec.link_model() + model4 = keras.Model(inputs=xinp, outputs=xout) + model_weights4 = [np.ones_like(w) for w in model4.get_weights()] + model4.set_weights(model_weights4) + actual = model4.predict([x1, x2]) + assert pytest.approx(y1) == actual[0] + assert pytest.approx(y2) == actual[1] + def test_attri2vec_serialize(): attri2vec = Attri2Vec( - layer_sizes=[4], bias=False, input_dim=2, node_num=4, normalize=None + layer_sizes=[4], + bias=False, + input_dim=2, + node_num=4, + activation="linear", + normalize=None, ) - attri2vec.activation = "linear" - attri2vec.initializer = "ones" inp = keras.Input(shape=(2,)) out = attri2vec(inp) From a50390f943170b5d5b5014985d3e507bc4cae777 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 10:58:46 +1000 Subject: [PATCH 25/82] add attri2vec link prediction demo --- .../stellargraph-attri2vec-DBLP.ipynb | 933 ++++++++++++++++++ 1 file changed, 933 insertions(+) create mode 100644 demos/link-prediction/attri2vec/stellargraph-attri2vec-DBLP.ipynb diff --git a/demos/link-prediction/attri2vec/stellargraph-attri2vec-DBLP.ipynb b/demos/link-prediction/attri2vec/stellargraph-attri2vec-DBLP.ipynb new file mode 100644 index 000000000..984cbb562 --- /dev/null +++ b/demos/link-prediction/attri2vec/stellargraph-attri2vec-DBLP.ipynb @@ -0,0 +1,933 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Inductive Node Representation Learning through attri2vec" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the python implementation of the attri2vec algorithm outlined in paper ***[Attributed Network Embedding Via Subspace Discovery](https://arxiv.org/abs/1901.04095)*** D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. The implementation uses the stellargraph libraries.\n", + "\n", + "## attri2vec\n", + "\n", + "attri2vec learns node representations by performing a linear/non-linear mapping on node content attributes. To make the learned node representations respect structural similarity, [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec) learning mechanism is used to make nodes sharing similar random walk context nodes represented closely in the subspace, which is achieved by maximizing the occurrence probability of context nodes conditioned on the representation of the target nodes. The probability is modelled by Softmax and negative sampling is used to speed up its calculation. This makes attri2vec equivalent to predict whether a node occurs in the given target node's context in random walks with the representation of the target node, by minimizing the cross-entropy loss. \n", + "\n", + "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes.\n", + "\n", + "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameter vector used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)` pair, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", + "\n", + "The entire model is trained end-to-end by minimizing the binary cross-entropy loss function with regards to predicted node pair labels and true node pair labels, using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' node pairs generated on demand and fed into the model.\n", + "\n", + "In this demo, we first train the attri2vec model on the in-sample subgraph and obtain a mapping function from node attributes to node representations, then apply the mapping function to the content attributes of out-of-sample nodes and obtain the representations of out-of-sample nodes. We evaluate the quality of inferred out-of-sample node representations by using it to predict the links of out-of-sample nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using TensorFlow backend.\n" + ] + } + ], + "source": [ + "import networkx as nx\n", + "import pandas as pd\n", + "import numpy as np\n", + "import os\n", + "import random\n", + "\n", + "import stellargraph as sg\n", + "from stellargraph.data import UnsupervisedSampler\n", + "from stellargraph.mapper import Attri2VecLinkGenerator, Attri2VecNodeGenerator\n", + "from stellargraph.layer import Attri2Vec, link_classification\n", + "\n", + "from tensorflow import keras\n", + "\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.metrics import roc_auc_score" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading DBLP network data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This demo uses a DBLP citation network, a subgraph extracted from [DBLP-Citation-network V3](https://aminer.org/citation). To form this subgraph, papers from four subjects are extracted according to their venue information: *Database, Data Mining, Artificial Intelligence and Computer Vision*, and papers with no citations are removed. The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. By ignoring the citation direction, we take the DBLP subgraph as an undirected network.\n", + "\n", + "As papers in DBLP are attached with publication year, the DBLP network with the dynamic property can be used to study the problem of out-of-sample node representation learning. From the DBLP network, we construct four in-sample subgraphs using papers published before 2006, 2007, 2008 and 2009, and denote the four subgraphs as DBLP2006, DBLP2007, DBLP2008, and DBLP2009. For each subgraph, the remaining papers are taken as out-of-sample nodes. We consider the case where new coming nodes have no links. We predict the links of out-of-sample nodes using the learned out-of-sample node representations and compare its performance with the node content feature baseline.\n", + "\n", + "The dataset used in this demo can be downloaded from https://www.kaggle.com/daozhang/dblp-subgraph.\n", + "The following is the description of the dataset:\n", + "\n", + "> The content.txt file contains descriptions of the papers in the following format:\n", + "\n", + " \t\t \n", + " \n", + "> The first entry in each line contains the unique integer ID (ranging from 0 to 18,447) of the paper followed by binary values indicating whether each word in the vocabulary is present (indicated by 1) or absent (indicated by 0) in the paper. Finally, the last two entries in the line are the class label and the publication year of the paper.\n", + "> The edgeList.txt file contains the citation relations. Each line describes a link in the following format:\n", + "\t\t\n", + " \n", + " \n", + "> Each line contains two paper IDs, with paper2 citing paper1 or paper1 citing paper2.\n", + "\n", + "\n", + "Download and unzip the dblp-subgraph.zip file to a location on your computer and set the `data_dir` variable to\n", + "point to the location of the dataset (the \"DBLP\" directory containing \"content.txt\" and \"edgeList.txt\")." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = \"~/data/DBLP\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the graph from the edgelist." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "edgelist = pd.read_csv(os.path.join(data_dir, \"edgeList.txt\"), sep='\\t', header=None, names=[\"source\", \"target\"])\n", + "edgelist[\"label\"] = \"cites\" # set the edge type" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load paper content features, subjects and publishing years." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "feature_names = [\"w_{}\".format(ii) for ii in range(2476)]\n", + "node_column_names = feature_names + [\"subject\", \"year\"]\n", + "node_data = pd.read_csv(os.path.join(data_dir, \"content.txt\"), sep='\\t', header=None, names=node_column_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the whole graph from edge list." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "G_all_nx = nx.from_pandas_edgelist(edgelist, edge_attr=\"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify node types." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "nx.set_node_attributes(G_all_nx, \"paper\", \"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get node features." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "all_node_features = node_data[feature_names]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Stellargraph with node features." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "G_all = sg.StellarGraph(G_all_nx, node_features=all_node_features)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StellarGraph: Undirected multigraph\n", + " Nodes: 18448, Edges: 45611\n", + "\n", + " Node types:\n", + " paper: [18448]\n", + " Edge types: paper-cites->paper\n", + "\n", + " Edge types:\n", + " paper-cites->paper: [45611]\n", + "\n" + ] + } + ], + "source": [ + "print(G_all.info())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Get DBLP Subgraph \n", + "### with papers published before a threshold year" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the edge list connecting in-sample nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "year_thresh = 2006 # the threshold year for in-sample and out-of-sample set split, which can be 2007, 2008 and 2009\n", + "subgraph_edgelist = []\n", + "for ii in range(len(edgelist)):\n", + " source_index = edgelist[\"source\"][ii]\n", + " target_index = edgelist[\"target\"][ii]\n", + " source_year = int(node_data[\"year\"][source_index])\n", + " target_year = int(node_data[\"year\"][target_index])\n", + " if source_year < year_thresh and target_year < year_thresh:\n", + " subgraph_edgelist.append([source_index, target_index])\n", + "subgraph_edgelist = pd.DataFrame(np.array(subgraph_edgelist), columns=[\"source\", \"target\"])\n", + "subgraph_edgelist[\"label\"] = \"cites\" # set the edge type" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the network from the selected edge list." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "G_sub_nx = nx.from_pandas_edgelist(subgraph_edgelist, edge_attr=\"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify node types." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "nx.set_node_attributes(G_sub_nx, \"paper\", \"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the ids of the nodes in the selected subgraph." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "subgraph_node_ids = sorted(list(G_sub_nx.nodes))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the node features of the selected subgraph." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "subgraph_node_features = node_data[feature_names].reindex(subgraph_node_ids)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Stellargraph with node features." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "G_sub = sg.StellarGraph(G_sub_nx, node_features=subgraph_node_features)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StellarGraph: Undirected multigraph\n", + " Nodes: 11776, Edges: 28937\n", + "\n", + " Node types:\n", + " paper: [11776]\n", + " Edge types: paper-cites->paper\n", + "\n", + " Edge types:\n", + " paper-cites->paper: [28937]\n", + "\n" + ] + } + ], + "source": [ + "print(G_sub.info())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train attri2vec on the DBLP Subgraph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify the other optional parameter values: root nodes, the number of walks to take per node, the length of each walk." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "nodes = list(G_sub.nodes())\n", + "number_of_walks = 2\n", + "length = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the UnsupervisedSampler instance with the relevant parameters passed to it." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "unsupervised_samples = UnsupervisedSampler(G_sub, nodes=nodes, length=length, number_of_walks=number_of_walks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the batch size and the number of epochs. " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 50\n", + "epochs = 6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define an attri2vec training generator, which generates a batch of (feature of target node, index of context node, label of node pair) pairs per iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running Attri2VecLinkGenerator with an estimated 4710 batches generated on the fly per epoch.\n" + ] + } + ], + "source": [ + "train_gen = Attri2VecLinkGenerator(G_sub, batch_size).flow(unsupervised_samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Building the model: a 1-hidden-layer node representation ('input embedding') of the `target` node and the parameter vector ('output embedding') for predicting the existence of `context node` for each `(target context)` pair, with a link classification layer performed on the dot product of the 'input embedding' of the `target` node and the 'output embedding' of the `context` node.\n", + "\n", + "Attri2Vec part of the model, with a 128-dimenssion hidden layer, no bias term, no dropout and no normalization. (Dropout can be switched on by specifying a positive dropout rate, 0 < dropout < 1 and normalization can be set to 'l2'). " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "layer_sizes = [128]\n", + "attri2vec = Attri2Vec(\n", + " layer_sizes=layer_sizes, generator=train_gen, bias=False, normalize=None\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0925 10:21:27.091693 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n", + "W0925 10:21:27.113364 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/initializers.py:119: calling RandomUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n" + ] + } + ], + "source": [ + "# Build the model and expose input and output sockets of attri2vec, for node pair inputs:\n", + "x_inp, x_out = attri2vec.build()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the link_classification function to generate the prediction, with the 'ip' edge embedding generation method and the 'sigmoid' activation, which actually performs the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node followed by a sigmoid activation. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "link_classification: using 'ip' method to combine node embeddings into edge embeddings\n" + ] + } + ], + "source": [ + "prediction = link_classification(\n", + " output_dim=1, output_act=\"sigmoid\", edge_embedding_method='ip'\n", + ")(x_out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Stack the Attri2Vec encoder and prediction layer into a Keras model, and specify the loss." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.Model(inputs=x_inp, outputs=prediction)\n", + "\n", + "model.compile(\n", + " optimizer=keras.optimizers.Adam(lr=1e-3),\n", + " loss=keras.losses.binary_crossentropy,\n", + " metrics=[keras.metrics.binary_accuracy],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Train the model." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0925 10:21:27.574651 140736388883392 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/6\n", + "4711/4711 [==============================] - 72s 15ms/step - loss: 0.7680 - binary_accuracy: 0.5814\n", + "Epoch 2/6\n", + "4711/4711 [==============================] - 72s 15ms/step - loss: 0.6447 - binary_accuracy: 0.6101\n", + "Epoch 3/6\n", + "4711/4711 [==============================] - 75s 16ms/step - loss: 0.5866 - binary_accuracy: 0.6483\n", + "Epoch 4/6\n", + "4711/4711 [==============================] - 75s 16ms/step - loss: 0.4925 - binary_accuracy: 0.7284\n", + "Epoch 5/6\n", + "4711/4711 [==============================] - 76s 16ms/step - loss: 0.3574 - binary_accuracy: 0.8300\n", + "Epoch 6/6\n", + "4711/4711 [==============================] - 76s 16ms/step - loss: 0.2242 - binary_accuracy: 0.9105\n" + ] + } + ], + "source": [ + "history = model.fit_generator(\n", + " train_gen,\n", + " epochs=epochs,\n", + " verbose=1,\n", + " use_multiprocessing=True,\n", + " workers=4,\n", + " shuffle=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Predicting links of out-of-sample nodes with the learned attri2vec model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Build the node based model for predicting node representations from node content attributes with the learned parameters. Below a Keras model is constructed, with x_inp[0] as input and x_out[0] as output. Note that this model's weights are the same as those of the corresponding node encoder in the previously trained node pair classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "x_inp_src = x_inp[0]\n", + "x_out_src = x_out[0]\n", + "embedding_model = keras.Model(inputs=x_inp_src, outputs=x_out_src)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the node embeddings, for both in-sample and out-of-sample nodes, by applying the learned mapping function to node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "369/369 [==============================] - 1s 1ms/step\n" + ] + } + ], + "source": [ + "node_ids = node_data.index\n", + "node_gen = Attri2VecNodeGenerator(G_all, batch_size).flow(node_ids)\n", + "node_embeddings = embedding_model.predict_generator(node_gen, workers=4, verbose=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the positive and negative edges for in-sample nodes and out-of-sample nodes. The edges of the in-sample nodes only include the edges between in-sample nodes, and the edges of out-of-sample nodes are referred to all the edges linked to out-of-sample nodes, including the edges connecting in-sample and out-of-sample edges." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "year_thresh = 2006\n", + "in_sample_edges = []\n", + "out_of_sample_edges = []\n", + "for ii in range(len(edgelist)):\n", + " source_index = edgelist[\"source\"][ii]\n", + " target_index = edgelist[\"target\"][ii]\n", + " if source_index > target_index: # neglect edge direction for the undirected graph\n", + " continue\n", + " source_year = int(node_data[\"year\"][source_index])\n", + " target_year = int(node_data[\"year\"][target_index])\n", + " if source_year < year_thresh and target_year < year_thresh:\n", + " in_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", + " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", + " in_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", + " else:\n", + " out_of_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", + " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", + " out_of_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", + "in_sample_edges = np.array(in_sample_edges)\n", + "out_of_sample_edges = np.array(out_of_sample_edges)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct the edge features from the learned node representations with l2 normed difference, where edge features are the element-wise square of the difference between the embeddings of two head nodes. Other strategy like element-wise product can also be used to construct edge features." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "in_sample_edge_feat_from_emb = (node_embeddings[in_sample_edges[:,0]]-node_embeddings[in_sample_edges[:,1]])**2\n", + "out_of_sample_edge_feat_from_emb = (node_embeddings[out_of_sample_edges[:,0]]-node_embeddings[out_of_sample_edges[:,1]])**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Train the Logistic Regression classifier from in-sample edges with the edge features constructed from attri2vec embeddings. " + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", + " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", + " multi_class='auto', n_jobs=None, penalty='l2',\n", + " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", + " warm_start=False)" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clf_edge_pred_from_emb = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", + "clf_edge_pred_from_emb.fit(in_sample_edge_feat_from_emb, in_sample_edges[:,2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predict the edge existence probability with the trained Logistic Regression classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "edge_pred_from_emb = clf_edge_pred_from_emb.predict_proba(out_of_sample_edge_feat_from_emb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the positive class index of `edge_pred_from_emb`." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "if clf_edge_pred_from_emb.classes_[0] == 1:\n", + " positive_class_index = 0\n", + "else:\n", + " positive_class_index = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluate the AUC score for the prediction with attri2vec embeddings." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.7842243817182476" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_emb[:,positive_class_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the baseline, we also investigate the performance of node content features in predicting the edges of out-of-sample nodes. Firstly, we construct edge features from node content features with the same strategy." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "in_sample_edge_rep_from_feat = (node_data[feature_names].values[in_sample_edges[:,0]]-node_data[feature_names].values[in_sample_edges[:,1]])**2\n", + "out_of_sample_edge_rep_from_feat = (node_data[feature_names].values[out_of_sample_edges[:,0]]-node_data[feature_names].values[out_of_sample_edges[:,1]])**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we train the Logistic Regression classifier from in-sample edges with the edge features constructed from node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", + " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", + " multi_class='auto', n_jobs=None, penalty='l2',\n", + " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", + " warm_start=False)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "clf_edge_pred_from_feat = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", + "clf_edge_pred_from_feat.fit(in_sample_edge_rep_from_feat, in_sample_edges[:,2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Predict the edge existence probability with the trained Logistic Regression classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "edge_pred_from_feat = clf_edge_pred_from_feat.predict_proba(out_of_sample_edge_rep_from_feat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get positive class index of `clf_edge_pred_from_feat`." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "if clf_edge_pred_from_feat.classes_[0] == 1:\n", + " positive_class_index = 0\n", + "else:\n", + " positive_class_index = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Evaluate the AUC score for the prediction with node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.6666971120688185" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_feat[:,positive_class_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "attri2vec can inductively infer the representations of out-of-sample nodes from their content attributes. As the inferred node representations well capture both structure and node content information, they perform much better than node content features in predicting the links of out-of-sample nodes." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 181c75e7f57abac9955145091222e081764a3438 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 10:59:42 +1000 Subject: [PATCH 26/82] add attri2vec DBLP embeddings demo --- .../stellargraph-attri2vec-DBLP.ipynb | 541 ++++-------------- 1 file changed, 103 insertions(+), 438 deletions(-) diff --git a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb index 618865352..5b9148316 100644 --- a/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb +++ b/demos/embeddings/stellargraph-attri2vec-DBLP.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Inferring Representations for Out-of-sample Nodes Through attri2vec" + "# Node Representation Learning with attri2vec on DBLP" ] }, { @@ -13,24 +13,16 @@ "source": [ "This is the python implementation of the attri2vec algorithm outlined in paper ***[Attributed Network Embedding Via Subspace Discovery](https://arxiv.org/abs/1901.04095)*** D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. The implementation uses the stellargraph libraries.\n", "\n", - "## Dataset\n", - "This demo uses a DBLP citation network, a subgraph extracted from [DBLP-Citation-network V3](https://aminer.org/citation). To form this subgraph, papers from four subjects are extracted according to their venue information: *Database, Data Mining, Artificial Intelligence and Computer Vision*, and papers with no citations are removed. The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. By ignoring the citation direction, we take the DBLP subgraph as an undirected network.\n", - "\n", - "As papers in DBLP are attached with publication year, the DBLP network with the dynamic property can be used to study the problem of out-of-sample node representation learning. From the DBLP network, we construct four in-sample subgraphs using papers published before 2006, 2007, 2008 and 2009, and denote the four subgraphs as DBLP2006, DBLP2007, DBLP2008, and DBLP2009. For each subgraph, the remaining papers are taken as out-of-sample nodes. We consider the case where new coming nodes have no links. We predict the links of out-of-sample nodes using the learned out-of-sample node representations and compare its performance with the node content feature baseline.\n", - "\n", - "\n", "\n", "## attri2vec\n", "\n", - "For networks attached with node content attributes, attri2vec infers node representations by discovering a latent node attribute subspace that respects network structure in a more consistent way. To transform network nodes from the original attribute space into the targeted subspace, a non-linear mapping is used. To make the mapped images respect structural similarity, [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec) learning mechanism is used to make nodes sharing similar random walk context nodes represented closely in the subspace. Following [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec), attri2vec learns node representations by maximizing the occurrence probability of context nodes conditioned on the representation of the target nodes. The probability is modelled by Softmax and negative sampling is used to speed up its calculation. This makes attri2vec equivalent to predict whether a node occurs in the given target node's context in random walks with the representation of the target node, by minimizing the cross-entropy loss. \n", - "\n", - "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes. Unlike the embeddings learned by DeepWalk/node2vec, the mapping is inductive. Different from the mapping generated by GraphSAGE, the mapping only performs on node content attributes and does not rely on any link information, which makes it possible to construct representations for new coming nodes having few or no link information from their content attributes.\n", + "attri2vec learns node representations by performing a linear/non-linear mapping on node content attributes. To make the learned node representations respect structural similarity, [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec) learning mechanism is used to make nodes sharing similar random walk context nodes represented closely in the subspace, which is achieved by maximizing the occurrence probability of context nodes conditioned on the representation of the target nodes. The probability is modelled by Softmax and negative sampling is used to speed up its calculation. This makes attri2vec equivalent to predict whether a node occurs in the given target node's context in random walks with the representation of the target node, by minimizing the cross-entropy loss. \n", "\n", - "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameter vector used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)` pair, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", + "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes. \n", "\n", - "The entire model is trained end-to-end by minimizing the binary cross-entropy loss function with regards to predicted node pair labels and true node pair labels, using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' node pairs generated on demand and fed into the model.\n", + "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a linear/non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameter vector used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)` pair, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", "\n", - "In this demo, we first train the attri2vec model on the in-sample subgraph and obtain a mapping function from node attributes to node representations, then apply the mapping function to the content attributes of out-of-sample nodes and obtain the representations of out-of-sample nodes. We evaluate the quality of inferred out-of-sample node representations by using it to predict the links of out-of-sample nodes." + "The entire model is trained end-to-end by minimizing the binary cross-entropy loss function with regards to predicted node pair labels and true node pair labels, using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' node pairs generated on demand and fed into the model." ] }, { @@ -54,15 +46,19 @@ "import random\n", "\n", "import stellargraph as sg\n", - "from stellargraph.data import UniformRandomWalk\n", "from stellargraph.data import UnsupervisedSampler\n", "from stellargraph.mapper import Attri2VecLinkGenerator, Attri2VecNodeGenerator\n", "from stellargraph.layer import Attri2Vec, link_classification\n", "\n", - "import keras\n", + "from tensorflow import keras\n", "\n", - "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.metrics import roc_auc_score" + "import matplotlib.pyplot as plt\n", + "from sklearn.manifold import TSNE\n", + "from sklearn.decomposition import PCA\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LogisticRegressionCV\n", + "from sklearn.metrics import accuracy_score" ] }, { @@ -76,6 +72,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "This demo uses a DBLP citation network, a subgraph extracted from [DBLP-Citation-network V3](https://aminer.org/citation). To form this subgraph, papers from four subjects are extracted according to their venue information: *Database, Data Mining, Artificial Intelligence and Computer Vision*, and papers with no citations are removed. The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. By ignoring the citation direction, we take the DBLP subgraph as an undirected network.\n", + "\n", "The dataset used in this demo can be downloaded from https://www.kaggle.com/daozhang/dblp-subgraph.\n", "The following is the description of the dataset:\n", "\n", @@ -143,7 +141,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Construct the whole graph from edge list." + "Construct the graph from edge list." ] }, { @@ -152,7 +150,7 @@ "metadata": {}, "outputs": [], "source": [ - "G_all_nx = nx.from_pandas_edgelist(edgelist, edge_attr=\"label\")" + "G_nx = nx.from_pandas_edgelist(edgelist, edge_attr=\"label\")" ] }, { @@ -168,7 +166,7 @@ "metadata": {}, "outputs": [], "source": [ - "nx.set_node_attributes(G_all_nx, \"paper\", \"label\")" + "nx.set_node_attributes(G_nx, \"paper\", \"label\")" ] }, { @@ -184,7 +182,7 @@ "metadata": {}, "outputs": [], "source": [ - "all_node_features = node_data[feature_names]" + "node_features = node_data[feature_names]" ] }, { @@ -200,7 +198,7 @@ "metadata": {}, "outputs": [], "source": [ - "G_all = sg.StellarGraph(G_all_nx, node_features=all_node_features)" + "G = sg.StellarGraph(G_nx, node_features=node_features)" ] }, { @@ -226,132 +224,7 @@ } ], "source": [ - "print(G_all.info())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Get DBLP Subgraph \n", - "### with papers published before a threshold year" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get the edge list connecting in-sample nodes." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "year_thresh = 2006 # the threshold year for in-sample and out-of-sample set split, which can be 2007, 2008 and 2009\n", - "subgraph_edgelist = []\n", - "for ii in range(len(edgelist)):\n", - " source_index = edgelist[\"source\"][ii]\n", - " target_index = edgelist[\"target\"][ii]\n", - " source_year = int(node_data[\"year\"][source_index])\n", - " target_year = int(node_data[\"year\"][target_index])\n", - " if source_year < year_thresh and target_year < year_thresh:\n", - " subgraph_edgelist.append([source_index, target_index])\n", - "subgraph_edgelist = pd.DataFrame(np.array(subgraph_edgelist), columns=[\"source\", \"target\"])\n", - "subgraph_edgelist[\"label\"] = \"cites\" # set the edge type" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Construct the network from the selected edge list." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "G_sub_nx = nx.from_pandas_edgelist(subgraph_edgelist, edge_attr=\"label\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Specify node types." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "nx.set_node_attributes(G_sub_nx, \"paper\", \"label\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get in-sample node features." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "subgraph_node_data = node_data[node_data[\"year\"]<2006]\n", - "subgraph_node_features = subgraph_node_data[feature_names]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the Stellargraph with node features." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "G_sub = sg.StellarGraph(G_sub_nx, node_features=subgraph_node_features)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "StellarGraph: Undirected multigraph\n", - " Nodes: 11776, Edges: 28937\n", - "\n", - " Node types:\n", - " paper: [11776]\n", - " Edge types: paper-cites->paper\n", - "\n", - " Edge types:\n", - " paper-cites->paper: [28937]\n", - "\n" - ] - } - ], - "source": [ - "print(G_sub.info())" + "print(G.info())" ] }, { @@ -365,17 +238,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Specify the other optional parameter values: root nodes, the number of walks to take per node, the length of each walk, and random seed." + "Specify the other optional parameter values: root nodes, the number of walks to take per node, the length of each walk." ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "nodes = list(G_sub.nodes())\n", - "number_of_walks = 2\n", + "nodes = list(G.nodes())\n", + "number_of_walks = 4\n", "length = 5" ] }, @@ -388,11 +261,11 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ - "unsupervised_samples = UnsupervisedSampler(G_sub, nodes=nodes, length=length, number_of_walks=number_of_walks)" + "unsupervised_samples = UnsupervisedSampler(G, nodes=nodes, length=length, number_of_walks=number_of_walks)" ] }, { @@ -404,12 +277,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "batch_size = 50\n", - "epochs = 4" + "epochs = 8" ] }, { @@ -421,19 +294,19 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Running Attri2VecLinkGenerator with an estimated 4710 batches generated on the fly per epoch.\n" + "Running Attri2VecLinkGenerator with an estimated 14758 batches generated on the fly per epoch.\n" ] } ], "source": [ - "train_gen = Attri2VecLinkGenerator(G_sub, batch_size).flow(unsupervised_samples)" + "train_gen = Attri2VecLinkGenerator(G, batch_size).flow(unsupervised_samples)" ] }, { @@ -442,44 +315,37 @@ "source": [ "Building the model: a 1-hidden-layer node representation ('input embedding') of the `target` node and the parameter vector ('output embedding') for predicting the existence of `context node` for each `(target context)` pair, with a link classification layer performed on the dot product of the 'input embedding' of the `target` node and the 'output embedding' of the `context` node.\n", "\n", - "Attri2Vec part of the model, with a 128-dimenssion hidden layer, no bias term, no dropout and no normalization. (Dropout can be switched on by specifying a positive dropout rate, 0 < dropout < 1 and normalization can be set to 'l2'). " + "Attri2Vec part of the model, with a 128-dimenssion hidden layer, no bias term and no normalization. (Normalization can be set to 'l2'). " ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 14, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: Logging before flag parsing goes to stderr.\n", - "W0822 10:43:54.482249 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "layer_sizes = [128]\n", "attri2vec = Attri2Vec(\n", - " layer_sizes=layer_sizes, generator=train_gen, bias=False, dropout=0.0, normalize=\"None\"\n", + " layer_sizes=layer_sizes, generator=train_gen, bias=False, normalize=None\n", ")" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "W0822 10:43:56.449973 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:517: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n", - "\n", - "W0822 10:43:56.455691 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:4138: The name tf.random_uniform is deprecated. Please use tf.random.uniform instead.\n", - "\n" + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0924 14:51:32.580700 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n", + "W0924 14:51:32.618021 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/initializers.py:119: calling RandomUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n" ] } ], @@ -497,7 +363,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -523,23 +389,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 17, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "W0822 10:44:02.083713 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/optimizers.py:790: The name tf.train.Optimizer is deprecated. Please use tf.compat.v1.train.Optimizer instead.\n", - "\n", - "W0822 10:44:02.091721 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:3376: The name tf.log is deprecated. Please use tf.math.log instead.\n", - "\n", - "W0822 10:44:02.102672 140736102417344 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/nn_impl.py:180: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", - "Instructions for updating:\n", - "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" - ] - } - ], + "outputs": [], "source": [ "model = keras.Model(inputs=x_inp, outputs=prediction)\n", "\n", @@ -559,31 +411,40 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 18, "metadata": { - "scrolled": true + "scrolled": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "W0822 10:44:04.704549 140736102417344 deprecation_wrapper.py:119] From /anaconda3/lib/python3.6/site-packages/keras/backend/tensorflow_backend.py:986: The name tf.assign_add is deprecated. Please use tf.compat.v1.assign_add instead.\n", - "\n" + "W0924 14:51:33.217601 140736388883392 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Epoch 1/4\n", - "4711/4711 [==============================] - 89s 19ms/step - loss: 0.6678 - binary_accuracy: 0.6432\n", - "Epoch 2/4\n", - "4711/4711 [==============================] - 92s 19ms/step - loss: 0.5859 - binary_accuracy: 0.6642\n", - "Epoch 3/4\n", - "4711/4711 [==============================] - 91s 19ms/step - loss: 0.4810 - binary_accuracy: 0.7541\n", - "Epoch 4/4\n", - "4711/4711 [==============================] - 93s 20ms/step - loss: 0.3283 - binary_accuracy: 0.8544\n" + "Epoch 1/8\n", + "14759/14759 [==============================] - 384s 26ms/step - loss: 0.7016 - binary_accuracy: 0.5404\n", + "Epoch 2/8\n", + "14759/14759 [==============================] - 397s 27ms/step - loss: 0.6156 - binary_accuracy: 0.6309\n", + "Epoch 3/8\n", + "14759/14759 [==============================] - 380s 26ms/step - loss: 0.5221 - binary_accuracy: 0.7362\n", + "Epoch 4/8\n", + "14759/14759 [==============================] - 407s 28ms/step - loss: 0.4527 - binary_accuracy: 0.7909\n", + "Epoch 5/8\n", + "14759/14759 [==============================] - 389s 26ms/step - loss: 0.4029 - binary_accuracy: 0.8219\n", + "Epoch 6/8\n", + "14759/14759 [==============================] - 409s 28ms/step - loss: 0.3673 - binary_accuracy: 0.8424\n", + "Epoch 7/8\n", + "14759/14759 [==============================] - 399s 27ms/step - loss: 0.3387 - binary_accuracy: 0.8573\n", + "Epoch 8/8\n", + "14759/14759 [==============================] - 387s 26ms/step - loss: 0.3189 - binary_accuracy: 0.8679\n" ] } ], @@ -592,8 +453,8 @@ " train_gen,\n", " epochs=epochs,\n", " verbose=1,\n", - " use_multiprocessing=True,\n", - " workers=4,\n", + " use_multiprocessing=False,\n", + " workers=1,\n", " shuffle=True,\n", ")" ] @@ -602,7 +463,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Predicting links of out-of-sample nodes with the learned attri2vec model" + "## Visualise Node Embeddings" ] }, { @@ -614,7 +475,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -627,12 +488,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Get the node embeddings, for both in-sample and out-of-sample nodes, by applying the learned mapping function to node content features." + "Get the node embeddings by applying the learned mapping function to node content features." ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -645,272 +506,76 @@ ], "source": [ "node_ids = node_data.index\n", - "node_gen = Attri2VecNodeGenerator(G_all, batch_size).flow(node_ids)\n", - "node_embeddings = embedding_model.predict_generator(node_gen, workers=4, verbose=1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get the positive and negative edges for in-sample nodes and out-of-sample nodes. The edges of the in-sample nodes only include the edges between in-sample nodes, and the edges of out-of-sample nodes are referred to all the edges linked to out-of-sample nodes, including the edges connecting in-sample and out-of-sample edges." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "year_thresh = 2006\n", - "in_sample_edges = []\n", - "out_of_sample_edges = []\n", - "for ii in range(len(edgelist)):\n", - " source_index = edgelist[\"source\"][ii]\n", - " target_index = edgelist[\"target\"][ii]\n", - " if source_index > target_index: # neglect edge direction for the undirected graph\n", - " continue\n", - " source_year = int(node_data[\"year\"][source_index])\n", - " target_year = int(node_data[\"year\"][target_index])\n", - " if source_year < year_thresh and target_year < year_thresh:\n", - " in_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", - " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", - " in_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", - " else:\n", - " out_of_sample_edges.append([source_index, target_index, 1]) # get the positive edge\n", - " negative_target_index = unsupervised_samples.random.choices(node_data.index.tolist(), k=1) # generate negative node\n", - " out_of_sample_edges.append([source_index, negative_target_index[0], 0]) # get the negative edge\n", - "in_sample_edges = np.array(in_sample_edges)\n", - "out_of_sample_edges = np.array(out_of_sample_edges)" + "node_gen = Attri2VecNodeGenerator(G, batch_size).flow(node_ids)\n", + "node_embeddings = embedding_model.predict_generator(node_gen, workers=1, verbose=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Construct the edge features from the learned node representations with l2 normed difference, where edge features are the element-wise square of the difference between the embeddings of two head nodes. Other strategy like element-wise product can also be used to construct edge features." + "Get node subjects." ] }, { "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "in_sample_edge_feat_from_emb = (node_embeddings[in_sample_edges[:,0]]-node_embeddings[in_sample_edges[:,1]])**2\n", - "out_of_sample_edge_feat_from_emb = (node_embeddings[out_of_sample_edges[:,0]]-node_embeddings[out_of_sample_edges[:,1]])**2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Train the Logistic Regression classifier from in-sample edges with the edge features constructed from attri2vec embeddings. " - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", - " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", - " multi_class='auto', n_jobs=None, penalty='l2',\n", - " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", - " warm_start=False)" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "clf_edge_pred_from_emb = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", - "clf_edge_pred_from_emb.fit(in_sample_edge_feat_from_emb, in_sample_edges[:,2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Predict the edge existence probability with the trained Logistic Regression classifier." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "edge_pred_from_emb = clf_edge_pred_from_emb.predict_proba(out_of_sample_edge_feat_from_emb)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get the positive class index of `edge_pred_from_emb`." - ] - }, - { - "cell_type": "code", - "execution_count": 31, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ - "if clf_edge_pred_from_emb.classes_[0] == 1:\n", - " positive_class_index = 0\n", - "else:\n", - " positive_class_index = 1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Evaluate the AUC score for the prediction with attri2vec embeddings." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.798202033278801" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_emb[:,positive_class_index])" + "node_targets = [ node_data[\"subject\"][node_id] for node_id in node_ids ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "As the baseline, we also investigate the performance of node content features in predicting the edges of out-of-sample nodes. Firstly, we construct edge features from node content features with the same strategy." + "Transform the embeddings to 2d space for visualisation." ] }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ - "in_sample_edge_rep_from_feat = (node_data[feature_names].values[in_sample_edges[:,0]]-node_data[feature_names].values[in_sample_edges[:,1]])**2\n", - "out_of_sample_edge_rep_from_feat = (node_data[feature_names].values[out_of_sample_edges[:,0]]-node_data[feature_names].values[out_of_sample_edges[:,1]])**2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then we train the Logistic Regression classifier from in-sample edges with the edge features constructed from node content features." + "transform = TSNE # PCA\n", + "\n", + "trans = transform(n_components=2)\n", + "node_embeddings_2d = trans.fit_transform(node_embeddings)" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 23, "metadata": {}, "outputs": [ { "data": { + "image/png": "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\n", "text/plain": [ - "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n", - " intercept_scaling=1, l1_ratio=None, max_iter=500,\n", - " multi_class='auto', n_jobs=None, penalty='l2',\n", - " random_state=None, solver='lbfgs', tol=0.0001, verbose=0,\n", - " warm_start=False)" + "
" ] }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "clf_edge_pred_from_feat = LogisticRegression(verbose=0, solver='lbfgs', multi_class=\"auto\", max_iter=500)\n", - "clf_edge_pred_from_feat.fit(in_sample_edge_rep_from_feat, in_sample_edges[:,2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Predict the edge existence probability with the trained Logistic Regression classifier." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "edge_pred_from_feat = clf_edge_pred_from_feat.predict_proba(out_of_sample_edge_rep_from_feat)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Get positive class index of `clf_edge_pred_from_feat`." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "if clf_edge_pred_from_feat.classes_[0] == 1:\n", - " positive_class_index = 0\n", - "else:\n", - " positive_class_index = 1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Evaluate the AUC score for the prediction with node content features." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.6638897794650095" - ] + "metadata": { + "needs_background": "light" }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "roc_auc_score(out_of_sample_edges[:,2], edge_pred_from_feat[:,positive_class_index])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "attri2vec performs much better than node content features in predicting the links of out-of-sample nodes." + "# draw the embedding points, coloring them by the target label (paper subject)\n", + "alpha = 0.7\n", + "label_map = { l: i for i, l in enumerate(np.unique(node_targets)) }\n", + "node_colours = [ label_map[target] for target in node_targets ]\n", + "\n", + "plt.figure(figsize=(7,7))\n", + "plt.axes().set(aspect=\"equal\")\n", + "plt.scatter(node_embeddings_2d[:,0], \n", + " node_embeddings_2d[:,1], \n", + " c=node_colours, cmap=\"jet\", alpha=alpha)\n", + "plt.title('{} visualization of node embeddings'.format(transform.__name__))\n", + "plt.show()" ] } ], From 5e122413bb49dcedf588334b512db3cbf0d0c21a Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:00:04 +1000 Subject: [PATCH 27/82] Add attrivec citeseer embeddings demo --- .../stellargraph-attri2vec-citeseer.ipynb | 684 ++++++++++++++++++ 1 file changed, 684 insertions(+) create mode 100644 demos/embeddings/stellargraph-attri2vec-citeseer.ipynb diff --git a/demos/embeddings/stellargraph-attri2vec-citeseer.ipynb b/demos/embeddings/stellargraph-attri2vec-citeseer.ipynb new file mode 100644 index 000000000..41f6b60ad --- /dev/null +++ b/demos/embeddings/stellargraph-attri2vec-citeseer.ipynb @@ -0,0 +1,684 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Node Representation Learning with attri2vec on Citeseer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the python implementation of the attri2vec algorithm outlined in paper ***[Attributed Network Embedding Via Subspace Discovery](https://arxiv.org/abs/1901.04095)*** D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. The implementation uses the stellargraph libraries.\n", + "\n", + "\n", + "## attri2vec\n", + "\n", + "attri2vec learns node representations by performing a linear/non-linear mapping on node content attributes. To make the learned node representations respect structural similarity, [`DeepWalk`](https://dl.acm.org/citation.cfm?id=2623732)/[`node2vec`](https://snap.stanford.edu/node2vec) learning mechanism is used to make nodes sharing similar random walk context nodes represented closely in the subspace, which is achieved by maximizing the occurrence probability of context nodes conditioned on the representation of the target nodes. The probability is modelled by Softmax and negative sampling is used to speed up its calculation. This makes attri2vec equivalent to predict whether a node occurs in the given target node's context in random walks with the representation of the target node, by minimizing the cross-entropy loss. \n", + "\n", + "In implementation, node embeddings are learnt by solving a simple classification task: given a large set of \"positive\" `(target, context)` node pairs generated from random walks performed on the graph (i.e., node pairs that co-occur within a certain context window in random walks), and an equally large set of \"negative\" node pairs that are randomly selected from the graph according to a certain distribution, learn a binary classifier that predicts whether arbitrary node pairs are likely to co-occur in a random walk performed on the graph. Through learning this simple binary node-pair-classification task, the model automatically learns an inductive mapping from attributes of nodes to node embeddings in a low-dimensional vector space, which preserves structural and feature similarities of the nodes. \n", + "\n", + "To train the attri2vec model, we first construct a training set of nodes, which is composed of an equal number of positive and negative `(target, context)` pairs from the graph. The positive `(target, context)` pairs are the node pairs co-occurring on random walks over the graph whereas the negative node pairs are the sampled randomly from the global node degree distribution of the graph. In attri2vec, each node is attached with two kinds of embeddings: 1) the inductive 'input embedding', i.e, the objective embedding, obtained by perform a linear/non-linear transformation on node content features, and 2) 'output embedding', i.e., the parameter vector used to predict its occurrence as a context node, obtained by looking up a parameter table. Given a `(target, context)` pair, attri2vec outputs a predictive value to indicate whether it is positive or negative, which is obtained by performing the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node, followed by a sigmoid activation. \n", + "\n", + "The entire model is trained end-to-end by minimizing the binary cross-entropy loss function with regards to predicted node pair labels and true node pair labels, using stochastic gradient descent (SGD) updates of the model parameters, with minibatches of 'training' node pairs generated on demand and fed into the model." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using TensorFlow backend.\n" + ] + } + ], + "source": [ + "import networkx as nx\n", + "import pandas as pd\n", + "import numpy as np\n", + "import os\n", + "import random\n", + "\n", + "import stellargraph as sg\n", + "from stellargraph.data import UnsupervisedSampler\n", + "from stellargraph.mapper import Attri2VecLinkGenerator, Attri2VecNodeGenerator\n", + "from stellargraph.layer import Attri2Vec, link_classification\n", + "\n", + "from tensorflow import keras\n", + "\n", + "from pandas.core.indexes.base import Index\n", + "\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.manifold import TSNE\n", + "from sklearn.decomposition import PCA\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.linear_model import LogisticRegressionCV\n", + "from sklearn.metrics import accuracy_score" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dataset is the citation network Citeseer.\n", + "\n", + "It can be downloaded by clicking [here](https://linqs-data.soe.ucsc.edu/public/lbc/citesser.tgz)\n", + "\n", + "The following is the description of the dataset from the publisher,\n", + "> The CiteSeer dataset consists of 3312 scientific publications classified into one of six classes. The citation network consists of 4732 links. Each publication in the dataset is described by a 0/1-valued word vector indicating the absence/presence of the corresponding word from the dictionary. The dictionary consists of 3703 unique words. The README file in the dataset provides more details.\n", + "\n", + "Download and unzip the citeseer.tgz file to a location on your computer. \n", + "\n", + "We assume that the dataset is stored in the directory\n", + "\n", + "`~/data/citeseer/`\n", + "\n", + "where the files `citeseer.cites` and `citeseer.content` can be located.\n", + "\n", + "We are going to load the data into a networkx object." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = \"~/data/citeseer\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load edges in order 'cited-paper' <- 'citing-paper'." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "citeseer_location = os.path.expanduser(os.path.join(data_dir, \"citeseer.cites\"))\n", + "g_nx = nx.read_edgelist(path=citeseer_location, create_using=nx.DiGraph()).reverse()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Convert the graph to undirected graph." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "g_nx = g_nx.to_undirected()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the node attribute data." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py:3057: DtypeWarning: Columns (0) have mixed types. Specify dtype option on import or set low_memory=False.\n", + " interactivity=interactivity, compiler=compiler, result=result)\n" + ] + } + ], + "source": [ + "citeseer_data_location = os.path.expanduser(os.path.join(data_dir, \"citeseer.content\"))\n", + "attr_names = [\"w_{}\".format(ii) for ii in range(3703)]\n", + "node_column_names = attr_names + [\"subject\"]\n", + "node_attr = pd.read_csv(citeseer_data_location, sep='\\t', header=None, names=node_column_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Change the type of the indexes of node_attr to str." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "node_attr.index = Index(list(map(str, list(node_attr.index))))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The original graph contains some nodes with no attributes. We remove them here." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "g_nx = g_nx.subgraph(list(node_attr.index))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Select the largest connected component. For clarity we ignore isolated nodes and subgraphs." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Largest subgraph statistics: 2110 nodes, 3720 edges\n" + ] + } + ], + "source": [ + "g_nx_ccs = (g_nx.subgraph(c).copy() for c in nx.connected_components(g_nx))\n", + "g_nx = max(g_nx_ccs, key=len)\n", + "print(\"Largest subgraph statistics: {} nodes, {} edges\".format(\n", + " g_nx.number_of_nodes(), g_nx.number_of_edges()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify node types." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "nx.set_node_attributes(g_nx, \"paper\", \"label\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the ids of the nodes in the selected largest connected component. " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "node_ids = sorted(list(g_nx.nodes))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get node features." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "node_features = node_attr[attr_names].reindex(node_ids)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the Stellargraph with node features." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "G = sg.StellarGraph(g_nx, node_features=node_features)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StellarGraph: Undirected multigraph\n", + " Nodes: 2110, Edges: 3720\n", + "\n", + " Node types:\n", + " paper: [2110]\n", + " Edge types: paper-default->paper\n", + "\n", + " Edge types:\n", + " paper-default->paper: [3720]\n", + "\n" + ] + } + ], + "source": [ + "print(G.info())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train attri2vec on Citeseer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify the other optional parameter values: root nodes, the number of walks to take per node, the length of each walk." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "nodes = list(G.nodes())\n", + "number_of_walks = 4\n", + "length = 5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create the UnsupervisedSampler instance with the relevant parameters passed to it." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "unsupervised_samples = UnsupervisedSampler(G, nodes=nodes, length=length, number_of_walks=number_of_walks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the batch size and the number of epochs. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "batch_size = 50\n", + "epochs = 4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define an attri2vec training generator, which generates a batch of (feature of target node, index of context node, label of node pair) pairs per iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running Attri2VecLinkGenerator with an estimated 1688 batches generated on the fly per epoch.\n" + ] + } + ], + "source": [ + "train_gen = Attri2VecLinkGenerator(G, batch_size).flow(unsupervised_samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Building the model: a 1-hidden-layer node representation ('input embedding') of the `target` node and the parameter vector ('output embedding') for predicting the existence of `context node` for each `(target context)` pair, with a link classification layer performed on the dot product of the 'input embedding' of the `target` node and the 'output embedding' of the `context` node.\n", + "\n", + "Attri2Vec part of the model, with a 128-dimenssion hidden layer, no bias term and no normalization. (Normalization can be set to 'l2'). " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "layer_sizes = [128]\n", + "attri2vec = Attri2Vec(\n", + " layer_sizes=layer_sizes, generator=train_gen, bias=False, normalize=None\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0925 10:19:03.073729 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n", + "W0925 10:19:03.096633 140736388883392 deprecation.py:506] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/initializers.py:119: calling RandomUniform.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Call initializer instance with the dtype argument instead of passing it to the constructor\n" + ] + } + ], + "source": [ + "# Build the model and expose input and output sockets of attri2vec, for node pair inputs:\n", + "x_inp, x_out = attri2vec.build()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the link_classification function to generate the prediction, with the 'ip' edge embedding generation method and the 'sigmoid' activation, which actually performs the dot product of the 'input embedding' of the target node and the 'output embedding' of the context node followed by a sigmoid activation. " + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "link_classification: using 'ip' method to combine node embeddings into edge embeddings\n" + ] + } + ], + "source": [ + "prediction = link_classification(\n", + " output_dim=1, output_act=\"sigmoid\", edge_embedding_method='ip'\n", + ")(x_out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Stack the Attri2Vec encoder and prediction layer into a Keras model, and specify the loss." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.Model(inputs=x_inp, outputs=prediction)\n", + "\n", + "model.compile(\n", + " optimizer=keras.optimizers.Adam(lr=1e-3),\n", + " loss=keras.losses.binary_crossentropy,\n", + " metrics=[keras.metrics.binary_accuracy],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Train the model." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/4\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0925 10:19:03.339447 140736388883392 deprecation.py:323] From /anaconda3/lib/python3.6/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support..wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use tf.where in 2.0, which has the same broadcast rule as np.where\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1688/1688 [==============================] - 12s 7ms/step - loss: 0.6820 - binary_accuracy: 0.5580\n", + "Epoch 2/4\n", + "1688/1688 [==============================] - 11s 7ms/step - loss: 0.5126 - binary_accuracy: 0.7584\n", + "Epoch 3/4\n", + "1688/1688 [==============================] - 11s 6ms/step - loss: 0.3356 - binary_accuracy: 0.8780\n", + "Epoch 4/4\n", + "1688/1688 [==============================] - 11s 7ms/step - loss: 0.2456 - binary_accuracy: 0.9161\n" + ] + } + ], + "source": [ + "history = model.fit_generator(\n", + " train_gen,\n", + " epochs=epochs,\n", + " verbose=1,\n", + " use_multiprocessing=False,\n", + " workers=1,\n", + " shuffle=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualise Node Embeddings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Build the node based model for predicting node representations from node content attributes with the learned parameters. Below a Keras model is constructed, with x_inp[0] as input and x_out[0] as output. Note that this model's weights are the same as those of the corresponding node encoder in the previously trained node pair classifier." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "x_inp_src = x_inp[0]\n", + "x_out_src = x_out[0]\n", + "embedding_model = keras.Model(inputs=x_inp_src, outputs=x_out_src)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get the node embeddings by applying the learned mapping function to node content features." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "43/43 [==============================] - 0s 2ms/step\n" + ] + } + ], + "source": [ + "node_gen = Attri2VecNodeGenerator(G, batch_size).flow(node_ids)\n", + "node_embeddings = embedding_model.predict_generator(node_gen, workers=1, verbose=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get node subjects." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "node_targets = [ node_attr[\"subject\"][node_id] for node_id in node_ids ]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Transform the embeddings to 2d space for visualisation." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "transform = TSNE # PCA\n", + "\n", + "trans = transform(n_components=2)\n", + "node_embeddings_2d = trans.fit_transform(node_embeddings)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# draw the embedding points, coloring them by the target label (paper subject)\n", + "alpha = 0.7\n", + "label_map = { l: i for i, l in enumerate(np.unique(node_targets)) }\n", + "node_colours = [ label_map[target] for target in node_targets ]\n", + "\n", + "plt.figure(figsize=(7,7))\n", + "plt.axes().set(aspect=\"equal\")\n", + "plt.scatter(node_embeddings_2d[:,0], \n", + " node_embeddings_2d[:,1], \n", + " c=node_colours, cmap=\"jet\", alpha=alpha)\n", + "plt.title('{} visualization of node embeddings'.format(transform.__name__))\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 67c3c452e89e1f7efbff4d254f12bdbd2c1da846 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:00:48 +1000 Subject: [PATCH 28/82] Add demos/node-classification/attri2vec/README.md file --- demos/node-classification/attri2vec/README.md | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 demos/node-classification/attri2vec/README.md diff --git a/demos/node-classification/attri2vec/README.md b/demos/node-classification/attri2vec/README.md new file mode 100644 index 000000000..38bab7ac9 --- /dev/null +++ b/demos/node-classification/attri2vec/README.md @@ -0,0 +1,63 @@ +## Node classification using attri2vec [1] + +This folder contains two [Jupyter](http://jupyter.org/) python notebooks demonstrating the combined use of +`stellargraph` (this library), `Scikit-learn` [3] libraries for node classification in two homogeneous graphs +attached with node attributes. + +The first example demonstrates node representation learning and node classification using the citeseer +paper citation network. This demo is included in the Jupyter notebook +`attri2vec-citeseer-node-classification-example.ipynb`. + +The second example demonstrates node representation learning and node classification using the DBLP +paper citation network. This demo is included in the Jupyter notebook +`attri2vec-DBLP-node-classification-example.ipynb`. + +The two Jupyter notebooks include all the information for downloading the corresponding datasets, training the GraphSAGE +models and using them to classify nodes with unknown (to the training algorithm) labels. + +To run the notebooks, install Jupyter to the same Python 3.6 environment as StellarGraph, following the instructions on +the Jupyter project website: http://jupyter.org/install.html + +After starting the Jupyter server on your computer, load either of the two notebooks and follow the instructions inside. + +## Requirements + +All examples use Python 3.6 and the StellarGraph library. To install the StellarGraph library +follow the instructions at: https://github.com/stellargraph/stellargraph + +Additional requirements are Pandas, Numpy and Scikit-Learn which are installed as dependencies +of the StellarGraph library. In addition Juptyer is required to run the notebook version of +the example. + +## Dataset + +The examples in this directory uses the citeseer and DBLP dataset. + +The citeseer dataset can be downloaded from [here](https://linqs-data.soe.ucsc.edu/public/lbc/citesser.tgz). + +The following is the description of the dataset: +> The CiteSeer dataset consists of 3312 scientific publications classified into one of six classes. +> The citation network consists of 4732 links. Each publication in the dataset is described by a +> 0/1-valued word vector indicating the absence/presence of the corresponding word from the dictionary. +> The dictionary consists of 3703 unique words. The README file in the dataset provides more details. + +Download and unzip the [citeseer.tgz](https://linqs-data.soe.ucsc.edu/public/lbc/citesser.tgz) file to a location on your +computer and pass this location as a command line argument to this script. + +The DBLP dataset can be downloaded from [here](https://www.kaggle.com/daozhang/dblp-subgraph). + +The following is the description of the dataset: +> The DBLP citation network is a subgraph extracted from DBLP-Citation-network V3 (https://aminer.org/citation). +> To form this subgraph, papers from four subjects are extracted according to their venue information: +> Database, Data Mining, Artificial Intelligence and Computer Vision, and papers with no citations are removed. +> The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct +> 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. +> By ignoring the citation direction, we take the DBLP subgraph as an undirected network. + +Download and unzip the [DBLP.zip](https://www.kaggle.com/daozhang/dblp-subgraph) file to a location on your computer +and pass this location as a command line argument to this script. + +## References + +**1.** Attributed Network Embedding via Subspace Discovery. D. Zhang, J, Yin, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) From 8fb54c1141dfa4d3cbe9182f39471ceb05d33db4 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:01:25 +1000 Subject: [PATCH 29/82] add attri2vec description to demos/node-classification/README.md file --- demos/node-classification/README.md | 33 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/demos/node-classification/README.md b/demos/node-classification/README.md index 9dbfd31c6..f3d42bcc1 100644 --- a/demos/node-classification/README.md +++ b/demos/node-classification/README.md @@ -6,17 +6,22 @@ examples demonstrate using the `StellarGraph` library to build machine learning workflows on both homogeneous and heterogeneous networks. Each folder contains one or more examples of using the StellarGraph implementations of the -state-of-the-art algorithms, GraphSAGE [3], HinSAGE, GCN [5], GAT [6], SGC [8], Node2Vec [1], and Metapath2Vec [2]. -GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [5]. Node2Vec and +state-of-the-art algorithms, attri2vec[4], GraphSAGE [3], HinSAGE, GCN [6], GAT [7], SGC [9], Node2Vec [1], and Metapath2Vec [2]. +GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [6]. Node2Vec and Metapath2Vec are methods based on graph random walks and representation learning using the -Word2Vec [4] algorithm. +Word2Vec [5] algorithm. attri2vec[4] is also based on graph random walks and learns node +representations by performing a mapping on node attributes. The examples folder structure is shown below. +* [`/attri2vec`] (https://github.com/stellargraph/stellargraph/tree/master/demos/node-classification/graphsage) + + Examples of supervised node classification for two homogeneous networks with attributes, using the attri2vec algorithm [4]. + * [`/graphsage`](https://github.com/stellargraph/stellargraph/tree/master/demos/node-classification/graphsage) Example of supervised node classification for a homogeneous network with attributed nodes, using the GraphSAGE algorithm [3]. - + * [`/gcn`](https://github.com/stellargraph/stellargraph/tree/master/demos/node-classification/gcn) Example of semi-supervised node classification for a homogeneous network, using the GCN algorithm [5]. @@ -42,28 +47,30 @@ The examples folder structure is shown below. ## References -1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on +1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 2016. ([link](https://snap.stanford.edu/node2vec/)) -2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and +2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and Ananthram Swami. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 135–144, 2017 ([link](https://ericdongyx.github.io/metapath2vec/m2v.html)) -3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 +3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) -4. Distributed representations of words and phrases and their compositionality. T. Mikolov, +4. Attributed Network Embedding via Subspace Discovery. D. Zhang, J, Yin, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) + +5. Distributed representations of words and phrases and their compositionality. T. Mikolov, I. Sutskever, K. Chen, G. S. Corrado, and J. Dean. In Advances in Neural Information Processing Systems (NIPS), pp. 3111-3119, 2013. ([link](https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf)) -5. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. +6. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. ICLR 2017. arXiv:1609.02907 ([link](https://arxiv.org/abs/1609.02907)) -6. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) +7. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) -7. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. +8. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. ICML 2017. ([link](https://geoffpleiss.com/nn_calibration)) -8. Simplifying Graph Convolutional Networks. F. Wu, T. Zhang, A. H. de Souza, C. Fifty, T. Yu, and K. Q. Weinberger. +9. Simplifying Graph Convolutional Networks. F. Wu, T. Zhang, A. H. de Souza, C. Fifty, T. Yu, and K. Q. Weinberger. arXiv:1902.07153. ([link](https://arxiv.org/abs/1902.07153)) - From 20046ec788389744c96e1be49fde47df7dfbd944 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:01:54 +1000 Subject: [PATCH 30/82] add demos/link-prediction/attri2vec/README.md file --- demos/link-prediction/attri2vec/README.md | 51 +++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 demos/link-prediction/attri2vec/README.md diff --git a/demos/link-prediction/attri2vec/README.md b/demos/link-prediction/attri2vec/README.md new file mode 100644 index 000000000..1fd1b57ba --- /dev/null +++ b/demos/link-prediction/attri2vec/README.md @@ -0,0 +1,51 @@ +# attri2vec Link Prediction for Out-of-sample Nodes + +This is an example of using the attri2vec [1] model, with a link classifier on top, +to predict links for out-of-sample nodes in a homogeneous citation network. + +In this demo, we first train the attri2vec model on the in-sample subgraph and infer +representations for out-of-sample nodes with the trained attri2vec model. The we use the +obtained node representations to perform link prediction for out-of-sample nodes. + +The link prediction problem is treated as a supervised binary classification problem for +`(src, dst)` node pairs that make up links in the graph, with positive examples +representing links that do exist in the graph, and negative examples representing +links that don't. + +In this example, we learn to predict citation links between papers in a DBLP dataset (see below). + +## Requirements +This example assumes the `stellargraph` library and its requirements have been +installed by following the installation instructions in the README +of the library's [root directory](https://github.com/stellargraph/stellargraph). + +## DBLP dataset + +This example is tested on the DBLP dataset. The attri2vec model assumes that node +features are available. + +The following is the description of the dataset: +> The DBLP citation network is a subgraph extracted from DBLP-Citation-network V3 (https://aminer.org/citation). +> To form this subgraph, papers from four subjects are extracted according to their venue information: +> Database, Data Mining, Artificial Intelligence and Computer Vision, and papers with no citations are removed. +> The DBLP network contains 18,448 papers and 45,661 citation relations. From paper titles, we construct +> 2,476-dimensional binary node feature vectors, with each element indicating the presence/absence of the corresponding word. +> By ignoring the citation direction, we take the DBLP subgraph as an undirected network. + +Download and unzip the [DBLP.zip](https://www.kaggle.com/daozhang/dblp-subgraph) file to a location on your computer +and pass this location as a command line argument to this script. + +## Running the notebook +The narrated version of this example is available in the `stellargraph-attri2vec-DBLP.ipynb` notebook. +To run the notebook: + - Activate the python 3.6 environment in which the +`stellargraph` library is installed + - Start `jupyter-notebook` + - note: you may need to first install `jupyter` by running `pip install jupyter` in your python environment + - Navigate to the notebook (`/demos/link-prediction/attri2vec/stellargraph-attri2vec-DBLP.ipynb`), and click on + it to launch the notebook. + +## References + +[1] Attributed Network Embedding via Subspace Discovery. D. Zhang, J, Yin, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) From 4121e333c56e7c960fc6d319f67bf30d3965e626 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:02:23 +1000 Subject: [PATCH 31/82] add attri2vec description to demos/link-prediction/README.md file --- demos/link-prediction/README.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/demos/link-prediction/README.md b/demos/link-prediction/README.md index b639e6515..77a98fb58 100644 --- a/demos/link-prediction/README.md +++ b/demos/link-prediction/README.md @@ -6,10 +6,11 @@ examples demonstrate using the `StellarGraph` library to build machine learning workflows on both homogeneous and heterogeneous networks. Each folder contains one or more examples of using the StellarGraph implementations of the -state-of-the-art algorithms, GraphSAGE [3], HinSAGE, GCN [5], GAT [6], Node2Vec [1], and Metapath2Vec [2]. -GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [5]. Node2Vec and +state-of-the-art algorithms, attri2vec[4], GraphSAGE [3], HinSAGE, GCN [6], GAT [7], Node2Vec [1], and Metapath2Vec [2]. +GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [6]. Node2Vec and Metapath2Vec are methods based on graph random walks and representation learning using the -Word2Vec [4] algorithm. +Word2Vec [5] algorithm. attri2vec[4] is also based on graph random walks and learns node +representations by performing a mapping on node attributes. The examples folder structure is shown below. @@ -28,27 +29,34 @@ The examples folder structure is shown below. Example of supervised link attribute prediction for a heterogeneous network with attributed nodes of different types, using the HinSAGE algorithm. +* [`/attri2vec`] (https://github.com/stellargraph/stellargraph/tree/master/demos/link-prediction/attri2vec) + + Example of link prediction for out-of-sample nodes for a homogeneous network with attributed nodes, + using the attri2vec algorithm. ## References -1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on +1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 2016. ([link](https://snap.stanford.edu/node2vec/)) -2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and +2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and Ananthram Swami. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 135–144, 2017 ([link](https://ericdongyx.github.io/metapath2vec/m2v.html)) -3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 +3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) -4. Distributed representations of words and phrases and their compositionality. T. Mikolov, +4. Attributed Network Embedding via Subspace Discovery. D. Zhang, J, Yin, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) + +5. Distributed representations of words and phrases and their compositionality. T. Mikolov, I. Sutskever, K. Chen, G. S. Corrado, and J. Dean. In Advances in Neural Information Processing Systems (NIPS), pp. 3111-3119, 2013. ([link](https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf)) -5. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. +6. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. ICLR 2017. arXiv:1609.02907 ([link](https://arxiv.org/abs/1609.02907)) -6. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) +7. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) -7. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. +8. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. ICML 2017. ([link](https://geoffpleiss.com/nn_calibration)) From 7b65cab5026f850f9c6f90f07792d856e329e48b Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:02:53 +1000 Subject: [PATCH 32/82] add attri2vec description to demos/embeddings/README.md file --- demos/embeddings/README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/demos/embeddings/README.md b/demos/embeddings/README.md index 18f4aa190..1a7ce176d 100644 --- a/demos/embeddings/README.md +++ b/demos/embeddings/README.md @@ -1,8 +1,8 @@ ## Representation Learning Examples -This folder contains three [Jupyter](http://jupyter.org/) python notebooks demonstrating the use of unsupervised graph representation learning methods implemented in the `stellargraph` library for homogeneous and hetrogenous graphs with or without node features. The original works are referenced below. +This folder contains three [Jupyter](http://jupyter.org/) python notebooks demonstrating the use of unsupervised graph representation learning methods implemented in the `stellargraph` library for homogeneous and hetrogenous graphs with or without node features. The original works are referenced below. -**Node2Vec** and **Metapath2Vec** notebooks demonstrate the combined use of `stellargraph` and `Gensim` [4] libraries for representation learning on homogeneous and heterogeneous graphs. +**Node2Vec** and **Metapath2Vec** notebooks demonstrate the combined use of `stellargraph` and `Gensim` [4] libraries for representation learning on homogeneous and heterogeneous graphs. **Unsupervised GraphSAGE** notebook demonstrates the use of `Stellargraph` library's GraphSAGE implementation for unsupervised learning of node embeddings for homogeneous graphs with node features. **attri2vec** notebook demonstrates the implementation of attri2vec with the `Stellargraph` library for unsupervised inductive learning of node embeddings for homogeneous graphs with node features, and the evaluation for its ability to infer the representations of out-of-sample nodes with the out-of-sample node link prediction task. @@ -10,24 +10,25 @@ The notebooks demonstrate the following algorithms. - `stellargraph-node2vec.ipynb` The **Node2Vec** algorithm [1] for representation learning on homogeneous graphs - `stellargraph-metapath2vec.ipynb` The **Metapath2Vec** algorithm [2] for representation learning on heterogeneous graphs. - `embeddings-unsupervised-graphsage-cora.ipynb` The **Unsupervised GraphSAGE** algorithm [5] for representation learning on homogeneous graphs with node features. -- `stellargraph-attri2vec-DBLP.ipynb` The **attri2vec** algorithm [6] for representation learning on homogeneous graphs with node features. +- `stellargraph-attri2vec-citeseer.ipynb` The **attri2vec** algorithm [6] for representation learning on the homogeneous graph citeseer with node features. +- `stellargraph-attri2vec-DBLP.ipynb` The **attri2vec** algorithm [6] for representation learning on the homogeneous graph DBLP with node features. -All examples demonstrate how to calculate embedding vectors for a graph's nodes in just a few lines of Python code. +All examples demonstrate how to calculate embedding vectors for a graph's nodes in just a few lines of Python code. The learned node representations can be used in numerous downstream tasks such as node attribute inference, link prediction, and community detection. ## References -**1.** Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference +**1.** Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 2016. ([link](https://snap.stanford.edu/node2vec/)) -**2.** Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and -Ananthram Swami. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 135–144, 2017. +**2.** Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and +Ananthram Swami. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 135–144, 2017. ([link](https://ericdongyx.github.io/papers/KDD17-dong-chawla-swami-metapath2vec.pdf)) -**3.** Distributed representations of words and phrases and their compositionality. T. Mikolov, I. Sutskever, K. Chen, -G. S. Corrado, and J. Dean. In Advances in Neural Information Processing Systems (NIPS), pp. 3111-3119, 2013. +**3.** Distributed representations of words and phrases and their compositionality. T. Mikolov, I. Sutskever, K. Chen, +G. S. Corrado, and J. Dean. In Advances in Neural Information Processing Systems (NIPS), pp. 3111-3119, 2013. ([link](https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf)) **4.** Gensim: Topic modelling for humans. ([link](https://radimrehurek.com/gensim/)) @@ -35,4 +36,5 @@ G. S. Corrado, and J. Dean. In Advances in Neural Information Processing System **5.** Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) -**6.** Attributed Network Embedding via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, [cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) +**6.** Attributed Network Embedding via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) From c68a62d4cd044066494d012247e23e8a534eb4e9 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:04:06 +1000 Subject: [PATCH 33/82] add attri2vec description to demos/README.md file --- demos/README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/demos/README.md b/demos/README.md index 970549801..12c117cd5 100644 --- a/demos/README.md +++ b/demos/README.md @@ -7,10 +7,10 @@ examples demonstrate using the `StellarGraph` library to build machine learning workflows on both homogeneous and heterogeneous networks. Each folder contains one or more examples of using the StellarGraph implementations of the -state-of-the-art algorithms, GraphSAGE [3], HinSAGE, GCN [5], GAT [6], Node2Vec [1], and Metapath2Vec [2]. -GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [5]. Node2Vec and +state-of-the-art algorithms, attri2vec [4], GraphSAGE [3], HinSAGE, GCN [6], GAT [7], Node2Vec [1], and Metapath2Vec [2]. +GraphSAGE, HinSAGE, and GAT are variants of Graph Convolutional Neural networks [6]. Node2Vec and Metapath2Vec are methods based on graph random walks and representation learning using the -Word2Vec [4] algorithm. +Word2Vec [5] algorithm. The examples folder structure is shown below. @@ -30,8 +30,8 @@ The examples folder structure is shown below. * [`/ensembles`](https://github.com/stellargraph/stellargraph/tree/master/demos/ensembles) Examples of using ensembles of graph convolutional neural networks, e.g., GraphSAGE, GCN, HinSAGE, etc., for - node classification and link prediction. Model ensembles usually yield better predictions than single models, - while also providing estimates of prediction uncertainty as a bonus. + node classification and link prediction. Model ensembles usually yield better predictions than single models, + while also providing estimates of prediction uncertainty as a bonus. * [`/calibration`](https://github.com/stellargraph/stellargraph/tree/master/demos/calibration) @@ -49,24 +49,27 @@ The examples folder structure is shown below. ## References -1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on +1. Node2Vec: Scalable Feature Learning for Networks. A. Grover, J. Leskovec. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 2016. ([link](https://snap.stanford.edu/node2vec/)) -2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and +2. Metapath2Vec: Scalable Representation Learning for Heterogeneous Networks. Yuxiao Dong, Nitesh V. Chawla, and Ananthram Swami. ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD), 135–144, 2017 ([link](https://ericdongyx.github.io/metapath2vec/m2v.html)) -3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 +3. Inductive Representation Learning on Large Graphs. W.L. Hamilton, R. Ying, and J. Leskovec arXiv:1706.02216 [cs.SI], 2017. ([link](http://snap.stanford.edu/graphsage/)) -4. Distributed representations of words and phrases and their compositionality. T. Mikolov, +4. Attributed Network Embedding via Subspace Discovery. D. Zhang, Y. Jie, X. Zhu and C. Zhang, arXiv:1901.04095, +[cs.SI], 2019. ([link](https://arxiv.org/abs/1901.04095)) + +5. Distributed representations of words and phrases and their compositionality. T. Mikolov, I. Sutskever, K. Chen, G. S. Corrado, and J. Dean. In Advances in Neural Information Processing Systems (NIPS), pp. 3111-3119, 2013. ([link](https://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf)) -5. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. +6. Semi-Supervised Classification with Graph Convolutional Networks. T. Kipf, M. Welling. ICLR 2017. arXiv:1609.02907 ([link](https://arxiv.org/abs/1609.02907)) -6. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) +7. Graph Attention Networks. P. Velickovic et al. ICLR 2018 ([link](https://arxiv.org/abs/1710.10903)) -7. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. +8. On Calibration of Modern Neural Networks. C. Guo, G. Pleiss, Y. Sun, and K. Q. Weinberger. ICML 2017. ([link](https://geoffpleiss.com/nn_calibration)) From a00b4cd3c42fe9753879bdf47526c2ac1ff22419 Mon Sep 17 00:00:00 2001 From: Daokun Zhang Date: Wed, 25 Sep 2019 11:04:27 +1000 Subject: [PATCH 34/82] add attri2vec description to README.md file --- README.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 63c55800c..18bf87413 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ The StellarGraph library can be used to solve tasks using graph-structured data, - Representation learning for nodes and edges, to be used for visualisation and various downstream machine learning tasks; - Classification and attribute inference of nodes or edges; - Link prediction; -- Interpretation of node classification through calculated importances of edges and neighbours for selected nodes [7]. +- Interpretation of node classification through calculated importances of edges and neighbours for selected nodes [8]. We provide [examples](https://github.com/stellargraph/stellargraph/tree/master/demos/) of using `StellarGraph` to solve such tasks using several real-world datasets. @@ -130,7 +130,7 @@ can be downloaded and installed from [python.org](https://python.org/). Alternat environment, available from [anaconda.com](https://www.anaconda.com/download/). *Note*: while the library works on Python 3.7 it is based on Keras which does not officially support Python 3.7. -Therefore, there may be unforseen bugs and you there are many warnings from the Python libraries that +Therefore, there may be unforseen bugs and you there are many warnings from the Python libraries that StellarGraph depends upon.