### Get Neural Network Solver Object (Pytorch Example) Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/utils.html Example demonstrating how to retrieve a neural network object using a provided solver function and parameters, specifically for Pytorch. ```python # Pytorch Example # :: # # >>> import torch # >>> import pygmtools as pygm # # >>> # Define a simple neural network solver function # >>> def my_nn_solver(x, y): # ... return torch.nn.functional.mse_loss(x, y) # # >>> # Get the network object # >>> net = pygm.utils.get_network(my_nn_solver, input_dim=10, output_dim=2) # >>> print(net) # MyNNSolver( # (layer1): Linear(in_features=10, out_features=5, bias=True) # (layer2): Linear(in_features=5, out_features=2, bias=True) # ) ``` -------------------------------- ### Pytorch Example for Multi-Graph Matching Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/multi_graph_solvers.html Initializes PyTorch backend and sets a manual seed for reproducibility. This snippet serves as a starting point for using pygmtools' multi-graph solvers with PyTorch. ```python import torch import pygmtools as pygm import itertools import time pygm.set_backend('pytorch') _ = torch.manual_seed(1) ``` -------------------------------- ### Setup and Helper Functions for RDKit Graph Matching Source: https://pygmtools.readthedocs.io/en/latest/_downloads/75612bf94cb916fe92aad63afe824859/plot_rdkit_graph_matching_paddle.ipynb Initializes the Paddle backend and defines helper functions for rendering molecules and visualizing matched pairs. Ensure RDKit, matplotlib, numpy, PIL, and pygmtools are installed. ```python # Author: Runzhong Wang and Codex # License: Mulan PSL v2 License from io import BytesIO import matplotlib.pyplot as plt import numpy as np import pygmtools as pygm from PIL import Image from rdkit import Chem from rdkit.Chem import rdDepictor from rdkit.Chem.Draw import rdMolDraw2D pygm.set_backend('paddle') def render_molecule(mol, width=420, height=280): drawer = rdMolDraw2D.MolDraw2DCairo(width, height) rdMolDraw2D.PrepareAndDrawMolecule(drawer, mol) atom_coords = np.array([ [drawer.GetDrawCoords(i).x, drawer.GetDrawCoords(i).y] for i in range(mol.GetNumAtoms()) ]) drawer.FinishDrawing() image = np.array(Image.open(BytesIO(drawer.GetDrawingText()))) return image, atom_coords def show_pair(ax, img1, coords1, img2, coords2, lines=None): height = max(img1.shape[0], img2.shape[0]) width1 = img1.shape[1] width2 = img2.shape[1] gap = 80 offset2 = width1 + gap ax.imshow(img1, extent=(0, width1, height, 0)) ax.imshow(img2, extent=(offset2, offset2 + width2, height, 0)) if lines is not None: for idx1, idx2 in lines: ax.plot( [coords1[idx1, 0], coords2[idx2, 0] + offset2], [coords1[idx1, 1], coords2[idx2, 1]], '--', color='0.35', lw=1.0, alpha=0.75 ) ax.set_xlim(0, offset2 + width2) ax.set_ylim(height, 0) ax.axis('off') ``` -------------------------------- ### PyTorch Example for A* Solver Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.classic_solvers.astar.html Demonstrates how to use the A* solver with PyTorch for graph matching. It includes generating isomorphic graphs, building an affinity matrix, and solving the matching problem. The example also shows how to check accuracy and highlights the effect of the beam_width parameter. ```python import torch import pygmtools as pygm pygm.set_backend('pytorch') _ = torch.manual_seed(1) # Generate a batch of isomorphic graphs batch_size = 10 X_gt = torch.zeros(batch_size, 4, 4) X_gt[:, torch.arange(0, 4, dtype=torch.int64), torch.randperm(4)] = 1 A1 = torch.rand(batch_size, 4, 4) A2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), A1), X_gt) n1 = torch.tensor([4] * batch_size) n2 = torch.tensor([4] * batch_size) # Build affinity matrix conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) import functools gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by A* X = pygm.astar(K, n1, n2) print(X[0]) # Accuracy print((X * X_gt).sum() / X_gt.sum()) # If beam_width=0, the solver will do an exhaustive search over the entire space and can be inefficient. # Consider setting a non-zero beam width to make it more efficient, especially for larger-sized problems X = pygm.astar(K, n1, n2, beam_width=1) # This function also supports non-batched input, by ignoring all batch dimensions in the input tensors. X_0 = pygm.astar(K[0], n1[0], n2[0]) print(X_0.shape) # Accuracy print((X_0 * X_gt[0]).sum() / X_gt[0].sum()) ``` -------------------------------- ### Jittor Example Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.neural_solvers.ngm.html This example demonstrates how to use the NGM solver with the Jittor backend. It covers graph generation, affinity matrix construction, solving with NGM, and evaluating accuracy. It also shows how to reuse a trained network and load pretrained weights. ```APIDOC ## Jittor Example ### Description This example demonstrates how to use the NGM solver with the Jittor backend. It covers graph generation, affinity matrix construction, solving with NGM, and evaluating accuracy. It also shows how to reuse a trained network and load pretrained weights. ### Code ```python >>> import jittor as jt >>> import pygmtools as pygm >>> pygm.set_backend('jittor') >>> _ = jt.seed(1) # Generate a batch of isomorphic graphs >>> batch_size = 10 >>> X_gt = jt.zeros((batch_size, 4, 4)) >>> X_gt[:, jt.arange(0, 4, dtype=jt.int64), jt.randperm(4)] = 1 >>> A1 = jt.rand(batch_size, 4, 4) >>> A2 = jt.bmm(jt.bmm(X_gt.transpose(1, 2), A1), X_gt) >>> n1 = n2 = jt.Var([4] * batch_size) # Build affinity matrix >>> conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) >>> conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) >>> import functools >>> gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function >>> K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by NGM >>> X, net = pygm.ngm(K, n1, n2, return_network=True) # Downloading to ~/.cache/pygmtools/ngm_voc_jittor.pt... >>> (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy jt.Var([1.], dtype=float32) # Pass the net object to avoid rebuilding the model agian >>> X = pygm.ngm(K, n1, n2, network=net) # You may also load other pretrained weights >>> X, net = pygm.ngm(K, n1, n2, return_network=True, pretrain='willow') # Downloading to ~/.cache/pygmtools/ngm_willow_jittor.pt... # You may configure your own model and integrate the model into a deep learning pipeline. For example: >>> net = pygm.utils.get_network(pygm.ngm, gnn_channels=(32, 64, 128, 64, 32), sk_emb=8, pretrain=False) >>> optimizer = jt.optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # K may be outputs by other neural networks (constructed K from node/edge features by pygm.utils.build_aff_mat) >>> X = pygm.ngm(K, n1, n2, network=net) >>> loss = pygm.utils.permutation_loss(X, X_gt) >>> optimizer.backward(loss) >>> optimizer.step() ``` ``` -------------------------------- ### Paddle Example Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.neural_solvers.ngm.html This example demonstrates how to use the NGM solver with the Paddle backend. It covers graph generation, affinity matrix construction, solving with NGM, and evaluating accuracy. It also shows how to reuse a trained network and load pretrained weights. ```APIDOC ## Paddle Example ### Description This example demonstrates how to use the NGM solver with the Paddle backend. It covers graph generation, affinity matrix construction, solving with NGM, and evaluating accuracy. It also shows how to reuse a trained network and load pretrained weights. ### Code ```python >>> import paddle >>> import pygmtools as pygm >>> pygm.set_backend('paddle') >>> _ = paddle.seed(1) # Generate a batch of isomorphic graphs >>> batch_size = 10 >>> X_gt = paddle.zeros((batch_size, 4, 4)) >>> X_gt[:, paddle.arange(0, 4, dtype=paddle.int64), paddle.randperm(4)] = 1 >>> A1 = paddle.rand((batch_size, 4, 4)) >>> A2 = paddle.bmm(paddle.bmm(X_gt.transpose((0, 2, 1)), A1), X_gt) >>> n1 = n2 = paddle.to_tensor([4] * batch_size) # Build affinity matrix >>> conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) >>> conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) >>> import functools >>> gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function >>> K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by NGM >>> X, net = pygm.ngm(K, n1, n2, return_network=True) Downloading to ~/.cache/pygmtools/ngm_voc_paddle.pdparams... >>> (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True, [1.]) # Pass the net object to avoid rebuilding the model agian >>> X = pygm.ngm(K, n1, n2, network=net) # You may also load other pretrained weights >>> X, net = pygm.ngm(K, n1, n2, return_network=True, pretrain='willow') Downloading to ~/.cache/pygmtools/ngm_willow_paddle.pdparams... # You may configure your own model and integrate the model into a deep learning pipeline. For example: >>> net = pygm.utils.get_network(pygm.ngm, gnn_channels=(32, 64, 128, 64, 32), sk_emb=8, pretrain=False) >>> optimizer = paddle.optimizer.SGD(parameters=net.parameters(), learning_rate=0.001) # K may be outputs by other neural networks (constructed K from node/edge features by pygm.utils.build_aff_mat) >>> X = pygm.ngm(K, n1, n2, network=net) >>> loss = pygm.utils.permutation_loss(X, X_gt) >>> loss.backward() >>> optimizer.step() ``` ``` -------------------------------- ### Build Documentation Source: https://pygmtools.readthedocs.io/en/latest/guide/contributing.html Use this command to build the HTML documentation from the 'docs/' directory. Ensure you have the required packages installed. ```bash make html ``` -------------------------------- ### Initialize Jittor Backend and Graph Matching Example Source: https://pygmtools.readthedocs.io/en/latest/guide/numerical_backends.html This snippet initializes the Jittor backend, sets a random seed, enables CUDA if available, and sets up for a graph matching example. It demonstrates generating isomorphic graphs, building an affinity matrix, and solving graph matching using RRWM and Hungarian algorithms. ```python import jittor as jt # jittor backend import pygmtools as pygm pygm.set_backend('jittor') dt.set_seed(1) # fix random seed dt.flags.use_cuda = jt.has_cuda # detect cuda num_nodes = 5 X_gt = jt.zeros((num_nodes, num_nodes)) X_gt[jt.arange(0, num_nodes, dtype=jt.int64), jt.randperm(num_nodes)] = 1 A1 = jt.rand(num_nodes, num_nodes) A1 = (A1 + A1.t() > 1.) * (A1 + A1.t()) / 2 A1[jt.arange(A1.shape[0]), jt.arange(A1.shape[0])] = 0 A2 = jt.matmul(jt.matmul(X_gt.t(), A1), X_gt) n1 = jt.Var([num_nodes]) n2 = jt.Var([num_nodes]) conn1, edge1 = pygm.utils.dense_to_sparse(A1) conn2, edge2 = pygm.utils.dense_to_sparse(A2) import functools gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) X = pygm.rrwm(K, n1, n2, beta=100) X = pygm.hungarian(X) X # X is the permutation matrix # jt.Var([[0. 1. 0. 0. 0.] # [0. 0. 0. 1. 0.] # [0. 0. 0. 0. 1.] # [1. 0. 0. 0. 0.] # [0. 0. 1. 0. 0.]], dtype=float32) (X * X_gt).sum() / X_gt.sum() # jt.Var([1.], dtype=float32) ``` -------------------------------- ### Setup and Helper Functions for RDKit Graph Matching Source: https://pygmtools.readthedocs.io/en/latest/auto_examples/8.rdkit_graph_matching/plot_rdkit_graph_matching_pytorch.html Imports necessary libraries and defines helper functions for rendering molecules and displaying matched pairs. Ensure RDKit and PyGML are installed. ```python # Author: Runzhong Wang and Codex # License: Mulan PSL v2 License from io import BytesIO import matplotlib.pyplot as plt import numpy as np import pygmtools as pygm from PIL import Image from rdkit import Chem from rdkit.Chem import rdDepictor from rdkit.Chem.Draw import rdMolDraw2D pygm.set_backend('pytorch') def render_molecule(mol, width=420, height=280): drawer = rdMolDraw2D.MolDraw2DCairo(width, height) rdMolDraw2D.PrepareAndDrawMolecule(drawer, mol) atom_coords = np.array([ [drawer.GetDrawCoords(i).x, drawer.GetDrawCoords(i).y] for i in range(mol.GetNumAtoms()) ]) drawer.FinishDrawing() image = np.array(Image.open(BytesIO(drawer.GetDrawingText()))) return image, atom_coords def show_pair(ax, img1, coords1, img2, coords2, lines=None): height = max(img1.shape[0], img2.shape[0]) width1 = img1.shape[1] width2 = img2.shape[1] gap = 80 offset2 = width1 + gap ax.imshow(img1, extent=(0, width1, height, 0)) ax.imshow(img2, extent=(offset2, offset2 + width2, height, 0)) if lines is not None: for idx1, idx2 in lines: ax.plot( [coords1[idx1, 0], coords2[idx2, 0] + offset2], [coords1[idx1, 1], coords2[idx2, 1]], '--', color='0.35', lw=1.0, alpha=0.75 ) ax.set_xlim(0, offset2 + width2) ax.set_ylim(height, 0) ax.axis('off') ``` -------------------------------- ### PyTorch Example for CIE Solver Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.neural_solvers.cie.html Illustrates the usage of the CIE solver with PyTorch tensors. This example covers graph generation, matching with pretrained models, and evaluating performance. It also demonstrates reusing a network object and loading alternative pretrained weights, as well as integrating the solver into a PyTorch training loop. ```python >>> import torch >>> import pygmtools as pygm >>> pygm.set_backend('pytorch') >>> _ = torch.manual_seed(1) # Generate a batch of isomorphic graphs >>> batch_size = 10 >>> X_gt = torch.zeros(batch_size, 4, 4) >>> X_gt[:, torch.arange(0, 4, dtype=torch.int64), torch.randperm(4)] = 1 >>> A1 = 1. * (torch.rand(batch_size, 4, 4) > 0.5) >>> torch.diagonal(A1, dim1=1, dim2=2)[:] = 0 # discard self-loop edges >>> e_feat1 = (torch.rand(batch_size, 4, 4) * A1).unsqueeze(-1) # shape: (10, 4, 4, 1) >>> A2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), A1), X_gt) >>> e_feat2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), e_feat1.squeeze(-1)), X_gt).unsqueeze(-1) >>> feat1 = torch.rand(batch_size, 4, 1024) - 0.5 >>> feat2 = torch.bmm(X_gt.transpose(1, 2), feat1) >>> n1 = n2 = torch.tensor([4] * batch_size) # Match by CIE (load pretrained model) >>> X, net = pygm.cie(feat1, feat2, A1, A2, e_feat1, e_feat2, n1, n2, return_network=True) Downloading to ~/.cache/pygmtools/cie_voc_pytorch.pt... >>> (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy tensor(1.) # Pass the net object to avoid rebuilding the model agian >>> X = pygm.cie(feat1, feat2, A1, A2, e_feat1, e_feat2, n1, n2, network=net) # You may also load other pretrained weights >>> X, net = pygm.cie(feat1, feat2, A1, A2, e_feat1, e_feat2, n1, n2, return_network=True, pretrain='willow') Downloading to ~/.cache/pygmtools/cie_willow_pytorch.pt... # You may configure your own model and integrate the model into a deep learning pipeline. For example: >>> net = pygm.utils.get_network(pygm.cie, in_node_channel=1024, in_edge_channel=1, hidden_channel=2048, out_channel=512, num_layers=3, pretrain=False) >>> optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # feat1/feat2/e_feat1/e_feat2 may be outputs by other neural networks >>> X = pygm.cie(feat1, feat2, A1, A2, e_feat1, e_feat2, n1, n2, network=net) >>> loss = pygm.utils.permutation_loss(X, X_gt) >>> loss.backward() >>> optimizer.step() ``` -------------------------------- ### Enable PyTorch Backend Source: https://pygmtools.readthedocs.io/en/latest/_sources/guide/numerical_backends.rst.txt Import necessary libraries and set the PyTorch backend for pygmtools. Ensure PyTorch is installed. ```python >>> import pygmtools as pygm >>> import torch >>> pygm.set_backend('pytorch') ``` -------------------------------- ### PyTorch Example for Neural Graph Matching Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/neural_solvers.html Demonstrates solving graph matching problems using PyTorch backend. Covers graph generation, affinity matrix construction, NGM solving, and accuracy calculation. Includes examples for using pre-trained models and integrating with deep learning pipelines. ```python import torch import pygmtools as pygm pygm.set_backend('pytorch') _ = torch.manual_seed(1) # Generate a batch of isomorphic graphs batch_size = 10 X_gt = torch.zeros(batch_size, 4, 4) X_gt[:, torch.arange(0, 4, dtype=torch.int64), torch.randperm(4)] = 1 A1 = torch.rand(batch_size, 4, 4) A2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), A1), X_gt) n1 = n2 = torch.tensor([4] * batch_size) # Build affinity matrix conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) import functools gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by NGM X, net = pygm.ngm(K, n1, n2, return_network=True) Downloading to ~/.cache/pygmtools/ngm_voc_pytorch.pt... (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy tensor(1.) # Pass the net object to avoid rebuilding the model agian X = pygm.ngm(K, n1, n2, network=net) # You may also load other pretrained weights X, net = pygm.ngm(K, n1, n2, return_network=True, pretrain='willow') Downloading to ~/.cache/pygmtools/ngm_willow_pytorch.pt... # You may configure your own model and integrate the model into a deep learning pipeline. For example: net = pygm.utils.get_network(pygm.ngm, gnn_channels=(32, 64, 128, 64, 32), sk_emb=8, pretrain=False) optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # K may be outputs by other neural networks (constructed K from node/edge features by pygm.utils.build_aff_mat) X = pygm.ngm(K, n1, n2, network=net) loss = pygm.utils.permutation_loss(X, X_gt) loss.backward() optimizer.step() ``` -------------------------------- ### Install Pygmtools using pip Source: https://pygmtools.readthedocs.io/en/latest/guide/get_started.html Installs the stable release of Pygmtools from PyPI. Use the second command to get the latest version from GitHub. ```bash $ pip install pygmtools ``` ```bash $ pip install -U https://github.com/Thinklab-SJTU/pygmtools/archive/master.zip # with --user for user install (no root) ``` -------------------------------- ### Set up Paddle Backend and Seed Source: https://pygmtools.readthedocs.io/en/latest/_downloads/cbae2ceefcdedd7a0898a56e8ca85e1f/plot_isomorphic_graphs_paddle.ipynb Initializes the pygmtools backend to Paddle and sets a random seed for reproducibility. Ensure Paddle is installed and configured. ```python import paddle # paddle backend import pygmtools as pygm import matplotlib.pyplot as plt # for plotting from matplotlib.patches import ConnectionPatch # for plotting matching result import networkx as nx # for plotting graphs import warnings warnings.filterwarnings("ignore") pygm.set_backend('paddle') # set default backend for pygmtools paddle.device.set_device('cpu') _ = paddle.seed(1) # fix random seed ``` -------------------------------- ### MindSpore: Isomorphic Graph Matching Example Source: https://pygmtools.readthedocs.io/en/latest/_sources/guide/numerical_backends.rst.txt Example demonstrating isomorphic graph matching with the MindSpore backend. It includes setup, graph generation, affinity matrix construction, and solving using RRWM. ```python >>> import mindspore as ms # mindspore backend >>> import pygmtools as pygm >>> pygm.set_backend('mindspore') >>> _ = ms.set_seed(1) # fix random seed ``` ```python >>> num_nodes = 5 >>> X_gt = ms.numpy.zeros((num_nodes, num_nodes)) >>> X_gt[ms.numpy.arange(0, num_nodes, dtype=ms.int32), ms.ops.Randperm(num_nodes)(ms.Tensor([num_nodes], dtype=ms.int32))] = 1 >>> A1 = ms.numpy.rand((num_nodes, num_nodes)) >>> A1[ms.numpy.arange(A1.shape[0]), ms.numpy.arange(A1.shape[1])] = 0 # mindspore.diagonal(A1)[:] = 0 >>> A2 = ms.ops.matmul(ms.ops.matmul(ms.ops.transpose(X_gt, (1, 0)), A1), X_gt) >>> n1 = n2 = ms.Tensor([num_nodes]) ``` ```python >>> conn1, edge1 = pygm.utils.dense_to_sparse(A1) >>> conn2, edge2 = pygm.utils.dense_to_sparse(A2) >>> import functools >>> gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=.1) # set affinity function >>> K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) ``` -------------------------------- ### PyTorch Example: Custom Model Configuration and Training Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.neural_solvers.genn_astar.html Demonstrates how to configure a custom GENN-A* model with specific parameters, integrate it into a deep learning pipeline, and perform a training step including loss calculation, backpropagation, and optimizer step. ```python # You may configure your own model and integrate the model into a deep learning pipeline. For example: net = pygm.utils.get_network(pygm.genn_astar, channel = 1000, filters_1 = 1024, filters_2 = 256, filters_3 = 128, pretrain=False) optimizer = torch.optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # feat1/feat2 may be outputs by other neural networks X = pygm.genn_astar(feat1, feat2, A1, A2, n1, n2, network=net) loss = pygm.utils.permutation_loss(X, X_gt) loss.backward() optimizer.step() ``` -------------------------------- ### Check for PEP8 Warnings Source: https://pygmtools.readthedocs.io/en/latest/guide/contributing.html Install pep8 and use it to check your Python code against the PEP 8 style guide. This ensures code consistency. ```bash $ pip install pep8 $ pep8 path/to/module.py ``` -------------------------------- ### MindSpore Backend Example for pygmtools Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/linear_solvers.html Initializes pygmtools to use the MindSpore backend and sets a random seed for reproducibility. This is a setup step before using pygmtools functions with MindSpore. ```python >>> import mindspore >>> import pygmtools as pygm >>> pygm.set_backend('mindspore') >>> np.random.seed(0) ``` -------------------------------- ### PyTorch Example: Graph Matching with GENN-A* Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/neural_solvers.html Demonstrates how to generate a batch of isomorphic graphs and use the genn_astar function to find the matching matrix. It shows how to set the backend, generate graph features and adjacency matrices, and evaluate the matching accuracy. ```python import torch import pygmtools as pygm pygm.set_backend('pytorch') _ = torch.manual_seed(1) # Generate a batch of isomorphic graphs batch_size = 10 nodes_num = 4 channel = 36 X_gt = torch.zeros(batch_size, nodes_num, nodes_num) X_gt[:, torch.arange(0, nodes_num, dtype=torch.int64), torch.randperm(nodes_num)] = 1 A1 = 1. * (torch.rand(batch_size, nodes_num, nodes_num) > 0.5) torch.diagonal(A1, dim1=1, dim2=2)[:] = 0 # discard self-loop edges A2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), A1), X_gt) feat1 = torch.rand(batch_size, nodes_num, channel) - 0.5 feat2 = torch.bmm(X_gt.transpose(1, 2), feat1) n1 = n2 = torch.tensor([nodes_num] * batch_size) # Match by GENN-A* (load pretrained model) X, net = pygm.genn_astar(feat1, feat2, A1, A2, n1, n2, return_network=True) Downloading to ~/.cache/pygmtools/best_genn_AIDS700nef_gcn_astar.pt... (X * X_gt).sum() / X_gt.sum()# accuracy ``` -------------------------------- ### astar Source: https://pygmtools.readthedocs.io/en/latest/_sources/api/_autosummary/pygmtools.classic_solvers.astar.rst.txt The A* algorithm finds the shortest path from a start node to a goal node in a graph. It uses a heuristic function to guide its search, making it more efficient than Dijkstra's algorithm in many cases. ```APIDOC ## astar ### Description Finds the shortest path from a start node to a goal node using the A* algorithm. ### Signature `astar(graph, start, goal, heuristic)` ### Parameters * **graph** (Graph) - The graph in which to find the path. * **start** (Node) - The starting node for the path. * **goal** (Node) - The goal node for the path. * **heuristic** (HeuristicFunction) - A function that estimates the cost from a node to the goal. ``` -------------------------------- ### Paddle NGM Example Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/neural_solvers.html Demonstrates solving graph matching with NGM using the Paddle backend. Includes generating graphs, building affinity matrices, solving, and evaluating accuracy. Shows how to reuse the network object and load pretrained weights. ```python import paddle import pygmtools as pygm pygm.set_backend('paddle') _ = paddle.seed(1) # Generate a batch of isomorphic graphs batch_size = 10 X_gt = paddle.zeros((batch_size, 4, 4)) X_gt[:, paddle.arange(0, 4, dtype=paddle.int64), paddle.randperm(4)] = 1 A1 = paddle.rand((batch_size, 4, 4)) A2 = paddle.bmm(paddle.bmm(X_gt.transpose((0, 2, 1)), A1), X_gt) n1 = n2 = paddle.to_tensor([4] * batch_size) # Build affinity matrix conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) import functools gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by NGM X, net = pygm.ngm(K, n1, n2, return_network=True) Downloading to ~/.cache/pygmtools/ngm_voc_paddle.pdparams... (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True, [1.]) # Pass the net object to avoid rebuilding the model agian X = pygm.ngm(K, n1, n2, network=net) # You may also load other pretrained weights X, net = pygm.ngm(K, n1, n2, return_network=True, pretrain='willow') Downloading to ~/.cache/pygmtools/ngm_willow_paddle.pdparams... # You may configure your own model and integrate the model into a deep learning pipeline. For example: net = pygm.utils.get_network(pygm.ngm, gnn_channels=(32, 64, 128, 64, 32), sk_emb=8, pretrain=False) optimizer = paddle.optimizer.SGD(parameters=net.parameters(), learning_rate=0.001) # K may be outputs by other neural networks (constructed K from node/edge features by pygm.utils.build_aff_mat) X = pygm.ngm(K, n1, n2, network=net) loss = pygm.utils.permutation_loss(X, X_gt) loss.backward() optimizer.step() ``` -------------------------------- ### PyTorch Example: GENN-A* with Different Pretrained Model (LINUX) Source: https://pygmtools.readthedocs.io/en/latest/api/_autosummary/pygmtools.neural_solvers.genn_astar.html Demonstrates matching graphs using the GENN-A* solver with a different pretrained model ('LINUX'), suitable for a specific node feature dimension (channel=8). ```python # You may also load other pretrained weights # However, it should be noted that each pretrained set supports different node feature dimensions # AIDS700nef(Default): channel = 36 # LINUX: channel = 8 # Generate a batch of isomorphic graphs batch_size = 10 nodes_num = 4 channel = 8 X_gt = torch.zeros(batch_size, nodes_num, nodes_num) X_gt[:, torch.arange(0, nodes_num, dtype=torch.int64), torch.randperm(nodes_num)] = 1 A1 = 1. * (torch.rand(batch_size, nodes_num, nodes_num) > 0.5) torch.diagonal(A1, dim1=1, dim2=2)[:] = 0 # discard self-loop edges A2 = torch.bmm(torch.bmm(X_gt.transpose(1, 2), A1), X_gt) feat1 = torch.rand(batch_size, nodes_num, channel) - 0.5 feat2 = torch.bmm(X_gt.transpose(1, 2), feat1) n1 = n2 = torch.tensor([nodes_num] * batch_size) X, net = pygm.genn_astar(feat1, feat2, A1, A2, n1, n2, pretrain='LINUX', return_network=True) Downloading to ~/.cache/pygmtools/best_genn_LINUX_gcn_astar.pt... (X * X_gt).sum() / X_gt.sum()# accuracy tensor(1.) ``` -------------------------------- ### TensorFlow RRWM and Hungarian Solver Example Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/classic_solvers.html Demonstrates solving graph matching with RRWM and evaluating accuracy using the Hungarian algorithm in TensorFlow. Covers backend setup, graph generation, affinity matrix construction, and gradient calculation. ```python >>> import tensorflow as tf >>> import pygmtools as pygm >>> pygm.set_backend('tensorflow') >>> _ = tf.random.set_seed(1) # Generate a batch of isomorphic graphs >>> batch_size = 10 >>> X_gt = tf.Variable(tf.zeros([batch_size, 4, 4])) >>> indices = tf.stack([tf.range(4),tf.random.shuffle(tf.range(4))], axis=1) >>> updates = tf.ones([4]) >>> for i in range(batch_size): ... _ = X_gt[i].assign(tf.tensor_scatter_nd_update(X_gt[i], indices, updates)) >>> A1 = tf.random.uniform([batch_size, 4, 4]) >>> A2 = tf.matmul(tf.matmul(tf.transpose(X_gt, perm=[0, 2, 1]), A1), X_gt) >>> n1 = n2 = tf.constant([4] * batch_size) # Build affinity matrix >>> conn1, edge1, ne1 = pygm.utils.dense_to_sparse(A1) >>> conn2, edge2, ne2 = pygm.utils.dense_to_sparse(A2) >>> import functools >>> gaussian_aff = functools.partial(pygm.utils.gaussian_aff_fn, sigma=1.) # set affinity function >>> K = pygm.utils.build_aff_mat(None, edge1, conn1, None, edge2, conn2, n1, None, n2, None, edge_aff_fn=gaussian_aff) # Solve by RRWM. Note that X is normalized with a sum of 1 >>> X = pygm.rrwm(K, n1, n2, beta=100) >>> tf.reduce_sum(X, axis=[1, 2]) # Accuracy >>> tf.reduce_sum((pygm.hungarian(X) * X_gt)) / tf.reduce_sum(X_gt) ``` -------------------------------- ### Setup PyTorch Backend and Molecule Rendering Utilities Source: https://pygmtools.readthedocs.io/en/latest/_downloads/21bf7efd3c31a6c046ee1ce1cee8cd7a/plot_rdkit_graph_matching_pytorch.ipynb Sets the PyGML backend to PyTorch and defines utility functions for rendering RDKit molecules and displaying matched pairs. Ensure RDKit, Matplotlib, NumPy, PIL, and PyGML are installed. ```python # Author: Runzhong Wang and Codex # License: Mulan PSL v2 License from io import BytesIO import matplotlib.pyplot as plt import numpy as np import pygmtools as pygm from PIL import Image from rdkit import Chem from rdkit.Chem import rdDepictor from rdkit.Chem.Draw import rdMolDraw2D pygm.set_backend('pytorch') def render_molecule(mol, width=420, height=280): drawer = rdMolDraw2D.MolDraw2DCairo(width, height) rdMolDraw2D.PrepareAndDrawMolecule(drawer, mol) atom_coords = np.array([ [drawer.GetDrawCoords(i).x, drawer.GetDrawCoords(i).y] for i in range(mol.GetNumAtoms()) ]) drawer.FinishDrawing() image = np.array(Image.open(BytesIO(drawer.GetDrawingText()))) return image, atom_coords def show_pair(ax, img1, coords1, img2, coords2, lines=None): height = max(img1.shape[0], img2.shape[0]) width1 = img1.shape[1] width2 = img2.shape[1] gap = 80 offset2 = width1 + gap ax.imshow(img1, extent=(0, width1, height, 0)) ax.imshow(img2, extent=(offset2, offset2 + width2, height, 0)) if lines is not None: for idx1, idx2 in lines: ax.plot( [coords1[idx1, 0], coords2[idx2, 0] + offset2], [coords1[idx1, 1], coords2[idx2, 1]], '--', color='0.35', lw=1.0, alpha=0.75 ) ax.set_xlim(0, offset2 + width2) ax.set_ylim(height, 0) ax.axis('off') ``` -------------------------------- ### Initialize Paddle Backend and Graph Data Source: https://pygmtools.readthedocs.io/en/latest/guide/numerical_backends.html Import Paddle, set the backend, fix the random seed, and set the device to CPU. Generates two isomorphic graphs by creating adjacency matrices and applying a permutation. ```python >>> import paddle # paddle backend >>> import pygmtools as pygm >>> pygm.set_backend('paddle') >>> paddle.seed(1) # fix random seed >>> paddle.device.set_device('cpu') # set cpu ``` ```python >>> num_nodes = 5 >>> X_gt = paddle.zeros((num_nodes, num_nodes)) >>> X_gt[paddle.arange(0, num_nodes, dtype=paddle.int64), paddle.randperm(num_nodes)] = 1 >>> A1 = paddle.rand((num_nodes, num_nodes)) >>> A1 = (A1 + A1.t() > 1.) / 2 * (A1 + A1.t()) >>> A1[paddle.arange(A1.shape[0]), paddle.arange(A1.shape[1])] = 0 # paddle.diagonal(A1)[:] = 0 >>> A2 = paddle.mm(paddle.mm(X_gt.t(), A1), X_gt) >>> n1 = paddle.to_tensor([num_nodes]) >>> n2 = paddle.to_tensor([num_nodes]) ``` -------------------------------- ### Setting the Numerical Backend Source: https://pygmtools.readthedocs.io/en/latest/_sources/api/pygmtools.rst.txt By default, API functions and modules in pygmtools run on the NumPy backend. You can change the default backend by calling `pygm.set_backend('new_backend')`. Ensure that the corresponding package (e.g., PyTorch) is installed if you are using other backends. Refer to the numerical backend guide for more details. ```APIDOC ```python import pygmtools as pygm # Set the backend to PyTorch (example) pygm.set_backend('torch') ``` ``` -------------------------------- ### Paddle Example for PCA-GM Source: https://pygmtools.readthedocs.io/en/latest/_modules/pygmtools/neural_solvers.html Demonstrates how to use the PCA-GM solver with the Paddle backend. Includes graph generation, feature extraction, model loading (pretrained and custom), and integration into a training loop. ```python import paddle import pygmtools as pygm pygm.set_backend('paddle') _ = paddle.seed(4) # Generate a batch of isomorphic graphs batch_size = 10 X_gt = paddle.zeros((batch_size, 4, 4)) X_gt[:, paddle.arange(0, 4, dtype=paddle.int64), paddle.randperm(4)] = 1 A1 = 1. * (paddle.rand((batch_size, 4, 4)) > 0.5) paddle.diagonal(A1, axis1=1, axis2=2)[:] = 0 # discard self-loop edges A2 = paddle.bmm(paddle.bmm(X_gt.transpose((0, 2, 1)), A1), X_gt) feat1 = paddle.rand((batch_size, 4, 1024)) - 0.5 feat2 = paddle.bmm(X_gt.transpose((0, 2, 1)), feat1) n1 = n2 = paddle.to_tensor([4] * batch_size) # Match by PCA-GM (load pretrained model) X, net = pygm.pca_gm(feat1, feat2, A1, A2, n1, n2, return_network=True) # Downloading to ~/.cache/pygmtools/pca_gm_voc_paddle.pdparams... (pygm.hungarian(X) * X_gt).sum() / X_gt.sum() # accuracy # Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True, # [1.]) # Pass the net object to avoid rebuilding the model agian X = pygm.pca_gm(feat1, feat2, A1, A2, n1, n2, network=net) # You may also load other pretrained weights X, net = pygm.pca_gm(feat1, feat2, A1, A2, n1, n2, return_network=True, pretrain='willow') # Downloading to ~/.cache/pygmtools/pca_gm_willow_paddle.pdparams... # You may configure your own model and integrate the model into a deep learning pipeline. For example: net = pygm.utils.get_network(pygm.pca_gm, in_channel=1024, hidden_channel=2048, out_channel=512, num_layers=3, pretrain=False) optimizer = paddle.optimizer.SGD(parameters=net.parameters(), learning_rate=0.001) # feat1/feat2 may be outputs by other neural networks X = pygm.pca_gm(feat1, feat2, A1, A2, n1, n2, network=net) loss = pygm.utils.permutation_loss(X, X_gt) loss.backward() optimizer.step() ``` -------------------------------- ### Install Pygmtools using pip Source: https://pygmtools.readthedocs.io/en/latest/_sources/guide/get_started.rst.txt Install the stable release of pygmtools from PyPI or the latest version from GitHub. Pip will automatically handle required package installations. ```bash pip install pygmtools ``` ```bash pip install -U https://github.com/Thinklab-SJTU/pygmtools/archive/master.zip # with --user for user install (no root) ```