From 82572c3db05d0a566b17ad00357d495db2345e10 Mon Sep 17 00:00:00 2001 From: Viktor Stenby Date: Thu, 21 Sep 2023 12:08:53 +0200 Subject: [PATCH] [Documentation] `Node2Vec` and `MetaPath2Vec` (#7938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of #7892 documentation sprint. I have added the tutorial to the documentation and started writing a bit. Will continue to fill out! 💪 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: rusty1s --- CHANGELOG.md | 1 + .../_figures/shallow_node_embeddings.png | Bin 0 -> 63999 bytes docs/source/tutorial/application.rst | 1 + .../tutorial/shallow_node_embeddings.rst | 145 ++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 docs/source/_figures/shallow_node_embeddings.png create mode 100644 docs/source/tutorial/shallow_node_embeddings.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb9d0e9ce66..2999faeffb03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Added +- Added a tutorial for `Node2Vec` and `MetaPath2Vec` usage ([#7938](https://github.com/pyg-team/pytorch_geometric/pull/7938) - Added a tutorial for multi-GPU training with pure PyTorch ([#7894](https://github.com/pyg-team/pytorch_geometric/pull/7894) - Added `edge_attr` support to `ResGatedGraphConv` ([#8048](https://github.com/pyg-team/pytorch_geometric/pull/8048)) - Added a `Database` interface and `SQLiteDatabase`/`RocksDatabase` implementations ([#8028](https://github.com/pyg-team/pytorch_geometric/pull/8028), [#8044](https://github.com/pyg-team/pytorch_geometric/pull/8044), [#8046](https://github.com/pyg-team/pytorch_geometric/pull/8046), [#8051](https://github.com/pyg-team/pytorch_geometric/pull/8051), [#8052](https://github.com/pyg-team/pytorch_geometric/pull/8052), [#8054](https://github.com/pyg-team/pytorch_geometric/pull/8054), [#8057](https://github.com/pyg-team/pytorch_geometric/pull/8057), [#8058](https://github.com/pyg-team/pytorch_geometric/pull/8058)) diff --git a/docs/source/_figures/shallow_node_embeddings.png b/docs/source/_figures/shallow_node_embeddings.png new file mode 100644 index 0000000000000000000000000000000000000000..c248e09a41e1154f52e2628cad479a821f50ccff GIT binary patch literal 63999 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/source/tutorial/application.rst b/docs/source/tutorial/application.rst index f9b541e0d3bd..83128b409950 100644 --- a/docs/source/tutorial/application.rst +++ b/docs/source/tutorial/application.rst @@ -5,3 +5,4 @@ Use-Cases & Applications :name: rst-gallery explain + shallow_node_embeddings diff --git a/docs/source/tutorial/shallow_node_embeddings.rst b/docs/source/tutorial/shallow_node_embeddings.rst new file mode 100644 index 000000000000..76a7f7876555 --- /dev/null +++ b/docs/source/tutorial/shallow_node_embeddings.rst @@ -0,0 +1,145 @@ +Shallow Node Embeddings +======================= + +In this tutorial, we will take a closer look at how to learn *shallow node embeddings* in an unsupervised fashion via :pyg:`PyG`. + +Introduction +------------ + +The key difference between *shallow* node embeddings (*e.g.,* :class:`~torch_geometric.nn.models.Node2Vec`) and *deep* node embeddings (*e.g.,* GNNs) is the choice of the encoder :math:`\textrm{ENC}(v, \mathcal{G}) = \mathbf{z}_v \in \mathbb{R}^d`. +Specifically, shallow node embedding techniques rely on embedding nodes into low-dimensional vectorial representations :math:`\mathbf{z}_v` via a *shallow embedding lookup table* such that the likelihood of preserving neighborhoods is maximized, *i.e.* nearby nodes should receive similar embeddings while distant nodes should receive distinct embedding. +These techniques generalize the famous `SkipGram `_ model for obtaining low-dimensional word embeddings, in which sequences of words are now interpreted as sequences of nodes, *e.g.*, given via randomly-generated walks: + +.. figure:: ../_figures/shallow_node_embeddings.png + :align: center + :width: 100% + +| + +Specifically, given a *random walk* :math:`\mathcal{W} = (v_{\pi(1)}, \ldots, v_{\pi_(k)})` of length :math:`k` starting at node :math:`v \in \mathcal{V}`, the objective is to maximize the likelihood of observing node :math:`v_{\pi(i)}` given node :math:`v`. +This objective can be efficiently trained via stochastic gradient descent in a contrastive learning scenario + +.. math:: + \mathcal{L} = \sum_{w \in \mathcal{W}} - \log \left(\sigma(\mathbf{z}_v^{\top} \mathbf{z}_w) \right) + \sum_{w \sim \mathcal{V} \setminus \mathcal{W}} - \log \left( 1 - \sigma(\mathbf{z}_v^{\top} \mathbf{z}_w) \right), + +in which non-existent walks (so called *negative examples*) are sampled and trained jointly, and :math:`\sigma` denotes the :math:`\textrm{sigmoid}` function. +Noteworthy, the dot-product :math:`\mathbf{z}_v^{\top} \mathbf{z}_w` between the embeddings is usually used to measure similarity, but other similarity measures are applicable as well. + +Importantly, shallow node embeddings are trained in an unsupervised fashion, and can eventually be used as input for a given down-stream task, *e.g.*, in node-level tasks :math:`\mathbf{z}_v` can directly be used as input to a final classifier. +For edge-level tasks, edge-level representations can be obtained via averaging :math:`\frac{1}{2} (\mathbf{z}_v + \mathbf{z}_w)` or via the Hadamard product :math:`\mathbf{z}_v \odot \mathbf{z}_w`. + +Despite the simplicity of node embedding techniques, they are also subject to certain shortcomings. +In particular, they fail to incorporate rich feature information attached to nodes and edges, and cannot be trivially applied to unseen +graphs as learnable parameters are fixed to the nodes of a particular graph (making this approach transductive by nature and hard-to-scale due to the :math:`\mathcal{O}(|\mathcal{V}| \cdot d)` parameter complexity). +However, it is still a commonly used technique to preserve structural graph information into fixed-size vectors, and is often times also used to generate inputs to GNNs for further processing in case the initial set of node features is not rich. + +Node2Vec +-------- + +.. note:: + + In this section of the tutorial, we will learn node embeddings for **homogenous graphs** using the :class:`~torch_geometric.nn.models.Node2Vec` module of :pyg:`PyG`. + The code is available in `examples/node2vec.py `_ and as a `Google Colab tutorial notebook `_. + +:class:`~torch_geometric.nn.models.Node2Vec` is a method for learning shallow node embeddings, which allows for flexible +control of random walk procedures based on breadth-first or depth-first samplers. +In particular, its parameter :obj:`p` dictates the likelihood of immediately revisiting a node in the walk, while its parameter :obj:`q` interpolates between breadth-first and depth-first strategies. + +To begin the example, let us load in the needed packages and the data that we will be working with: + +.. code-block:: python + + from torch_geometric.nn import Node2Vec + + data = Planetoid('./data/Planetoid', name='Cora')[0] + +We are now ready to initialize our :class:`~torch_geometric.nn.module.Node2Vec` module: + +.. code-block:: python + + import torch + from torch_geometric.nn import Node2Vec + + device = 'cuda' if torch.cuda.is_available() else 'cpu' + + model = Node2Vec( + data.edge_index, + embedding_dim=128, + walks_per_node=10, + walk_length=20, + context_size=10, + p=1.0, + q=1.0, + num_negative_samples=1, + ).to(device) + + optimizer = torch.optim.Adam(model.parameters(), lr=0.01) + +:class:`~torch_geometric.nn.models.Node2Vec` takes the graph structure :obj:`edge_index` as input (but none of its feature information), the :obj:`embedding_dim` of the shallow embeddings, and additional parameters to control the random walk and negative sampling procedures. +In particular, :obj:`walks_per_node` and :obj:`walk_length` specify the number of walks to perform for each node and their length, respectively. +The :obj:`context_size` then denotes how many nodes in the walk are actually used for gradient optimization, *i.e* :class:`~torch_geometric.nn.models.Node2Vec` slides over each sampled walk and splits them into windows of size :obj:`context_size`. +As previously mentioned, :obj:`p` and :obj:`q` denote how random walks are generated. +Finally, :obj:`num_negative_samples` specifies how many negative walks we want to generate for each positive walk. + +After initializing, we can go ahead and train our :class:`~torch_geometric.nn.models.Node2Vec` model right away. +We start this by creating a data loader that will generate positive and negative random walks for us: + +.. code-block:: python + + loader = model.loader(batch_size=128, shuffle=True, num_workers=4) + +To generate random walks, we can simply iterate over the data loader, *e.g.*: + +.. code-block:: python + + pos_rw, neg_rw = next(iter(loader)) + +Here, :obj:`pos_rw` will contain the node indices of positive random walks and :obj:`neg_rw` will contain the node indices of negative walks. +In particular, :obj:`pos_rw` is a two-dimensional matrix of shape :obj:`[batch_size * walks_per_node * (2 + walk_length - context_size), context_size]`, and :obj:`neg_rw` is a two-dimensional matrix of shape :obj:`[num_negative_samples * pos_rw.size(0), context_size]`. + +Using this :obj:`loader` and the built-in constrastive :meth:`~torch_geometric.nn.models.Node2Vec.loss` function, we can define our :meth:`train` function as follows: + +.. code-block:: python + + def train(): + model.train() + total_loss = 0 + for pos_rw, neg_rw in loader: + optimizer.zero_grad() + loss = model.loss(pos_rw.to(device), neg_rw.to(device)) + loss.backward() + optimizer.step() + total_loss += loss.item() + return total_loss / len(loader) + +After finishing training, we can obtain the final node embeddings from the model as follows: + +.. code-block:: python + + z = model() # Full node-level embeddings. + z = model(torch.tensor([0, 1, 2])) # Embeddings of first three nodes. + + +MetaPath2Vec +------------ + +.. note:: + + In this section of the tutorial, we will learn node embeddings for **heterogenous graphs** using the :class:`~torch_geometric.nn.models.MetaPath2Vec` module of :pyg:`PyG`. + The code is available as `examples/hetero/metapath2vec.py `_ and as a `Google Colab tutorial notebook `_. + + +An extension of :class:`~torch_geometric.nn.models.Node2Vec` to *heterogeneous graphs* is the :class:`~torch_geometric.nn.models.MetaPath2Vec` model. +:class:`~torch_geometric.nn.models.MetaPath2Vec` works similar to :class:`~torch_geometric.nn.models.Node2Vec` but expects a dictionary of edge indices as input (holding the :obj:`edge_index` for each edge type in the graph), and samples random walks based on a given :obj:`metapath` formulation, *e.g.*, + +.. code-block:: python + + metapath = [ + ('author', 'writes', 'paper'), + ('paper', 'published_in', 'venue'), + ('venue', 'publishes', 'paper'), + ('paper', 'written_by', 'author'), + ] + +denotes that random walk sampling is performed from author nodes to paper nodes to venue nodes back to paper nodes and author nodes. +Otherwise, initialization and training of the model stays the same as in the :class:`~torch_geometric.nn.models.Node2Vec` case.