Update the TensorBoard backend to use a new binning algorithm.

Update the TensorBoard backend size guidelines for the new histograms.
Change: 129806300
This commit is contained in:
Renato Utsch 2016-08-09 15:14:03 -08:00 committed by TensorFlower Gardener
parent cf6857d476
commit bfcbc262af
5 changed files with 91 additions and 47 deletions

View File

@ -41,7 +41,7 @@ TENSORBOARD_SIZE_GUIDANCE = {
event_accumulator.IMAGES: 4,
event_accumulator.AUDIO: 4,
event_accumulator.SCALARS: 1000,
event_accumulator.HISTOGRAMS: 1,
event_accumulator.HISTOGRAMS: 50,
}

View File

@ -182,11 +182,16 @@ module TF.Backend {
let url = this.router.histograms(tag, run);
p = this.requestManager.request(url);
return p.then(map(detupler(createHistogram))).then(function(histos) {
// Get the minimum and maximum values across all histograms so that the
// visualization is aligned for all timesteps.
let min = d3.min(histos, d => d.min);
let max = d3.max(histos, d => d.max);
return histos.map(function(histo, i) {
return {
wall_time: histo.wall_time,
step: histo.step,
bins: convertBins(histo)
bins: convertBins(histo, min, max)
};
});
});
@ -367,34 +372,59 @@ module TF.Backend {
* Takes histogram data as stored by tensorboard backend and converts it to
* the standard d3 histogram data format to make it more compatible and easier
* to visualize. When visualizing histograms, having the left edge and width
* makes things quite a bit easier.
* makes things quite a bit easier. The bins are also converted to have an
* uniform width, what makes the visualization easier to understand.
*
* @param histogram A histogram from tensorboard backend.
* @param min The leftmost edge. The binning will start on it.
* @param max The rightmost edge. The binning will end on it.
* @param numBins The number of bins of the converted data. The default of 30
* is a sensible default, using more starts to get artifacts because the event
* data is stored in buckets, and you start being able to see the aliased
* borders between each bucket.
* @return A histogram bin. Each bin has an x (left edge), a dx (width),
* and a y (count).
*
* If given rightedges are inclusive, then these left edges (x) are exclusive.
*/
export function convertBins(histogram: Histogram) {
export function convertBins(
histogram: Histogram, min: number, max: number, numBins = 30) {
if (histogram.bucketRightEdges.length !== histogram.bucketCounts.length) {
throw(new Error('Edges and counts are of different lengths.'));
}
var previousRightEdge = histogram.min;
return histogram.bucketRightEdges.map(function(
rightEdge: number, i: number) {
let binWidth = (max - min) / numBins;
let bucketLeft = min; // Use the min as the starting point for the bins.
let bucketPos = 0;
return d3.range(min, max, binWidth).map(function(binLeft) {
let binRight = binLeft + binWidth;
// Use the previous bin's rightEdge as the new leftEdge
var left = previousRightEdge;
// Take the count of each existing bucket, multiply it by the proportion
// of overlap with the new bin, then sum and store as the count for the
// new bin. If no overlap, will add to zero, if 100% overlap, will include
// the full count into new bin.
let binY = 0;
while (bucketPos < histogram.bucketRightEdges.length) {
// Clip the right edge because right-most edge can be infinite-sized.
let bucketRight = Math.min(max, histogram.bucketRightEdges[bucketPos]);
// We need to clip the rightEdge because right-most edge can be
// infinite-sized
var right = Math.min(histogram.max, rightEdge);
let intersect =
Math.min(bucketRight, binRight) - Math.max(bucketLeft, binLeft);
let count = (intersect / (bucketRight - bucketLeft)) *
histogram.bucketCounts[bucketPos];
// Store rightEdgeValue for next iteration
previousRightEdge = rightEdge;
binY += intersect > 0 ? count : 0;
return {x: left, dx: right - left, y: histogram.bucketCounts[i]};
// If bucketRight is bigger than binRight, than this bin is finished and
// there is data for the next bin, so don't increment bucketPos.
if (bucketRight > binRight) {
break;
}
bucketLeft = Math.max(min, bucketRight);
bucketPos++;
};
return {x: binLeft, dx: binWidth, y: binY};
});
}

View File

@ -191,13 +191,16 @@ module TF.Backend {
it('Throws and error if the inputs are of different lengths', function() {
assert.throws(function() {
convertBins(
{bucketRightEdges: [0], bucketCounts: [1, 2], min: 1, max: 2});
{bucketRightEdges: [0], bucketCounts: [1, 2], min: 1, max: 2}, 1, 2,
2);
}, 'Edges and counts are of different lengths.');
});
it('Handles data with no bins', function() {
assert.deepEqual(
convertBins({bucketRightEdges: [], bucketCounts: [], min: 0, max: 0}),
convertBins(
{bucketRightEdges: [], bucketCounts: [], min: 0, max: 0}, 0, 0,
0),
[]);
});
@ -205,12 +208,14 @@ module TF.Backend {
let counts = [1];
let rightEdges = [1.21e-12];
let histogram = [{x: 1.1e-12, dx: 1.21e-12 - 1.1e-12, y: 1}];
let newHistogram = convertBins({
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: 1.1e-12,
max: 1.21e-12
});
let newHistogram = convertBins(
{
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: 1.1e-12,
max: 1.21e-12
},
1.1e-12, 1.21e-12, 1);
assertHistogramEquality(newHistogram, histogram);
});
@ -218,15 +223,17 @@ module TF.Backend {
let counts = [1, 2];
let rightEdges = [1.1e-12, 1.21e-12];
let histogram = [
{x: 1.0e-12, dx: 1.1e-12 - 1.0e-12, y: 1},
{x: 1.1e-12, dx: 1.21e-12 - 1.1e-12, y: 2}
{x: 1.0e-12, dx: 1.05e-13, y: 1.09090909090909},
{x: 1.105e-12, dx: 1.05e-13, y: 1.9090909090909}
];
let newHistogram = convertBins({
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: 1.0e-12,
max: 1.21e-12
});
let newHistogram = convertBins(
{
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: 1.0e-12,
max: 1.21e-12
},
1.0e-12, 1.21e-12, 2);
assertHistogramEquality(newHistogram, histogram);
});
@ -236,15 +243,17 @@ module TF.Backend {
let counts = [1, 2];
let rightEdges = [-1.0e-12, 1.0e-12];
let histogram = [
{x: -1.1e-12, dx: 1.1e-12 - 1.0e-12, y: 1},
{x: -1.0e-12, dx: 2.0e-12, y: 2}
{x: -1.1e-12, dx: 1.05e-12, y: 1.95},
{x: -0.5e-13, dx: 1.05e-12, y: 1.05}
];
let newHistogram = convertBins({
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: -1.1e-12,
max: 1.0e-12
});
let newHistogram = convertBins(
{
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: -1.1e-12,
max: 1.0e-12
},
-1.1e-12, 1.0e-12, 2);
assertHistogramEquality(newHistogram, histogram);
});
@ -253,15 +262,18 @@ module TF.Backend {
let counts = [1, 2, 3];
let rightEdges = [0, 1.0e-12, 1.0e14];
let histogram = [
{x: -1.0e-12, dx: 1.0e-12, y: 1}, {x: 0, dx: 1.0e-12, y: 2},
{x: 1.0e-12, dx: 1.1e-12 - 1.0e-12, y: 3}
{x: -1.0e-12, dx: 0.7e-12, y: 0.7},
{x: -0.3e-12, dx: 0.7e-12, y: 1.1},
{x: 0.4e-12, dx: 0.7e-12, y: 4.2}
];
let newHistogram = convertBins({
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: -1.0e-12,
max: 1.1e-12
});
let newHistogram = convertBins(
{
bucketRightEdges: rightEdges,
bucketCounts: counts,
min: -1.0e-12,
max: 1.1e-12
},
-1.0e-12, 1.1e-12, 3);
assertHistogramEquality(newHistogram, histogram);
});
});

View File

@ -19,6 +19,7 @@ limitations under the License.
<script src="../../webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../../tf-imports/d3.html">
</head>
<body>
<test-fixture id="testElementFixture">

View File

@ -1,5 +1,6 @@
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../tf-imports/lodash.html">
<link rel="import" href="../tf-imports/d3.html">
<script src="requestManager.js"></script>
<script src="urlPathHelpers.js"></script>