"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This example shows the application of *directed* GraphSAGE to a *directed* graph, where the in-node and out-node neighbourhoods are separately sampled and have different weights.\n",
"\n",
"Subgraphs are sampled directly from Neo4j, which eliminate the need to store the whole graph structure in NetworkX. Node features, however, still need to be loaded in memory.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"nbsphinx": "hidden",
"tags": [
"CloudRunner"
]
},
"outputs": [],
"source": [
"# install StellarGraph if running on Google Colab\n",
"import sys\n",
"if 'google.colab' in sys.modules:\n",
" %pip install -q stellargraph[demos]==1.0.0"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"nbsphinx": "hidden",
"tags": [
"VersionCheck"
]
},
"outputs": [],
"source": [
"# verify that we're using the correct version of StellarGraph for this notebook\n",
"import stellargraph as sg\n",
"\n",
"try:\n",
" sg.utils.validate_notebook_version(\"1.0.0\")\n",
"except AttributeError:\n",
" raise ValueError(\n",
" f\"This notebook requires StellarGraph version 1.0.0, but a different version {sg.__version__} is installed. Please see .\"\n",
" ) from None"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import os\n",
"\n",
"import stellargraph as sg\n",
"from stellargraph.connector.neo4j import Neo4JDirectedGraphSAGENodeGenerator\n",
"from stellargraph.layer import DirectedGraphSAGE\n",
"\n",
"from tensorflow.keras import layers, optimizers, losses, metrics, Model\n",
"from sklearn import preprocessing, feature_extraction, model_selection\n",
"\n",
"import time\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Loading the CORA data from Neo4j\n",
"\n",
"It is assumed that the cora dataset has already been loaded into Neo4j. [This notebook](./load-cora-into-neo4j.ipynb) demonstrates how to load cora dataset into Neo4j.\n",
"\n",
"It is still required to load the node features into memory. We use ```py2neo```, which provides tools to connect to Neo4j databases from Python applications. ```py2neo``` documentation could be found [here](https://py2neo.org/v4/)."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import py2neo\n",
"\n",
"default_host = os.environ.get(\"STELLARGRAPH_NEO4J_HOST\")\n",
"\n",
"# Create the Neo4j Graph database object; the arguments can be edited to specify location and authentication\n",
"neo4j_graphdb = py2neo.Graph(host=default_host, port=None, user=None, password=None)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7.74 s: Loaded node data from neo4j database to memory\n"
]
}
],
"source": [
"def get_node_data_from_neo4j(neo4j_graphdb):\n",
" fetch_node_query = \"MATCH (node) RETURN id(node), properties(node)\"\n",
" # run the query\n",
" node_records = neo4j_graphdb.run(fetch_node_query)\n",
" # convert the node records into pandas dataframe\n",
" return pd.DataFrame(node_records).rename(columns={0: \"id\", 1: \"attr\"})\n",
"\n",
"\n",
"start = time.time()\n",
"node_data = get_node_data_from_neo4j(neo4j_graphdb)\n",
"end = time.time()\n",
"\n",
"print(f\"{end - start:.2f} s: Loaded node data from neo4j database to memory\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Extract the node features which will be consumed by GraphSAGE."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"node_data = node_data.set_index(\"id\")\n",
"attribute_df = node_data[\"attr\"].apply(pd.Series)\n",
"node_data = attribute_df.drop(labels=[\"ID\"], axis=1)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
0
\n",
"
1
\n",
"
2
\n",
"
3
\n",
"
4
\n",
"
5
\n",
"
6
\n",
"
7
\n",
"
8
\n",
"
9
\n",
"
...
\n",
"
1423
\n",
"
1424
\n",
"
1425
\n",
"
1426
\n",
"
1427
\n",
"
1428
\n",
"
1429
\n",
"
1430
\n",
"
1431
\n",
"
1432
\n",
"
\n",
"
\n",
"
id
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
...
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
...
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
2
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
...
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
...
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
...
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
5 rows × 1433 columns
\n",
"
"
],
"text/plain": [
" 0 1 2 3 4 5 6 7 8 9 ... 1423 \\\n",
"id ... \n",
"0 0 0 0 0 0 0 0 0 0 0 ... 0 \n",
"1 0 0 0 0 0 0 0 0 0 0 ... 0 \n",
"2 0 0 0 0 0 0 0 0 0 0 ... 0 \n",
"3 0 0 0 0 0 0 0 0 0 0 ... 0 \n",
"4 0 0 0 0 0 0 0 0 0 0 ... 0 \n",
"\n",
" 1424 1425 1426 1427 1428 1429 1430 1431 1432 \n",
"id \n",
"0 0 0 1 0 0 0 0 0 0 \n",
"1 0 1 0 0 0 0 0 0 0 \n",
"2 0 0 0 0 0 0 0 0 0 \n",
"3 0 0 0 0 0 0 0 0 0 \n",
"4 0 0 0 0 0 0 0 0 0 \n",
"\n",
"[5 rows x 1433 columns]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"node_features = pd.DataFrame(node_data[\"features\"].values.tolist(), index=node_data.index)\n",
"node_features.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We aim to train a graph-ML model that will predict the \"subject\" attribute on the nodes. These subjects are one of 7 categories:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'Case_Based',\n",
" 'Genetic_Algorithms',\n",
" 'Neural_Networks',\n",
" 'Probabilistic_Methods',\n",
" 'Reinforcement_Learning',\n",
" 'Rule_Learning',\n",
" 'Theory'}"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"labels = np.array(node_data[\"subject\"])\n",
"set(labels)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Splitting the data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For machine learning we want to take a subset of the nodes for training, and use the rest for testing. We'll use scikit-learn again to do this."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"train_data, test_data = model_selection.train_test_split(\n",
" node_data, train_size=0.1, test_size=None, stratify=node_data[\"subject\"]\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Converting to numeric arrays"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For our categorical target, we will use one-hot vectors that will be fed into a soft-max Keras layer during training."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"target_encoding = feature_extraction.DictVectorizer(sparse=False)\n",
"\n",
"train_targets = target_encoding.fit_transform(train_data[[\"subject\"]].to_dict(\"records\"))\n",
"test_targets = target_encoding.transform(test_data[[\"subject\"]].to_dict(\"records\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Creating the GraphSAGE model in Keras"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now create a *directed* StellarGraph object storing the node data. Since the subgraph is sampled directly from Neo4j, we only need to retain the node features and do not need to store any edges."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"G = sg.StellarDiGraph(nodes={\"paper\": node_features}, edges={})"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"StellarDiGraph: Directed multigraph\n",
" Nodes: 2708, Edges: 0\n",
"\n",
" Node types:\n",
" paper: [2708]\n",
" Features: float32 vector, length 1433\n",
" Edge types: none\n",
"\n",
" Edge types:\n"
]
}
],
"source": [
"print(G.info())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To feed data from the graph to the Keras model we need a data generator that feeds data from the graph to the model. The generators are specialized to the model and the learning task so we choose the `Neo4JDirectedGraphSAGENodeGenerator` as we are predicting node attributes with a `DirectedGraphSAGE` model, sampling directly from Neo4j database.\n",
"\n",
"We need two other parameters, the `batch_size` to use for training and the number of nodes to sample at each level of the model. Here we choose a two-level model with 10 nodes sampled in the first layer (5 in-nodes and 5 out-nodes), and 4 in the second layer (2 in-nodes and 2 out-nodes)."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 50\n",
"in_samples = [5, 2]\n",
"out_samples = [5, 2]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A `Neo4JDirectedGraphSAGENodeGenerator` object is required to send the node features in sampled subgraphs to Keras."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"generator = Neo4JDirectedGraphSAGENodeGenerator(\n",
" G, batch_size, in_samples, out_samples, neo4j_graphdb=neo4j_graphdb\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using the `generator.flow()` method, we can create iterators over nodes that should be used to train, validate, or evaluate the model. For training we use only the training nodes returned from our splitter and the target values. The `shuffle=True` argument is given to the `flow` method to improve training."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"train_gen = generator.flow(train_data.index, train_targets, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can specify our machine learning model, we need a few more parameters for this:\n",
"\n",
" * the `layer_sizes` is a list of hidden feature sizes of each layer in the model. In this example we use 32-dimensional hidden node features at each layer, which corresponds to 12 weights for each head node, 10 for each in-node and 10 for each out-node.\n",
" * The `bias` and `dropout` are internal parameters of the model. "
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"graphsage_model = DirectedGraphSAGE(\n",
" layer_sizes=[32, 32], generator=generator, bias=False, dropout=0.5,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we create a model to predict the 7 categories using Keras softmax layers."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"x_inp, x_out = graphsage_model.in_out_tensors()\n",
"prediction = layers.Dense(units=train_targets.shape[1], activation=\"softmax\")(x_out)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Training the model"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's create the actual Keras model with the graph inputs `x_inp` provided by the `graph_model` and outputs being the predictions from the softmax layer"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"model = Model(inputs=x_inp, outputs=prediction)\n",
"model.compile(\n",
" optimizer=optimizers.Adam(lr=0.005),\n",
" loss=losses.categorical_crossentropy,\n",
" metrics=[\"acc\"],\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Train the model, keeping track of its loss and accuracy on the training set, and its generalisation performance on the test set (we need to create another generator over the test data for this)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"test_gen = generator.flow(test_data.index, test_targets)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ['...']\n",
" ['...']\n",
"Train for 6 steps, validate for 49 steps\n",
"Epoch 1/20\n",
"6/6 - 19s - loss: 1.9219 - acc: 0.2037 - val_loss: 1.7854 - val_acc: 0.3954\n",
"Epoch 2/20\n",
"6/6 - 17s - loss: 1.7039 - acc: 0.4593 - val_loss: 1.6917 - val_acc: 0.4180\n",
"Epoch 3/20\n",
"6/6 - 16s - loss: 1.6037 - acc: 0.5148 - val_loss: 1.6101 - val_acc: 0.4705\n",
"Epoch 4/20\n",
"6/6 - 15s - loss: 1.4970 - acc: 0.6037 - val_loss: 1.5216 - val_acc: 0.5513\n",
"Epoch 5/20\n",
"6/6 - 10s - loss: 1.3823 - acc: 0.7333 - val_loss: 1.4318 - val_acc: 0.6304\n",
"Epoch 6/20\n",
"6/6 - 7s - loss: 1.2758 - acc: 0.7963 - val_loss: 1.3518 - val_acc: 0.6813\n",
"Epoch 7/20\n",
"6/6 - 7s - loss: 1.1964 - acc: 0.8407 - val_loss: 1.2790 - val_acc: 0.7047\n",
"Epoch 8/20\n",
"6/6 - 7s - loss: 1.0813 - acc: 0.8556 - val_loss: 1.2154 - val_acc: 0.7182\n",
"Epoch 9/20\n",
"6/6 - 7s - loss: 0.9830 - acc: 0.9074 - val_loss: 1.1496 - val_acc: 0.7313\n",
"Epoch 10/20\n",
"6/6 - 7s - loss: 0.9067 - acc: 0.9037 - val_loss: 1.0901 - val_acc: 0.7477\n",
"Epoch 11/20\n",
"6/6 - 7s - loss: 0.8347 - acc: 0.9185 - val_loss: 1.0489 - val_acc: 0.7506\n",
"Epoch 12/20\n",
"6/6 - 8s - loss: 0.7650 - acc: 0.9481 - val_loss: 1.0055 - val_acc: 0.7559\n",
"Epoch 13/20\n",
"6/6 - 7s - loss: 0.6984 - acc: 0.9556 - val_loss: 0.9626 - val_acc: 0.7629\n",
"Epoch 14/20\n",
"6/6 - 7s - loss: 0.6449 - acc: 0.9704 - val_loss: 0.9329 - val_acc: 0.7715\n",
"Epoch 15/20\n",
"6/6 - 7s - loss: 0.5915 - acc: 0.9778 - val_loss: 0.9083 - val_acc: 0.7654\n",
"Epoch 16/20\n",
"6/6 - 7s - loss: 0.5647 - acc: 0.9593 - val_loss: 0.8725 - val_acc: 0.7810\n",
"Epoch 17/20\n",
"6/6 - 7s - loss: 0.5161 - acc: 0.9630 - val_loss: 0.8562 - val_acc: 0.7769\n",
"Epoch 18/20\n",
"6/6 - 7s - loss: 0.4708 - acc: 0.9889 - val_loss: 0.8447 - val_acc: 0.7736\n",
"Epoch 19/20\n",
"6/6 - 7s - loss: 0.4557 - acc: 0.9778 - val_loss: 0.8155 - val_acc: 0.7879\n",
"Epoch 20/20\n",
"6/6 - 7s - loss: 0.4216 - acc: 0.9778 - val_loss: 0.8091 - val_acc: 0.7826\n"
]
}
],
"source": [
"history = model.fit(\n",
" train_gen, epochs=20, validation_data=test_gen, verbose=2, shuffle=False\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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yy+/TExMDGVlZYcdf/rpp0lLS6O6uppf/epXdO/enbCwMLp168ZDDz1EeXn5Ud9zwYIFGGPIzj50VWL+/PkMGjSI0NBQBg0axPz584943aRJk+jbty/h4eGkpqZy++23U1BQcPA9b7jBOUlijHNddty4cYBzCv3ss88++D7WWv785z/TrVs3QkJC6N69O88999xhn5Wens4jjzzC3XffTWxsLImJidxzzz0HLwO0JRtyi7jshW+Z9vVmbjy1Cx/edXqTwxucP4/Q4EDiItvRpWME/TvHMLxrLGf2SeDiwZ0ZOzyN20Z24+6ze3LPOb04b0ASnWLCFN4ifsLX1iz8f8AoY8xSYBSQA1TXb2StnWqtzbDWZsTHx3u6Ro+4+uqrqaio4IMPPjjs+BtvvMH111+PMYaEhARmzpzJmjVreO6553jttdd46qmnmvwZO3bs4KKLLmLYsGH8+OOP/OUvf+Huu+8+ol1YWBhTp05l9erVTJ8+nQULFvCb3/wGcE7L//3vfwdg586d7Ny5kylTpjT4eS+++CK///3veeCBB1i1ahX33XcfDzzwAK+88sph7Z5//nk6derEokWLeP755/n73//O66+/3uTv5e+stcxctI2Lnv+KnQWlvHxjBk+MGUBosBY9EZFDPHkKPQdIrfM4pebYQdbaHdT0wI0xkcAV1tr9LVrFvx+AXSta9C2bJGkgnD+58XY1YmJiGDNmDG+88Qa//OUvAcjMzGT16tXMmTOHgIAAnnzyyYPt09PT2bhxIy+++CKPP/54kz7jxRdfJC4ujpdffpmgoCD69evHU089xcUXX3xYu4cffviwz/nTn/7E2LFjee211wgJCTl4qryx0/OTJ0/mrrvuYvz48QD07NmTrKwsnnzySW699daD7UaOHMkDDzxwsM1rr73G559/flib1mpfcQUPzFnOp6t2c3qPOP5y9WASo0O9XZaI+CBPBvhioKcxpitOcI8Frq3bwBgTB+y11rqAB3FGpLdZN910E5dccgm5ubkkJCTwxhtvMHz4cHr37g04p9mnTZvGli1bKC4upqqqqlmDxlavXs3w4cMJCjr01+D0008/ot2cOXN47rnn2LBhA4WFhbhcLioqKti1axedO3du0mcVFhaSnZ3NGWeccdjxUaNGMWXKFEpKSggPDwdgyJAhh7Xp3LkzmzdvbvL38lffbszn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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"sg.utils.plot_history(history)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we have trained the model we can evaluate on the test set."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" ['...']\n",
"\n",
"Test Set Metrics:\n",
"\tloss: 0.8150\n",
"\tacc: 0.7826\n"
]
}
],
"source": [
"test_metrics = model.evaluate(test_gen)\n",
"print(\"\\nTest Set Metrics:\")\n",
"for name, val in zip(model.metrics_names, test_metrics):\n",
" print(\"\\t{}: {:0.4f}\".format(name, val))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Making predictions with the model"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's get the predictions themselves for all nodes using another node iterator:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": []
}
],
"source": [
"all_nodes = node_data.index\n",
"all_mapper = generator.flow(all_nodes)\n",
"all_predictions = model.predict(all_mapper)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These predictions will be the output of the softmax layer, so to get final categories we'll use the `inverse_transform` method of our target attribute specifcation to turn these values back to the original categories"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"node_predictions = target_encoding.inverse_transform(all_predictions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's have a look at a few:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"