A framework for working with graphs alongside PyTorch
Project description
Lign
A graph framework that can be used to implement graph convolutional networks (GCNs), geometry machine learning, continual lifelong learning on graphs and other graph-based machine learning methods alongside PyTorch
View Docs · View Examples · Report Bugs · Request Feature
Table of Contents
About The Project
Lign (Lifelong learning Induced by Graph Neural networks) is a framework that can be used for a wide range of graph-related problems including but not limited to graph convolutional networks (GCNs), geometry machine learning, continual lifelong learning on graphs and other graph-related machine learning methods with a tight integration to PyTorch. It was build as a component of my master thesis for a proposed lifelong learning techinique (also named Lign) that works on both graph and vector data.
Ligns currently supports a wide range of functionalities such as clustering techiniques, GCN PyTorch module, graph creation and processing, data set to graph convention, rehersal methods/retraining for GCNS and coventional neural networks, and more. Future planned additions include STL file to graph conversion, graph to STL model along with others features.
Getting Started
These are instructions for getting started with development. If only interested in the package, please install Lign via pip install lign
, conda install lign -c josuecom -c pytorch
or by downloading the package from github and saving it in the site-packages/
directory of your python interpreter.
For more details, please read the developer documentation
Installation
-
Clone the repo
git clone https://github.com/JosueCom/Lign.git
-
Switch directory
cd Lign
-
Install prerequisites
It is recommended to install PyTorch via the official site first for optimal performance
pip install -r docs/dev/requirements.txt
Or
conda env create -f docs/dev/environment.yml -n lign conda activate lign
-
Install package
pip install . --upgrade
Usage
It is recommended to run the following instructions in a python console to view all produced output
-
Create a new graph, assign some values and view properties
import lign as lg import torch as th n = 5 g = lg.Graph() g.add(n) g['x'] = th.rand(n, 3) ## Or, g.set_data('x', th.rand(n, 3)) print(g) print(g['x']) ## Or, g.get_data('x') print(g[0]) ## Or, g.get_nodes(0) print(g[[1, 2]]) ## Or, g.get_nodes([1, 2]) print(g[3:]) ## Or, g.get_nodes(slice(3, None)) print(g[(4,)]) ## Or, g.get_edges(4)
-
Process data with a conventional neural network
import lign as lg import torch as th from torch import nn n = 5 g = lg.Graph().add(n, self_loop=False, inplace=True) ## No self loop edges added since no relational data is present g['x'] = th.rand(n, 3) print(g['x']) # Data that is not relational maybe be process without the need of ligh graphs x = = th.rand(n, 3) x = linear(x) print(x) # However, you can use if you desire to use graph strctures linear = nn.Linear(3, 2) g['x'] = linear(g['x']) ## Or, g.apply(linear, data = 'x') print(g['x'])
-
Process relational data with a GCN
import lign as lg import torch as th from torch import nn from lign.nn import GCN from lign.utils.functions import sum_tensors n = 5 g = lg.Graph().add(n, inplace=True) g['x'] = th.rand(n, 3) print(g['x']) # 1^{st} Approach: Basic gcn with no message passing # ## It can also be processed as if it is not a graph since edge information is not used gcn = GCN(nn.Linear(3, 2)) g['x'] = gcn(g, g['x']) print(g['x']) # 2^{nd} Approach: Basic gcn with message passing via neighbors data summation g[(2, 3, 4)] = {2, 3, 4} ## Add edges to nodes 2, 3, 4; nodes can be removed via g.remove_edges() gcn = GCN(nn.Linear(2, 3), aggregation = sum_tensors) g['x'] = gcn(g, g['x']) print(g['x']) # 3^{rd} Approach: Proposed GCN with discovery and inclusion layers gcn = GCN(nn.Linear(3, 2), aggregation = sum_tensors, inclusion = nn.Linear(2, 3)) g['x'] = gcn(g, g['x']) print(g['x'])
-
Apply function
import lign as lg import torch as th from torch import nn from lign.nn import GCN n = 5 g = lg.Graph().add(n, inplace=True) g['x'] = th.rand(n, 3) # Use apply if involving individual nodes ## Adds 3 to all node's 'x' data in the data set; doesn't require neighbors g.apply(lambda x: x + 3, data='x') print(g['x']) # Use push or pull if only involving multiple nodes. Nodes will push/pull data via edges ## Sums neighbors 'x' value together; require neighbors def sum_tensors(neighs): return th.stack(neighs).sum(dim = 0) g[(2, 3, 4)] = {2, 3, 4} g.push(sum_tensors, data='x') print(g['x'])
-
Use clustering techniques for PyTorch
from lign.utils.clustering import NN, KNN, KMeans import torch as th n = 20 x = th.rand(n, 3) labels = (x[:, 0] > 0.5)*1 predict = th.rand(4, 3) print(predict) cluster = NN(x, labels) print(cluster(predict)) cluster = KNN(x, labels, k=3) print(cluster(predict)) cluster = KMeans(x, k=2) print(cluster(predict))
-
Create sub graphs
import lign as lg import torch as th n = 5 g = lg.Graph().add(n, inplace=True) g['x'] = th.rand(n, 3) g[tuple(range(n))] = set(range(3, n)) ## Add edge from each node to 3 and 4 print(g) # Make sub graph with all data and edges from parent; edges are updated to reflect new indexes sub = g.sub_graph([2, 3, 4], get_data = True, get_edges = True) print(sub) # Make sub graph with only edges from parent; edges are updated to reflect new indexes sub = g.sub_graph(2, get_edges = True) sub.add(2) print(sub) # Make sub graph with only data from parent ## Add nodes not known to the parent graph sub = g.sub_graph([3, 4], get_data = True) sub.add([lg.node({'x': th.rand(3)}) for i in range(2)], self_loop = False) print(sub) sub[(2, 3)] = sub.get_parent_edges([0, 2]) print(sub)
-
Save and load created graphs
import lign as lg import torch as th n = 5 g = lg.Graph().add(n, inplace=True) g['x'] = th.rand(n, 3) # Save to file g.save("data/graph.lign") # Load from file f = lg.Graph("data/graph.lign") # Check all data are the same print((f['x'] == g['x']).all())
-
Convert common data set to lign graphs
import lign.utils as utl g0, g0_train, g0_validate = utl.load.mnist_to_lign("datasets/CIFAR100") g1, g1_train, g1_validate = utl.load.cifar_to_lign("datasets/CIFAR100") g2, g2_train, g2_validate = utl.load.cora_to_lign("datasets/CIFAR100")
Please refer to the documentation for other examples
Future
See the open issues for a list of proposed features (and known issues).
Citation
Refer to CITATION.bib for BibTex citation
Contributing
Read CONTRIBUTING.md for details on how to add to this repository.
tl;dr Fork, create a new branch, commits features and make a pull request with documented changes
License
Distributed under the Mozilla Public License Version 2.0. See LICENSE for more information.
Contact
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file lign-0.1.1.tar.gz
.
File metadata
- Download URL: lign-0.1.1.tar.gz
- Upload date:
- Size: 19.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/3.10.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.7.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2db9c61fe8bb479bddca42227ab70d29dc02de254dbf5b2907e5496983d7aa57 |
|
MD5 | 241b6a5446f031b945e9c0266d3d4a2e |
|
BLAKE2b-256 | a0fbdd6695ac3e1eaeb90117b238d842089c32a54ba7d0c37e1f01a1ccc056cd |
File details
Details for the file lign-0.1.1-py3-none-any.whl
.
File metadata
- Download URL: lign-0.1.1-py3-none-any.whl
- Upload date:
- Size: 24.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/3.10.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.7.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c374b9bacbbcbed3e9e60a74d5c9abbfbf316e2b3f366f9278d430f679706284 |
|
MD5 | b31c4e9663630ebdcc1564bde2c03ed7 |
|
BLAKE2b-256 | 1eab4ec255e82cb62dfe8611301833ef28d5862e28f041e09b515731a7b4102f |