Readable Dump Documentation
Overview
Readable Dump is a high-readability graph structure export format provided by GE (Graph Engine), using text representation similar to Dynamo fx graph style, facilitating developers to directly read and understand computation graph structures.
Design Principles
Readability as highest priority, simplicity over completeness:
- Display method: Through function-call-like approach, display IR attributes, inputs, outputs information
- Information filtering: Non-IR defined information like control edges and private attributes not displayed (affects overall readability)
- Value abbreviation: Values carried by Const use abbreviated display, see Appendix: Const Constant Display Rules
readable File Parsing
Example 1: Below is a complete ge_readable*.txt file:
graph("MakeTransformerSubGraph"):
%input_0 : [#users=1] = Node[type=Data] (attrs = {index: 0})
%input_1 : [#users=1] = Node[type=Data] (attrs = {index: 1})
%input_2 : [#users=1] = Node[type=Data] (attrs = {index: 2})
%Const_0 : [#users=1] = Node[type=Const] (attrs = {value: [-1 7168]})
%Reshape_1 : [#users=1] = Node[type=Reshape] (inputs = (x=%input_0, shape=%Const_0), attrs = {axis: 0, num_axes: -1})
%Cast_2 : [#users=1] = Node[type=Cast] (inputs = (x=%Reshape_1), attrs = {dst_type: 0})
%Cast_3 : [#users=1] = Node[type=Cast] (inputs = (x=%input_1), attrs = {dst_type: 0})
%Const_4 : [#users=1] = Node[type=Const] (attrs = {value: [1 0]})
%Transpose_5 : [#users=1] = Node[type=Transpose] (inputs = (x=%Cast_3, perm=%Const_4))
%MatMul_6 : [#users=1] = Node[type=MatMul] (inputs = (x1=%Cast_2, x2=%Transpose_5), attrs = {transpose_x1: false, transpose_x2: false})
%Sigmoid_7 : [#users=1] = Node[type=Sigmoid] (inputs = (x=%MatMul_6))
%Const_8 : [#users=1] = Node[type=Const] (attrs = {value: [-1 256]})
%Reshape_9 : [#users=1] = Node[type=Reshape] (inputs = (x=%Sigmoid_7, shape=%Const_8), attrs = {axis: 0, num_axes: -1})
%Unsqueeze_10 : [#users=1] = Node[type=Unsqueeze] (inputs = (x=%input_2), attrs = {axes: {0}})
%Cast_11 : [#users=1] = Node[type=Cast] (inputs = (x=%Unsqueeze_10), attrs = {dst_type: 0})
%Add_12 : [#users=1] = Node[type=Add] (inputs = (x1=%Reshape_9, x2=%Cast_11))
%Const_13 : [#users=1] = Node[type=Const] (attrs = {value: [2]})
%TopKV2_14 : [#users=2] = Node[type=TopKV2] (inputs = (x=%Add_12, k=%Const_13), attrs = {sorted: true, dim: -1, largest: true, indices_dtype: 3})
%ret : [users=1] = get_element[node=%TopKV2_14](0)
%ret_1 : [users=0] = get_element[node=%TopKV2_14](1)
%Const_15 : [#users=1] = Node[type=Const] (attrs = {value: [-1]})
%ReduceSum_16 : [#users=1] = Node[type=ReduceSum] (inputs = (x=%ret, axes=%Const_15), attrs = {keep_dims: false, noop_with_empty_axes: true})
%Const_17 : [#users=1] = Node[type=Const] (attrs = {value: [4]})
%TopKV2_18 : [#users=2] = Node[type=TopKV2] (inputs = (x=%ReduceSum_16, k=%Const_17), attrs = {sorted: false, dim: -1, largest: true, indices_dtype: 3})
%ret_2 : [users=0] = get_element[node=%TopKV2_18](0)
%ret_3 : [users=1] = get_element[node=%TopKV2_18](1)
%Cast_19 : [#users=1] = Node[type=Cast] (inputs = (x=%ret_3), attrs = {dst_type: 9})
%ZerosLike_20 : [#users=1] = Node[type=ZerosLike] (inputs = (x=%ReduceSum_16))
%Shape_21 : [#users=1] = Node[type=Shape] (inputs = (x=%Cast_19), attrs = {dtype: 3})
%Const_22 : [#users=1] = Node[type=Const] (attrs = {value: [1.000000]})
%Cast_23 : [#users=1] = Node[type=Cast] (inputs = (x=%Const_22), attrs = {dst_type: 0})
%Fill_24 : [#users=1] = Node[type=Fill] (inputs = (dims=%Shape_21, value=%Cast_23))
%ScatterElements_25 : [#users=1] = Node[type=ScatterElements] (inputs = (data=%ZerosLike_20, indices=%Cast_19, updates=%Fill_24), attrs = {axis: 0, reduction: "none"})
%Unsqueeze_26 : [#users=1] = Node[type=Unsqueeze] (inputs = (x=%ScatterElements_25), attrs = {axes: {-1}})
%Const_27 : [#users=1] = Node[type=Const] (attrs = {value: [256 256]})
%BroadcastTo_28 : [#users=1] = Node[type=BroadcastTo] (inputs = (x=%Unsqueeze_26, shape=%Const_27))
%Identity_29 : [#users=1] = Node[type=Identity] (inputs = (x=%BroadcastTo_28))
%Const_30 : [#users=1] = Node[type=Const] (attrs = {value: [256 256]})
%Reshape_31 : [#users=1] = Node[type=Reshape] (inputs = (x=%Identity_29, shape=%Const_30), attrs = {axis: 0, num_axes: -1})
%Cast_32 : [#users=1] = Node[type=Cast] (inputs = (x=%Reshape_31), attrs = {dst_type: 12})
%LogicalNot_33 : [#users=1] = Node[type=LogicalNot] (inputs = (x=%Cast_32))
%Const_34 : [#users=1] = Node[type=Const] (attrs = {value: [0.000000]})
%MaskedFill_35 : [#users=1] = Node[type=MaskedFill] (inputs = (x=%Add_12, mask=%LogicalNot_33, value=%Const_34))
%Const_36 : [#users=1] = Node[type=Const] (attrs = {value: [4]})
%TopKV2_37 : [#users=2] = Node[type=TopKV2] (inputs = (x=%MaskedFill_35, k=%Const_36), attrs = {sorted: false, dim: -1, largest: true, indices_dtype: 3})
%ret_4 : [users=0] = get_element[node=%TopKV2_37](0)
%ret_5 : [users=1] = get_element[node=%TopKV2_37](1)
%Cast_38 : [#users=1] = Node[type=Cast] (inputs = (x=%ret_5), attrs = {dst_type: 9})
%GatherElements_39 : [#users=1] = Node[type=GatherElements] (inputs = (x=%Sigmoid_7, index=%Cast_38), attrs = {dim: 1})
%Const_40 : [#users=1] = Node[type=Const] (attrs = {value: [0.000001]})
%RealDiv_41 : [#users=1] = Node[type=RealDiv] (inputs = (x1=%GatherElements_39, x2=%Const_40))
%Const_42 : [#users=1] = Node[type=Const] (attrs = {value: [2.500000]})
%Mul_43 : [#users=1] = Node[type=Mul] (inputs = (x1=%RealDiv_41, x2=%Const_42))
%Cast_44 : [#users=1] = Node[type=Cast] (inputs = (x=%Mul_43), attrs = {dst_type: 0})
return (output_0=%Cast_38, output_1=%Cast_44)
Example 2: Below is a file containing subgraphs:
graph("TransformerBlockSubgraph"):
%input_0 : [#users=1] = Node[type=Data] (attrs = {index: 0})
%pred_1 : [#users=1] = Node[type=Data] (attrs = {index: 1})
%If_0 : [#users=1] = Node[type=If] (inputs = (cond=%pred_1, input_0=%input_0), attrs = {then_branch: %If_then, else_branch: %If_else})
%Const_1 : [#users=1] = Node[type=Const] (attrs = {value: [0]})
%Const_2 : [#users=1] = Node[type=Const] (attrs = {value: [4]})
%Const_3 : [#users=1] = Node[type=Const] (attrs = {value: [1]})
%For_6 : [#users=2] = Node[type=For] (inputs = (start=%Const_1, limit=%Const_2, delta=%Const_3, input_1=%If_0), attrs = {body: %For_body})
%ret : [users=1] = get_element[node=%For_6](0)
%ret_1 : [users=1] = get_element[node=%For_6](1)
return (output_0=%ret, output_1=%ret_1)
graph("If_then"):
%input_0 : [#users=1] = Node[type=Data] (attrs = {index: 0})
%Const_0 : [#users=1] = Node[type=Const] (attrs = {value: [0.900000]})
%Mul_1 : [#users=1] = Node[type=Mul] (inputs = (x1=%input_0, x2=%Const_0))
return (%Mul_1)
graph("If_else"):
%input_0 : [#users=1] = Node[type=Data] (attrs = {index: 0})
%Identity_0 : [#users=1] = Node[type=Identity] (inputs = (x=%input_0))
return (%Identity_0)
graph("For_body"):
%iter : [#users=1] = Node[type=Data] (attrs = {index: 0})
%hidden : [#users=1] = Node[type=Data] (attrs = {index: 1})
%Const_0 : [#users=1] = Node[type=Const] (attrs = {value: [1]})
%Add_0 : [#users=1] = Node[type=Add] (inputs = (x1=%iter, x2=%Const_0))
%Const_1 : [#users=1] = Node[type=Const] (attrs = {value: [0.500000]})
%Mul_1 : [#users=1] = Node[type=Mul] (inputs = (x1=%hidden, x2=%Const_1))
%Add_2 : [#users=1] = Node[type=Add] (inputs = (x1=%hidden, x2=%Mul_1))
return (output_0=%Add_0, output_1=%Add_2)
Field explanations:
- Graph name:
graph("<graph_name>"). - Node instance:
%<node_instance_name> : [#users=<out_degree>] = Node[type=<node_type>](inputs = (<input_name1>=%<input_instance1>, ...), attrs = {<attribute_name1>: <attribute_value1>, ...}).%<node_instance_name>: Node instance name.[#users=<out_degree>]: Number of node outputs.Node[type=<node_type>]: Operator type corresponding to the node, for example MatMul node displays asNode[type=MatMul].inputs = (<input_name1>=%<input_instance1>, ...): Node inputs are displayed in "parameter_name=instance_name" format; when parameter name parsing fails, it falls back to_input_Nsequence. This field is omitted when the node has no inputs.- Dynamic inputs: Dynamic input parameters use
input_name_#cntnumbering format (input_name_0, input_name_1, ...).
- Dynamic inputs: Dynamic input parameters use
attrs = {<attribute_name1>: <attribute_value1>, ...}: Node attribute collection, containing subgraph attribute items and regular attribute items. This field is omitted when attributes are empty.
- Multi-output node output reference:
%ret/ret_#cnt : [#users=<consumer_count>] = get_element[node=%<node_instance_name>](<output_index>).%ret/ret_#cnt: Each output of a multi-output node uses the unified ret namingret, ret_1, ret_2, ....[#users=<consumer_count>]: Number of consumers for this output.get_element[node=%<node_instance_name>](<output_index>): Usesget_elementto represent "extract the<output_index>-th output from a multi-output node".
- Graph output:
return (<output_list>)Represents graph output, corresponding toNetOutputnode inputs.- Single output:
return (%<output_instance>). - Multiple outputs:
return (output_0=%<output_instance0>, output_1=%<output_instance1>, ...). Outputs useoutput_#cntnumbering format (output_0, output_1, ...).
- Single output:
- Subgraph representation:
Nodes containing subgraphs are represented according to the following rules:
- Subgraph declaration: Declared in parent node's
attrs:attrs = {<subgraph_attribute_name>: %<subgraph_instance_name>, ... }; when subgraph attribute name parsing fails, it falls back to_graph_Nsequence. - Input correspondence: Parent node input
input_#cnt(orargs_#cnt) corresponds to theDatanode withindexattribute value ofcntin the subgraph. For example: Parent node'sinput_0→ Subgraph'sData(attrs = {index: 0}). - Output correspondence:
- Single output: Subgraph return value directly serves as parent node output.
- Multiple outputs: Subgraph output
output_#cntcorresponds to parent node'scnt-th output. Parent node extracts corresponding output viaget_element[node=%<parent_node>](cnt).
- Subgraph display position:
Subgraph content is displayed separately after the main parent graph output ends; each subgraph starts with
graph("<subgraph_instance_name>"):.
- Subgraph declaration: Declared in parent node's
Appendix
Const Constant Display Rules
To balance readability and information completeness, the value attribute of Const nodes is displayed with the following abbreviation rules:
- No value attribute: Not displayed
- Empty tensor: Indicates no data content, displayed as
value: <empty> - Single value: Represents scalar
[]or single element[1], displays the actual value directly, e.g.value: [1.5] - Multiple values: When values exceed 6, use abbreviated form keeping first 3 and last 3 values, e.g.
value: [1 2 3 ... 98 99 100] - Unsupported data type: Displayed as
value: <not_supported>