diff options
author | Jonathan J Hunt <jjhunt@google.com> | 2014-11-19 21:31:07 +0300 |
---|---|---|
committer | Jonathan J Hunt <jjhunt@google.com> | 2015-01-14 15:20:09 +0300 |
commit | 6dc7823207a32fb93f3979bf659fb6cce71d1df5 (patch) | |
tree | 9990f3d3547759153576accd50b3de7ecbc9e3ea | |
parent | 518b60b632179b09db4b06c953c2ac4fc66097ce (diff) |
Added support for annotating graphs (depends also on changes in graph).
Replaces node:name.
-rw-r--r-- | README.md | 35 | ||||
-rw-r--r-- | doc/annotation_bg.svg | 166 | ||||
-rw-r--r-- | doc/annotation_fg.svg | 166 | ||||
-rw-r--r-- | node.lua | 65 | ||||
-rw-r--r-- | test/test_nngraph.lua | 38 |
5 files changed, 460 insertions, 10 deletions
@@ -131,3 +131,38 @@ graph.dot(gmod.fg,'Big MLP') <img src= "https://raw.github.com/koraykv/torch-nngraph/master/doc/mlp4_backward.png" width="300px"/> +## Annotations + +It is possible to add annotations to your network, such as labeling nodes +with names or attributes which will show up when you graph the network. +This can be helpful in large graphs. + +For the full list of graph attributes see the +[graphviz documentation](http://www.graphviz.org/doc/info/attrs.html). + +``` + input = nn.Identity()() + L1 = nn.Tanh()(nn.Linear(10,20)(input)):annotate{ + name = 'L1', description = 'Level 1 Node', + graphAttributes = {color = 'red'}} + L2 = nn.Tanh()(nn.Linear(30,60)(nn.JoinTable(1)({input,L1}))):annotate{ + name = 'L2', description = 'Level 2 Node', + graphAttributes = {color = 'blue', fontcolor = 'green'}} + L3 = nn.Tanh()(nn.Linear(80,160)(nn.JoinTable(1)({L1,L2}))):annotate{ + name = 'L3', descrption = 'Level 3 Node', + graphAttributes = {color = 'green', + style='filled', fillcolor = 'yellow'}} + + g = nn.gModule({input},{L3}) + + indata = torch.rand(10) + gdata = torch.rand(160) + g:forward(indata) + g:backward(indata,gdata) + + graph.dot(g.fg,'Forward Graph', '/tmp/fg') + graph.dot(g.bg,'Backward Graph', '/tmp/bg') +``` + +![Annotated forward graph](doc/annotation_fg.svg?raw=true) +![Annotated backward graph](doc/annotation_bg.svg?raw=true) diff --git a/doc/annotation_bg.svg b/doc/annotation_bg.svg new file mode 100644 index 0000000..96af42a --- /dev/null +++ b/doc/annotation_bg.svg @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.36.0 (20140111.2315) + --> +<!-- Title: G Pages: 1 --> +<svg width="477pt" height="1539pt" + viewBox="0.00 0.00 477.00 1539.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1535)"> +<title>G</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-1535 473,-1535 473,4 -4,4"/> +<text text-anchor="middle" x="234.5" y="-1515.8" font-family="Times,serif" font-size="14.00">Backward Graph</text> +<!-- n1 --> +<g id="node1" class="node"><title>n1</title> +<ellipse fill="none" stroke="black" cx="236" cy="-1470" rx="123.055" ry="37.4533"/> +<text text-anchor="middle" x="236" y="-1481.3" font-family="Times,serif" font-size="14.00">Node1</text> +<text text-anchor="start" x="157" y="-1466.3" font-family="Times,serif" font-size="14.00">input = {Tensor[160]}</text> +<text text-anchor="middle" x="236" y="-1451.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +</g> +<!-- n2 --> +<g id="node2" class="node"><title>n2</title> +<ellipse fill="yellow" stroke="green" cx="236" cy="-1348" rx="123.055" ry="48.1667"/> +<text text-anchor="middle" x="236" y="-1366.8" font-family="Times,serif" font-size="14.00">L3 (2)</text> +<text text-anchor="start" x="157" y="-1351.8" font-family="Times,serif" font-size="14.00">input = {Tensor[160]}</text> +<text text-anchor="start" x="157" y="-1336.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +<text text-anchor="middle" x="236" y="-1321.8" font-family="Times,serif" font-size="14.00">module = nn.Tanh</text> +</g> +<!-- n1->n2 --> +<g id="edge1" class="edge"><title>n1->n2</title> +<path fill="none" stroke="black" d="M236,-1432.34C236,-1424.22 236,-1415.42 236,-1406.68"/> +<polygon fill="black" stroke="black" points="239.5,-1406.5 236,-1396.5 232.5,-1406.5 239.5,-1406.5"/> +</g> +<!-- n3 --> +<g id="node3" class="node"><title>n3</title> +<ellipse fill="none" stroke="black" cx="236" cy="-1216" rx="123.055" ry="48.1667"/> +<text text-anchor="middle" x="236" y="-1234.8" font-family="Times,serif" font-size="14.00">Node3</text> +<text text-anchor="start" x="157" y="-1219.8" font-family="Times,serif" font-size="14.00">input = {Tensor[80]}</text> +<text text-anchor="start" x="157" y="-1204.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +<text text-anchor="middle" x="236" y="-1189.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n2->n3 --> +<g id="edge2" class="edge"><title>n2->n3</title> +<path fill="none" stroke="black" d="M236,-1299.7C236,-1291.54 236,-1282.99 236,-1274.6"/> +<polygon fill="black" stroke="black" points="239.5,-1274.48 236,-1264.48 232.5,-1274.48 239.5,-1274.48"/> +</g> +<!-- n4 --> +<g id="node4" class="node"><title>n4</title> +<ellipse fill="none" stroke="black" cx="236" cy="-1073" rx="138.951" ry="58.8803"/> +<text text-anchor="middle" x="236" y="-1099.3" font-family="Times,serif" font-size="14.00">Node4</text> +<text text-anchor="start" x="145.5" y="-1084.3" font-family="Times,serif" font-size="14.00">input = {Tensor[20],Tensor[60]}</text> +<text text-anchor="start" x="145.5" y="-1069.3" font-family="Times,serif" font-size="14.00">mapindex = {Node5,Node6}</text> +<text text-anchor="start" x="145.5" y="-1054.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[80]}</text> +<text text-anchor="middle" x="236" y="-1039.3" font-family="Times,serif" font-size="14.00">module = nn.JoinTable</text> +</g> +<!-- n3->n4 --> +<g id="edge3" class="edge"><title>n3->n4</title> +<path fill="none" stroke="black" d="M236,-1167.66C236,-1159.38 236,-1150.62 236,-1141.91"/> +<polygon fill="black" stroke="black" points="239.5,-1141.74 236,-1131.74 232.5,-1141.74 239.5,-1141.74"/> +</g> +<!-- n5 --> +<g id="node5" class="node"><title>n5</title> +<ellipse fill="none" stroke="red" cx="163" cy="-468" rx="163.013" ry="69.0935"/> +<text text-anchor="middle" x="163" y="-501.8" font-family="Times,serif" font-size="14.00">L1 (5)</text> +<text text-anchor="middle" x="163" y="-486.8" font-family="Times,serif" font-size="14.00">desc = Level 1 Node</text> +<text text-anchor="start" x="55.5" y="-471.8" font-family="Times,serif" font-size="14.00">input = {Tensor[20]}</text> +<text text-anchor="start" x="55.5" y="-456.8" font-family="Times,serif" font-size="14.00">gradOutputBuffer = Tensor[20]</text> +<text text-anchor="start" x="55.5" y="-441.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[20],Tensor[20]}</text> +<text text-anchor="middle" x="163" y="-426.8" font-family="Times,serif" font-size="14.00">module = nn.Tanh</text> +</g> +<!-- n4->n5 --> +<g id="edge4" class="edge"><title>n4->n5</title> +<path fill="none" stroke="black" d="M198.203,-1016.31C191.643,-1004.16 185.737,-991.025 182,-978 139.683,-830.489 146.007,-649.067 154.472,-547.496"/> +<polygon fill="black" stroke="black" points="157.978,-547.583 155.35,-537.319 151.004,-546.981 157.978,-547.583"/> +</g> +<!-- n6 --> +<g id="node6" class="node"><title>n6</title> +<ellipse fill="none" stroke="blue" cx="309" cy="-919" rx="118.13" ry="58.8803"/> +<text text-anchor="middle" x="309" y="-945.3" font-family="Times,serif" font-size="14.00" fill="green">L2 (6)</text> +<text text-anchor="middle" x="309" y="-930.3" font-family="Times,serif" font-size="14.00" fill="green">desc = Level 2 Node</text> +<text text-anchor="start" x="233.5" y="-915.3" font-family="Times,serif" font-size="14.00" fill="green">input = {Tensor[60]}</text> +<text text-anchor="start" x="233.5" y="-900.3" font-family="Times,serif" font-size="14.00" fill="green">gradOutput = {Tensor[60]}</text> +<text text-anchor="middle" x="309" y="-885.3" font-family="Times,serif" font-size="14.00" fill="green">module = nn.Tanh</text> +</g> +<!-- n4->n6 --> +<g id="edge5" class="edge"><title>n4->n6</title> +<path fill="none" stroke="black" d="M263.183,-1015.4C267.9,-1005.58 272.84,-995.292 277.658,-985.261"/> +<polygon fill="black" stroke="black" points="280.864,-986.67 282.038,-976.14 274.554,-983.639 280.864,-986.67"/> +</g> +<!-- n7 --> +<g id="node7" class="node"><title>n7</title> +<ellipse fill="none" stroke="black" cx="186" cy="-314" rx="118.13" ry="48.1667"/> +<text text-anchor="middle" x="186" y="-332.8" font-family="Times,serif" font-size="14.00">Node7</text> +<text text-anchor="start" x="110.5" y="-317.8" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="start" x="110.5" y="-302.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[20]}</text> +<text text-anchor="middle" x="186" y="-287.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n5->n7 --> +<g id="edge6" class="edge"><title>n5->n7</title> +<path fill="none" stroke="black" d="M173.356,-398.559C174.693,-389.724 176.051,-380.751 177.356,-372.125"/> +<polygon fill="black" stroke="black" points="180.824,-372.597 178.86,-362.186 173.903,-371.55 180.824,-372.597"/> +</g> +<!-- n8 --> +<g id="node8" class="node"><title>n8</title> +<ellipse fill="none" stroke="black" cx="319" cy="-776" rx="118.13" ry="48.1667"/> +<text text-anchor="middle" x="319" y="-794.8" font-family="Times,serif" font-size="14.00">Node8</text> +<text text-anchor="start" x="243.5" y="-779.8" font-family="Times,serif" font-size="14.00">input = {Tensor[30]}</text> +<text text-anchor="start" x="243.5" y="-764.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[60]}</text> +<text text-anchor="middle" x="319" y="-749.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n6->n8 --> +<g id="edge7" class="edge"><title>n6->n8</title> +<path fill="none" stroke="black" d="M313.096,-860.243C313.702,-851.7 314.326,-842.899 314.932,-834.364"/> +<polygon fill="black" stroke="black" points="318.442,-834.344 315.658,-824.121 311.459,-833.848 318.442,-834.344"/> +</g> +<!-- n9 --> +<g id="node9" class="node"><title>n9</title> +<ellipse fill="none" stroke="black" cx="270" cy="-171" rx="163.013" ry="58.8803"/> +<text text-anchor="middle" x="270" y="-197.3" font-family="Times,serif" font-size="14.00">Node9</text> +<text text-anchor="start" x="162.5" y="-182.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="start" x="162.5" y="-167.3" font-family="Times,serif" font-size="14.00">gradOutputBuffer = Tensor[10]</text> +<text text-anchor="start" x="162.5" y="-152.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[10],Tensor[10]}</text> +<text text-anchor="middle" x="270" y="-137.3" font-family="Times,serif" font-size="14.00">module = nn.Identity</text> +</g> +<!-- n7->n9 --> +<g id="edge8" class="edge"><title>n7->n9</title> +<path fill="none" stroke="black" d="M213.505,-266.831C219.13,-257.389 225.15,-247.283 231.088,-237.317"/> +<polygon fill="black" stroke="black" points="234.161,-238.996 236.273,-228.614 228.148,-235.413 234.161,-238.996"/> +</g> +<!-- n10 --> +<g id="node10" class="node"><title>n10</title> +<ellipse fill="none" stroke="black" cx="330" cy="-633" rx="138.951" ry="58.8803"/> +<text text-anchor="middle" x="330" y="-659.3" font-family="Times,serif" font-size="14.00">Node10</text> +<text text-anchor="start" x="239.5" y="-644.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10],Tensor[20]}</text> +<text text-anchor="start" x="239.5" y="-629.3" font-family="Times,serif" font-size="14.00">mapindex = {Node9,Node5}</text> +<text text-anchor="start" x="239.5" y="-614.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[30]}</text> +<text text-anchor="middle" x="330" y="-599.3" font-family="Times,serif" font-size="14.00">module = nn.JoinTable</text> +</g> +<!-- n8->n10 --> +<g id="edge9" class="edge"><title>n8->n10</title> +<path fill="none" stroke="black" d="M322.693,-727.657C323.339,-719.376 324.023,-710.617 324.702,-701.909"/> +<polygon fill="black" stroke="black" points="328.207,-701.986 325.495,-691.744 321.228,-701.442 328.207,-701.986"/> +</g> +<!-- n11 --> +<g id="node11" class="node"><title>n11</title> +<ellipse fill="none" stroke="black" cx="270" cy="-38" rx="118.13" ry="37.4533"/> +<text text-anchor="middle" x="270" y="-49.3" font-family="Times,serif" font-size="14.00">Node11</text> +<text text-anchor="start" x="194.5" y="-34.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="middle" x="270" y="-19.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[10]}</text> +</g> +<!-- n9->n11 --> +<g id="edge10" class="edge"><title>n9->n11</title> +<path fill="none" stroke="black" d="M270,-112.16C270,-103.389 270,-94.4321 270,-85.9302"/> +<polygon fill="black" stroke="black" points="273.5,-85.8285 270,-75.8285 266.5,-85.8285 273.5,-85.8285"/> +</g> +<!-- n10->n5 --> +<g id="edge12" class="edge"><title>n10->n5</title> +<path fill="none" stroke="black" d="M275.318,-578.628C262.396,-566.015 248.424,-552.378 234.869,-539.148"/> +<polygon fill="black" stroke="black" points="236.992,-536.329 227.391,-531.849 232.103,-541.338 236.992,-536.329"/> +</g> +<!-- n10->n9 --> +<g id="edge11" class="edge"><title>n10->n9</title> +<path fill="none" stroke="black" d="M336.006,-574.074C341.673,-500.625 345.121,-370.921 313,-266 310.212,-256.894 306.732,-247.524 302.967,-238.391"/> +<polygon fill="black" stroke="black" points="306.097,-236.808 298.958,-228.98 299.658,-239.551 306.097,-236.808"/> +</g> +</g> +</svg> diff --git a/doc/annotation_fg.svg b/doc/annotation_fg.svg new file mode 100644 index 0000000..12148fa --- /dev/null +++ b/doc/annotation_fg.svg @@ -0,0 +1,166 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 2.36.0 (20140111.2315) + --> +<!-- Title: G Pages: 1 --> +<svg width="477pt" height="1539pt" + viewBox="0.00 0.00 477.00 1539.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1535)"> +<title>G</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-1535 473,-1535 473,4 -4,4"/> +<text text-anchor="middle" x="234.5" y="-1515.8" font-family="Times,serif" font-size="14.00">Forward Graph</text> +<!-- n1 --> +<g id="node1" class="node"><title>n1</title> +<ellipse fill="yellow" stroke="green" cx="238" cy="-160" rx="123.055" ry="48.1667"/> +<text text-anchor="middle" x="238" y="-178.8" font-family="Times,serif" font-size="14.00">L3 (1)</text> +<text text-anchor="start" x="159" y="-163.8" font-family="Times,serif" font-size="14.00">input = {Tensor[160]}</text> +<text text-anchor="start" x="159" y="-148.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +<text text-anchor="middle" x="238" y="-133.8" font-family="Times,serif" font-size="14.00">module = nn.Tanh</text> +</g> +<!-- n2 --> +<g id="node2" class="node"><title>n2</title> +<ellipse fill="none" stroke="black" cx="238" cy="-38" rx="123.055" ry="37.4533"/> +<text text-anchor="middle" x="238" y="-49.3" font-family="Times,serif" font-size="14.00">Node2</text> +<text text-anchor="start" x="159" y="-34.3" font-family="Times,serif" font-size="14.00">input = {Tensor[160]}</text> +<text text-anchor="middle" x="238" y="-19.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +</g> +<!-- n1->n2 --> +<g id="edge1" class="edge"><title>n1->n2</title> +<path fill="none" stroke="black" d="M238,-111.573C238,-103.096 238,-94.269 238,-85.8099"/> +<polygon fill="black" stroke="black" points="241.5,-85.7224 238,-75.7224 234.5,-85.7224 241.5,-85.7224"/> +</g> +<!-- n3 --> +<g id="node3" class="node"><title>n3</title> +<ellipse fill="none" stroke="black" cx="238" cy="-292" rx="123.055" ry="48.1667"/> +<text text-anchor="middle" x="238" y="-310.8" font-family="Times,serif" font-size="14.00">Node3</text> +<text text-anchor="start" x="159" y="-295.8" font-family="Times,serif" font-size="14.00">input = {Tensor[80]}</text> +<text text-anchor="start" x="159" y="-280.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[160]}</text> +<text text-anchor="middle" x="238" y="-265.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n3->n1 --> +<g id="edge2" class="edge"><title>n3->n1</title> +<path fill="none" stroke="black" d="M238,-243.699C238,-235.544 238,-226.987 238,-218.597"/> +<polygon fill="black" stroke="black" points="241.5,-218.483 238,-208.483 234.5,-218.483 241.5,-218.483"/> +</g> +<!-- n4 --> +<g id="node4" class="node"><title>n4</title> +<ellipse fill="none" stroke="black" cx="238" cy="-435" rx="138.951" ry="58.8803"/> +<text text-anchor="middle" x="238" y="-461.3" font-family="Times,serif" font-size="14.00">Node4</text> +<text text-anchor="start" x="147.5" y="-446.3" font-family="Times,serif" font-size="14.00">input = {Tensor[20],Tensor[60]}</text> +<text text-anchor="start" x="147.5" y="-431.3" font-family="Times,serif" font-size="14.00">mapindex = {Node5,Node6}</text> +<text text-anchor="start" x="147.5" y="-416.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[80]}</text> +<text text-anchor="middle" x="238" y="-401.3" font-family="Times,serif" font-size="14.00">module = nn.JoinTable</text> +</g> +<!-- n4->n3 --> +<g id="edge3" class="edge"><title>n4->n3</title> +<path fill="none" stroke="black" d="M238,-376.243C238,-367.7 238,-358.899 238,-350.364"/> +<polygon fill="black" stroke="black" points="241.5,-350.121 238,-340.121 234.5,-350.121 241.5,-350.121"/> +</g> +<!-- n5 --> +<g id="node5" class="node"><title>n5</title> +<ellipse fill="none" stroke="red" cx="163" cy="-1040" rx="163.013" ry="69.0935"/> +<text text-anchor="middle" x="163" y="-1073.8" font-family="Times,serif" font-size="14.00">L1 (5)</text> +<text text-anchor="middle" x="163" y="-1058.8" font-family="Times,serif" font-size="14.00">desc = Level 1 Node</text> +<text text-anchor="start" x="55.5" y="-1043.8" font-family="Times,serif" font-size="14.00">input = {Tensor[20]}</text> +<text text-anchor="start" x="55.5" y="-1028.8" font-family="Times,serif" font-size="14.00">gradOutputBuffer = Tensor[20]</text> +<text text-anchor="start" x="55.5" y="-1013.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[20],Tensor[20]}</text> +<text text-anchor="middle" x="163" y="-998.8" font-family="Times,serif" font-size="14.00">module = nn.Tanh</text> +</g> +<!-- n5->n4 --> +<g id="edge4" class="edge"><title>n5->n4</title> +<path fill="none" stroke="black" d="M156.686,-970.368C149.678,-871.134 144.38,-682.741 187,-530 189.695,-520.343 193.522,-510.577 197.884,-501.179"/> +<polygon fill="black" stroke="black" points="201.161,-502.442 202.402,-491.92 194.871,-499.373 201.161,-502.442"/> +</g> +<!-- n10 --> +<g id="node10" class="node"><title>n10</title> +<ellipse fill="none" stroke="black" cx="330" cy="-875" rx="138.951" ry="58.8803"/> +<text text-anchor="middle" x="330" y="-901.3" font-family="Times,serif" font-size="14.00">Node10</text> +<text text-anchor="start" x="239.5" y="-886.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10],Tensor[20]}</text> +<text text-anchor="start" x="239.5" y="-871.3" font-family="Times,serif" font-size="14.00">mapindex = {Node9,Node5}</text> +<text text-anchor="start" x="239.5" y="-856.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[30]}</text> +<text text-anchor="middle" x="330" y="-841.3" font-family="Times,serif" font-size="14.00">module = nn.JoinTable</text> +</g> +<!-- n5->n10 --> +<g id="edge12" class="edge"><title>n5->n10</title> +<path fill="none" stroke="black" d="M227.567,-975.98C240.964,-962.903 255.048,-949.156 268.339,-936.184"/> +<polygon fill="black" stroke="black" points="270.92,-938.556 275.631,-929.067 266.03,-933.547 270.92,-938.556"/> +</g> +<!-- n6 --> +<g id="node6" class="node"><title>n6</title> +<ellipse fill="none" stroke="blue" cx="314" cy="-589" rx="118.13" ry="58.8803"/> +<text text-anchor="middle" x="314" y="-615.3" font-family="Times,serif" font-size="14.00" fill="green">L2 (6)</text> +<text text-anchor="middle" x="314" y="-600.3" font-family="Times,serif" font-size="14.00" fill="green">desc = Level 2 Node</text> +<text text-anchor="start" x="238.5" y="-585.3" font-family="Times,serif" font-size="14.00" fill="green">input = {Tensor[60]}</text> +<text text-anchor="start" x="238.5" y="-570.3" font-family="Times,serif" font-size="14.00" fill="green">gradOutput = {Tensor[60]}</text> +<text text-anchor="middle" x="314" y="-555.3" font-family="Times,serif" font-size="14.00" fill="green">module = nn.Tanh</text> +</g> +<!-- n6->n4 --> +<g id="edge5" class="edge"><title>n6->n4</title> +<path fill="none" stroke="black" d="M285.916,-531.833C281.028,-522.056 275.904,-511.808 270.9,-501.801"/> +<polygon fill="black" stroke="black" points="273.952,-500.077 266.349,-492.698 267.691,-503.208 273.952,-500.077"/> +</g> +<!-- n7 --> +<g id="node7" class="node"><title>n7</title> +<ellipse fill="none" stroke="black" cx="185" cy="-1194" rx="118.13" ry="48.1667"/> +<text text-anchor="middle" x="185" y="-1212.8" font-family="Times,serif" font-size="14.00">Node7</text> +<text text-anchor="start" x="109.5" y="-1197.8" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="start" x="109.5" y="-1182.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[20]}</text> +<text text-anchor="middle" x="185" y="-1167.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n7->n5 --> +<g id="edge6" class="edge"><title>n7->n5</title> +<path fill="none" stroke="black" d="M178.16,-1145.74C176.95,-1137.38 175.662,-1128.48 174.366,-1119.53"/> +<polygon fill="black" stroke="black" points="177.801,-1118.83 172.905,-1109.43 170.874,-1119.83 177.801,-1118.83"/> +</g> +<!-- n8 --> +<g id="node8" class="node"><title>n8</title> +<ellipse fill="none" stroke="black" cx="324" cy="-732" rx="118.13" ry="48.1667"/> +<text text-anchor="middle" x="324" y="-750.8" font-family="Times,serif" font-size="14.00">Node8</text> +<text text-anchor="start" x="248.5" y="-735.8" font-family="Times,serif" font-size="14.00">input = {Tensor[30]}</text> +<text text-anchor="start" x="248.5" y="-720.8" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[60]}</text> +<text text-anchor="middle" x="324" y="-705.8" font-family="Times,serif" font-size="14.00">module = nn.Linear</text> +</g> +<!-- n8->n6 --> +<g id="edge7" class="edge"><title>n8->n6</title> +<path fill="none" stroke="black" d="M320.642,-683.657C320.055,-675.376 319.434,-666.617 318.816,-657.909"/> +<polygon fill="black" stroke="black" points="322.294,-657.472 318.095,-647.744 315.312,-657.967 322.294,-657.472"/> +</g> +<!-- n9 --> +<g id="node9" class="node"><title>n9</title> +<ellipse fill="none" stroke="black" cx="280" cy="-1337" rx="163.013" ry="58.8803"/> +<text text-anchor="middle" x="280" y="-1363.3" font-family="Times,serif" font-size="14.00">Node9</text> +<text text-anchor="start" x="172.5" y="-1348.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="start" x="172.5" y="-1333.3" font-family="Times,serif" font-size="14.00">gradOutputBuffer = Tensor[10]</text> +<text text-anchor="start" x="172.5" y="-1318.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[10],Tensor[10]}</text> +<text text-anchor="middle" x="280" y="-1303.3" font-family="Times,serif" font-size="14.00">module = nn.Identity</text> +</g> +<!-- n9->n7 --> +<g id="edge8" class="edge"><title>n9->n7</title> +<path fill="none" stroke="black" d="M242.181,-1279.87C235.308,-1269.67 228.154,-1259.05 221.326,-1248.92"/> +<polygon fill="black" stroke="black" points="224.171,-1246.87 215.681,-1240.54 218.366,-1250.79 224.171,-1246.87"/> +</g> +<!-- n9->n10 --> +<g id="edge11" class="edge"><title>n9->n10</title> +<path fill="none" stroke="black" d="M301.065,-1278.76C305.049,-1266.72 308.925,-1254.03 312,-1242 342.052,-1124.46 338.223,-1091.28 335,-970 334.777,-961.604 334.442,-952.792 334.049,-944.067"/> +<polygon fill="black" stroke="black" points="337.536,-943.719 333.564,-933.897 330.544,-944.052 337.536,-943.719"/> +</g> +<!-- n10->n8 --> +<g id="edge9" class="edge"><title>n10->n8</title> +<path fill="none" stroke="black" d="M327.542,-816.243C327.179,-807.7 326.804,-798.899 326.441,-790.364"/> +<polygon fill="black" stroke="black" points="329.927,-789.963 326.005,-780.121 322.934,-790.261 329.927,-789.963"/> +</g> +<!-- n11 --> +<g id="node11" class="node"><title>n11</title> +<ellipse fill="none" stroke="black" cx="280" cy="-1470" rx="118.13" ry="37.4533"/> +<text text-anchor="middle" x="280" y="-1481.3" font-family="Times,serif" font-size="14.00">Node11</text> +<text text-anchor="start" x="204.5" y="-1466.3" font-family="Times,serif" font-size="14.00">input = {Tensor[10]}</text> +<text text-anchor="middle" x="280" y="-1451.3" font-family="Times,serif" font-size="14.00">gradOutput = {Tensor[10]}</text> +</g> +<!-- n11->n9 --> +<g id="edge10" class="edge"><title>n11->n9</title> +<path fill="none" stroke="black" d="M280,-1432.51C280,-1424.26 280,-1415.24 280,-1406.15"/> +<polygon fill="black" stroke="black" points="283.5,-1405.9 280,-1395.9 276.5,-1405.9 283.5,-1405.9"/> +</g> +</g> +</svg> @@ -3,15 +3,29 @@ local utils = paths.dofile('utils.lua') local istensor = utils.istensor local istable = utils.istable local istorchclass = utils.istorchclass +require 'debug' local nnNode,parent = torch.class('nngraph.Node','graph.Node') function nnNode:__init(data) parent.__init(self,data) + self.data.annotations = self.data.annotations or {} self.data.mapindex = self.data.mapindex or {} + if not self.data.annotations._debugLabel then + self:_makeDebugLabel(debug.getinfo(6, 'Sl')) + end end + +--[[ Build a string label which will be used a tooltip when + making a graph.]] +function nnNode:_makeDebugLabel(dinfo) + self.data.annotations._debugLabel = string.format('[%s]:%d', + dinfo.short_src, dinfo.currentline, dinfo.name) +end + + -- domap ensures that this node will keep track of the order its children are added. -- mapindex is a forward/backward list -- index = self.data.mapindex[child.data] @@ -28,7 +42,7 @@ function nnNode:add(child,domap) end -- this function returns noutput number of new nodes --- that each take a single component of the output of this +-- that each take a single component of the output of this -- node in the order they are returned. function nnNode:split(noutput) assert(noutput >= 2, "splitting to one output is not supported") @@ -44,13 +58,37 @@ function nnNode:split(noutput) return unpack(selectnodes) end -function nnNode:name(name) - if self.data and istable(self.data) then - self.data.name = name - end - return self + +function nnNode:annotate(annotations) + for k, v in pairs(annotations) do + self.data.annotations[k] = v + end + + return self +end + + +function nnNode:graphNodeName() + if self.data.annotations.name then + return self.data.annotations.name .. ' (' .. self.id .. ')' + else + return 'Node' .. self.id + end +end + + +function nnNode:graphNodeAttributes() + self.data.annotations.graphAttributes = + self.data.annotations.graphAttributes or {} + if not self.data.annotations.graphAttributes.tooltip then + self.data.annotations.graphAttributes.tooltip = + self.data.annotations._debugLabel + end + + return self.data.annotations.graphAttributes end + function nnNode:label() local lbl = {} @@ -85,17 +123,24 @@ function nnNode:label() for k,v in pairs(self.data) do local vstr = '' - if k == 'mapindex' then - if #v > 1 then + if k== 'mapindex' then + if #v > 1 then vstr = getmapindexstr(v) table.insert(lbl, k .. ' = ' .. vstr) end - elseif k == 'forwardNodeId' then + elseif k== 'forwardNodeId' or k== 'annotations' then -- the forwardNodeId is not displayed in the label. else vstr = getstr(v) table.insert(lbl, k .. ' = ' .. vstr) end end - return table.concat(lbl,"\\l") + + local desc + if self.data.annotations.description then + desc = 'desc = ' .. self.data.annotations.description .. '\\n' + else + desc = '' + end + return desc .. table.concat(lbl,"\\l") end diff --git a/test/test_nngraph.lua b/test/test_nngraph.lua index 1193dc9..4062c5a 100644 --- a/test/test_nngraph.lua +++ b/test/test_nngraph.lua @@ -303,4 +303,42 @@ function test.test_resizeNestedAs() checkGradients(net, input) end + +function test.test_annotateGraph() + local input = nn.Identity()():annotate( + {name = 'Input', description = 'DescA', + graphAttributes = {color = 'red'}}) + + local hidden_a = nn.Linear(10, 10)(input):annotate( + {name = 'Hidden A', description = 'DescB', + graphAttributes = {color = 'blue', fontcolor='green', tooltip = 'I am green'}}) + local hidden_b = nn.Sigmoid()(hidden_a) + local output = nn.Linear(10, 10)(hidden_b) + local net = nn.gModule({input}, {output}) + + tester:assert(hidden_a:label():match('DescB')) + local fg_tmpfile = os.tmpname() + local bg_tmpfile = os.tmpname() + graph.dot(net.fg, 'Test', fg_tmpfile) + graph.dot(net.fg, 'Test BG', bg_tmpfile) + + local function checkDotFile(tmpfile) + local dotcontent = io.open(tmpfile .. '.dot', 'r'):read("*all") + tester:assert( + dotcontent:match('%[label=%"Input.*DescA.*%" color=red%]')) + tester:assert( + dotcontent:match( + '%[label=%"Hidden A.*DescB.*%".*fontcolor=green.*%]')) + tester:assert( + dotcontent:match('%[label=%".*DescB.*%".*color=blue.*%]')) + tester:assert( + dotcontent:match( + '%[label=%".*DescB.*%".*tooltip=%".*test_nngraph.lua.*%".*%]')) + end + + checkDotFile(fg_tmpfile) + checkDotFile(bg_tmpfile) +end + + tester:add(test):run() |