From bfcbc262afaf9a3e9affd21c0819681d4f209525 Mon Sep 17 00:00:00 2001 From: Renato Utsch Date: Tue, 9 Aug 2016 15:14:03 -0800 Subject: [PATCH] Update the TensorBoard backend to use a new binning algorithm. Update the TensorBoard backend size guidelines for the new histograms. Change: 129806300 --- tensorflow/tensorboard/backend/server.py | 2 +- .../components/tf-backend/backend.ts | 58 ++++++++++---- .../tf-backend/test/backendTests.ts | 76 +++++++++++-------- .../components/tf-backend/test/index.html | 1 + .../components/tf-backend/tf-backend.html | 1 + 5 files changed, 91 insertions(+), 47 deletions(-) diff --git a/tensorflow/tensorboard/backend/server.py b/tensorflow/tensorboard/backend/server.py index 796a96a584c..952e15110ae 100644 --- a/tensorflow/tensorboard/backend/server.py +++ b/tensorflow/tensorboard/backend/server.py @@ -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, } diff --git a/tensorflow/tensorboard/components/tf-backend/backend.ts b/tensorflow/tensorboard/components/tf-backend/backend.ts index 1f060bf07f6..5c75d790106 100644 --- a/tensorflow/tensorboard/components/tf-backend/backend.ts +++ b/tensorflow/tensorboard/components/tf-backend/backend.ts @@ -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}; }); } diff --git a/tensorflow/tensorboard/components/tf-backend/test/backendTests.ts b/tensorflow/tensorboard/components/tf-backend/test/backendTests.ts index e75c91217e0..15cdd0bf95e 100644 --- a/tensorflow/tensorboard/components/tf-backend/test/backendTests.ts +++ b/tensorflow/tensorboard/components/tf-backend/test/backendTests.ts @@ -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); }); }); diff --git a/tensorflow/tensorboard/components/tf-backend/test/index.html b/tensorflow/tensorboard/components/tf-backend/test/index.html index ad92f694029..c97873f46ab 100644 --- a/tensorflow/tensorboard/components/tf-backend/test/index.html +++ b/tensorflow/tensorboard/components/tf-backend/test/index.html @@ -19,6 +19,7 @@ limitations under the License. + diff --git a/tensorflow/tensorboard/components/tf-backend/tf-backend.html b/tensorflow/tensorboard/components/tf-backend/tf-backend.html index 4f6a1680e19..bc4f16a5f70 100644 --- a/tensorflow/tensorboard/components/tf-backend/tf-backend.html +++ b/tensorflow/tensorboard/components/tf-backend/tf-backend.html @@ -1,5 +1,6 @@ +