o
    2hfE                     @   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s-d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ZG dd dZG dd dZdd 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reej! dS 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_runtime	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;}
/* Constrain table cells to a max size and make them scrollable. */
.data-table td {
  max-width: 900px;
}
.data-table .cell-content {
  max-height: 200px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
}
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   *   t jj D ]\}}|| kr|  S qdS )z4Converts a numerical enum to a readable tensor type.N)	schema_fb
TensorType__dict__items)tensor_typenamevalue r   Z/var/www/html/chatgem/venv/lib/python3.10/site-packages/tensorflow/lite/tools/visualize.pyTensorTypeToName   
   r   c                 C   r   )z3Converts a builtin op code enum to a readable name.N)r   BuiltinOperatorr   r	   )coder   r   r   r   r   BuiltinCodeToName   r   r   c                 C   s8   t | tr| S d}| dur| D ]
}|tt| }q|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                   @       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 )Nz%d bytesz--)len)r%   r*   r   r   r   r,     s   zDataSizeMapper.__call__N)r.   r/   r0   r1   r,   r   r   r   r   r2     s    r2   c                   @   r   )TensorMapperzGMaps a list of tensor indices to a tooltip hoverable indicator of more.c                 C   s
   || _ d S N)r&   )r%   subgraph_datar   r   r   r)     s   
zTensorMapper.__init__c                 C   s   d}|d u r|S |d7 }|D ]C}| j d | }|t|d 7 }|t|d d 7 }|t|d d 7 }|d|v r>t|d nd7 }|d	|v rLt|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   r4     s    r4   c              	   C   s   | sdS g }|   D ]C\}}t|}t|tr?t|dkr?|dd }|dd }ddtt| ddtt| d	}nt|}|| d
|  q
dd| dS )zBPretty-print the quantization dictionary, truncating large arrays.r      N
   i[z, z, ..., ]z: {})r	   r<   r   listr3   joinmapappend)q	items_strkeyr   key_strheadtail	value_strr   r   r   QuantizationMapper)  s   
rQ   c              	   C   s  dd }dd }g }g }i }i }d}	d}
t |d pg D ]{\}}|d d	urQt |d D ]$\}}||vrD|d
 d |	 |d |
 f||< |||||d q,|d d	urt |d D ]$\}}||vru|d
 d |	 |d |
 f||< |||||d q]|||||d d|	|d |	 d qt |d D ]/\}}||v r|| n	||v r|| nd}|||dt|dg |f d|d |d d qt||d}t|| f }|S )zAProduces the HTML required to have a d3 visualization of the dag.c                 S      d|  S )Nzt%dr   r'   r   r   r   
TensorNameA     z!GenerateGraph.<locals>.TensorNamec                 S   rR   )Nzo%dr   rS   r   r   r   OpNameD  rU   zGenerateGraph.<locals>.OpName      	operatorsinputsNg      ?   )sourcetargetoutputs)r]   r\   opcode_index   )idr   groupr*   yr7   )r   r   z%r (%d)r:   r   )nodesedges)r$   rI   getattrjsondumps_D3_HTML_TEMPLATE)subgraph_idxgopcode_mapperrT   rV   re   rd   firstsecond
pixel_mult
width_multop_indexoptensor_input_positiontensor_indextensor_output_positionr?   	initial_y	graph_strr=   r   r   r   GenerateGraph>  sd   







rx   Tc           	      C   s   d}|d7 }|d7 }|r|d7 }|D ]
\}}|d| 7 }q|d7 }t | D ]5\}}|d7 }|r5|d| 7 }|D ]\}}||v rC|| nd}|du rK|n||}|d	| 7 }q7|d7 }q%|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   <table class='data-table'>
z<tr>
z<th>index</th>z<th>%s</th>z</tr>
z<td>%d</td>Nz,<td><div class='cell-content'>%s</div></td>
	</table>
)r$   )	r	   keys_to_printdisplay_indexr=   hmapperr'   r?   r   r   r   r   GenerateTableHtmlz  s&   
r   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)camel_case_inputs1r   r   r   CamelCaseToSnakeCase  s   r   c                    s   t | tst | tst | tr| S t| drCi }t| D ]$}| |}t|s@|d dkr@t|}|dkr7dn }t	||||< q|S t | t
jrQ rM| S |  S t| dr_ fdd| D S | 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>  s    z$FlatbufferToDict.<locals>.<listcomp>)r   r   floatr   hasattrdir__getattribute__callabler   r   npndarraytolist)fbr   r   attribute_name	attribute
snake_namepreserver   r   r   r     s"   


r   c                 C   s&   t j| d}t j|}t|ddS )Nr   Fr   )r   ModelGetRootAsModelModelTInitFromObjr   )buffer_data	model_objmodelr   r   r   CreateDictFromFlatbuffer  s   r   c                 C   s  |rIt j| std|  | ds| dr8t| d}t| }W d   n1 s.w   Y  t|}n| drEt	
t| }ntdt| }d}|t7 }|d	7 }|r[| nd
|d< g d}|d7 }|D ]\}}|ssdd }|||}	|d||	f 7 }qi|d7 }dt fg}
dtfdtfdg}|d D ]}t|d |d |d< qt|d D ]}\}}|d7 }t|}t|}d|fd|fdd|fg}dtfdtfd d!d"d#tf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))r   NversionN)descriptionNry   c                 S   s   | S r5   r   )r*   r   r   r   <lambda>  s    zcreate_html.<locals>.<lambda>z@<tr><th>%s</th><td><div class='cell-content'>%s</div></td></tr>
rz   r&   r    r"   r   r   deprecated_builtin_code	subgraphsz<div class='subgraph'>rZ   r^   )builtin_optionsNr_   r   r9   )r:   N)r;   N)bufferNquantizationz<h2>Subgraph %d</h2>
z<h3>Inputs/Outputs</h3>
)rZ   r^   F)r|   z<h3>Tensors</h3>
r7   rY   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readr   rg   load_CSSgetr2   r   r   maxr$   r4   r   r   rQ   r   rx   )tflite_inputinput_is_filepathfile_handle	file_datar&   r=   toplevel_stuffrL   mappingr   buffer_keys_to_displayoperator_keys_to_displayr(   rj   rk   tensor_mapperrl   op_keys_to_displaytensor_keys_to_displayr   r   r   create_html  s   



r   c                 C   s|   z
| d }| d }W n t y   td| d   Y d S w t|}t|d}|| W d    d S 1 s7w   Y  d S )Nr[   r`   z&Usage: %s <input tflite> <output html>r   w)
IndexErrorprintr   r   write)argvr   html_outputr=   output_filer   r   r   main9  s   "r   __main__)T)"r1   rg   r   r   sysnumpyr   r   splitext__file__r   rG   tensorflow.lite.pythonr   r   r   r   ri   r   r   r   r   r2   r4   rQ   rx   r   r   r   r   r   r   r.   r   r   r   r   r   <module>   s<   Jf

<& 
m