Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add graph neural networks #110

Merged
merged 35 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b9a1dfb
add graph neural networks
zshiqiang Jun 8, 2023
703f058
fix input issue for max pooling
zshiqiang Jun 13, 2023
0592729
update formulation for GNN
zshiqiang Jun 21, 2023
da3317c
Merge branch 'cog-imperial:main' into add-gnn
zshiqiang Jun 21, 2023
78207c1
add torch_geometric_reader
zshiqiang Aug 14, 2023
2d5a44d
Merge branch 'add-gnn' of https://github.com/zshiqiang/OMLT into add-gnn
zshiqiang Aug 14, 2023
52d25fa
update torch_geometric
zshiqiang Aug 17, 2023
6ef1aa8
fix format issue
zshiqiang Aug 28, 2023
67446c7
fix formate issue
zshiqiang Aug 28, 2023
27175bd
add test dependencies
zshiqiang Aug 29, 2023
8cc9761
update GNN formulation
zshiqiang Aug 29, 2023
b75b991
update GNN formulation
zshiqiang Aug 29, 2023
1326138
update GNN formulation
zshiqiang Aug 29, 2023
af61bb6
update GNN notebook and comments
zshiqiang Sep 13, 2023
62349e1
update GNN comments
zshiqiang Sep 13, 2023
dfb739d
update GNN comments
zshiqiang Sep 13, 2023
e0b543e
update GNN formulation
zshiqiang Sep 13, 2023
f2ec3f3
update GNN tests
zshiqiang Sep 20, 2023
bc14d84
Merge branch 'main' into add-gnn
zshiqiang Sep 20, 2023
a2e1751
update GNN notebook
zshiqiang Sep 20, 2023
84ec479
Merge branch 'main' of https://github.com/zshiqiang/OMLT into add-gnn
zshiqiang Oct 4, 2023
24f3b96
add documentations
zshiqiang Oct 4, 2023
5879b3e
add tests for exceptions
zshiqiang Oct 4, 2023
85aead1
add full path in __init__.py
zshiqiang Oct 10, 2023
18ffcc5
update comments
zshiqiang Oct 10, 2023
5a6794b
Merge branch 'cog-imperial:main' into add-gnn
zshiqiang Nov 1, 2023
f923482
update exceptions
zshiqiang Dec 5, 2023
bef0c04
update exceptions
zshiqiang Dec 5, 2023
51263ec
add contributors
zshiqiang Dec 5, 2023
f832f27
update documentations
zshiqiang Dec 6, 2023
72b9f65
update documentations
zshiqiang Dec 6, 2023
6add77b
update documentations
zshiqiang Dec 6, 2023
92cc2c5
update documentations
zshiqiang Dec 6, 2023
905a9a7
update documentations
zshiqiang Dec 6, 2023
26b8522
add citation
zshiqiang Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/notebooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github `page <https://github.com/cog-imperial/OMLT/tree/main/docs/notebooks/>`_.

* `mnist_example_convolutional.ipynb <https://github.com/cog-imperial/OMLT/blob/main/docs/notebooks/neuralnet/mnist_example_convolutional.ipynb>`_ trains a convolutional neural network on MNIST and uses OMLT to find adversarial examples.

* `graph_neural_network_formulation.ipynb <https://github.com/cog-imperial/OMLT/blob/main/docs/notebooks/graph_neural_network_formulation.ipynb>`_ transforms graph neural networks into OMLT and builds formulation to solve optimization problems.

* `auto-thermal-reformer.ipynb <https://github.com/cog-imperial/OMLT/blob/main/docs/notebooks/neuralnet/auto-thermal-reformer.ipynb>`_ develops a neural network surrogate (using sigmoid activations) with data from a process model built using `IDAES-PSE <https://github.com/IDAES/idaes-pse>`_.

* `auto-thermal-reformer-relu.ipynb <https://github.com/cog-imperial/OMLT/blob/main/docs/notebooks/neuralnet/auto-thermal-reformer-relu.ipynb>`_ develops a neural network surrogate (using ReLU activations) with data from a process model built using `IDAES-PSE <https://github.com/IDAES/idaes-pse>`_.
Expand Down
666 changes: 666 additions & 0 deletions docs/notebooks/neuralnet/graph_neural_network_formulation.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ testing =
torchvision
tqdm
protobuf==3.20.3
torch_geometric

testing_lean =
setuptools
Expand Down
3 changes: 3 additions & 0 deletions src/omlt/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
onnx, onnx_available = attempt_import("onnx")
keras, keras_available = attempt_import("tensorflow.keras")

torch, torch_available = attempt_import("torch")

torch_geometric, torch_geometric_available = attempt_import("torch_geometric")
lineartree, lineartree_available = attempt_import("lineartree")
7 changes: 6 additions & 1 deletion src/omlt/io/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from omlt.dependencies import keras_available, onnx_available
from omlt.dependencies import (
onnx_available,
keras_available,
torch_available,
torch_geometric_available,
)

