a
    B=icA                     @   s
  d Z ddlZddlZddlZddlZddlZeje	d 
ejddsZddlmZ nddlmZ dZdZdd	 Zd
d Zdd ZG dd deZG dd deZG dd deZdd Zd$ddZdd Zdd Zdd Zd%dd Zd!d" Ze d#kreej! dS )&z}This tool creates an html visualization of a TensorFlow Lite graph.

Example usage:

python visualize.py foo.tflite foo.html
    Ntflite_runtimeZ	visualize)schema_py_generateda  
<html>
<head>
<style>
body {font-family: sans-serif; background-color: #fa0;}
table {background-color: #eca;}
th {background-color: black; color: white;}
h1 {
  background-color: ffaa00;
  padding:5px;
  color: black;
}

svg {
  margin: 10px;
  border: 2px;
  border-style: solid;
  border-color: black;
  background: white;
}

div {
  border-radius: 5px;
  background-color: #fec;
  padding:5px;
  margin:5px;
}

.tooltip {color: blue;}
.tooltip .tooltipcontent  {
    visibility: hidden;
    color: black;
    background-color: yellow;
    padding: 5px;
    border-radius: 4px;
    position: absolute;
    z-index: 1;
}
.tooltip:hover .tooltipcontent {
    visibility: visible;
}

.edges line {
  stroke: #333;
}

text {
  font-weight: bold;
}

.nodes text {
  color: black;
  pointer-events: none;
  font-family: sans-serif;
  font-size: 11px;
}
</style>

<script src="https://d3js.org/d3.v4.min.js"></script>

</head>
<body>
a  
  <script>
    function buildGraph() {
      // Build graph data
      var graph = %s;

      var svg = d3.select("#subgraph%d")
      var width = svg.attr("width");
      var height = svg.attr("height");
      // Make the graph scrollable.
      svg = svg.call(d3.zoom().on("zoom", function() {
        svg.attr("transform", d3.event.transform);
      })).append("g");


      var color = d3.scaleOrdinal(d3.schemeDark2);

      var simulation = d3.forceSimulation()
          .force("link", d3.forceLink().id(function(d) {return d.id;}))
          .force("charge", d3.forceManyBody())
          .force("center", d3.forceCenter(0.5 * width, 0.5 * height));

      var edge = svg.append("g").attr("class", "edges").selectAll("line")
        .data(graph.edges).enter().append("path").attr("stroke","black").attr("fill","none")

      // Make the node group
      var node = svg.selectAll(".nodes")
        .data(graph.nodes)
        .enter().append("g")
        .attr("x", function(d){return d.x})
        .attr("y", function(d){return d.y})
        .attr("transform", function(d) {
          return "translate( " + d.x + ", " + d.y + ")"
        })
        .attr("class", "nodes")
          .call(d3.drag()
              .on("start", function(d) {
                if(!d3.event.active) simulation.alphaTarget(1.0).restart();
                d.fx = d.x;d.fy = d.y;
              })
              .on("drag", function(d) {
                d.fx = d3.event.x; d.fy = d3.event.y;
              })
              .on("end", function(d) {
                if (!d3.event.active) simulation.alphaTarget(0);
                d.fx = d.fy = null;
              }));
      // Within the group, draw a box for the node position and text
      // on the side.

      var node_width = 150;
      var node_height = 30;

      node.append("rect")
          .attr("r", "5px")
          .attr("width", node_width)
          .attr("height", node_height)
          .attr("rx", function(d) { return d.group == 1 ? 1 : 10; })
          .attr("stroke", "#000000")
          .attr("fill", function(d) { return d.group == 1 ? "#dddddd" : "#000000"; })
      node.append("text")
          .text(function(d) { return d.name; })
          .attr("x", 5)
          .attr("y", 20)
          .attr("fill", function(d) { return d.group == 1 ? "#000000" : "#eeeeee"; })
      // Setup force parameters and update position callback


      var node = svg.selectAll(".nodes")
        .data(graph.nodes);

      // Bind the links
      var name_to_g = {}
      node.each(function(data, index, nodes) {
        console.log(data.id)
        name_to_g[data.id] = this;
      });

      function proc(w, t) {
        return parseInt(w.getAttribute(t));
      }
      edge.attr("d", function(d) {
        function lerp(t, a, b) {
          return (1.0-t) * a + t * b;
        }
        var x1 = proc(name_to_g[d.source],"x") + node_width /2;
        var y1 = proc(name_to_g[d.source],"y") + node_height;
        var x2 = proc(name_to_g[d.target],"x") + node_width /2;
        var y2 = proc(name_to_g[d.target],"y");
        var s = "M " + x1 + " " + y1
            + " C " + x1 + " " + lerp(.5, y1, y2)
            + " " + x2 + " " + lerp(.5, y1, y2)
            + " " + x2  + " " + y2
      return s;
    });

  }
  buildGraph()
</script>
c                 C   s*   t jj D ]\}}|| kr|  S qdS )z4Converts a numerical enum to a readable tensor type.N)	schema_fbZ
TensorType__dict__items)Ztensor_typenamevalue r	   p/home/droni/.local/share/virtualenvs/DPS-5Je3_V2c/lib/python3.9/site-packages/tensorflow/lite/tools/visualize.pyTensorTypeToName   s    
r   c                 C   s*   t jj D ]\}}|| kr|  S qdS )z3Converts a builtin op code enum to a readable name.N)r   ZBuiltinOperatorr   r   )coder   r   r	   r	   r
   BuiltinCodeToName   s    
