stellargraph/stellargraph

View on GitHub
demos/connector/neo4j/undirected-graphsage-on-cora-neo4j-example.ipynb

Summary

Maintainability
Test Coverage
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "# GraphSAGE with Neo4j"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1",
   "metadata": {
    "nbsphinx": "hidden",
    "tags": [
     "CloudRunner"
    ]
   },
   "source": [
    "<table><tr><td>Run the latest release of this notebook:</td><td><a href=\"https://mybinder.org/v2/gh/stellargraph/stellargraph/master?urlpath=lab/tree/demos/connector/neo4j/undirected-graphsage-on-cora-neo4j-example.ipynb\" alt=\"Open In Binder\" target=\"_parent\"><img src=\"https://mybinder.org/badge_logo.svg\"/></a></td><td><a href=\"https://colab.research.google.com/github/stellargraph/stellargraph/blob/master/demos/connector/neo4j/undirected-graphsage-on-cora-neo4j-example.ipynb\" alt=\"Open In Colab\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\"/></a></td></tr></table>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "This example shows the application of GraphSAGE on the Cora dataset stored in Neo4j.\n",
    "\n",
    "Subgraphs are sampled directly from Neo4j, which eliminate the need to store the whole graph structure in NetworkX. In this demo, node features are cached in memory for faster access since the dataset is relatively small."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3",
   "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.3.0b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4",
   "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.3.0b\")\n",
    "except AttributeError:\n",
    "    raise ValueError(\n",
    "        f\"This notebook requires StellarGraph version 1.3.0b, but a different version {sg.__version__} is installed.  Please see <https://github.com/stellargraph/stellargraph/issues/1172>.\"\n",
    "    ) from None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import os\n",
    "\n",
    "import stellargraph as sg\n",
    "from stellargraph.connector.neo4j import Neo4jGraphSAGENodeGenerator, Neo4jStellarGraph\n",
    "from stellargraph.layer import GraphSAGE\n",
    "\n",
    "import numpy as np\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",
   "id": "6",
   "metadata": {},
   "source": [
    "## Connect to 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."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7",
   "metadata": {},
   "outputs": [],
   "source": [
    "import py2neo\n",
    "\n",
    "default_host = os.environ.get(\"STELLARGRAPH_NEO4J_HOST\")\n",
    "\n",
    "# Create the Neo4j Graph database object; port, user, password parameters can be add to specify location and authentication\n",
    "neo4j_graphdb = py2neo.Graph(host=default_host)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8",
   "metadata": {},
   "source": [
    "## Create a Neo4jStellarGraph object\n",
    "\n",
    "Using the `py2neo.Graph` instance, we can create a `Neo4jStellarGraph` object that will be useful for the rest of the stellargraph workflow.\n",
    "\n",
    "For this demo, we introduce two additional details that help us execute the notebook faster:\n",
    "\n",
    "* Our Cora dataset loaded into Neo4j has an index on the `ID` property of `paper` entities. By specifying the `node_label` parameter when constructing `Neo4jStellarGraph`, this lets downstream queries to use this index and therefore run much faster, since many of the queries will require matching nodes by their `ID`.\n",
    "* We also cache the node features in memory. Since we know the graph is relatively small, we can safely cache the node features in memory for faster access. Note that this should be avoided for larger graphs where the node features are large."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9",
   "metadata": {},
   "outputs": [],
   "source": [
    "neo4j_sg = Neo4jStellarGraph(neo4j_graphdb, node_label=\"paper\")\n",
    "neo4j_sg.cache_all_nodes_in_memory()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10",
   "metadata": {},
   "source": [
    "## Data labels\n",
    "\n",
    "Each node has a \"subject\" property in the database, which we want to use as labels for training. We can load the labels into memory using a Cypher query and split them into training/test sets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "11",
   "metadata": {},
   "outputs": [],
   "source": [
    "labels_query = \"\"\"\n",
    "    MATCH (node:paper)\n",
    "    WITH {ID: node.ID, label: node.subject} as node_data\n",
    "    RETURN node_data\n",
    "    \"\"\"\n",
    "rows = neo4j_graphdb.run(labels_query).data()\n",
    "labels = pd.Series(\n",
    "    [r[\"node_data\"][\"label\"] for r in rows], index=[r[\"node_data\"][\"ID\"] for r in rows]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "12",
   "metadata": {},
   "outputs": [],
   "source": [
    "# split the node labels into train/test\n",
    "\n",
    "train_labels, test_labels = model_selection.train_test_split(\n",
    "    labels, train_size=0.1, test_size=None, stratify=labels\n",
    ")\n",
    "\n",
    "target_encoding = preprocessing.LabelBinarizer()\n",
    "\n",
    "train_targets = target_encoding.fit_transform(train_labels)\n",
    "test_targets = target_encoding.transform(test_labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13",
   "metadata": {},
   "source": [
    "## Creating the GraphSAGE model in Keras"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14",
   "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 `Neo4jGraphSAGENodeGenerator` as we are predicting node attributes with a GraphSAGE 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, and 5 in the second."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "15",
   "metadata": {
    "tags": [
     "parameters"
    ]
   },
   "outputs": [],
   "source": [
    "batch_size = 50\n",
    "num_samples = [10, 5]\n",
    "epochs = 20"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16",
   "metadata": {},
   "source": [
    "A `Neo4jGraphSAGENodeGenerator` object is required to send the node features in sampled subgraphs to Keras."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "17",
   "metadata": {},
   "outputs": [],
   "source": [
    "generator = Neo4jGraphSAGENodeGenerator(neo4j_sg, batch_size, num_samples)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18",
   "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": 10,
   "id": "19",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_gen = generator.flow(train_labels.index, train_targets, shuffle=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20",
   "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.\n",
    " * The `bias` and `dropout` are internal parameters of the model. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "21",
   "metadata": {},
   "outputs": [],
   "source": [
    "graphsage_model = GraphSAGE(\n",
    "    layer_sizes=[32, 32], generator=generator, bias=True, dropout=0.5,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22",
   "metadata": {},
   "source": [
    "Now we create a model to predict the 7 categories using Keras softmax layers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "23",
   "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",
   "id": "24",
   "metadata": {},
   "source": [
    "### Training the model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25",
   "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": 13,
   "id": "26",
   "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",
   "id": "27",
   "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": 14,
   "id": "28",
   "metadata": {},
   "outputs": [],
   "source": [
    "test_gen = generator.flow(test_labels.index, test_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "29",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/20\n",
      "6/6 - 6s - loss: 1.8420 - acc: 0.3000 - val_loss: 1.6646 - val_acc: 0.3888\n",
      "Epoch 2/20\n",
      "6/6 - 6s - loss: 1.5992 - acc: 0.4704 - val_loss: 1.4935 - val_acc: 0.5447\n",
      "Epoch 3/20\n",
      "6/6 - 6s - loss: 1.4202 - acc: 0.6741 - val_loss: 1.3581 - val_acc: 0.6653\n",
      "Epoch 4/20\n",
      "6/6 - 6s - loss: 1.2718 - acc: 0.7889 - val_loss: 1.2407 - val_acc: 0.7215\n",
      "Epoch 5/20\n",
      "6/6 - 5s - loss: 1.1286 - acc: 0.8593 - val_loss: 1.1424 - val_acc: 0.7543\n",
      "Epoch 6/20\n",
      "6/6 - 5s - loss: 1.0310 - acc: 0.8852 - val_loss: 1.0652 - val_acc: 0.7732\n",
      "Epoch 7/20\n",
      "6/6 - 5s - loss: 0.9338 - acc: 0.8926 - val_loss: 1.0227 - val_acc: 0.7580\n",
      "Epoch 8/20\n",
      "6/6 - 5s - loss: 0.8403 - acc: 0.9296 - val_loss: 0.9651 - val_acc: 0.7633\n",
      "Epoch 9/20\n",
      "6/6 - 5s - loss: 0.7482 - acc: 0.9481 - val_loss: 0.9277 - val_acc: 0.7908\n",
      "Epoch 10/20\n",
      "6/6 - 6s - loss: 0.6885 - acc: 0.9778 - val_loss: 0.8926 - val_acc: 0.7945\n",
      "Epoch 11/20\n",
      "6/6 - 6s - loss: 0.6433 - acc: 0.9667 - val_loss: 0.8423 - val_acc: 0.8068\n",
      "Epoch 12/20\n",
      "6/6 - 5s - loss: 0.5693 - acc: 0.9593 - val_loss: 0.8221 - val_acc: 0.8015\n",
      "Epoch 13/20\n",
      "6/6 - 5s - loss: 0.5259 - acc: 0.9778 - val_loss: 0.8009 - val_acc: 0.7986\n",
      "Epoch 14/20\n",
      "6/6 - 5s - loss: 0.4732 - acc: 0.9926 - val_loss: 0.7852 - val_acc: 0.7974\n",
      "Epoch 15/20\n",
      "6/6 - 5s - loss: 0.4317 - acc: 0.9889 - val_loss: 0.7527 - val_acc: 0.8093\n",
      "Epoch 16/20\n",
      "6/6 - 5s - loss: 0.4011 - acc: 0.9926 - val_loss: 0.7533 - val_acc: 0.8019\n",
      "Epoch 17/20\n",
      "6/6 - 5s - loss: 0.3802 - acc: 0.9889 - val_loss: 0.7341 - val_acc: 0.7986\n",
      "Epoch 18/20\n",
      "6/6 - 5s - loss: 0.3410 - acc: 0.9963 - val_loss: 0.7174 - val_acc: 0.8002\n",
      "Epoch 19/20\n",
      "6/6 - 5s - loss: 0.3153 - acc: 0.9815 - val_loss: 0.7141 - val_acc: 0.8023\n",
      "Epoch 20/20\n",
      "6/6 - 5s - loss: 0.2734 - acc: 1.0000 - val_loss: 0.7045 - val_acc: 0.8121\n"
     ]
    }
   ],
   "source": [
    "history = model.fit(\n",
    "    train_gen, epochs=epochs, validation_data=test_gen, verbose=2, shuffle=False\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "30",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 504x576 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "sg.utils.plot_history(history)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31",
   "metadata": {},
   "source": [
    "Now we have trained the model we can evaluate on the test set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "32",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "49/49 [==============================] - 5s 92ms/step - loss: 0.7004 - acc: 0.8105\n",
      "\n",
      "Test Set Metrics:\n",
      "\tloss: 0.7004\n",
      "\tacc: 0.8105\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",
   "id": "33",
   "metadata": {},
   "source": [
    "### Making predictions with the model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34",
   "metadata": {},
   "source": [
    "Now let's get the predictions themselves for all nodes using another node iterator:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "35",
   "metadata": {},
   "outputs": [],
   "source": [
    "all_nodes = labels.index\n",
    "all_mapper = generator.flow(all_nodes)\n",
    "all_predictions = model.predict(all_mapper)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36",
   "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 specification to turn these values back to the original categories"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "37",
   "metadata": {},
   "outputs": [],
   "source": [
    "node_predictions = target_encoding.inverse_transform(all_predictions)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38",
   "metadata": {},
   "source": [
    "Let's have a look at a few:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "39",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Predicted</th>\n",
       "      <th>True</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>31336</th>\n",
       "      <td>Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1061127</th>\n",
       "      <td>Rule_Learning</td>\n",
       "      <td>Rule_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1106406</th>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13195</th>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37879</th>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1126012</th>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1107140</th>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "      <td>Theory</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1102850</th>\n",
       "      <td>Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31349</th>\n",
       "      <td>Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1106418</th>\n",
       "      <td>Theory</td>\n",
       "      <td>Theory</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      Predicted                    True\n",
       "31336           Neural_Networks         Neural_Networks\n",
       "1061127           Rule_Learning           Rule_Learning\n",
       "1106406  Reinforcement_Learning  Reinforcement_Learning\n",
       "13195    Reinforcement_Learning  Reinforcement_Learning\n",
       "37879     Probabilistic_Methods   Probabilistic_Methods\n",
       "1126012   Probabilistic_Methods   Probabilistic_Methods\n",
       "1107140  Reinforcement_Learning                  Theory\n",
       "1102850         Neural_Networks         Neural_Networks\n",
       "31349           Neural_Networks         Neural_Networks\n",
       "1106418                  Theory                  Theory"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.DataFrame({\"Predicted\": node_predictions, \"True\": labels})\n",
    "df.head(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40",
   "metadata": {},
   "source": [
    "Please refer to [the non-Neo4j GraphSAGE node classification demo](./../../node-classification/graphsage-node-classification.ipynb) for **node embedding visualization**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41",
   "metadata": {
    "nbsphinx": "hidden",
    "tags": [
     "CloudRunner"
    ]
   },
   "source": [
    "<table><tr><td>Run the latest release of this notebook:</td><td><a href=\"https://mybinder.org/v2/gh/stellargraph/stellargraph/master?urlpath=lab/tree/demos/connector/neo4j/undirected-graphsage-on-cora-neo4j-example.ipynb\" alt=\"Open In Binder\" target=\"_parent\"><img src=\"https://mybinder.org/badge_logo.svg\"/></a></td><td><a href=\"https://colab.research.google.com/github/stellargraph/stellargraph/blob/master/demos/connector/neo4j/undirected-graphsage-on-cora-neo4j-example.ipynb\" alt=\"Open In Colab\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\"/></a></td></tr></table>"
   ]
  }
 ],
 "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.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}