if onnx_available:
from omlt.io.onnx import (
Expand Down
8 changes: 8 additions & 0 deletions src/omlt/io/torch_geometric/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from omlt.io.torch_geometric.torch_geometric_reader import (
load_torch_geometric_sequential,
)

from omlt.io.torch_geometric.build_gnn_formulation import (
gnn_with_fixed_graph,
gnn_with_non_fixed_graph,
)
148 changes: 148 additions & 0 deletions src/omlt/io/torch_geometric/build_gnn_formulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import numpy as np
import pyomo.environ as pyo
from omlt.neuralnet import FullSpaceNNFormulation
from omlt.io.torch_geometric import load_torch_geometric_sequential


def gnn_with_non_fixed_graph(
block,
nn,
N,
scaling_object=None,
scaled_input_bounds=None,
unscaled_input_bounds=None,
):
"""
Build formulation for a torch_geometric graph neural network model (built with Sequential).
Since the input graph is not fixed, the elements in adjacency matrix are decision variables.

Parameters
----------
block : Block
the Pyomo block
nn : torch_geometric.model
A torch_geometric model that was built with Sequential
N : int
The number of nodes of input graph
scaling_object : instance of ScalingInterface or None
Provide an instance of a scaling object to use to scale iputs --> scaled_inputs
and scaled_outputs --> outputs. If None, no scaling is performed. See scaling.py.
scaled_input_bounds : dict or None
A dict that contains the bounds on the scaled variables (the
direct inputs to the neural network). If None, then no bounds
are specified or they are generated using unscaled bounds.
unscaled_input_bounds : dict or None
A dict that contains the bounds on the unscaled variables (the
direct inputs to the neural network). If specified the scaled_input_bounds
dictionary will be generated using the provided scaling object.
If None, then no bounds are specified.

Returns
-------
OmltBlock (formulated)
"""

# build NetworkDefinition for nn
net = load_torch_geometric_sequential(
nn=nn,
N=N,
A=None,
scaling_object=scaling_object,
scaled_input_bounds=scaled_input_bounds,
unscaled_input_bounds=unscaled_input_bounds,
)

# define binary variables for adjacency matrix
block.A = pyo.Var(
pyo.Set(initialize=range(N)),
pyo.Set(initialize=range(N)),
within=pyo.Binary,
)
# assume that the self contribution always exists
for u in range(N):
block.A[u, u].fix(1)
# assume the adjacency matrix is always symmetric
block.symmetric_adjacency = pyo.ConstraintList()
for u in range(N):
for v in range(u + 1, N):
block.symmetric_adjacency.add((block.A[u, v] == block.A[v, u]))

# build formulation for GNN
block.build_formulation(FullSpaceNNFormulation(net))

return block


def gnn_with_fixed_graph(
block,
nn,
N,
A,
scaling_object=None,
scaled_input_bounds=None,
unscaled_input_bounds=None,
):
"""
Build formulation for a torch_geometric graph neural network model (built with Sequential).
Given the adjacency matrix, the input graph structure is fixed.

Parameters
----------
block : Block
the Pyomo block
nn : torch_geometric.model
A torch_geometric model that was built with Sequential
N : int
The number of nodes of input graph
A : matrix-like
The adjacency matrix of input graph
scaling_object : instance of ScalingInterface or None
Provide an instance of a scaling object to use to scale iputs --> scaled_inputs
and scaled_outputs --> outputs. If None, no scaling is performed. See scaling.py.
scaled_input_bounds : dict or None
A dict that contains the bounds on the scaled variables (the
direct inputs to the neural network). If None, then no bounds
are specified or they are generated using unscaled bounds.
unscaled_input_bounds : dict or None
A dict that contains the bounds on the unscaled variables (the
direct inputs to the neural network). If specified the scaled_input_bounds
dictionary will be generated using the provided scaling object.
If None, then no bounds are specified.

Returns
-------
OmltBlock (formulated)
"""

# assume the adjacency matrix is always symmetric
assert np.array_equal(A, np.transpose(A))

# build NetworkDefinition for nn
net = load_torch_geometric_sequential(
nn=nn,
N=N,
A=A,
scaling_object=scaling_object,
scaled_input_bounds=scaled_input_bounds,
unscaled_input_bounds=unscaled_input_bounds,
)

# define binary variables for adjacency matrix
block.A = pyo.Var(
pyo.Set(initialize=range(N)),
pyo.Set(initialize=range(N)),
within=pyo.Binary,
)
# fix A using given values
for u in range(N):
for v in range(N):
block.A[u, v].fix(A[u, v])

# assume that the self contribution always exists
for u in range(N):
block.A[u, u].fix(1)

# build formulation for GNN
block.build_formulation(FullSpaceNNFormulation(net))

return block
Loading
Loading