Rename to TIDL
[tidl/tidl-api.git] / viewer / dot_graph.cpp
1 /******************************************************************************
2  * Copyright (c) 2017-18, Texas Instruments Incorporated - http://www.ti.com/
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *      * Redistributions of source code must retain the above copyright
8  *        notice, this list of conditions and the following disclaimer.
9  *      * Redistributions in binary form must reproduce the above copyright
10  *        notice, this list of conditions and the following disclaimer in the
11  *        documentation and/or other materials provided with the distribution.
12  *      * Neither the name of Texas Instruments Incorporated nor the
13  *        names of its contributors may be used to endorse or promote products
14  *        derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  *  THE POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 #include "dot_graph.h"
30 using Edge   =  boost::graph_traits<Graph>::edge_descriptor;
32 template<typename T>
33 using VertexPropertyMap =
34               typename boost::property_map<T, boost::vertex_attribute_t>::type;
36 template<typename T>
37 using EdgePropertyMap =
38               typename boost::property_map<T, boost::edge_attribute_t>::type;
40 using LayerIdMap = std::map<uint32_t, Graph*>;
42 static const char* FILLED = "filled";
43 static const char* LABEL  = "label";
44 static const char* COLOR  = "color";
45 static const char* STYLE  = "style";
46 static const char* SHAPE  = "shape";
47 static const char* BOLD   = "bold";
49 static const char* GetVertexColor(uint32_t layer_type);
50 static std::string PoolingProperties(const sTIDL_PoolingParams_t& p);
51 static std::string BiasProperties(const sTIDL_BiasParams_t& p);
52 static std::string ReLUProperties(const sTIDL_ReLUParams_t& p);
55 DotGraph::DotGraph(const sTIDL_Network_t& net):
56                     graph_m(net.numLayers), net_m(net)
57 {
58     AddVertices();
59     AddEdges();
60     AddMetaData();
61 }
64 void DotGraph::AddVertices()
65 {
66     // Add a vertex for each layer
67     LayerIdMap layerid_map;
68     for (int i = 0 ; i < net_m.numLayers; i++)
69     {
70         const sTIDL_Layer_t& layer = net_m.TIDLLayers[i];
72         // Special handling for input & output data layers:
73         // Do not put them in the same subgraph
74         if (layer.layerType == TIDL_DataLayer)
75         {
76             auto V = vertex(i, graph_m);
77             VertexPropertyMap<Graph> vpm = boost::get(vertex_attribute, graph_m);
78             vpm[V][LABEL] = TIDL_LayerString[layer.layerType];
79             vpm[V][COLOR] = GetVertexColor(layer.layerType);
80             vpm[V][STYLE] = FILLED;
81             vpm[V][SHAPE] = "ellipse";
83             continue;
84         }
86         // Use the layer group ID to create subgraphs
87         // Place all layers with the same ID into a single subgraph
88         uint32_t layerGroupId = layer.layersGroupId;
89         Graph* sub = nullptr;
90         if (layerid_map.find(layerGroupId) == layerid_map.end())
91         {
92             sub = &(graph_m.create_subgraph());
93             layerid_map[layerGroupId] = sub;
94             get_property(*sub, graph_name) = std::string("cluster") +
95                                              std::to_string(layerGroupId);
96             get_property(*sub, graph_graph_attribute)[LABEL] =
97                                     "Group " + std::to_string(layerGroupId);
98             get_property(*sub, graph_graph_attribute)[STYLE] = BOLD;
99         }
100         else
101             sub = layerid_map[layerGroupId];
103         auto V = add_vertex(i, *sub);
105         AddVertexProperties(V, sub, layer);
106     }
110 void DotGraph::AddVertexProperties(Vertex& V, Graph* g,
111                                    const sTIDL_Layer_t& layer)
113     VertexPropertyMap<Graph> vpm = boost::get(vertex_attribute, *g);
114     vpm[V][COLOR] = GetVertexColor(layer.layerType);
115     vpm[V][STYLE] = BOLD;
116     vpm[V][LABEL] = "{";
118     switch (layer.layerType)
119     {
120         case TIDL_ConvolutionLayer:
121         {
122             vpm[V][LABEL] += TIDL_LayerString[layer.layerType];
123             const sTIDL_ConvParams_t& p = layer.layerParams.convParams;
124             vpm[V][LABEL] += "\\n" + std::to_string(p.kernelW) + "x" +
125                              std::to_string(p.kernelH);
127             if (p.enablePooling)
128                 vpm[V][LABEL] += "|" + PoolingProperties(p.poolParams);
130             if (p.enableRelU)
131                 vpm[V][LABEL] += "|" + ReLUProperties(p.reluParams);
133             if (p.enableBias)
134                 vpm[V][LABEL] += "|" +
135                                  std::string(TIDL_LayerString[TIDL_BiasLayer]);
137             break;
138         }
140         case TIDL_PoolingLayer:
141         {
142             const sTIDL_PoolingParams_t& p = layer.layerParams.poolParams;
143             vpm[V][LABEL] += PoolingProperties(p);
144             break;
145         }
147         case TIDL_BiasLayer:
148         {
149             const sTIDL_BiasParams_t& p = layer.layerParams.biasParams;
150             vpm[V][LABEL] += BiasProperties(p);
151             break;
152         }
154         case TIDL_ReLULayer:
155         {
156             const sTIDL_ReLUParams_t& p = layer.layerParams.reluParams;
157             vpm[V][LABEL] += ReLUProperties(p);
158             break;
159         }
161         case TIDL_EltWiseLayer:
162         {
164             vpm[V][LABEL] += TIDL_LayerString[layer.layerType];
165             const sTIDL_EltWiseParams_t& p = layer.layerParams.eltWiseParams;
166             if (p.eltWiseType == TIDL_EltWiseProduct)
167                 vpm[V][LABEL] += " Product";
168             else if (p.eltWiseType == TIDL_EltWiseSum)
169                 vpm[V][LABEL] += " Sum";
170             else if (p.eltWiseType == TIDL_EltWiseMax)
171                 vpm[V][LABEL] += " Max";
173             break;
174         }
176         default:
177             vpm[V][LABEL] += TIDL_LayerString[layer.layerType];
178             break;
179     }
181     vpm[V][LABEL] += "}";
185 void DotGraph::AddEdges()
187     // Add edges based on dataId i.e. there is an edge from layer A -> B
188     // iff dataId is in outData for A and inData for B.
189     EdgePropertyMap<Graph> ep = boost::get(boost::edge_attribute, graph_m);
190     for (int i = 0 ; i < net_m.numLayers; i++)
191     {
192         const sTIDL_Layer_t& layer = net_m.TIDLLayers[i];
194         if (layer.numOutBufs < 0)
195             continue;
197         // Create a string to  annotate the edge - num_channels, height, width
198         const sTIDL_DataParams_t& outData = layer.outData[0];
199         int32_t out_id = outData.dataId;
200         std::string edge_info = std::to_string(outData.dimValues[1])+ "x" +
201                                 std::to_string(outData.dimValues[2])+ "x" +
202                                 std::to_string(outData.dimValues[3]);
204         for (int j = 0; j < net_m.numLayers; j++)
205         {
206             if (j == i) continue;
208             for (int x = 0; x < net_m.TIDLLayers[j].numInBufs; x++)
209                 if (net_m.TIDLLayers[j].inData[x].dataId == out_id)
210                 {
211                     Edge e = add_edge(i, j, graph_m).first;
212                     ep[e][LABEL] = edge_info;
213                 }
215         }
216     }
220 void DotGraph::AddMetaData()
222     get_property(graph_m, graph_name) = "TIDL Network";
223     get_property(graph_m, graph_vertex_attribute)[SHAPE] = "Mrecord";
224     get_property(graph_m, graph_graph_attribute)["fontname"] = "Arial";
225     get_property(graph_m, graph_vertex_attribute)["fontname"] = "Arial";
226     get_property(graph_m, graph_vertex_attribute)["fontsize"] = "12";
227     get_property(graph_m, graph_edge_attribute)["fontname"] = "Arial";
228     get_property(graph_m, graph_edge_attribute)["fontsize"] = "10";
232 // Generate dot file from boost graph
233 void DotGraph::Write(const std::string& filename) const
235     std::ofstream dot(filename);
236     boost::write_graphviz(dot, graph_m);
239 std::string PoolingProperties(const sTIDL_PoolingParams_t& p)
241     std::string s = TIDL_LayerString[TIDL_PoolingLayer];
243     if (p.poolingType == TIDL_MaxPooling)
244         s += " Max";
245     else if (p.poolingType == TIDL_AveragePooling)
246         s += " Average";
248     s+= "\\n" + std::to_string(p.kernelW) + "x" + std::to_string(p.kernelH);
250     return s;
253 std::string ReLUProperties(const sTIDL_ReLUParams_t& p)
255     std::string s;
257     if (p.reluType == TIDL_RelU)
258         s += "ReLU";
259     else if (p.reluType == TIDL_PRelU)
260         s += "PReLU";
261     else if (p.reluType == TIDL_RelU6)
262         s += "ReLU6";
264     return s;
267 std::string BiasProperties(const sTIDL_BiasParams_t& p)
269     std::string s = TIDL_LayerString[TIDL_BiasLayer];
270     s += "\\n (BQ: " + std::to_string(p.biasQ) + ")";
271     return s;
276 const char* GetVertexColor(uint32_t layer_type)
278     static const char* LayerColors[] =
279     {
280         "lightblue",
281         "red",
282         "darkorange",
283         "royalblue",
284         "darkgreen",
285         "yellow",
286         "magenta",
287         "darkviolet",
288         "brown",
289         "darksalmon",
290         "violet",
291         "darkturquoise",
292         "darkseagreen",
293         "limegreen"
295     };
297     return LayerColors[layer_type % (sizeof(LayerColors)/sizeof(char *))];
301 const char* TIDL_LayerString[] =
303     "Data",
304     "Convolution",
305     "Pooling",
306     "ReLU",
307     "PReLU",
308     "EltWise",
309     "InnerProduct",
310     "SoftMax",
311     "BatchNorm",
312     "Bias",
313     "Scale",
314     "Deconv2D",
315     "Concat",
316     "Split",
317     "Slice",
318     "Crop",
319     "Flatten",
320     "DropOut",
321     "ArgMax",
322     "DetectionOutput",
323     "Reshape",
324 };