r   c                 C   s<   t | tr| S d}| dur4| D ]}|tt| }q|S dS )z;Converts a list of integers to the equivalent ASCII string. N)
isinstancestrchrint)	name_listresultvalr	   r	   r
   NameListToString   s    
r   c                   @   s    e Zd ZdZdd Zdd ZdS )OpCodeMapperz#Maps an opcode index to an op name.c                 C   sR   i | _ t|d D ]:\}}t|d | j |< | j | dkrt|d | j |< qd S )Noperator_codesbuiltin_codeCUSTOMcustom_code)code_to_name	enumerater   r   )selfdataidxdr	   r	   r
   __init__   s
    zOpCodeMapper.__init__c                 C   s&   || j vrd}n
| j | }d||f S )Nz	<UNKNOWN>z%s (%d))r   )r   xsr	   r	   r
   __call__   s    

zOpCodeMapper.__call__N__name__
__module____qualname____doc__r"   r%   r	   r	   r	   r
   r      s   r   c                   @   s   e Zd ZdZdd ZdS )DataSizeMapperz(For buffers, report the number of bytes.c                 C   s   |d urdt | S dS d S )Nz%d bytesz--)len)r   r#   r	   r	   r
   r%      s    zDataSizeMapper.__call__N)r'   r(   r)   r*   r%   r	   r	   r	   r
   r+      s   r+   c                   @   s    e Zd ZdZdd Zdd ZdS )TensorMapperzGMaps a list of tensor indices to a tooltip hoverable indicator of more.c                 C   s
   || _ d S N)r   )r   Zsubgraph_datar	   r	   r
   r"     s    zTensorMapper.__init__c                 C   s   d}|d u r|S |d7 }|D ]}| j d | }|t|d 7 }|t|d d 7 }|t|d d 7 }|d|v r|t|d nd7 }|d	|v rt|d	 ndd
 7 }q|d7 }|t|7 }|d7 }|S )Nr   z3<span class='tooltip'><span class='tooltipcontent'>tensors r   typeshapez[]shape_signaturez<br>z</span>)r   r   r   r   repr)r   r#   htmlitensorr	   r	   r
   r%     s&    zTensorMapper.__call__Nr&   r	   r	   r	   r
   r-     s   r-   c              	   C   s  dd }dd }g }g }i }i }d}	d}
t |d p4g D ]\}}|d d	urt |d D ]H\}}||vr|d
 d |	 |d |
 f||< |||||d qX|d d	urt |d D ]H\}}||vr|d
 d |	 |d |
 f||< |||||d q|||||d d|	|d |	 d q8t |d D ]d\}}||v rX|| n||v rj|| nd}|||dt|dg |f d|d |d d q>t||d}t|| f }|S )zAProduces the HTML required to have a d3 visualization of the dag.c                 S   s   d|  S )Nzt%dr	   r    r	   r	   r
   
TensorName"  s    z!GenerateGraph.<locals>.TensorNamec                 S   s   d|  S )Nzo%dr	   r8   r	   r	   r
   OpName%  s    zGenerateGraph.<locals>.OpName      	operatorsinputsNg      ?   )sourcetargetoutputs)rA   r@   opcode_index   )idr   groupr#   yr/   )r   r   z%r (%d)r2   r   )nodesedges)r   appendgetattrjsondumps_D3_HTML_TEMPLATE)subgraph_idxgopcode_mapperr9   r:   rI   rH   firstsecondZ
pixel_multZ
width_multZop_indexopZtensor_input_positionZtensor_indexZtensor_output_positionr7   Z	initial_yZ	graph_strr5   r	   r	   r
   GenerateGraph  sd    






rU   Tc           	      C   s   d}|d7 }|d7 }|r |d7 }|D ]\}}|d| 7 }q$|d7 }t | D ]j\}}|d7 }|rj|d| 7 }|D ]<\}}||v r|| nd}|du r|n||}|d	| 7 }qn|d7 }qJ|d
7 }|S )a  Given a list of object values and keys to print, make an HTML table.

  Args:
    items: Items to print an array of dicts.
    keys_to_print: (key, display_fn). `key` is a key in the object. i.e.
      items[0][key] should exist. display_fn is the mapping function on display.
      i.e. the displayed html cell will have the string returned by
      `mapping_fn(items[0][key])`.
    display_index: add a column which is the index of each row in `items`.

  Returns:
    An html table.
  r   z<table><tr>
