diff --git a/WORKSPACE b/WORKSPACE
index 60b69a9c1a7..981ac77ea46 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -56,7 +56,7 @@ new_git_repository(
new_git_repository(
name = "iron_a11y_keys_behavior",
build_file = "bower.BUILD",
- remote = "https://github.com/PolymerElements/iron-a11y-keys-behavior.git",
+ remote = "https://github.com/polymerelements/iron-a11y-keys-behavior.git",
tag = "v1.1.1",
)
@@ -77,7 +77,7 @@ new_git_repository(
new_git_repository(
name = "iron_behaviors",
build_file = "bower.BUILD",
- remote = "https://github.com/polymerelements/iron-behaviors.git",
+ remote = "https://github.com/PolymerElements/iron-behaviors.git",
tag = "v1.0.13",
)
@@ -168,7 +168,7 @@ new_git_repository(
new_git_repository(
name = "iron_meta",
build_file = "bower.BUILD",
- remote = "https://github.com/PolymerElements/iron-meta.git",
+ remote = "https://github.com/polymerelements/iron-meta.git",
tag = "v1.1.1",
)
@@ -322,7 +322,7 @@ new_git_repository(
new_git_repository(
name = "paper_ripple",
build_file = "bower.BUILD",
- remote = "https://github.com/polymerelements/paper-ripple.git",
+ remote = "https://github.com/PolymerElements/paper-ripple.git",
tag = "v1.0.5",
)
@@ -371,7 +371,7 @@ new_git_repository(
new_git_repository(
name = "polymer",
build_file = "bower.BUILD",
- remote = "https://github.com/polymer/polymer.git",
+ remote = "https://github.com/Polymer/polymer.git",
tag = "v1.3.1",
)
diff --git a/tensorflow/tensorboard/TAG b/tensorflow/tensorboard/TAG
index b1bd38b62a0..8351c19397f 100644
--- a/tensorflow/tensorboard/TAG
+++ b/tensorflow/tensorboard/TAG
@@ -1 +1 @@
-13
+14
diff --git a/tensorflow/tensorboard/dist/tf-tensorboard.html b/tensorflow/tensorboard/dist/tf-tensorboard.html
index 3fcd43c7d54..492a5d45cee 100644
--- a/tensorflow/tensorboard/dist/tf-tensorboard.html
+++ b/tensorflow/tensorboard/dist/tf-tensorboard.html
@@ -16,8 +16,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
-///
var TF;
(function (TF) {
/* The DataCoordinator generates TF.Datasets for each run/tag combination,
@@ -65,11 +63,16 @@ var TF;
return dataset;
};
return DataCoordinator;
- })();
+ }());
TF.DataCoordinator = DataCoordinator;
})(TF || (TF = {}));
-
@@ -770,8 +766,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
-///
var TF;
(function (TF) {
var Urls;
@@ -791,8 +785,18 @@ var TF;
function individualImageUrl(query) {
return "/data/individualImage?" + query;
}
- function graphUrl(run) {
- return "/data/graph?run=" + encodeURIComponent(run);
+ function graphUrl(run, limit_attr_size, large_attrs_key) {
+ var query_params = [["run", run]];
+ if (limit_attr_size != null) {
+ query_params.push(["limit_attr_size", String(limit_attr_size)]);
+ }
+ if (large_attrs_key != null) {
+ query_params.push(["large_attrs_key", large_attrs_key]);
+ }
+ var query = query_params.map(function (param) {
+ return param[0] + "=" + encodeURIComponent(param[1]);
+ }).join("&");
+ return "/data/graph?" + query;
}
return {
runs: function () { return "/data/runs"; },
@@ -806,7 +810,21 @@ var TF;
}
Urls.productionRouter = productionRouter;
;
- function demoRouter(dataDir) {
+ function demoRouter(dataDir, oldVersion) {
+ if (oldVersion === void 0) { oldVersion = false; }
+ if (oldVersion) {
+ return {
+ runs: function () { return dataDir + "runs.json"; },
+ graph: function (run) { return dataDir + run + "-graph.pbtxt"; },
+ scalars: function (tag, run) {
+ return dataDir + run.split("_")[0] + ".json";
+ },
+ histograms: function () { return null; },
+ compressedHistograms: function () { return null; },
+ images: function () { return null; },
+ individualImage: function () { return null; }
+ };
+ }
/* Retrieves static .json data generated by demo_from_server.py */
function demoRoute(route) {
return function (tag, run) {
@@ -858,7 +876,7 @@ var TF;
},
};
TF.Urls.routes.forEach(function(route) {
- /* for each route (other than runs, handled seperately):
+ /* for each route (other than runs, handled separately):
* out`RouteName`: {
* type: Function,
* readOnly: true,
@@ -1254,7 +1272,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
var Categorizer;
(function (Categorizer) {
/* Canonical TensorFlow ops are namespaced using forward slashes.
@@ -1568,11 +1585,16 @@ var Plottable;
draw();
};
return DragZoomLayer;
- })(Plottable.Components.SelectionBoxLayer);
+ }(Plottable.Components.SelectionBoxLayer));
Plottable.DragZoomLayer = DragZoomLayer;
})(Plottable || (Plottable = {}));
-
@@ -2527,7 +2540,6 @@ Polymer({
progress: {
type: Object,
notify: true,
- readOnly: true // Produces, does not consume.
},
datasets: Array,
hasStats: {
@@ -2554,39 +2566,35 @@ Polymer({
type: String,
readOnly: true,
notify: true
- }
+ },
+ outHierarchyParams: {
+ type: Object,
+ readOnly: true,
+ notify: true
+ },
},
observers: [
'_selectedDatasetChanged(selectedDataset, datasets)'
],
_parseAndConstructHierarchicalGraph: function(dataset, pbTxtContent) {
- var self = this;
// Reset the progress bar to 0.
- self._setProgress({
+ this.set('progress', {
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 tracker = tf.getTracker(this);
+ var hierarchyParams = {
+ verifyTemplate: true,
+ // If a set of numbered op nodes has at least this number of nodes
+ // then group them into a series node.
+ seriesNodeMinSize: 5,
+ // A map of series node names to series grouping settings, to indicate
+ // if a series is to be rendered as grouped or ungrouped.
+ // Starts out empty which allows the renderer to decide which series
+ // are initially rendered grouped and which aren't.
+ seriesMap: {},
};
+ this._setOutHierarchyParams(hierarchyParams);
var statsJson;
var dataTracker = tf.getSubtaskTracker(tracker, 30, 'Data');
tf.graph.parser.readAndParseData(dataset, pbTxtContent, dataTracker)
@@ -2630,12 +2638,6 @@ Polymer({
tf.graph.joinStatsInfoWithGraph(graph, statsJson);
});
}
- var hierarchyParams = {
- verifyTemplate: true,
- // If a set of numbered op nodes has at least this number of nodes
- // then group them into a series node.
- seriesNodeMinSize: 5,
- };
var hierarchyTracker = tf.getSubtaskTracker(tracker, 50,
'Namespace hierarchy');
return tf.graph.hierarchy.build(graph, hierarchyParams, hierarchyTracker);
@@ -2646,8 +2648,10 @@ Polymer({
this._setHasStats(statsJson != null);
this._setOutGraphHierarchy(graphHierarchy);
}.bind(this))
- .catch(function(reason) {
- tracker.reportError("Graph visualization failed: " + reason);
+ .catch(function(e) {
+ // Generic error catch, for errors that happened outside
+ // asynchronous tasks.
+ tracker.reportError("Graph visualization failed: " + e, e);
});
},
_selectedDatasetChanged: function(datasetIndex, datasets) {
@@ -2692,7 +2696,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
var tf;
(function (tf) {
/**
@@ -2709,6 +2712,40 @@ var tf;
return result;
}
tf.time = time;
+ /**
+ * Creates a tracker that sets the progress property of the
+ * provided polymer component. The provided component must have
+ * a property called 'progress' that is not read-only. The progress
+ * property is an object with a numerical 'value' property and a
+ * string 'msg' property.
+ */
+ function getTracker(polymerComponent) {
+ return {
+ setMessage: function (msg) {
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value,
+ msg: msg
+ });
+ },
+ updateProgress: function (value) {
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value + value,
+ msg: polymerComponent.progress.msg
+ });
+ },
+ reportError: function (msg, err) {
+ // Log the stack trace in the console.
+ console.error(err.stack);
+ // And send a user-friendly message to the UI.
+ polymerComponent.set("progress", {
+ value: polymerComponent.progress.value,
+ msg: msg,
+ error: true
+ });
+ },
+ };
+ }
+ tf.getTracker = getTracker;
/**
* Creates a tracker for a subtask given the parent tracker, the total progress
* of the subtask and the subtask message. The parent task should pass a
@@ -2720,7 +2757,7 @@ var tf;
setMessage: function (progressMsg) {
// The parent should show a concatenation of its message along with
// its subtask tracker message.
- parentTracker.setMessage(subtaskMsg + " : " + progressMsg);
+ parentTracker.setMessage(subtaskMsg + ": " + progressMsg);
},
updateProgress: function (incrementValue) {
// Update the parent progress relative to the child progress.
@@ -2729,10 +2766,10 @@ var tf;
parentTracker
.updateProgress(incrementValue * impactOnTotalProgress / 100);
},
- reportError: function (errorMsg) {
+ reportError: function (msg, err) {
// The parent should show a concatenation of its message along with
// its subtask error message.
- parentTracker.reportError(subtaskMsg + " : " + errorMsg);
+ parentTracker.reportError(subtaskMsg + ": " + msg, err);
}
};
}
@@ -2755,7 +2792,9 @@ var tf;
resolve(result);
}
catch (e) {
- reject(result);
+ // Errors that happen inside asynchronous tasks are
+ // reported to the tracker using a user-friendly message.
+ tracker.reportError("Failed " + msg, e);
}
}, ASYNC_TASK_DELAY);
});
@@ -2785,8 +2824,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
-///
var tf;
(function (tf) {
var graph;
@@ -2794,6 +2831,13 @@ var tf;
/** Delimiter used in node names to denote namespaces. */
graph_1.NAMESPACE_DELIM = "/";
graph_1.ROOT_NAME = "__root__";
+ /** Attribute key used for storing attributes that are too large. */
+ graph_1.LARGE_ATTRS_KEY = "_too_large_attrs";
+ /**
+ * Maximum allowed size in bytes, before the attribute is considered large
+ * and filtered out of the graph.
+ */
+ graph_1.LIMIT_ATTR_SIZE = 1024;
// Separator between the source and the destination name of the edge.
graph_1.EDGE_KEY_DELIM = "--";
(function (GraphType) {
@@ -2825,6 +2869,15 @@ var tf;
})(graph_1.InclusionType || (graph_1.InclusionType = {}));
var InclusionType = graph_1.InclusionType;
;
+ /** Indicates if a series is to be grouped in the graph when rendered. */
+ (function (SeriesGroupingType) {
+ SeriesGroupingType[SeriesGroupingType["GROUP"] = 0] = "GROUP";
+ SeriesGroupingType[SeriesGroupingType["UNGROUP"] = 1] = "UNGROUP";
+ })(graph_1.SeriesGroupingType || (graph_1.SeriesGroupingType = {}));
+ var SeriesGroupingType = graph_1.SeriesGroupingType;
+ ;
+ /** Attribute key reserved for the shapes of the output tensors. */
+ var OUTPUT_SHAPES_KEY = "_output_shapes";
/**
* A SlimGraph is inspired by graphlib.Graph, but having only the functionality
* that we need.
@@ -2835,7 +2888,7 @@ var tf;
this.edges = [];
}
return SlimGraph;
- })();
+ }());
graph_1.SlimGraph = SlimGraph;
var EllipsisNodeImpl = (function () {
/**
@@ -2857,7 +2910,7 @@ var tf;
this.name = "... " + numNodes + " more";
};
return EllipsisNodeImpl;
- })();
+ }());
graph_1.EllipsisNodeImpl = EllipsisNodeImpl;
;
/**
@@ -2869,17 +2922,18 @@ var tf;
* Constructs a new Op node.
*
* @param rawNode The raw node.
- * @param normalizedInputs An array of normalized
- * inputs that denote the incoming edges to the current node. Each input
- * contains the normalized name of the source node, whether it has a
- * number part and whether it is a control dependency.
*/
- function OpNodeImpl(rawNode, normalizedInputs) {
+ function OpNodeImpl(rawNode) {
this.op = rawNode.op;
this.name = rawNode.name;
this.device = rawNode.device;
this.attr = rawNode.attr;
- this.inputs = normalizedInputs;
+ // An array of normalized inputs that denote the incoming edges to
+ // the current node. Each input contains the normalized name of the
+ // source node, whether it has a number part and whether it is a
+ // control dependency.
+ this.inputs = normalizeInputs(rawNode.input);
+ this.outputShapes = extractOutputShapes(rawNode.attr);
// additional properties
this.type = NodeType.OP;
this.isGroupNode = false;
@@ -2888,9 +2942,10 @@ var tf;
this.outEmbeddings = [];
this.parentNode = null;
this.include = InclusionType.UNSPECIFIED;
+ this.owningSeries = null;
}
return OpNodeImpl;
- })();
+ }());
;
function createMetanode(name, opt) {
if (opt === void 0) { opt = {}; }
@@ -2912,11 +2967,11 @@ var tf;
nodeStats.nodeName + graph_1.NAMESPACE_DELIM + "(" + nodeStats.nodeName + ")";
if (nodeName in graph.nodes) {
// Compute the total bytes used.
- var totalBytes = 0;
+ var totalBytes_1 = 0;
if (nodeStats.memory) {
_.each(nodeStats.memory, function (alloc) {
if (alloc.totalBytes) {
- totalBytes += Number(alloc.totalBytes);
+ totalBytes_1 += Number(alloc.totalBytes);
}
});
}
@@ -2926,7 +2981,7 @@ var tf;
return _.map(output.tensorDescription.shape.dim, function (dim) { return Number(dim.size); });
});
}
- graph.nodes[nodeName].stats = new NodeStats(totalBytes, Number(nodeStats.allEndRelMicros), outputSize);
+ graph.nodes[nodeName].stats = new NodeStats(totalBytes_1, Number(nodeStats.allEndRelMicros), outputSize);
}
});
});
@@ -2955,7 +3010,7 @@ var tf;
}
};
return NodeStats;
- })();
+ }());
graph_1.NodeStats = NodeStats;
var MetanodeImpl = (function () {
/** A label object for meta-nodes in the graph hierarchy */
@@ -3025,7 +3080,7 @@ var tf;
return leaves;
};
return MetanodeImpl;
- })();
+ }());
;
function createMetaedge(v, w) {
return new MetaedgeImpl(v, w);
@@ -3043,8 +3098,9 @@ var tf;
this.numRegularEdges = 0;
this.numControlEdges = 0;
this.numRefEdges = 0;
+ this.totalSize = 0;
}
- MetaedgeImpl.prototype.addBaseEdge = function (edge) {
+ MetaedgeImpl.prototype.addBaseEdge = function (edge, h) {
this.baseEdgeList.push(edge);
if (edge.isControlDependency) {
this.numControlEdges += 1;
@@ -3055,9 +3111,39 @@ var tf;
if (edge.isReferenceEdge) {
this.numRefEdges += 1;
}
+ // Compute the size of the tensor flowing through this
+ // base edge.
+ this.totalSize += MetaedgeImpl.computeSizeOfEdge(edge, h);
+ };
+ MetaedgeImpl.computeSizeOfEdge = function (edge, h) {
+ var opNode = h.node(edge.v);
+ if (opNode.outputShapes == null) {
+ // No shape information. Asssume a single number. This gives
+ // a lower bound for the total size.
+ return 1;
+ }
+ // Sum the sizes of all output tensors.
+ return _(opNode.outputShapes).map(function (shape) {
+ // If the shape is unknown, treat it as 1 when computing
+ // total size. This gives a lower bound for the total size.
+ if (shape == null) {
+ return 1;
+ }
+ // Multiply all shapes to get the total size of the tensor.
+ // E.g. The total size of [4, 2, 1] is 4 * 2 * 1.
+ return _(shape).reduce(function (accumulated, currSize) {
+ // If this particular dimension is unknown, treat
+ // it as 1 when computing total size. This gives a lower bound
+ // for the total size.
+ if (currSize === -1) {
+ currSize = 1;
+ }
+ return accumulated * currSize;
+ }, 1);
+ }).sum();
};
return MetaedgeImpl;
- })();
+ }());
function createSeriesNode(prefix, suffix, parent, clusterId, name) {
return new SeriesNodeImpl(prefix, suffix, parent, clusterId, name);
}
@@ -3091,7 +3177,49 @@ var tf;
this.include = InclusionType.UNSPECIFIED;
}
return SeriesNodeImpl;
- })();
+ }());
+ /**
+ * Extracts the shapes of the output tensors from the attr property in the
+ * node proto.
+ */
+ function extractOutputShapes(attr) {
+ var result = null;
+ // We don't know anything about the output tensors.
+ if (!attr) {
+ return null;
+ }
+ for (var i = 0; i < attr.length; i++) {
+ var _a = attr[i], key = _a.key, value = _a.value;
+ if (key === OUTPUT_SHAPES_KEY) {
+ // Map all output tensors into array of numbers denoting their shape.
+ var result_1 = value.list.shape.map(function (shape) {
+ if (shape.unknown_rank) {
+ // This output tensor is of unknown rank. We don't know if it is a
+ // scalar, or a tensor, or of what shape it is.
+ return null;
+ }
+ if (shape.dim == null ||
+ (shape.dim.length === 1 && shape.dim[0].size == null)) {
+ // This output tensor is a scalar.
+ return [];
+ }
+ // This output tensor has a known rank. Map each dimension size
+ // into a number.
+ return shape.dim.map(function (dim) {
+ // Size can be -1 if this particular dimension is unknown.
+ return dim.size;
+ });
+ });
+ // Since we already processed it, remove the entry from the attribute
+ // list (saves memory).
+ attr.splice(i, 1);
+ return result_1;
+ }
+ }
+ // We didn't find OUTPUT_SHAPES_KEY in attributes, so we don't know anything
+ // about the output tensors.
+ return result;
+ }
/**
* Normalizes the inputs and extracts associated metadata:
* 1) Inputs can contain a colon followed by a number at the end
@@ -3169,8 +3297,7 @@ var tf;
var opNodes = new Array(rawNodes.length);
var index = 0;
_.each(rawNodes, function (rawNode) {
- var normalizedInputs = normalizeInputs(rawNode.input);
- var opNode = new OpNodeImpl(rawNode, normalizedInputs);
+ var opNode = new OpNodeImpl(rawNode);
if (isInEmbeddedPred(opNode)) {
embeddingNodeNames.push(opNode.name);
inEmbedding[opNode.name] = opNode;
@@ -3252,9 +3379,6 @@ var tf;
});
return graph;
}, tracker);
- })
- .catch(function (reason) {
- throw new Error("Failure creating graph");
});
}
graph_1.build = build;
@@ -3410,6 +3534,34 @@ var tf;
}
graph_1.getIncludeNodeButtonString = getIncludeNodeButtonString;
;
+ /**
+ * Returns the string for the series node grouping toggle button, dependant
+ * on the provided current SeriesGroupingType.
+ */
+ function getGroupSeriesNodeButtonString(group) {
+ if (group === tf.graph.SeriesGroupingType.GROUP) {
+ return "Ungroup this series of nodes";
+ }
+ else {
+ return "Group this series of nodes";
+ }
+ }
+ graph_1.getGroupSeriesNodeButtonString = getGroupSeriesNodeButtonString;
+ ;
+ /**
+ * Toggle the node series grouping option in the provided map, setting it
+ * to ungroup if the series is not already in the map.
+ */
+ function toggleNodeSeriesGroup(map, name) {
+ if (!(name in map) || map[name] === tf.graph.SeriesGroupingType.GROUP) {
+ map[name] = tf.graph.SeriesGroupingType.UNGROUP;
+ }
+ else {
+ map[name] = tf.graph.SeriesGroupingType.GROUP;
+ }
+ }
+ graph_1.toggleNodeSeriesGroup = toggleNodeSeriesGroup;
+ ;
})(graph = tf.graph || (tf.graph = {}));
})(tf || (tf = {})); // close module tf.graph
@@ -3427,8 +3579,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
-///
var tf;
(function (tf) {
var graph;
@@ -3512,9 +3662,6 @@ var tf;
nodes: nodes,
statsJson: statsJson
};
- })
- .catch(function (reason) {
- throw new Error("Failure parsing graph definition");
});
}
parser.readAndParseData = readAndParseData;
@@ -3552,7 +3699,10 @@ var tf;
"node.attr.value.list.type": true,
"node.attr.value.shape.dim": true,
"node.attr.value.tensor.string_val": true,
- "node.attr.value.tensor.tensor_shape.dim": true
+ "node.attr.value.tensor.tensor_shape.dim": true,
+ "node.attr.value.list.shape": true,
+ "node.attr.value.list.shape.dim": true,
+ "node.attr.value.list.s": true
};
/**
* Adds a value, given the attribute name and the host object. If the
@@ -3630,8 +3780,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
-///
-///
/**
* Package for the Graph Hierarchy for TensorFlow graph.
*/
@@ -3727,7 +3875,7 @@ var tf;
}
// Copy the BaseEdge from the parent's Metaedge into this
// bridgegraph Metaedge.
- bridgeMetaedge.addBaseEdge(baseEdge);
+ bridgeMetaedge.addBaseEdge(baseEdge, _this);
});
})
.value(); // force lodash chain execution.
@@ -3819,16 +3967,14 @@ var tf;
HierarchyImpl.prototype.getOneWayEdges = function (node, inEdges) {
var edges = { control: [], regular: [] };
// A node with no parent cannot have any edges.
- if (!node.parentNode) {
+ if (!node.parentNode || !node.parentNode.isGroupNode) {
return edges;
}
- if (node.parentNode.isGroupNode) {
- var parentNode = node.parentNode;
- var metagraph = parentNode.metagraph;
- var bridgegraph = this.getBridgegraph(parentNode.name);
- findEdgeTargetsInGraph(metagraph, node, inEdges, edges);
- findEdgeTargetsInGraph(bridgegraph, node, inEdges, edges);
- }
+ var parentNode = node.parentNode;
+ var metagraph = parentNode.metagraph;
+ var bridgegraph = this.getBridgegraph(parentNode.name);
+ findEdgeTargetsInGraph(metagraph, node, inEdges, edges);
+ findEdgeTargetsInGraph(bridgegraph, node, inEdges, edges);
return edges;
};
/**
@@ -3909,7 +4055,7 @@ var tf;
return function (templateId) { return templateIndex(templateId); };
};
return HierarchyImpl;
- })();
+ }());
/**
* Internal utility function - given a graph (should be either a metagraph or a
* bridgegraph) and a node which is known to be in that graph, determine
@@ -3923,21 +4069,23 @@ var tf;
* Discovered target names are appended to the targets array.
*/
function findEdgeTargetsInGraph(graph, node, inbound, targets) {
- _.each(graph.edges(), function (e) {
- var _a = inbound ? [e.w, e.v] : [e.v, e.w], selfName = _a[0], otherName = _a[1];
- if (selfName === node.name) {
- if (node.isGroupNode) {
- var targetList = graph.edge(e).numRegularEdges
- ? targets.regular : targets.control;
- targetList.push(otherName);
- }
- else {
- _.each(graph.edge(e).baseEdgeList, function (baseEdge) {
- var targetList = baseEdge.isControlDependency
- ? targets.control : targets.regular;
- targetList.push(inbound ? baseEdge.v : baseEdge.w);
- });
- }
+ var edges = inbound ? graph.inEdges(node.name) : graph.outEdges(node.name);
+ _.each(edges, function (e) {
+ var otherName = inbound ? e.v : e.w;
+ var metaedge = graph.edge(e);
+ if (node.isGroupNode && metaedge.baseEdgeList.length > 1) {
+ var targetList = metaedge.numRegularEdges
+ ? targets.regular : targets.control;
+ targetList.push(otherName);
+ }
+ else {
+ // Enumerate all the base edges if the node is an OpNode, or the
+ // metaedge has only 1 edge in it.
+ _.each(metaedge.baseEdgeList, function (baseEdge) {
+ var targetList = baseEdge.isControlDependency
+ ? targets.control : targets.regular;
+ targetList.push(inbound ? baseEdge.v : baseEdge.w);
+ });
}
});
}
@@ -3962,7 +4110,7 @@ var tf;
.then(function () {
return tf.runAsyncTask("Detect series", 20, function () {
if (params.seriesNodeMinSize > 0) {
- groupSeries(h.root, h, seriesNames, params.seriesNodeMinSize);
+ groupSeries(h.root, h, seriesNames, params.seriesNodeMinSize, params.seriesMap);
}
}, tracker);
})
@@ -3978,8 +4126,6 @@ var tf;
})
.then(function () {
return h;
- }).catch(function (reason) {
- throw new Error("Failure creating graph hierarchy");
});
}
hierarchy_1.build = build;
@@ -4091,7 +4237,7 @@ var tf;
!baseEdge.isControlDependency) {
sharedAncestorNode.hasNonControlEdges = true;
}
- metaedge.addBaseEdge(baseEdge);
+ metaedge.addBaseEdge(baseEdge, h);
});
}
;
@@ -4103,17 +4249,21 @@ var tf;
*
* @param metanode
* @param hierarchy
+ * @param seriesNames Map of node names to their series they are contained in.
+ * This should be provided empty and is populated by this method.
* @param threshold If the series has this many nodes or more, then group them
* into a series.
+ * @param map Map of series names to their series grouping type, if one has
+ * been set.
* @return A dictionary from node name to series node name that contains the
* node.
*/
- function groupSeries(metanode, hierarchy, seriesNames, threshold) {
+ function groupSeries(metanode, hierarchy, seriesNames, threshold, map) {
var metagraph = metanode.metagraph;
_.each(metagraph.nodes(), function (n) {
var child = metagraph.node(n);
if (child.type === tf.graph.NodeType.META) {
- groupSeries(child, hierarchy, seriesNames, threshold);
+ groupSeries(child, hierarchy, seriesNames, threshold, map);
}
});
var clusters = clusterNodes(metagraph);
@@ -4122,7 +4272,21 @@ var tf;
// metagraph.
_.each(seriesDict, function (seriesNode, seriesName) {
var nodeMemberNames = seriesNode.metagraph.nodes();
- if (nodeMemberNames.length < threshold) {
+ _.each(nodeMemberNames, function (n) {
+ var child = metagraph.node(n);
+ if (!child.owningSeries) {
+ child.owningSeries = seriesName;
+ }
+ });
+ // If the series contains less than the threshold number of nodes and
+ // this series has not been adding to the series map, then set this
+ // series to be shown ungrouped in the map.
+ if (nodeMemberNames.length < threshold && !(seriesNode.name in map)) {
+ map[seriesNode.name] = tf.graph.SeriesGroupingType.UNGROUP;
+ }
+ // If the series is in the map as ungrouped then do not group the series.
+ if (seriesNode.name in map
+ && map[seriesNode.name] === tf.graph.SeriesGroupingType.UNGROUP) {
return;
}
hierarchy.setNode(seriesName, seriesNode); // add to the index
@@ -4202,9 +4366,6 @@ var tf;
}
else {
prefix = isGroup ? leaf.substr(0, leaf.length - 1) : leaf;
- if (prefix.charAt(prefix.length - 1) !== "_") {
- prefix += "_";
- }
id = 0;
suffix = isGroup ? "*" : "";
}
@@ -4252,19 +4413,24 @@ var tf;
function addSeriesToDict(seriesNodes, seriesDict, clusterId, metagraph) {
if (seriesNodes.length > 1) {
var curSeriesName = graph_1.getSeriesNodeName(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, seriesNodes[0].clusterId, seriesNodes[seriesNodes.length - 1].clusterId);
- var curSeriesNode = graph_1.createSeriesNode(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, clusterId, curSeriesName);
+ var curSeriesNode_1 = graph_1.createSeriesNode(seriesNodes[0].prefix, seriesNodes[0].suffix, seriesNodes[0].parent, clusterId, curSeriesName);
_.each(seriesNodes, function (node) {
- curSeriesNode.ids.push(node.clusterId);
- curSeriesNode.metagraph.setNode(node.name, metagraph.node(node.name));
+ curSeriesNode_1.ids.push(node.clusterId);
+ curSeriesNode_1.metagraph.setNode(node.name, metagraph.node(node.name));
});
- seriesDict[curSeriesName] = curSeriesNode;
+ seriesDict[curSeriesName] = curSeriesNode_1;
}
}
})(hierarchy = graph_1.hierarchy || (graph_1.hierarchy = {}));
})(graph = tf.graph || (tf.graph = {}));
})(tf || (tf = {})); // close module tf.graph.hierarchy
-
@@ -9793,7 +10130,7 @@ Polymer({
-
[[_getNodeName(nodeName)]]
+
@@ -9840,7 +10177,7 @@ Polymer({
([[_totalPredecessors]])
-
+
@@ -9870,7 +10207,7 @@ Polymer({
([[_totalSuccessors]])
-
+
@@ -9899,6 +10236,13 @@ Polymer({
[[_auxButtonText]]
+
+
+
+ [[_groupButtonText]]
+
+
+
@@ -9969,7 +10313,8 @@ Polymer({
type: Boolean,
value: false
},
- _auxButtonText: String
+ _auxButtonText: String,
+ _groupButtonText: String
},
expandNode: function() {
this.fire('_node.expand', this.node);
@@ -9980,20 +10325,60 @@ Polymer({
_getNode: function(nodeName, graphHierarchy) {
return graphHierarchy.node(nodeName);
},
- _getNodeName: function(nodeName) {
- // Insert a zero-width whitespace character before each slash so that
+ _getPrintableHTMLNodeName: function(nodeName) {
+ // Insert an optional line break before each slash so that
// long node names wrap cleanly at path boundaries.
- return (nodeName || '').replace(/\//g, '\u200B/');
+ return (nodeName || '').replace(/\//g, '/');
+ },
+ _getPredEdgeLabel: function(sourceName) {
+ return this._getEdgeLabel(sourceName, this.nodeName);
+ },
+ _getSuccEdgeLabel: function(destName) {
+ return this._getEdgeLabel(this.nodeName, destName);
+ },
+ _getEdgeLabel: function(sourceName, destName) {
+ if (!this._node) {
+ // The user clicked outside, thus no node is selected and
+ // the info card should be hidden.
+ return;
+ }
+ var parent = this._node.parentNode;
+ var sourceNode = this.graphHierarchy.node(sourceName);
+ if (!sourceNode.isGroupNode) {
+ // Show the tensor shape directly.
+ return tf.graph.scene.edge.getShapeLabelFromNode(sourceNode);
+ }
+ sourceName = this.renderHierarchy.getNearestVisibleAncestor(sourceName);
+ destName = this.renderHierarchy.getNearestVisibleAncestor(destName);
+ var metaedge = parent.metagraph.edge(sourceName, destName) ||
+ parent.bridgegraph.edge(sourceName, destName);
+ return tf.graph.scene.edge.getLabelForEdge(metaedge,
+ this.renderHierarchy);
},
_getRenderInfo: function(nodeName, renderHierarchy) {
return this.renderHierarchy.getOrCreateRenderNodeByName(nodeName);
},
_getAttributes: function(node) {
this.async(this._resizeList.bind(this, "#attributesList"));
- return node && node.attr ? node.attr.map(function(entry) {
- return {key: entry.key, value: JSON.stringify(entry.value)};
- }) : [];
-
+ if (!node || !node.attr) {
+ return [];
+ }
+ var attrs = [];
+ _.each(node.attr, function(entry) {
+ // Unpack the "too large" attributes into separate attributes
+ // in the info card, with values "too large to show".
+ if (entry.key === tf.graph.LARGE_ATTRS_KEY) {
+ attrs = attrs.concat(entry.value.list.s.map(function(key) {
+ return {key: key, value: "Too large to show..."};
+ }));
+ } else {
+ attrs.push({
+ key: entry.key,
+ value: JSON.stringify(entry.value)
+ });
+ }
+ });
+ return attrs;
},
_getDevice: function(node) {
return node ? node.device : null;
@@ -10030,6 +10415,14 @@ Polymer({
_resetState: function() {
this._openedControlPred = false;
this._openedControlSucc = false;
+
+ this.set("_groupButtonText",
+ tf.graph.scene.node.getGroupSettingLabel(this._node));
+
+ if (this._node) {
+ Polymer.dom(this.$.nodetitle).innerHTML =
+ this._getPrintableHTMLNodeName(this._node.name);
+ }
},
_resizeList: function(selector) {
var list = document.querySelector(selector);
@@ -10046,6 +10439,14 @@ Polymer({
_nodeIncludeStateChanged: function(include, oldInclude) {
this.set("_auxButtonText",
tf.graph.getIncludeNodeButtonString(include));
+ },
+ _toggleGroup: function() {
+ var graphElem = document.querySelector("#graph");
+ var seriesName = tf.graph.scene.node.getSeriesName(this._node);
+ graphElem.fire("node-toggle-seriesgroup", { name: seriesName });
+ },
+ _isInSeries: function(node) {
+ return tf.graph.scene.node.canBeInSeries(node);
}
});
})();
@@ -10222,7 +10623,7 @@ paper-progress {
-
+
@@ -10806,10 +11207,10 @@ function convertToHumanReadable(value, units, unitIndex) {
-
+
@@ -10849,7 +11250,8 @@ Polymer({
return _.map(runsWithGraph, function(runName) {
return {
name: runName,
- path: graphUrlGen(runName)
+ path: graphUrlGen(runName, tf.graph.LIMIT_ATTR_SIZE,
+ tf.graph.LARGE_ATTRS_KEY)
};
});
},
@@ -10865,11 +11267,11 @@ Polymer({
TensorBoard
-
- Events
- Images
- Graph
- Histograms
+
+ Events
+ Images
+ Graph
+ Histograms
@@ -10944,14 +11346,24 @@ Polymer({
type: Object,
value: TF.Urls.productionRouter(),
},
+ // Which tab is selected (events, graph, images etc).
mode: {
type: String,
- value: "events",
+ computed: '_getModeFromIndex(modeIndex)'
},
+ // If true, tab switching in TensorBoard will not update
+ // location hash. Hash update interferes with selenium tests.
+ noHash: {
+ type: Boolean,
+ value: false
+ }
},
- changeMode: function(ev) {
- var mode = ev.target.parentElement.getAttribute('data-mode');
- this._changeMode(mode, true);
+ _getModeFromIndex: function(modeIndex) {
+ var mode = this.tabs[modeIndex];
+ if (!this.noHash) {
+ window.location.hash = mode;
+ }
+ return mode;
},
eventDashboard: function(mode) {
return mode === "events";
@@ -10965,36 +11377,26 @@ Polymer({
histogramDashboard: function(mode) {
return mode === "histograms";
},
- loadPreviousMode: function() {
- this._changeMode(this._getMode(), false);
- },
ready: function() {
- this._changeMode(this._getMode(), true);
-
- var self = this;
- window.addEventListener('hashchange', function(){
- self.loadPreviousMode();
+ this.tabs = [].slice.call(this.querySelectorAll('paper-tab')).map(function(a) {
+ return a.dataset.mode;
});
+ this._getModeFromHash();
+ window.addEventListener('hashchange', function() {
+ this._getModeFromHash();
+ }.bind(this));
},
- _changeMode: function(mode, isNewState) {
- this.mode = mode;
-
- // Change the selected tab
- this.$.tabs.selected = this._tabs().indexOf(mode);
-
- if (isNewState){
- window.location.hash = mode;
- }
- },
- _getMode: function() {
+ _getModeFromHash: function() {
// Return the mode as it is stored in the hash.
- // If no mode can be found, default to the first tab.
- var hash = window.location.hash;
- return hash.length > 0 ? hash.slice(1, hash.length) : this._tabs()[0];
- },
- _tabs: function() {
- var elts = Array.prototype.slice.call(this.querySelectorAll('paper-tab'));
- return elts.map(function(elt){ return elt.getAttribute('data-mode')});
+ var tabName = window.location.hash.trim().slice(1);
+ var modeIndex = this.tabs.indexOf(tabName);
+ if (modeIndex == -1 && this.modeIndex == null) {
+ // Selecting the first tab as default.
+ this.set('modeIndex', 0);
+ }
+ if (modeIndex != -1 && modeIndex != this.modeIndex) {
+ this.set('modeIndex', modeIndex);
+ }
},
});