dmlc--dgl
2db8ccb487
* [Feature] Add full graph training with dgl built-in dataset. * [Feature] Add full graph training with dgl built-in dataset. * [Feature] Add full graph training with dgl built-in dataset. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Bug] fix model to cuda. * [Feature] Add test loss and accuracy * [Feature] Add test loss and accuracy * [Feature] Add test loss and accuracy * [Feature] Add test loss and accuracy * [Feature] Add test loss and accuracy * [Feature] Add test loss and accuracy * [Fix] Add random * [Bug] Fix batch norm error * [Doc] Test with CN in Sphinx * [Doc] Test with CN in Sphinx * [Doc] Remove the test CN docs. * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Feature] Add input embedding layer * [Doc] fill readme with new performance results * [Doc] Add Chinese User Guide, graph and 1.5 * [Doc] Add Chinese User Guide, graph and 1.5 * Update README.md * [Fix] Temporary remove compgcn * [Doc] Add CN user guide chapter2 * [Test] Tunning format * [Test] Tunning format * [Test] Tunning format * [Test] Tunning format * [Test] Tunning format * [Test] Section headers * [Fix] Fix format errors * [Fix] Fix format errors * [Fix] Fix format errors * [Doc] Add CN-EN EN-CN links * [Doc] Add CN-EN EN-CN links * [Doc] Copyedit chapter2 * [Doc] Copyedit chapter2 * [Doc] Remove EN in 2.1 * [Doc] Remove EN in chapter 2 * [Doc] Copyedit first 2 sections * [Doc] Copyedit first 2 sections * [Doc] copyedited chapter 2 CN * [Doc] Add chapter 3 raw texts * [Doc] Add chapter 3 preface and 3.1 * [Doc] Add chapter 3.2 and 3.3 * [Doc] Add chapter 3.2 and 3.3 * [Doc] Add chapter 3.2 and 3.3 * [Doc] Remove EN parts * [Doc] Copyediting 3.1 * [Doc] Copyediting 3.2 and 3.3 * [Doc] Proofreading 3.1 and 3.2 * [Doc] Proofreading 3.2 and 3.3 * [Doc] Add chapter 4 CN raw text. * [Clean] Remove codes in other branches * [Doc] Start to copyedit chapter 4 preface * [Doc] copyedit CN section 4.1 * [Doc] Remove EN in User Guide Chapter 4 * [Doc] Copyedit chapter 4.1 * [Doc] copyedit cn chapter 4.2, 4.3, 4.4, and 4.5. * [Doc] Fix errors in EN user guide graph feature and heterograph * [Doc] 2nd round copyediting with Murph's comments * [Doc] 3rd round copyediting with Murph's comments * [Doc] 3rd round copyediting with Murph's comments * [Doc] 3rd round copyediting with Murph's comments * [Sync] syncronize with the dgl master * [Doc] edited after Minjie's comments, 1st round * update cub Co-authored-by: Minjie Wang <wmjlyjemaine@gmail.com>
164 行
6.4 KiB
ReStructuredText
164 行
6.4 KiB
ReStructuredText
.. _guide-nn-forward:
|
|
|
|
3.2 DGL NN Module Forward Function
|
|
----------------------------------
|
|
|
|
:ref:`(中文版) <guide_cn-nn-forward>`
|
|
|
|
In NN module, ``forward()`` function does the actual message passing and
|
|
computation. Compared with PyTorch’s NN module which usually takes
|
|
tensors as the parameters, DGL NN module takes an additional parameter
|
|
:class:`dgl.DGLGraph`. The
|
|
workload for ``forward()`` function can be split into three parts:
|
|
|
|
- Graph checking and graph type specification.
|
|
|
|
- Message passing.
|
|
|
|
- Feature update.
|
|
|
|
The rest of the section takes a deep dive into the ``forward()`` function in SAGEConv example.
|
|
|
|
Graph checking and graph type specification
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code::
|
|
|
|
def forward(self, graph, feat):
|
|
with graph.local_scope():
|
|
# Specify graph type then expand input feature according to graph type
|
|
feat_src, feat_dst = expand_as_pair(feat, graph)
|
|
|
|
``forward()`` needs to handle many corner cases on the input that can
|
|
lead to invalid values in computing and message passing. One typical check in conv modules
|
|
like :class:`~dgl.nn.pytorch.conv.GraphConv` is to verify that the input graph has no 0-in-degree nodes.
|
|
When a node has 0 in-degree, the ``mailbox`` will be empty and the reduce function will produce
|
|
all-zero values. This may cause silent regression in model performance. However, in
|
|
:class:`~dgl.nn.pytorch.conv.SAGEConv` module, the aggregated representation will be concatenated
|
|
with the original node feature, the output of ``forward()`` will not be all-zero. No such check is
|
|
needed in this case.
|
|
|
|
DGL NN module should be reusable across different types of graph input
|
|
including: homogeneous graph, heterogeneous
|
|
graph (:ref:`guide-graph-heterogeneous`), subgraph
|
|
block (:ref:`guide-minibatch`).
|
|
|
|
The math formulas for SAGEConv are:
|
|
|
|
.. math::
|
|
|
|
|
|
h_{\mathcal{N}(dst)}^{(l+1)} = \mathrm{aggregate}
|
|
\left(\{h_{src}^{l}, \forall src \in \mathcal{N}(dst) \}\right)
|
|
|
|
.. math::
|
|
|
|
h_{dst}^{(l+1)} = \sigma \left(W \cdot \mathrm{concat}
|
|
(h_{dst}^{l}, h_{\mathcal{N}(dst)}^{l+1}) + b \right)
|
|
|
|
.. math::
|
|
|
|
h_{dst}^{(l+1)} = \mathrm{norm}(h_{dst}^{l+1})
|
|
|
|
One needs to specify the source node feature ``feat_src`` and destination
|
|
node feature ``feat_dst`` according to the graph type.
|
|
:meth:`~dgl.utils.expand_as_pair` is a function that specifies the graph
|
|
type and expand ``feat`` into ``feat_src`` and ``feat_dst``.
|
|
The detail of this function is shown below.
|
|
|
|
.. code::
|
|
|
|
def expand_as_pair(input_, g=None):
|
|
if isinstance(input_, tuple):
|
|
# Bipartite graph case
|
|
return input_
|
|
elif g is not None and g.is_block:
|
|
# Subgraph block case
|
|
if isinstance(input_, Mapping):
|
|
input_dst = {
|
|
k: F.narrow_row(v, 0, g.number_of_dst_nodes(k))
|
|
for k, v in input_.items()}
|
|
else:
|
|
input_dst = F.narrow_row(input_, 0, g.number_of_dst_nodes())
|
|
return input_, input_dst
|
|
else:
|
|
# Homogeneous graph case
|
|
return input_, input_
|
|
|
|
For homogeneous whole graph training, source nodes and destination nodes
|
|
are the same. They are all the nodes in the graph.
|
|
|
|
For heterogeneous case, the graph can be split into several bipartite
|
|
graphs, one for each relation. The relations are represented as
|
|
``(src_type, edge_type, dst_dtype)``. When it identifies that the input feature
|
|
``feat`` is a tuple, it will treat the graph as bipartite. The first
|
|
element in the tuple will be the source node feature and the second
|
|
element will be the destination node feature.
|
|
|
|
In mini-batch training, the computing is applied on a subgraph sampled
|
|
based on a bunch of destination nodes. The subgraph is called as
|
|
``block`` in DGL. In the block creation phase,
|
|
``dst nodes`` are in the front of the node list. One can find the
|
|
``feat_dst`` by the index ``[0:g.number_of_dst_nodes()]``.
|
|
|
|
After determining ``feat_src`` and ``feat_dst``, the computing for the
|
|
above three graph types are the same.
|
|
|
|
Message passing and reducing
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code::
|
|
|
|
import dgl.function as fn
|
|
import torch.nn.functional as F
|
|
from dgl.utils import check_eq_shape
|
|
|
|
if self._aggre_type == 'mean':
|
|
graph.srcdata['h'] = feat_src
|
|
graph.update_all(fn.copy_u('h', 'm'), fn.mean('m', 'neigh'))
|
|
h_neigh = graph.dstdata['neigh']
|
|
elif self._aggre_type == 'gcn':
|
|
check_eq_shape(feat)
|
|
graph.srcdata['h'] = feat_src
|
|
graph.dstdata['h'] = feat_dst
|
|
graph.update_all(fn.copy_u('h', 'm'), fn.sum('m', 'neigh'))
|
|
# divide in_degrees
|
|
degs = graph.in_degrees().to(feat_dst)
|
|
h_neigh = (graph.dstdata['neigh'] + graph.dstdata['h']) / (degs.unsqueeze(-1) + 1)
|
|
elif self._aggre_type == 'max_pool':
|
|
graph.srcdata['h'] = F.relu(self.fc_pool(feat_src))
|
|
graph.update_all(fn.copy_u('h', 'm'), fn.max('m', 'neigh'))
|
|
h_neigh = graph.dstdata['neigh']
|
|
else:
|
|
raise KeyError('Aggregator type {} not recognized.'.format(self._aggre_type))
|
|
|
|
# GraphSAGE GCN does not require fc_self.
|
|
if self._aggre_type == 'gcn':
|
|
rst = self.fc_neigh(h_neigh)
|
|
else:
|
|
rst = self.fc_self(h_self) + self.fc_neigh(h_neigh)
|
|
|
|
The code actually does message passing and reducing computing. This part
|
|
of code varies module by module. Note that all the message passing in
|
|
the above code are implemented using :meth:`~dgl.DGLGraph.update_all` API and
|
|
``built-in`` message/reduce functions to fully utilize DGL’s performance
|
|
optimization as described in :ref:`guide-message-passing-efficient`.
|
|
|
|
Update feature after reducing for output
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. code::
|
|
|
|
# activation
|
|
if self.activation is not None:
|
|
rst = self.activation(rst)
|
|
# normalization
|
|
if self.norm is not None:
|
|
rst = self.norm(rst)
|
|
return rst
|
|
|
|
The last part of ``forward()`` function is to update the feature after
|
|
the ``reduce function``. Common update operations are applying
|
|
activation function and normalization according to the option set in the
|
|
object construction phase.
|