aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/tensorboard/components/tf-graph-loader/tf-graph-loader.html
blob: 3f290f215244176a1031ad0f1ecea4476f5578a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<link rel="import" href="../../bower_components/polymer/polymer.html">

<!--
An element which provides a filter parsing for pbtxt to graph output.
-->
<dom-module id="tf-graph-loader">
</dom-module>

<script>
Polymer({

  is: 'tf-graph-loader',

  properties: {
    /**
     * @type {value: number, msg: string}
     *
     * A number between 0 and 100 denoting the % of progress
     * for the progress bar and the displayed message.
     */
    progress: {
      type: Object,
      notify: true,
      readOnly: true // Produces, does not consume.
    },
    datasets: Array,
    hasStats: {
      type: Boolean,
      readOnly: true, // This property produces data.
      notify: true
    },
    selectedDataset: Number,
    selectedFile: {
      type: Object,
      observer: '_selectedFileChanged'
    },
    outGraphHierarchy: {
      type: Object,
      readOnly: true, //readonly so outsider can't change this via binding
      notify: true
    },
    outGraph: {
      type: Object,
      readOnly: true, //readonly so outsider can't change this via binding
      notify: true
    },
    outGraphName: {
      type: String,
      readOnly: true,
      notify: true
    }
  },
  observers: [
    '_selectedDatasetChanged(selectedDataset, datasets)'
  ],
  _parseAndConstructHierarchicalGraph: function(dataset, pbTxtContent) {
    var self = this;
    // Reset the progress bar to 0.
    self._setProgress({
      value: 0,
      msg: ''
    });
    var tracker = {
      setMessage: function(msg) {
        self._setProgress({
          value: self.progress.value,
          msg: msg
        });
      },
      updateProgress: function(value) {
        self._setProgress({
          value: self.progress.value + value,
          msg: self.progress.msg
        });
      },
      reportError: function(msg) {
        self._setProgress({
          value: self.progress.value,
          msg: msg,
          error: true
        });
      },
    };
    var statsJson;
    var dataTracker = tf.getSubtaskTracker(tracker, 30, 'Data');
    tf.graph.parser.readAndParseData(dataset, pbTxtContent, dataTracker)
    .then(function(result) {
      // Build the flat graph (consists only of Op nodes).
      var nodes = result.nodes;
      statsJson = result.statsJson;

      // This is the whitelist of inputs on op types that are considered
      // reference edges. "Assign 0" indicates that the first input to
      // an OpNode with operation type "Assign" is a reference edge.
      var refEdges = {};
      refEdges["Assign 0"] = true;
      refEdges["AssignAdd 0"] = true;
      refEdges["AssignSub 0"] = true;
      refEdges["assign 0"] = true;
      refEdges["assign_add 0"] = true;
      refEdges["assign_sub 0"] = true;
      refEdges["count_up_to 0"] = true;
      refEdges["ScatterAdd 0"] = true;
      refEdges["ScatterSub 0"] = true;
      refEdges["ScatterUpdate 0"] = true;
      refEdges["scatter_add 0"] = true;
      refEdges["scatter_sub 0"] = true;
      refEdges["scatter_update 0"] = true;
      var buildParams = {
        enableEmbedding: true,
        inEmbeddingTypes: ['Const'],
        outEmbeddingTypes: ['^[a-zA-Z]+Summary$'],
        refEdges: refEdges
      };
      var graphTracker = tf.getSubtaskTracker(tracker, 20,
          'Graph');
      return tf.graph.build(nodes, buildParams, graphTracker);
    })
    .then(function(graph) {
      this._setOutGraph(graph);
      if (statsJson) {
        // If there are associated stats, join them with the graph.
        tf.time('Joining stats info with graph...', function() {
          tf.graph.joinStatsInfoWithGraph(graph, statsJson);
        });
      }
      var hierarchyParams = {
        verifyTemplate: true,
        groupSeries: true,
      };
      var hierarchyTracker = tf.getSubtaskTracker(tracker, 50,
          'Namespace hierarchy');
      return tf.graph.hierarchy.build(graph, hierarchyParams, hierarchyTracker);
    }.bind(this))
    .then(function(graphHierarchy) {
      // Update the properties which notify the parent with the
      // graph hierarchy and whether the data has live stats or not.
      this._setHasStats(statsJson != null);
      this._setOutGraphHierarchy(graphHierarchy);
    }.bind(this))
    .catch(function(reason) {
      tracker.reportError("Graph visualization failed: " + reason);
    });
  },
  _selectedDatasetChanged: function(datasetIndex, datasets) {
    var dataset = datasets[datasetIndex];
    this._parseAndConstructHierarchicalGraph(dataset);
    this._setOutGraphName(dataset.name);
  },
  _selectedFileChanged: function(e) {
    if (!e) {
      return;
    }
    var file = e.target.files[0];
    if (!file) {
      return;
    }

    // Clear out the value of the file chooser. This ensures that if the user
    // selects the same file, we'll re-read it.
    e.target.value = '';

    var reader = new FileReader();

    reader.onload = function(e) {
      this._parseAndConstructHierarchicalGraph(null, e.target.result);
    }.bind(this);

    reader.readAsText(file);
  }
});
</script>