Skip to content

Commit 300b526

Browse files
authored
Add trendline to visualize model performance over time, call dataSync for every run (tensorflow#1396)
- Added a trendline to visualize the speed of each inference so we can get a more granular sense of model performance. This is helpful in the case that, for example, an optimization introduces overhead for the first several inferences, but leads to better model performance in the long run. Average prediction time itself can vary significantly depending on `numRuns`. - Changed `measureAveragePredictTime` to call `dataSync` for every run, rather than only once at the end.
1 parent 4f32484 commit 300b526

File tree

1 file changed

+132
-36
lines changed

1 file changed

+132
-36
lines changed

integration_tests/benchmarks/benchmark.html

Lines changed: 132 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@
1515
}
1616

1717
body {
18-
margin: 30px 0 0 30px;
18+
margin: 20px 100px;
19+
}
20+
21+
h2 {
22+
margin-bottom: 30px;
23+
}
24+
25+
#kernels {
26+
max-width: 750px;
1927
}
2028

2129
#container {
@@ -25,8 +33,8 @@
2533
}
2634

2735
.box {
28-
margin-right: 20px;
29-
margin-bottom: 20px;
36+
margin-right: 30px;
37+
margin-bottom: 30px;
3038
}
3139

3240
.box pre {
@@ -36,6 +44,42 @@
3644
font-size: 10px;
3745
}
3846

47+
#trendline-container svg {
48+
overflow: visible;
49+
border-bottom: 1px solid #ccc;
50+
border-left: 1px solid #ccc;
51+
}
52+
53+
#trendline-container .label {
54+
font-size: 14px;
55+
font-weight: bold;
56+
}
57+
58+
#trendline-container path {
59+
fill: none;
60+
stroke: #222;
61+
}
62+
63+
#trendline {
64+
position: relative;
65+
margin-top: 20px;
66+
}
67+
68+
#trendline #yMax, #trendline #yMin {
69+
position: absolute;
70+
right: calc(100% + 6px);
71+
font-size: 11px;
72+
white-space: nowrap;
73+
}
74+
75+
#trendline #yMin {
76+
bottom: 0;
77+
}
78+
79+
#trendline #yMax {
80+
top: 0;
81+
}
82+
3983
#modal-msg {
4084
border-radius: 5px;
4185
background-color: black;
@@ -48,8 +92,8 @@
4892
}
4993

5094
.table {
51-
margin-right: 20px;
52-
margin-bottom: 20px;
95+
margin-right: 30px;
96+
margin-bottom: 30px;
5397
border: 1px solid #ccc;
5498
border-collapse: collapse;
5599
border-spacing: 0;
@@ -87,19 +131,29 @@
87131
<h2>TensorFlow.js Model Benchmark</h2>
88132
<div id="modal-msg"></div>
89133
<div id="container">
90-
<div class="box">
91-
<pre id="env"></pre>
134+
<div id="stats">
135+
<div class="box">
136+
<pre id="env"></pre>
137+
</div>
138+
<table class="table" id="timings">
139+
<thead>
140+
<tr>
141+
<th>Type</th>
142+
<th>Value</th>
143+
</tr>
144+
</thead>
145+
<tbody>
146+
</tbody>
147+
</table>
148+
<div class="box" id="trendline-container">
149+
<div class="label"></div>
150+
<div id="trendline">
151+
<div id="yMax"></div>
152+
<div id="yMin">0 ms</div>
153+
<svg><path></path></svg>
154+
</div>
155+
</div>
92156
</div>
93-
<table class="table" id="timings">
94-
<thead>
95-
<tr>
96-
<th>Type</th>
97-
<th>Value</th>
98-
</tr>
99-
</thead>
100-
<tbody>
101-
</tbody>
102-
</table>
103157
<table class="table" id="kernels">
104158
<thead>
105159
<tr>
@@ -131,19 +185,21 @@ <h2>TensorFlow.js Model Benchmark</h2>
131185
//////////////////////////////////
132186
// Place model prediction code here.
133187
//////////////////////////////////
188+
if (isAsync) {
189+
return model.executeAsync(zeros);
190+
}
134191
return model.predict(zeros);
135192
}
136193
</script>
137194
<script>
138195
'use strict';
139196
const state = {
140-
numRuns: 20,
141-
197+
numRuns: 50,
142198
};
143199
const modalDiv = document.getElementById('modal-msg');
144200
const timeTable = document.querySelector('#timings tbody');
145201
const envDiv = document.getElementById('env');
146-
let model;
202+
let model, isAsync;
147203

