= Digraph("Computational Graph of Value", comment="Comp Graph"); g
g = g.node("A")
a = g.node("B")
b # g.node?
utils
Some utilities for minion for visualizations, context managers etc…
= Value(2.0, label="a")
a = Value(-3.0, label="b")
b = Value(10.0, label="c")
c
= a*b; d.label = "d"
d = d+c; e.label = "e"
e = Value(-2.0, label="f")
f = e*f; L.label="L"
L L
Value(L|data=-8.0)
for i in e._prev:
print(i, i._op)
Value(c|data=10.0) None
Value(d|data=-6.0) *
= Digraph("Computational Graph of Value", comment="Comp Graph"); g
g str(1), "A|data=4")
g.node(str(2), "A|data=9")
g.node("12"])
g.edges([ g
# Below doesn't work
# def build_graph(root, g = None):
# if not g: g = graphviz.Digraph("Computational Graph of Value", comment="Comp Graph"); g
# g.node("a", f"{root.label}|{root.data}")
# if root._prev:
# t = ""
# for i, val in enumerate(root._prev):
# g.node(str(i),f"{val.label}|{val.data}" )
# g.edges([str(i)+"a"])
# build_graph(val,)
# return g
# build_graph(e)
In order for us to build a visualization of computational graph of Value
object. We need to first create a set of all nodes and connections/ edges between them. We can then use graphviz to visualize the graph in one shot. This would be the simplest algorithm for now
trace
trace (root)
It’s interesting to choose a glocal sets for nodes and edges, calling them implicity within trace inside recursion. It does make for one simpler and efficient algorithm
trace(L)
({Value(L|data=-8.0),
Value(a|data=2.0),
Value(b|data=-3.0),
Value(c|data=10.0),
Value(d|data=-6.0),
Value(e|data=4.0),
Value(f|data=-2.0)},
{(Value(a|data=2.0), Value(d|data=-6.0)),
(Value(b|data=-3.0), Value(d|data=-6.0)),
(Value(c|data=10.0), Value(e|data=4.0)),
(Value(d|data=-6.0), Value(e|data=4.0)),
(Value(e|data=4.0), Value(L|data=-8.0)),
(Value(f|data=-2.0), Value(L|data=-8.0))})
draw_dot
draw_dot (root)
draw_dot(L)
draw_dot(a)
draw_dot(d)