diff --git a/.gitignore b/.gitignore
index 7280af7..c960c0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,84 @@
*.aux
*.log
*.gz
+
+__pycache__
+books
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
\ No newline at end of file
diff --git a/README.md b/README.md
index 36d3bd5..eb8ac66 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,48 @@
# PlotNeuralNet
[](https://doi.org/10.5281/zenodo.2526396)
-Latex code for drawing neural networks for reports and presentation. Have a look into examples to see how they are made. Additionally, lets consolidate any improvements that you make and fix any bugs to help more people with this code.
+Latex code for drawing neural networks for reports and presentation. Have a look into examples to see how they are made. Additionally, lets consolidate any improvements that you make and fix any bugs to help more people with this code.
+
+## TODO
+
+- [X] Python interfaz
+- [ ] Pytorch generate graph arquiture
+- [ ] Add easy legend functionality
+- [ ] Add more layer shapes like TruncatedPyramid, 2DSheet etc
+
+## Usage
+
+ mkdir my_project
+ cd my_project
+ vim my_arch.py
+
+ import sys
+ sys.path.append('../')
+ from core.tikzeng import *
+
+ # defined your arch
+ arch = [
+ to_head( '..' ),
+ to_cor(),
+ to_begin(),
+ to_Conv( 'conv1', 572, 64, offset="(0,0,0)", to="(0,0,0)" ),
+ to_Pool("pool1", offset="(0,0,0)", to="(conv1-east)"),
+ to_SoftMax( "soft1", "SOFT", 10 ,"(3,0,0)", "(pool1-east)" ),
+ to_connection( "pool1", "soft1"),
+ to_end()
+ ]
+
+ def main():
+ namefile = str(sys.argv[0]).split('.')[0]
+ to_generate(arch, namefile + '.tex' )
+
+ if __name__ == '__main__':
+ main()
+
+ bash ../tikzmake.sh my_arch
+
+## Examples
+
Following are some network representations:

diff --git a/core/__init__.py b/core/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/core/blocks.py b/core/blocks.py
new file mode 100644
index 0000000..09789a3
--- /dev/null
+++ b/core/blocks.py
@@ -0,0 +1,45 @@
+
+from .tikzeng import *
+
+#define new block
+def block_2ConvPool( name, botton, top, s_filer=256, n_filer=64, offset="(1,0,0)", size=(32,32,3.5), opacity=0.5 ):
+ return [
+ to_ConvConvRelu(
+ name="ccr_{}".format( name ),
+ s_filer=str(s_filer),
+ n_filer=(n_filer,n_filer),
+ offset=offset,
+ to="({}-east)".format( botton ),
+ width=(size[2],size[2]),
+ height=size[0],
+ depth=size[1],
+ ),
+ to_Pool(
+ name="{}".format( top ),
+ offset="(0,0,0)",
+ to="(ccr_{}-east)".format( name ),
+ width=1,
+ height=size[0] - int(size[0]/4),
+ depth=size[1] - int(size[0]/4),
+ opacity=opacity, ),
+ to_connection(
+ "{}".format( botton ),
+ "ccr_{}".format( name )
+ )
+ ]
+
+
+def block_Unconv( name, botton, top, s_filer=256, n_filer=64, offset="(1,0,0)", size=(32,32,3.5), opacity=0.5 ):
+ return [
+ to_UnPool( name='unpool_{}'.format(name), offset=offset, to="({}-east)".format(botton), width=1, height=size[0], depth=size[1], opacity=opacity ),
+ to_ConvRes( name='ccr_res_{}'.format(name), offset="(0,0,0)", to="(unpool_{}-east)".format(name), s_filer=str(s_filer), n_filer=str(n_filer), width=size[2], height=size[0], depth=size[1], opacity=opacity ),
+ to_Conv( name='ccr_{}'.format(name), offset="(0,0,0)", to="(ccr_res_{}-east)".format(name), s_filer=str(s_filer), n_filer=str(n_filer), width=size[2], height=size[0], depth=size[1] ),
+ to_ConvRes( name='ccr_res_c_{}'.format(name), offset="(0,0,0)", to="(ccr_{}-east)".format(name), s_filer=str(s_filer), n_filer=str(n_filer), width=size[2], height=size[0], depth=size[1], opacity=opacity ),
+ to_Conv( name='{}'.format(top), offset="(0,0,0)", to="(ccr_res_c_{}-east)".format(name), s_filer=str(s_filer), n_filer=str(n_filer), width=size[2], height=size[0], depth=size[1] ),
+ to_connection(
+ "{}".format( botton ),
+ "unpool_{}".format( name )
+ )
+ ]
+
+
diff --git a/core/tikzeng.py b/core/tikzeng.py
new file mode 100644
index 0000000..4f6adb5
--- /dev/null
+++ b/core/tikzeng.py
@@ -0,0 +1,193 @@
+
+import os
+
+def to_head( projectpath ):
+ pathlayers = os.path.join( projectpath, 'layers/' )
+ return r"""
+\documentclass[border=8pt, multi, tikz]{standalone}
+\usepackage{import}
+\subimport{"""+ pathlayers + r"""}{init}
+\usetikzlibrary{positioning}
+"""
+
+def to_cor():
+ return r"""
+\def\ConvColor{rgb:yellow,5;red,2.5;white,5}
+\def\ConvReluColor{rgb:yellow,5;red,5;white,5}
+\def\PoolColor{rgb:red,1;black,0.3}
+\def\UnpoolColor{rgb:blue,2;green,1;black,0.3}
+\def\FcColor{rgb:blue,5;red,2.5;white,5}
+\def\FcReluColor{rgb:blue,5;red,5;white,4}
+\def\SoftmaxColor{rgb:magenta,5;black,7}
+"""
+
+def to_begin():
+ return r"""
+\newcommand{\copymidarrow}{\tikz \draw[-Stealth,line width=0.8mm,draw={rgb:blue,4;red,1;green,1;black,3}] (-0.3,0) -- ++(0.3,0);}
+
+\begin{document}
+\begin{tikzpicture}
+\tikzstyle{connection}=[ultra thick,every node/.style={sloped,allow upside down},draw=\edgecolor,opacity=0.7]
+\tikzstyle{copyconnection}=[ultra thick,every node/.style={sloped,allow upside down},draw={rgb:blue,4;red,1;green,1;black,3},opacity=0.7]
+"""
+
+
+
+# layers definition
+
+# Conv
+def to_Conv( name, s_filer=256, n_filer=64, offset="(0,0,0)", to="(0,0,0)", width=1, height=40, depth=40, caption=" " ):
+ return r"""
+\pic[shift={"""+ offset +"""}] at """+ to +"""
+ {Box={
+ name=""" + name +""",
+ caption="""+ caption +r""",
+ xlabel={{"""+ str(n_filer) +""", }},
+ zlabel="""+ str(s_filer) +""",
+ fill=\ConvColor,
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+# Conv,Conv,relu
+# Bottleneck
+def to_ConvConvRelu( name, s_filer=256, n_filer=(64,64), offset="(0,0,0)", to="(0,0,0)", width=(2,2), height=40, depth=40, caption=" " ):
+ return r"""
+\pic[shift={ """+ offset +""" }] at """+ to +"""
+ {RightBandedBox={
+ name="""+ name +""",
+ caption="""+ caption +""",
+ xlabel={{ """+ str(n_filer[0]) +""", """+ str(n_filer[1]) +""" }},
+ zlabel="""+ str(s_filer) +""",
+ fill=\ConvColor,
+ bandfill=\ConvReluColor,
+ height="""+ str(height) +""",
+ width={ """+ str(width[0]) +""" , """+ str(width[1]) +""" },
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+
+
+# Pool
+def to_Pool(name, offset="(0,0,0)", to="(0,0,0)", width=1, height=32, depth=32, opacity=0.5, caption=" "):
+ return r"""
+\pic[shift={ """+ offset +""" }] at """+ to +"""
+ {Box={
+ name="""+name+""",
+ caption="""+ caption +r""",
+ fill=\PoolColor,
+ opacity="""+ str(opacity) +""",
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+# unpool4,
+def to_UnPool(name, offset="(0,0,0)", to="(0,0,0)", width=1, height=32, depth=32, opacity=0.5, caption=" "):
+ return r"""
+\pic[shift={ """+ offset +""" }] at """+ to +"""
+ {Box={
+ name="""+ name +r""",
+ caption="""+ caption +r""",
+ fill=\UnpoolColor,
+ opacity="""+ str(opacity) +""",
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+
+
+def to_ConvRes( name, s_filer=256, n_filer=64, offset="(0,0,0)", to="(0,0,0)", width=6, height=40, depth=40, opacity=0.2, caption=" " ):
+ return r"""
+\pic[shift={ """+ offset +""" }] at """+ to +"""
+ {RightBandedBox={
+ name="""+ name + """,
+ caption="""+ caption + """,
+ xlabel={{ """+ str(n_filer) + """, }},
+ zlabel="""+ str(s_filer) +r""",
+ fill={rgb:white,1;black,3},
+ bandfill={rgb:white,1;black,2},
+ opacity="""+ str(opacity) +""",
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+
+# ConvSoftMax
+def to_ConvSoftMax( name, s_filer=40, offset="(0,0,0)", to="(0,0,0)", width=1, height=40, depth=40, caption=" " ):
+ return r"""
+\pic[shift={"""+ offset +"""}] at """+ to +"""
+ {Box={
+ name=""" + name +""",
+ caption="""+ caption +""",
+ zlabel="""+ str(s_filer) +""",
+ fill=\SoftmaxColor,
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+# SoftMax
+def to_SoftMax( name, s_filer=10, offset="(0,0,0)", to="(0,0,0)", width=1.5, height=3, depth=25, opacity=0.8, caption=" " ):
+ return r"""
+\pic[shift={"""+ offset +"""}] at """+ to +"""
+ {Box={
+ name=""" + name +""",
+ caption="""+ caption +""",
+ xlabel={{"","dummy"}},
+ zlabel="""+ str(s_filer) +""",
+ fill=\SoftmaxColor,
+ opacity="""+ str(opacity) +""",
+ height="""+ str(height) +""",
+ width="""+ str(width) +""",
+ depth="""+ str(depth) +"""
+ }
+ };
+"""
+
+
+def to_connection( of, to):
+ return r"""
+\draw [connection] ("""+of+"""-east) -- node {\midarrow} ("""+to+"""-west);
+"""
+
+def to_skip( of, to, pos=1.25):
+ return r"""
+\path ("""+ of +"""-southeast) -- ("""+ of +"""-northeast) coordinate[pos="""+ str(pos) +"""] ("""+ of +"""-top) ;
+\path ("""+ to +"""-south) -- ("""+ to +"""-north) coordinate[pos=1.25] ("""+ to +"""-top) ;
+\draw [copyconnection] ("""+of+"""-northeast)
+-- node {\copymidarrow}("""+of+"""-top)
+-- node {\copymidarrow}("""+to+"""-top)
+-- node {\copymidarrow} ("""+to+"""-north);
+"""
+
+def to_end():
+ return r"""
+\end{tikzpicture}
+\end{document}
+"""
+
+
+def to_generate( arch, pathname="file.tex" ):
+ with open(pathname, "w") as f:
+ for c in arch:
+ print(c)
+ f.write( c )
+
+
+
diff --git a/test/test_simple.py b/test/test_simple.py
new file mode 100644
index 0000000..10ac860
--- /dev/null
+++ b/test/test_simple.py
@@ -0,0 +1,23 @@
+
+import sys
+sys.path.append('../')
+from core.tikzeng import *
+
+# defined your arch
+arch = [
+ to_head( '..' ),
+ to_cor(),
+ to_begin(),
+ to_Conv( 'conv1', 572, 64, offset="(0,0,0)", to="(0,0,0)" ),
+ to_Pool("pool1", offset="(0,0,0)", to="(conv1-east)"),
+ to_SoftMax( "soft1", "SOFT", 10 ,"(3,0,0)", "(pool1-east)" ),
+ to_connection( "pool1", "soft1"),
+ to_end()
+ ]
+
+def main():
+ namefile = str(sys.argv[0]).split('.')[0]
+ to_generate(arch, namefile + '.tex' )
+
+if __name__ == '__main__':
+ main()
diff --git a/test/unet.py b/test/unet.py
new file mode 100644
index 0000000..845cb1e
--- /dev/null
+++ b/test/unet.py
@@ -0,0 +1,54 @@
+
+
+
+import sys
+sys.path.append('../')
+from core.tikzeng import *
+from core.blocks import *
+
+arch = [
+ to_head('..'),
+ to_cor(),
+ to_begin(),
+
+ #input
+ ## code here
+
+ #block-001
+ to_ConvConvRelu( name='ccr_b1', s_filer=500, n_filer=(64,64), offset="(0,0,0)", to="(0,0,0)", width=(2,2), height=40, depth=40 ),
+ to_Pool(name="pool_b1", offset="(0,0,0)", to="(ccr_b1-east)", width=1, height=32, depth=32, opacity=0.5),
+
+ *block_2ConvPool( name='b2', botton='pool_b1', top='pool_b2', s_filer=256, n_filer=128, offset="(1,0,0)", size=(32,32,3.5), opacity=0.5 ),
+ *block_2ConvPool( name='b3', botton='pool_b2', top='pool_b3', s_filer=128, n_filer=256, offset="(1,0,0)", size=(25,25,4.5), opacity=0.5 ),
+ *block_2ConvPool( name='b4', botton='pool_b3', top='pool_b4', s_filer=64, n_filer=512, offset="(1,0,0)", size=(16,16,5.5), opacity=0.5 ),
+
+ #Bottleneck
+ #block-005
+ to_ConvConvRelu( name='ccr_b5', s_filer=32, n_filer=(1024,1024), offset="(2,0,0)", to="(pool_b4-east)", width=(8,8), height=8, depth=8, caption="Bottleneck" ),
+ to_connection( "pool_b4", "ccr_b5"),
+
+ #Decoder
+ *block_Unconv( name="b6", botton="ccr_b5", top='end_b6', s_filer=64, n_filer=512, offset="(2.1,0,0)", size=(16,16,5.0), opacity=0.5 ),
+ to_skip( of='ccr_b4', to='ccr_res_b6', pos=1.25),
+ *block_Unconv( name="b7", botton="end_b6", top='end_b7', s_filer=128, n_filer=256, offset="(2.1,0,0)", size=(25,25,4.5), opacity=0.5 ),
+ to_skip( of='ccr_b3', to='ccr_res_b7', pos=1.25),
+ *block_Unconv( name="b8", botton="end_b7", top='end_b8', s_filer=256, n_filer=128, offset="(2.1,0,0)", size=(32,32,3.5), opacity=0.5 ),
+ to_skip( of='ccr_b2', to='ccr_res_b8', pos=1.25),
+
+ *block_Unconv( name="b9", botton="end_b8", top='end_b9', s_filer=512, n_filer=64, offset="(2.1,0,0)", size=(40,40,2.5), opacity=0.5 ),
+ to_skip( of='ccr_b1', to='ccr_res_b9', pos=1.25),
+
+ to_ConvSoftMax( name="soft1", s_filer=512, offset="(0.75,0,0)", to="(end_b9-east)", width=1, height=40, depth=40, caption="SOFT" ),
+ to_connection( "end_b9", "soft1"),
+
+ to_end()
+ ]
+
+
+def main():
+ namefile = str(sys.argv[0]).split('.')[0]
+ to_generate(arch, namefile + '.tex' )
+
+if __name__ == '__main__':
+ main()
+
\ No newline at end of file
diff --git a/tikzmake.sh b/tikzmake.sh
new file mode 100644
index 0000000..1c4b6d6
--- /dev/null
+++ b/tikzmake.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+
+python $1.py
+pdflatex $1.tex
+
+rm *.aux *.log *.vscodeLog
+rm *.tex
+
+evince $1.pdf
+