148204
async function showMsg(message) {
149205
if (message != null) {
@@ -169,6 +225,10 @@ <h2>TensorFlow.js Model Benchmark</h2>
169225
envDiv.innerHTML += `<br/>${JSON.stringify(tf.ENV.features, null, 2)}`;
170226
}
171227

228+
function printTime(elapsed) {
229+
return elapsed.toFixed(1) + ' ms';
230+
}
231+
172232
function printMemory(bytes) {
173233
if (bytes < 1024) {
174234
return bytes + ' B';
@@ -200,12 +260,14 @@ <h2>TensorFlow.js Model Benchmark</h2>
200260
if (res instanceof Promise) {
201261
res = await res;
202262
}
263+
203264
if (res instanceof tf.Tensor) {
204-
await res.data();
265+
res.dataSync();
205266
}
267+
206268
const elapsed = performance.now() - start;
207269
await showMsg(null);
208-
appendRow(timeTable, 'Warmup', elapsed.toFixed(1) + ' ms');
270+
appendRow(timeTable, '1st inference', printTime(start));
209271
}
210272

211273
function sleep(timeMs) {
@@ -216,34 +278,66 @@ <h2>TensorFlow.js Model Benchmark</h2>
216278
await showMsg('Loading the model');
217279
const start = performance.now();
218280
model = await load();
281+
isAsync = model.executor != null && model.executor.isControlFlowModel;
282+
219283
const elapsed = performance.now() - start;
220284
await showMsg(null);
221-
appendRow(timeTable, 'Model load', elapsed.toFixed(1) + ' ms');
285+
appendRow(timeTable, 'Model load', printTime(elapsed));
222286
}
223287

224288
async function measureAveragePredictTime() {
289+
document.querySelector("#trendline-container .label").textContent = `Inference times over ${state.numRuns} runs`;
225290
await showMsg(`Running predict ${state.numRuns} times`);
226-
const start = performance.now();
227-
let res;
291+
const chartHeight = 150;
292+
const chartWidth = document.querySelector("#trendline-container").getBoundingClientRect().width;
293+
document.querySelector("#trendline-container svg").setAttribute("width", chartWidth);
294+
document.querySelector("#trendline-container svg").setAttribute("height", chartHeight);
295+
296+
const times = [];
228297
for (let i = 0; i < state.numRuns; i++) {
229-
res = predict(model);
298+
const start = performance.now();
299+
let res = predict(model);
300+
if (res instanceof Promise) {
301+
res = await res;
302+
}
303+
304+
if (res instanceof tf.Tensor) {
305+
res.dataSync();
306+
}
307+
308+
times.push(performance.now() - start);
230309
}
310+
311+
const average = times.reduce((acc, curr) => acc + curr, 0) / times.length;
312+
const max = Math.max(...times);
313+
const min = Math.min(...times);
314+
const xIncrement = chartWidth / times.length;
315+
316+
document.querySelector("#trendline-container #yMax").textContent = printTime(max);
317+
document.querySelector("#trendline-container path")
318+
.setAttribute("d", `M${times.map((d, i) => `${i * xIncrement},${chartHeight - (d / max) * chartHeight}`).join('L')}`);
319+
320+
await showMsg(null);
321+
appendRow(timeTable, `Subsequent average (${state.numRuns} runs)`, printTime(average));
322+
appendRow(timeTable, 'Best time', printTime(min));
323+
}
324+
325+
async function profileMemory() {
326+
await showMsg('Profile memory');
327+
const start = performance.now();
328+
let res;
329+
const data = await tf.profile(() => res = predict(model));
231330
if (res instanceof Promise) {
232331
res = await res;
233332
}
333+
234334
if (res instanceof tf.Tensor) {
235335
res.dataSync();
236336
}
237-
const elapsed = (performance.now() - start) / state.numRuns;
238-
await showMsg(null);
239-
appendRow(timeTable, `Predict (${state.numRuns} runs)`, elapsed.toFixed(1) + ' ms');
240-
}
241-
242-
async function profileMemory() {
243-
await showMsg('Profile memory');
244-
const data = await tf.profile(() => predict(model));
337+
const elapsed = performance.now() - start;
245338
await showMsg(null);
246339
appendRow(timeTable, 'Peak memory', printMemory(data.peakBytes));
340+
appendRow(timeTable, '2nd inference', printTime(elapsed));
247341
}
248342

249343
function showKernelTime(kernels) {
@@ -285,12 +379,14 @@ <h2>TensorFlow.js Model Benchmark</h2>
285379
}
286380
}
287381
let res = predict(model);
288-
if (res instanceof Promise) {
382+
if(res instanceof Promise) {
289383
res = await res;
290384
}
291-
if (res instanceof tf.Tensor) {
385+
386+
if(res instanceof tf.Tensor) {
292387
res.dataSync();
293388
}
389+
294390
await showMsg(null);
295391
await sleep(10);
296392
kernels = kernels.sort((a, b) => b.time - a.time);

0 commit comments

Comments
 (0)