z<tr>
z<th>index</th>z<th>%s</th>z</tr>
z<td>%d</td>Nz<td>%s</td>
	</table>
)r   )	r   Zkeys_to_printdisplay_indexr5   hZmapperr    r7   r   r	   r	   r
   GenerateTableHtml[  s&    
rY   c                 C   s    t dd| }t dd| S )z2Converts an identifier in CamelCase to snake_case.z(.)([A-Z][a-z]+)z\1_\2z([a-z0-9])([A-Z]))resublower)Zcamel_case_inputs1r	   r	   r
   CamelCaseToSnakeCase  s    r^   c                    s   t | tst | tst | tr"| S t| dri }t| D ]H}| |}t|s8|d dkr8t|}|dkrndn }t	||||< q8|S t | t
jr r| S |  S t| dr fdd| D S | S d	S )
a  Converts a hierarchy of FB objects into a nested dict.

  We avoid transforming big parts of the flat buffer into python arrays. This
  speeds conversion from ten minutes to a few seconds on big graphs.

  Args:
    fb: a flat buffer structure. (i.e. ModelT)
    preserve_as_numpy: true if all downstream np.arrays should be preserved.
      false if all downstream np.array should become python arrays
  Returns:
    A dictionary representing the flatbuffer rather than a flatbuffer object.
  r   r   _buffersT__len__c                    s   g | ]}t | qS r	   )FlatbufferToDict).0entrypreserve_as_numpyr	   r
   
<listcomp>      z$FlatbufferToDict.<locals>.<listcomp>N)r   r   floatr   hasattrdir__getattribute__callabler^   rb   npZndarraytolist)Zfbrf   r   Zattribute_name	attributeZ
snake_namepreserver	   re   r
   rb     s     


rb   c                 C   s&   t j| d}t j|}t|ddS )Nr   Fre   )r   ZModelZGetRootAsModelZModelTZInitFromObjrb   )Zbuffer_dataZ	model_objmodelr	   r	   r
   CreateDictFromFlatbuffer  s    rs   c                 C   s  |rt j| std|  | ds0| drpt| d}t| }W d   n1 s\0    Y  t|}q| drt	
t| }qtdnt| }d}|t7 }|d	7 }|r| nd
|d< g d}|d7 }|D ].\}}|sdd }|d||||f 7 }q|d7 }dt fg}	dtfdtfdg}
|d D ]}t|d |d |d< q2t|d D ]\}}|d7 }t|}t|}d|fd|fdd|fg}dtfdtfd d!d"d#g}|d$| 7 }|d%7 }|t|d |d d&gd|fd|fgd'd(7 }|d)7 }|t|d* |7 }|d+ r,|d,7 }|t|d+ |7 }|d-|f 7 }|t|||7 }|d.7 }q\|d/7 }|t|d0 |	7 }|d17 }|t|d |
7 }|d27 }|S )3aH  Returns html description with the given tflite model.

  Args:
    tflite_input: TFLite flatbuffer model path or model object.
    input_is_filepath: Tells if tflite_input is a model path or a model object.

  Returns:
    Dump of the given tflite model in HTML format.

  Raises:
    RuntimeError: If the input is not valid.
  zInvalid filename %rz.tflitez.binrbNz.jsonz#Input file was not .tflite or .jsonr   z<h1>TensorFlow Lite Model</h2>zNull (used model object)filename))ru   NversionN)descriptionNz<table>
c                 S   s   | S r.   r	   )r#   r	   r	   r
   <lambda>  rh   zcreate_html.<locals>.<lambda>z <tr><th>%s</th><td>%s</td></tr>
rV   r   r   r   rv   r   Zdeprecated_builtin_codeZ	subgraphsz<div class='subgraph'>r>   rB   )Zbuiltin_optionsNrC   r   r1   )r2   N)r3   N)bufferN)ZquantizationNz<h2>Subgraph %d</h2>
z<h3>Inputs/Outputs</h3>
)r>   rB   F)rW   z<h3>Tensors</h3>
r/   r=   z<h3>Ops</h3>
z6<svg id='subgraph%d' width='1600' height='900'></svg>
z</div>z<h2>Buffers</h2>
r`   z<h2>Operator Codes</h2>
z</body></html>
)ospathexistsRuntimeErrorendswithopen	bytearrayreadrs   rL   load_CSSgetr+   r   r   maxr   r-   r   r   rY   rU   )tflite_inputZinput_is_filepathZfile_handle	file_datar   r5   Ztoplevel_stuffkeymappingZbuffer_keys_to_displayZoperator_keys_to_displayr!   rO   rP   Ztensor_mapperrQ   Zop_keys_to_displayZtensor_keys_to_displayr	   r	   r
   create_html  s    *



r   c                 C   sx   z| d }| d }W n" t y6   td| d   Y n>0 t|}t|d}|| W d    n1 sj0    Y  d S )Nr?   rD   z&Usage: %s <input tflite> <output html>r   w)
IndexErrorprintr   r   write)argvr   Zhtml_outputr5   Zoutput_filer	   r	   r
   main  s    r   __main__)T)T)"r*   rL   r{   rZ   sysnumpyrn   r|   splitext__file__r   joinZtensorflow.lite.pythonr   r   r   r   rN   r   r   r   objectr   r+   r-   rU   rY   r^   rb   rs   r   r   r'   r   r	   r	   r	   r
   <module>   s6   @f
<
& 
k
