0
# TensorBoard Integration
1
2
TensorFlow.js Node provides comprehensive TensorBoard integration for logging training metrics, visualizing model performance, and monitoring training progress. This enables the same rich visualization capabilities available in Python TensorFlow directly in Node.js applications.
3
4
## Capabilities
5
6
### Summary File Writer
7
8
#### Create Summary Writer
9
10
Create a TensorBoard summary writer for logging scalar and histogram data.
11
12
```typescript { .api }
13
/**
14
* Create a TensorBoard summary writer
15
* @param logdir - Directory to write TensorBoard logs
16
* @param maxQueue - Maximum number of summaries to queue before writing (default: 10)
17
* @param flushMillis - How often to flush summaries to disk in milliseconds (default: 120000)
18
* @param filenameSuffix - Optional suffix for log filenames
19
* @returns SummaryFileWriter instance
20
*/
21
function summaryFileWriter(
22
logdir: string,
23
maxQueue?: number,
24
flushMillis?: number,
25
filenameSuffix?: string
26
): SummaryFileWriter;
27
```
28
29
**Usage Example:**
30
31
```typescript
32
import * as tf from '@tensorflow/tfjs-node';
33
34
// Create a summary writer
35
const writer = tf.node.summaryFileWriter('./logs/training');
36
37
// Log scalar values
38
writer.scalar('loss', 0.5, 1);
39
writer.scalar('accuracy', 0.85, 1);
40
writer.scalar('learning_rate', 0.001, 1);
41
42
// Log with different step
43
writer.scalar('loss', 0.4, 2);
44
writer.scalar('accuracy', 0.87, 2);
45
46
// Force write to disk
47
writer.flush();
48
```
49
50
### TensorBoard Callback
51
52
#### Create TensorBoard Callback
53
54
Create a callback for automatic logging during model training.
55
56
```typescript { .api }
57
/**
58
* Create a TensorBoard callback for model training
59
* @param logdir - Directory to write TensorBoard logs (optional, defaults to './logs')
60
* @param args - Additional configuration options
61
* @returns TensorBoardCallback instance
62
*/
63
function tensorBoard(
64
logdir?: string,
65
args?: TensorBoardCallbackArgs
66
): TensorBoardCallback;
67
68
interface TensorBoardCallbackArgs {
69
/** How often to log ('batch' or 'epoch') */
70
updateFreq?: 'batch' | 'epoch';
71
72
/** How often to log histograms (0 = never) */
73
histogramFreq?: number;
74
}
75
```
76
77
**Usage Example:**
78
79
```typescript
80
import * as tf from '@tensorflow/tfjs-node';
81
82
// Create model
83
const model = tf.sequential({
84
layers: [
85
tf.layers.dense({ inputShape: [4], units: 10, activation: 'relu' }),
86
tf.layers.dense({ units: 3, activation: 'softmax' })
87
]
88
});
89
90
model.compile({
91
optimizer: 'adam',
92
loss: 'sparseCategoricalCrossentropy',
93
metrics: ['accuracy']
94
});
95
96
// Create TensorBoard callback
97
const tensorboardCallback = tf.node.tensorBoard('./logs/experiment_1', {
98
updateFreq: 'epoch',
99
histogramFreq: 1 // Log histograms every epoch
100
});
101
102
// Generate training data
103
const xs = tf.randomNormal([1000, 4]);
104
const ys = tf.randomUniform([1000, 1], 0, 3, 'int32');
105
106
// Train with TensorBoard logging
107
await model.fit(xs, ys, {
108
epochs: 50,
109
batchSize: 32,
110
validationSplit: 0.2,
111
callbacks: [tensorboardCallback]
112
});
113
114
console.log('Training complete. View logs with: tensorboard --logdir ./logs');
115
```
116
117
## SummaryFileWriter Interface
118
119
The `SummaryFileWriter` class provides methods for logging different types of data to TensorBoard.
120
121
```typescript { .api }
122
interface SummaryFileWriter {
123
/** Write a scalar value */
124
scalar(name: string, value: number, step: number, description?: string): void;
125
126
/** Write a histogram of tensor values */
127
histogram(name: string, data: Tensor, step: number, buckets?: number, description?: string): void;
128
129
/** Force write buffered summaries to disk */
130
flush(): void;
131
}
132
```
133
134
### Scalar Logging
135
136
Log scalar metrics like loss, accuracy, and learning rate.
137
138
```typescript { .api }
139
/**
140
* Write a scalar summary
141
* @param name - Name of the scalar (will appear in TensorBoard)
142
* @param value - Scalar value to log
143
* @param step - Training step or epoch number
144
* @param description - Optional description for the metric
145
*/
146
scalar(name: string, value: number, step: number, description?: string): void;
147
```
148
149
**Usage Example:**
150
151
```typescript
152
const writer = tf.node.summaryFileWriter('./logs/metrics');
153
154
// Log training metrics
155
for (let epoch = 0; epoch < 100; epoch++) {
156
// Simulate training
157
const loss = Math.exp(-epoch * 0.1) + Math.random() * 0.1;
158
const accuracy = 1 - Math.exp(-epoch * 0.05) - Math.random() * 0.05;
159
const lr = 0.001 * Math.pow(0.95, epoch);
160
161
// Log to TensorBoard
162
writer.scalar('training/loss', loss, epoch, 'Cross-entropy loss during training');
163
writer.scalar('training/accuracy', accuracy, epoch, 'Classification accuracy');
164
writer.scalar('hyperparameters/learning_rate', lr, epoch, 'Current learning rate');
165
166
// Log validation metrics (simulated)
167
if (epoch % 5 === 0) {
168
const valLoss = loss + Math.random() * 0.05;
169
const valAccuracy = accuracy - Math.random() * 0.02;
170
171
writer.scalar('validation/loss', valLoss, epoch);
172
writer.scalar('validation/accuracy', valAccuracy, epoch);
173
}
174
}
175
176
writer.flush();
177
console.log('Metrics logged. Run: tensorboard --logdir ./logs');
178
```
179
180
### Histogram Logging
181
182
Log histograms of tensor values to visualize weight distributions and activations.
183
184
```typescript { .api }
185
/**
186
* Write a histogram summary
187
* @param name - Name of the histogram
188
* @param data - Tensor containing the data to histogram
189
* @param step - Training step or epoch number
190
* @param buckets - Number of histogram buckets (default: 30)
191
* @param description - Optional description
192
*/
193
histogram(name: string, data: Tensor, step: number, buckets?: number, description?: string): void;
194
```
195
196
**Usage Example:**
197
198
```typescript
199
const writer = tf.node.summaryFileWriter('./logs/weights');
200
201
// Create a model to monitor
202
const model = tf.sequential({
203
layers: [
204
tf.layers.dense({ inputShape: [10], units: 5, activation: 'relu', name: 'hidden' }),
205
tf.layers.dense({ units: 1, activation: 'sigmoid', name: 'output' })
206
]
207
});
208
209
// Log initial weight distributions
210
model.layers.forEach((layer, layerIndex) => {
211
if ('getWeights' in layer) {
212
const weights = layer.getWeights();
213
weights.forEach((weight, weightIndex) => {
214
writer.histogram(
215
`layer_${layerIndex}/weights_${weightIndex}`,
216
weight,
217
0,
218
50,
219
`Weight distribution for layer ${layer.name}`
220
);
221
});
222
}
223
});
224
225
// Simulate training and log weight changes
226
for (let epoch = 1; epoch <= 10; epoch++) {
227
// ... training code here ...
228
229
// Log weight distributions periodically
230
if (epoch % 5 === 0) {
231
model.layers.forEach((layer, layerIndex) => {
232
if ('getWeights' in layer) {
233
const weights = layer.getWeights();
234
weights.forEach((weight, weightIndex) => {
235
writer.histogram(
236
`layer_${layerIndex}/weights_${weightIndex}`,
237
weight,
238
epoch,
239
50
240
);
241
});
242
}
243
});
244
}
245
}
246
247
writer.flush();
248
```
249
250
## TensorBoard Callback Interface
251
252
The `TensorBoardCallback` automatically logs metrics during training.
253
254
```typescript { .api }
255
class TensorBoardCallback extends CustomCallback {
256
constructor(logdir?: string, updateFreq?: 'batch' | 'epoch', histogramFreq?: number);
257
}
258
259
interface TensorBoardCallbackArgs {
260
/** How often to log: 'batch' logs after each batch, 'epoch' logs after each epoch */
261
updateFreq?: 'batch' | 'epoch';
262
263
/** How often to log weight/activation histograms (in epochs, 0 = never) */
264
histogramFreq?: number;
265
}
266
```
267
268
## Advanced Usage Patterns
269
270
### Multi-Experiment Logging
271
272
```typescript
273
async function runExperiment(
274
experimentName: string,
275
learningRate: number,
276
batchSize: number
277
) {
278
const logdir = `./logs/${experimentName}`;
279
const writer = tf.node.summaryFileWriter(logdir);
280
281
// Log hyperparameters
282
writer.scalar('hyperparameters/learning_rate', learningRate, 0);
283
writer.scalar('hyperparameters/batch_size', batchSize, 0);
284
285
// Create model
286
const model = tf.sequential({
287
layers: [
288
tf.layers.dense({ inputShape: [784], units: 128, activation: 'relu' }),
289
tf.layers.dropout({ rate: 0.2 }),
290
tf.layers.dense({ units: 10, activation: 'softmax' })
291
]
292
});
293
294
model.compile({
295
optimizer: tf.train.adam(learningRate),
296
loss: 'sparseCategoricalCrossentropy',
297
metrics: ['accuracy']
298
});
299
300
// Create TensorBoard callback
301
const tbCallback = tf.node.tensorBoard(logdir, {
302
updateFreq: 'epoch',
303
histogramFreq: 5
304
});
305
306
// Generate dummy data
307
const xs = tf.randomNormal([5000, 784]);
308
const ys = tf.randomUniform([5000, 1], 0, 10, 'int32');
309
310
// Train
311
const history = await model.fit(xs, ys, {
312
epochs: 50,
313
batchSize: batchSize,
314
validationSplit: 0.2,
315
callbacks: [tbCallback]
316
});
317
318
// Log final metrics
319
const finalLoss = history.history.loss.slice(-1)[0];
320
const finalAccuracy = history.history.acc.slice(-1)[0];
321
322
writer.scalar('final/loss', finalLoss, 50);
323
writer.scalar('final/accuracy', finalAccuracy, 50);
324
325
writer.flush();
326
327
// Cleanup
328
xs.dispose();
329
ys.dispose();
330
model.dispose();
331
332
return { finalLoss, finalAccuracy };
333
}
334
335
// Run multiple experiments
336
async function hyperparameterSweep() {
337
const experiments = [
338
{ name: 'exp_lr_001_bs_32', lr: 0.001, bs: 32 },
339
{ name: 'exp_lr_01_bs_32', lr: 0.01, bs: 32 },
340
{ name: 'exp_lr_001_bs_64', lr: 0.001, bs: 64 },
341
{ name: 'exp_lr_01_bs_64', lr: 0.01, bs: 64 }
342
];
343
344
for (const exp of experiments) {
345
console.log(`Running experiment: ${exp.name}`);
346
const results = await runExperiment(exp.name, exp.lr, exp.bs);
347
console.log(`Results: loss=${results.finalLoss}, acc=${results.finalAccuracy}`);
348
}
349
350
console.log('All experiments complete. Run: tensorboard --logdir ./logs');
351
}
352
```
353
354
### Custom Metrics Logging
355
356
```typescript
357
class CustomMetricsLogger {
358
private writer: tf.SummaryFileWriter;
359
360
constructor(logdir: string) {
361
this.writer = tf.node.summaryFileWriter(logdir);
362
}
363
364
logTrainingStep(
365
step: number,
366
loss: number,
367
accuracy: number,
368
gradientNorm: number,
369
learningRate: number
370
) {
371
this.writer.scalar('training/loss', loss, step);
372
this.writer.scalar('training/accuracy', accuracy, step);
373
this.writer.scalar('training/gradient_norm', gradientNorm, step);
374
this.writer.scalar('training/learning_rate', learningRate, step);
375
}
376
377
logValidationStep(step: number, valLoss: number, valAccuracy: number) {
378
this.writer.scalar('validation/loss', valLoss, step);
379
this.writer.scalar('validation/accuracy', valAccuracy, step);
380
}
381
382
logModelWeights(model: tf.LayersModel, step: number) {
383
model.layers.forEach((layer, layerIdx) => {
384
if ('getWeights' in layer && layer.getWeights().length > 0) {
385
const weights = layer.getWeights();
386
387
weights.forEach((weight, weightIdx) => {
388
// Log weight statistics
389
const mean = tf.mean(weight);
390
const std = tf.moments(weight).variance.sqrt();
391
const min = tf.min(weight);
392
const max = tf.max(weight);
393
394
this.writer.scalar(`weights/layer_${layerIdx}_${weightIdx}/mean`, mean.dataSync()[0], step);
395
this.writer.scalar(`weights/layer_${layerIdx}_${weightIdx}/std`, std.dataSync()[0], step);
396
this.writer.scalar(`weights/layer_${layerIdx}_${weightIdx}/min`, min.dataSync()[0], step);
397
this.writer.scalar(`weights/layer_${layerIdx}_${weightIdx}/max`, max.dataSync()[0], step);
398
399
// Log histogram
400
this.writer.histogram(`weights/layer_${layerIdx}_${weightIdx}/distribution`, weight, step);
401
402
// Cleanup
403
mean.dispose();
404
std.dispose();
405
min.dispose();
406
max.dispose();
407
});
408
}
409
});
410
}
411
412
flush() {
413
this.writer.flush();
414
}
415
}
416
417
// Usage
418
const logger = new CustomMetricsLogger('./logs/detailed');
419
420
// During training loop
421
for (let step = 0; step < 1000; step++) {
422
// ... training step ...
423
424
logger.logTrainingStep(step, loss, accuracy, gradNorm, lr);
425
426
if (step % 100 === 0) {
427
logger.logValidationStep(step, valLoss, valAccuracy);
428
logger.logModelWeights(model, step);
429
}
430
}
431
432
logger.flush();
433
```
434
435
### Real-time Monitoring
436
437
```typescript
438
class RealTimeTrainingMonitor {
439
private writer: tf.SummaryFileWriter;
440
private startTime: number;
441
442
constructor(logdir: string) {
443
this.writer = tf.node.summaryFileWriter(logdir, 1, 1000); // Flush every second
444
this.startTime = Date.now();
445
}
446
447
logSystemMetrics(step: number) {
448
const memUsage = process.memoryUsage();
449
const timeElapsed = (Date.now() - this.startTime) / 1000; // seconds
450
451
// Log memory usage
452
this.writer.scalar('system/memory_rss_mb', memUsage.rss / 1024 / 1024, step);
453
this.writer.scalar('system/memory_heap_used_mb', memUsage.heapUsed / 1024 / 1024, step);
454
this.writer.scalar('system/memory_heap_total_mb', memUsage.heapTotal / 1024 / 1024, step);
455
456
// Log timing
457
this.writer.scalar('system/time_elapsed_sec', timeElapsed, step);
458
459
// Log TensorFlow.js memory
460
const tfMemory = tf.memory();
461
this.writer.scalar('tensorflow/num_tensors', tfMemory.numTensors, step);
462
this.writer.scalar('tensorflow/num_data_buffers', tfMemory.numDataBuffers, step);
463
this.writer.scalar('tensorflow/num_bytes', tfMemory.numBytes, step);
464
}
465
466
flush() {
467
this.writer.flush();
468
}
469
}
470
471
// Usage during training
472
const monitor = new RealTimeTrainingMonitor('./logs/monitoring');
473
474
// Log system metrics every 10 steps
475
for (let step = 0; step < 1000; step++) {
476
// ... training ...
477
478
if (step % 10 === 0) {
479
monitor.logSystemMetrics(step);
480
monitor.flush();
481
}
482
}
483
```
484
485
## Starting TensorBoard
486
487
After logging data, start TensorBoard to visualize the results:
488
489
```bash
490
tensorboard --logdir ./logs
491
492
# For multiple experiments
493
tensorboard --logdir ./logs --port 6007
494
495
# With custom sampling
496
tensorboard --logdir ./logs --reload_interval 5
497
```
498
499
Then open your browser to `http://localhost:6006` (or the specified port) to view the visualizations.