nirviz 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nirviz/__init__.py +12 -0
- nirviz/__main__.py +31 -0
- nirviz/nirviz.py +72 -0
- nirviz-0.1.0.dist-info/METADATA +77 -0
- nirviz-0.1.0.dist-info/RECORD +8 -0
- nirviz-0.1.0.dist-info/WHEEL +5 -0
- nirviz-0.1.0.dist-info/licenses/LICENSE +27 -0
- nirviz-0.1.0.dist-info/top_level.txt +1 -0
nirviz/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from importlib.metadata import version as metadata_version, PackageNotFoundError
|
|
2
|
+
|
|
3
|
+
# Exposing imports
|
|
4
|
+
from .nirviz import visualize
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
# For pyproject.toml dynamic versioning
|
|
8
|
+
__version__ = version = metadata_version("nirviz")
|
|
9
|
+
del metadata_version
|
|
10
|
+
except PackageNotFoundError:
|
|
11
|
+
print('nirviz: package not found')
|
|
12
|
+
pass
|
nirviz/__main__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import nirviz
|
|
5
|
+
|
|
6
|
+
if __name__ == "__main__":
|
|
7
|
+
parser = argparse.ArgumentParser(description="CLI tool for visualizing NIR graphs.")
|
|
8
|
+
parser.add_argument("file", type=argparse.FileType('r'), help="The NIR graph file to read from.")
|
|
9
|
+
parser.add_argument("output", type=str, default="stdout", nargs='?', help="The output file to write the graph to. Defaults to stdout.")
|
|
10
|
+
parser.add_argument("yaml", type=argparse.FileType('r'), default="./style.yml", nargs='?', help="Style file defined in yaml. Defaults to ./style.yml.")
|
|
11
|
+
args = parser.parse_args()
|
|
12
|
+
|
|
13
|
+
nir_file = args.file.name
|
|
14
|
+
yaml_file = args.yaml.name
|
|
15
|
+
# Load the NIR graph
|
|
16
|
+
if args.output == "stdout":
|
|
17
|
+
graph = nirviz.visualize(nir_file, style_file=yaml_file)
|
|
18
|
+
graph_svg = str(graph)
|
|
19
|
+
sys.stdout.write(graph_svg)
|
|
20
|
+
elif args.output.endswith(".svg"):
|
|
21
|
+
graph = nirviz.visualize(nir_file, style_file=yaml_file)
|
|
22
|
+
graph_svg = str(graph)
|
|
23
|
+
with open(args.output, "w") as f:
|
|
24
|
+
f.write(graph_svg)
|
|
25
|
+
elif args.output.endswith(".png"):
|
|
26
|
+
graph = nirviz.visualize(nir_file, style_file=yaml_file)
|
|
27
|
+
graph_image = graph.to_image()
|
|
28
|
+
graph_image.save(args.output)
|
|
29
|
+
|
|
30
|
+
else:
|
|
31
|
+
raise ValueError("Output file must be either .svg or .png format.")
|
nirviz/nirviz.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
import yaml
|
|
3
|
+
import re
|
|
4
|
+
import graphviz
|
|
5
|
+
import cairosvg
|
|
6
|
+
import nir
|
|
7
|
+
import typing
|
|
8
|
+
import importlib.util
|
|
9
|
+
import pathlib
|
|
10
|
+
import PIL
|
|
11
|
+
import io
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class visualize:
|
|
16
|
+
nir_graph: typing.Union[nir.NIRGraph, str, pathlib.Path]
|
|
17
|
+
style_file: pathlib.Path = field(default_factory=lambda: pathlib.Path("./style.yml"))
|
|
18
|
+
|
|
19
|
+
def __post_init__(self):
|
|
20
|
+
if isinstance(self.nir_graph, (str, pathlib.Path)):
|
|
21
|
+
self.nir_graph = nir.read(self.nir_graph)
|
|
22
|
+
|
|
23
|
+
self.style_dict = self.__load_style_file()
|
|
24
|
+
self.viz_graph = self.__construct_graph()
|
|
25
|
+
|
|
26
|
+
def __load_style_file(self) -> typing.Dict[str, typing.Dict[str, str]]:
|
|
27
|
+
with open(self.style_file, 'r') as f:
|
|
28
|
+
config = yaml.safe_load(f)
|
|
29
|
+
return config
|
|
30
|
+
|
|
31
|
+
def __pick_style(self, name: str) -> typing.Dict[str, str]:
|
|
32
|
+
categories = self.style_dict['node-categories']
|
|
33
|
+
for cat_id in categories:
|
|
34
|
+
cat = categories[cat_id]
|
|
35
|
+
if name in cat['patterns']:
|
|
36
|
+
return cat['style']
|
|
37
|
+
|
|
38
|
+
return self.style_dict['defaults']['node']['style']
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def __construct_graph(self) -> graphviz.Digraph:
|
|
42
|
+
viz_graph = graphviz.Digraph(format="svg",
|
|
43
|
+
graph_attr={'rankdir': 'LR'})
|
|
44
|
+
# Generate nodes
|
|
45
|
+
for node_id in self.nir_graph.nodes:
|
|
46
|
+
name = type(self.nir_graph.nodes[node_id]).__name__
|
|
47
|
+
style = self.__pick_style(name)
|
|
48
|
+
viz_graph.node(node_id, label=name, **style)
|
|
49
|
+
|
|
50
|
+
# Generate edges
|
|
51
|
+
for src_id, tgt_id in self.nir_graph.edges:
|
|
52
|
+
viz_graph.edge(src_id, tgt_id)
|
|
53
|
+
|
|
54
|
+
return viz_graph
|
|
55
|
+
|
|
56
|
+
def show(self) -> None:
|
|
57
|
+
if importlib.util.find_spec("IPython"):
|
|
58
|
+
import IPython
|
|
59
|
+
|
|
60
|
+
svg_output = self.viz_graph.pipe(format="svg")
|
|
61
|
+
image = IPython.display.SVG(svg_output)
|
|
62
|
+
IPython.display.display(image)
|
|
63
|
+
else:
|
|
64
|
+
print("error: cannot display graph: no IPython environment detected.")
|
|
65
|
+
|
|
66
|
+
def to_image(self) -> PIL.Image.Image:
|
|
67
|
+
svg_output = self.viz_graph.pipe(format="svg")
|
|
68
|
+
png_bytes = cairosvg.svg2png(bytestring=svg_output)
|
|
69
|
+
return PIL.Image.open(io.BytesIO(png_bytes))
|
|
70
|
+
|
|
71
|
+
def __repr__(self) -> str:
|
|
72
|
+
return self.viz_graph.pipe(format="svg", encoding="utf-8")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nirviz
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Visualisation tool for the Neuromorphic Intermediate Representation
|
|
5
|
+
Author-email: Jens Egholm Pedersen <jens@jepedersen.dk>, Michail Rontionov <mrontionov@mront.io>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: homepage, https://github.com/open-neuromorphic/nirviz
|
|
8
|
+
Classifier: Development Status :: 1 - Planning
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: nir
|
|
21
|
+
Requires-Dist: graphviz
|
|
22
|
+
Requires-Dist: cairosvg
|
|
23
|
+
Requires-Dist: pyyaml
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Neuromorphic Intermediate Representation Visualisation Tool
|
|
27
|
+
|
|
28
|
+
Turn your NIR definitions into a nice graph, the original publication serving as a template.
|
|
29
|
+
|
|
30
|
+
Customise your node colour preferences in [style.yml](./style.yml), and quickly generate graphs from your neuromorphic networks.
|
|
31
|
+
|
|
32
|
+
This work is in progress.
|
|
33
|
+
|
|
34
|
+
## Running Example (Jupyter Notebook)
|
|
35
|
+
By running the following code (from a notebook),
|
|
36
|
+
```python
|
|
37
|
+
import nir
|
|
38
|
+
import nirviz
|
|
39
|
+
import numpy as np
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
a = np.random.randn(2)
|
|
43
|
+
ir = nir.NIRGraph(
|
|
44
|
+
nodes={
|
|
45
|
+
"input": nir.Input(input_type=np.array([2])),
|
|
46
|
+
"affine1": nir.Affine(weight=np.zeros((2,2)), bias=False),
|
|
47
|
+
"cu1": nir.CubaLIF(tau_mem=a, tau_syn=a, r=a, v_leak=a, v_threshold=a, v_reset=a),
|
|
48
|
+
"affine_rec": nir.Affine(weight=np.zeros((2,2)), bias=False),
|
|
49
|
+
"affine2": nir.Affine(weight=np.zeros((2,2)), bias=False),
|
|
50
|
+
"cu2": nir.CubaLIF(tau_mem=a, tau_syn=a, r=a, v_leak=a, v_threshold=a, v_reset=a),
|
|
51
|
+
"output": nir.Output(output_type=np.array([2]))
|
|
52
|
+
},
|
|
53
|
+
edges=[("input", "affine1"), ("affine1", "cu1"), ("affine_rec", "cu1"), ("cu1", "affine_rec"), ("cu1", "affine2"), ("affine2", "cu2"), ("cu2", "output")])
|
|
54
|
+
|
|
55
|
+
viz = nirviz.visualize(ir)
|
|
56
|
+
viz.show()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
You would get the following visualisation
|
|
60
|
+
|
|
61
|
+
<picture>
|
|
62
|
+
<img alt="nirviz output" src="https://raw.githubusercontent.com/open-neuromorphic/nirviz/main/img/srnn.png">
|
|
63
|
+
</picture>
|
|
64
|
+
|
|
65
|
+
Similar to Figure 3 of the publication.
|
|
66
|
+
|
|
67
|
+
<picture>
|
|
68
|
+
<img alt="Figure 3 of NIR paper for comparison to output" src="https://raw.githubusercontent.com/open-neuromorphic/nirviz/main/img/fig3.png">
|
|
69
|
+
</picture>
|
|
70
|
+
|
|
71
|
+
## Running example (CLI)
|
|
72
|
+
To convert a saved NIR graph (e.g. srnn.nir) to a PNG or SVG, you can use one of the following commands:
|
|
73
|
+
```bash
|
|
74
|
+
python -m nirviz srnn.nir # SVG -> stdout
|
|
75
|
+
python -m nirviz srnn.nir img/srnn.png # PNG -> file
|
|
76
|
+
python -m nirviz srnn.nir img/srnn.svg # SVG -> file
|
|
77
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
nirviz/__init__.py,sha256=RqjX1IhDxsVnfwW6xha5rTZ4gcjbmFjjgVIwdh66qB0,338
|
|
2
|
+
nirviz/__main__.py,sha256=pjNFvsnk6rr1obCBcmUQ82rC3tOnA1pUzMAPlEw76Ck,1315
|
|
3
|
+
nirviz/nirviz.py,sha256=Ux29RrDZjUPen1ycQfxBG_LuN4qqzWfyLkfCN5dNKgM,2340
|
|
4
|
+
nirviz-0.1.0.dist-info/licenses/LICENSE,sha256=fFCmUBqfYPQBzBbI51UGu3yGokvK8pTdwo3pJHXLrp4,1509
|
|
5
|
+
nirviz-0.1.0.dist-info/METADATA,sha256=CP8cAocxvHOodU7jRYncVsihydD8XZRSg-xvltlyESE,2936
|
|
6
|
+
nirviz-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
nirviz-0.1.0.dist-info/top_level.txt,sha256=jVzOdKkNMl2P6SiMBUFIbNQy7qd945yixwXyijuwN4A,7
|
|
8
|
+
nirviz-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2025, open-neuromorphic/nirviz
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nirviz
|