0
# MathBackendCPU Class
1
2
The `MathBackendCPU` class is the core CPU backend implementation for TensorFlow.js, extending the base `KernelBackend` class to provide high-performance tensor operations using vanilla JavaScript.
3
4
## Class Definition
5
6
```typescript { .api }
7
import { KernelBackend, DataType, TensorInfo, DataId, DataStorage } from '@tensorflow/tfjs-core';
8
9
export class MathBackendCPU extends KernelBackend {
10
// Public properties
11
public blockSize: number = 48;
12
data: DataStorage<TensorData<DataType>>;
13
14
// Methods documented below...
15
}
16
```
17
18
## Type Definitions
19
20
### TensorData Interface
21
22
```typescript { .api }
23
interface TensorData<D extends DataType> {
24
values?: BackendValues;
25
dtype: D;
26
complexTensorInfos?: { real: TensorInfo, imag: TensorInfo };
27
refCount: number;
28
}
29
```
30
31
### BackendValues Type
32
33
```typescript { .api }
34
import type { BackendValues } from '@tensorflow/tfjs-core';
35
36
// BackendValues can be:
37
// - TypedArray (Float32Array, Int32Array, Uint8Array, etc.)
38
// - number[]
39
// - string[]
40
// - Uint8Array[] (for string tensors)
41
```
42
43
### Memory and Timing Types
44
45
```typescript { .api }
46
interface MemoryInfo {
47
numTensors: number;
48
numDataBuffers: number;
49
numBytes: number;
50
unreliable: boolean;
51
}
52
53
interface BackendTimingInfo {
54
kernelMs: number;
55
}
56
```
57
58
## Public Properties
59
60
### blockSize
61
62
```typescript { .api }
63
public blockSize: number = 48;
64
```
65
66
The block size used for various operations and memory allocation strategies. This value is optimized for CPU performance and affects how operations are chunked for processing.
67
68
### data
69
70
```typescript { .api }
71
data: DataStorage<TensorData<DataType>>;
72
```
73
74
Internal data storage that manages all tensor data using a reference counting system. Each tensor gets a unique `DataId` that maps to its `TensorData`.
75
76
## Core Methods
77
78
### write()
79
80
```typescript { .api }
81
write(values: BackendValues, shape: number[], dtype: DataType): DataId
82
```
83
84
Writes tensor data to the backend storage system.
85
86
**Parameters:**
87
- `values: BackendValues` - The tensor values (TypedArray, number[], or string[])
88
- `shape: number[]` - The dimensions of the tensor
89
- `dtype: DataType` - The data type ('float32', 'int32', 'bool', 'string', etc.)
90
91
**Returns:** `DataId` - Unique identifier for the stored tensor data
92
93
**Example:**
94
```typescript { .api }
95
import { MathBackendCPU } from '@tensorflow/tfjs-backend-cpu/base';
96
97
const backend = new MathBackendCPU();
98
99
// Write float32 data
100
const dataId1 = backend.write(
101
new Float32Array([1.0, 2.5, 3.7, 4.2]),
102
[2, 2],
103
'float32'
104
);
105
106
// Write integer data
107
const dataId2 = backend.write(
108
new Int32Array([10, 20, 30]),
109
[3],
110
'int32'
111
);
112
113
// Write string data
114
const dataId3 = backend.write(
115
['hello', 'world'],
116
[2],
117
'string'
118
);
119
```
120
121
### makeTensorInfo()
122
123
```typescript { .api }
124
makeTensorInfo(
125
shape: number[],
126
dtype: DataType,
127
values?: BackendValues | string[]
128
): TensorInfo
129
```
130
131
Creates a `TensorInfo` object with data stored in the CPU backend.
132
133
**Parameters:**
134
- `shape: number[]` - The tensor dimensions
135
- `dtype: DataType` - The data type
136
- `values?: BackendValues | string[]` - Optional initial values (if not provided, creates uninitialized tensor)
137
138
**Returns:** `TensorInfo` - Complete tensor information object
139
140
**Example:**
141
```typescript { .api }
142
const backend = new MathBackendCPU();
143
144
// Create tensor with initial values
145
const tensorInfo1 = backend.makeTensorInfo(
146
[3, 3],
147
'float32',
148
new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9])
149
);
150
151
// Create uninitialized tensor
152
const tensorInfo2 = backend.makeTensorInfo([5], 'int32');
153
154
// Create boolean tensor
155
const tensorInfo3 = backend.makeTensorInfo(
156
[2, 2],
157
'bool',
158
new Uint8Array([1, 0, 1, 0])
159
);
160
```
161
162
### read()
163
164
```typescript { .api }
165
read(dataId: DataId): Promise<BackendValues>
166
```
167
168
Asynchronously reads tensor data from storage.
169
170
**Parameters:**
171
- `dataId: DataId` - The unique identifier for the tensor data
172
173
**Returns:** `Promise<BackendValues>` - Promise resolving to the tensor values
174
175
**Example:**
176
```typescript { .api }
177
const backend = new MathBackendCPU();
178
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
179
180
// Async read
181
const values = await backend.read(dataId);
182
console.log(values); // Float32Array([1, 2, 3])
183
```
184
185
### readSync()
186
187
```typescript { .api }
188
readSync(dataId: DataId): BackendValues
189
```
190
191
Synchronously reads tensor data from storage.
192
193
**Parameters:**
194
- `dataId: DataId` - The unique identifier for the tensor data
195
196
**Returns:** `BackendValues` - The tensor values
197
198
**Example:**
199
```typescript { .api }
200
const backend = new MathBackendCPU();
201
const dataId = backend.write(new Int32Array([10, 20, 30]), [3], 'int32');
202
203
// Sync read
204
const values = backend.readSync(dataId);
205
console.log(values); // Int32Array([10, 20, 30])
206
```
207
208
### bufferSync()
209
210
```typescript { .api }
211
bufferSync<R extends Rank, D extends DataType>(t: TensorInfo): TensorBuffer<R, D>
212
```
213
214
Creates a `TensorBuffer` that provides indexed access to tensor data.
215
216
**Parameters:**
217
- `t: TensorInfo` - The tensor information object
218
219
**Returns:** `TensorBuffer<R, D>` - Buffer providing get/set access by indices
220
221
**Example:**
222
```typescript { .api }
223
const backend = new MathBackendCPU();
224
const tensorInfo = backend.makeTensorInfo([2, 3], 'float32');
225
const buffer = backend.bufferSync(tensorInfo);
226
227
// Set values using multi-dimensional indexing
228
buffer.set(1.5, 0, 0); // Set value at [0, 0]
229
buffer.set(2.7, 0, 1); // Set value at [0, 1]
230
buffer.set(3.9, 1, 2); // Set value at [1, 2]
231
232
// Get values
233
const val = buffer.get(0, 0); // 1.5
234
235
// Access underlying values array
236
const allValues = buffer.values; // Float32Array
237
```
238
239
### makeOutput()
240
241
```typescript { .api }
242
makeOutput<T extends Tensor>(
243
values: BackendValues,
244
shape: number[],
245
dtype: DataType
246
): T
247
```
248
249
Creates an output tensor from computed values.
250
251
**Parameters:**
252
- `values: BackendValues` - The computed output values
253
- `shape: number[]` - The output tensor shape
254
- `dtype: DataType` - The output data type
255
256
**Returns:** `T extends Tensor` - The output tensor
257
258
**Example:**
259
```typescript { .api }
260
const backend = new MathBackendCPU();
261
262
// Create output from computation
263
const result = backend.makeOutput(
264
new Float32Array([2, 4, 6, 8]), // computed values
265
[2, 2], // output shape
266
'float32' // dtype
267
);
268
269
// Use in kernel implementations
270
function doubleKernel(inputs: { x: TensorInfo }, backend: MathBackendCPU): TensorInfo {
271
const { x } = inputs;
272
const values = backend.readSync(x.dataId) as Float32Array;
273
const doubled = values.map(v => v * 2);
274
275
return backend.makeOutput(doubled, x.shape, x.dtype);
276
}
277
```
278
279
## Memory Management Methods
280
281
### refCount()
282
283
```typescript { .api }
284
refCount(dataId: DataId): number
285
```
286
287
Returns the current reference count for tensor data.
288
289
**Parameters:**
290
- `dataId: DataId` - The data identifier
291
292
**Returns:** `number` - Current reference count
293
294
**Example:**
295
```typescript { .api }
296
const backend = new MathBackendCPU();
297
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
298
299
console.log(backend.refCount(dataId)); // 1
300
```
301
302
### incRef()
303
304
```typescript { .api }
305
incRef(dataId: DataId): void
306
```
307
308
Increments the reference count for tensor data. Use this when storing additional references to prevent premature cleanup.
309
310
**Parameters:**
311
- `dataId: DataId` - The data identifier
312
313
**Example:**
314
```typescript { .api }
315
const backend = new MathBackendCPU();
316
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
317
318
backend.incRef(dataId);
319
console.log(backend.refCount(dataId)); // 2
320
321
// Now dataId won't be cleaned up until refCount reaches 0
322
```
323
324
### decRef()
325
326
```typescript { .api }
327
decRef(dataId: DataId): void
328
```
329
330
Decrements the reference count for tensor data. When count reaches 0, data becomes eligible for cleanup.
331
332
**Parameters:**
333
- `dataId: DataId` - The data identifier
334
335
**Example:**
336
```typescript { .api }
337
const backend = new MathBackendCPU();
338
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
339
340
backend.incRef(dataId); // refCount = 2
341
backend.decRef(dataId); // refCount = 1
342
backend.decRef(dataId); // refCount = 0 (eligible for cleanup)
343
```
344
345
### disposeData()
346
347
```typescript { .api }
348
disposeData(dataId: DataId, force?: boolean): boolean
349
```
350
351
Disposes tensor data from memory if reference count allows.
352
353
**Parameters:**
354
- `dataId: DataId` - The data identifier
355
- `force?: boolean = false` - If true, dispose regardless of reference count
356
357
**Returns:** `boolean` - True if memory was actually released
358
359
**Example:**
360
```typescript { .api }
361
const backend = new MathBackendCPU();
362
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
363
364
// Won't dispose if refCount > 0
365
let disposed = backend.disposeData(dataId);
366
console.log(disposed); // false (refCount is 1)
367
368
// Force disposal
369
disposed = backend.disposeData(dataId, true);
370
console.log(disposed); // true (memory released)
371
372
// Or decrement refCount first
373
const dataId2 = backend.write(new Float32Array([4, 5, 6]), [3], 'float32');
374
backend.decRef(dataId2); // refCount becomes 0
375
disposed = backend.disposeData(dataId2);
376
console.log(disposed); // true
377
```
378
379
### disposeIntermediateTensorInfo()
380
381
```typescript { .api }
382
disposeIntermediateTensorInfo(tensorInfo: TensorInfo): void
383
```
384
385
Disposes intermediate tensor data created during computations.
386
387
**Parameters:**
388
- `tensorInfo: TensorInfo` - The intermediate tensor to dispose
389
390
**Example:**
391
```typescript { .api }
392
function complexOperation(backend: MathBackendCPU, input: TensorInfo): TensorInfo {
393
// Create intermediate result
394
const intermediate = backend.makeTensorInfo([10], 'float32', new Float32Array(10));
395
396
// Use intermediate in computation...
397
const finalResult = backend.makeOutput(
398
backend.readSync(intermediate.dataId),
399
[10],
400
'float32'
401
);
402
403
// Clean up intermediate
404
backend.disposeIntermediateTensorInfo(intermediate);
405
406
return finalResult;
407
}
408
```
409
410
## Utility Methods
411
412
### move()
413
414
```typescript { .api }
415
move(
416
dataId: DataId,
417
values: BackendValues,
418
shape: number[],
419
dtype: DataType,
420
refCount: number
421
): void
422
```
423
424
Moves tensor data to a new location with updated metadata.
425
426
**Parameters:**
427
- `dataId: DataId` - The data identifier
428
- `values: BackendValues` - New tensor values
429
- `shape: number[]` - New tensor shape
430
- `dtype: DataType` - New data type
431
- `refCount: number` - New reference count
432
433
**Example:**
434
```typescript { .api }
435
const backend = new MathBackendCPU();
436
const dataId = backend.write(new Float32Array([1, 2]), [2], 'float32');
437
438
// Move data to new configuration
439
backend.move(
440
dataId,
441
new Float32Array([1, 2, 3, 4]), // new values
442
[2, 2], // new shape
443
'float32', // same dtype
444
1 // reset refCount
445
);
446
```
447
448
### numDataIds()
449
450
```typescript { .api }
451
numDataIds(): number
452
```
453
454
Returns the total number of data items currently stored.
455
456
**Returns:** `number` - Count of stored tensor data items
457
458
**Example:**
459
```typescript { .api }
460
const backend = new MathBackendCPU();
461
462
console.log(backend.numDataIds()); // 0
463
464
const dataId1 = backend.write(new Float32Array([1, 2]), [2], 'float32');
465
const dataId2 = backend.write(new Int32Array([3, 4]), [2], 'int32');
466
467
console.log(backend.numDataIds()); // 2
468
469
backend.disposeData(dataId1, true);
470
console.log(backend.numDataIds()); // 1
471
```
472
473
### time()
474
475
```typescript { .api }
476
time(f: () => void): Promise<BackendTimingInfo>
477
```
478
479
Times the execution of a function and returns performance information.
480
481
**Parameters:**
482
- `f: () => void` - Function to time
483
484
**Returns:** `Promise<BackendTimingInfo>` - Timing information with `kernelMs` property
485
486
**Example:**
487
```typescript { .api }
488
const backend = new MathBackendCPU();
489
490
const timingInfo = await backend.time(() => {
491
// Expensive operation
492
const dataId = backend.write(new Float32Array(10000).fill(1), [10000], 'float32');
493
const values = backend.readSync(dataId);
494
const sum = Array.from(values).reduce((a, b) => a + b, 0);
495
});
496
497
console.log(`Operation took ${timingInfo.kernelMs}ms`);
498
```
499
500
### memory()
501
502
```typescript { .api }
503
memory(): MemoryInfo
504
```
505
506
Returns memory usage information (note: marked as unreliable due to JavaScript garbage collection).
507
508
**Returns:** `MemoryInfo` - Memory information object
509
510
**Example:**
511
```typescript { .api }
512
const backend = new MathBackendCPU();
513
514
const memInfo = backend.memory();
515
console.log({
516
numTensors: memInfo.numTensors,
517
numDataBuffers: memInfo.numDataBuffers,
518
numBytes: memInfo.numBytes,
519
unreliable: memInfo.unreliable // Always true for CPU backend
520
});
521
```
522
523
### where()
524
525
```typescript { .api }
526
where(condition: Tensor): Tensor2D
527
```
528
529
Returns the indices where the condition tensor is true.
530
531
**Parameters:**
532
- `condition: Tensor` - Boolean condition tensor
533
534
**Returns:** `Tensor2D` - 2D tensor of indices where condition is true
535
536
**Example:**
537
```typescript { .api }
538
import * as tf from '@tensorflow/tfjs-core';
539
540
const backend = new MathBackendCPU();
541
542
// Create condition tensor
543
const condition = tf.tensor1d([true, false, true, false], 'bool');
544
const indices = backend.where(condition);
545
546
console.log(await indices.data()); // Indices where condition is true
547
```
548
549
### floatPrecision()
550
551
```typescript { .api }
552
floatPrecision(): 16 | 32
553
```
554
555
Returns the floating-point precision used by the backend.
556
557
**Returns:** `32` - Always returns 32 for CPU backend (32-bit floats)
558
559
**Example:**
560
```typescript { .api }
561
const backend = new MathBackendCPU();
562
console.log(backend.floatPrecision()); // 32
563
```
564
565
### epsilon()
566
567
```typescript { .api }
568
epsilon(): number
569
```
570
571
Returns the machine epsilon (smallest representable positive number).
572
573
**Returns:** `number` - Machine epsilon value
574
575
**Example:**
576
```typescript { .api }
577
const backend = new MathBackendCPU();
578
console.log(backend.epsilon()); // ~1.1920928955078125e-7
579
```
580
581
### dispose()
582
583
```typescript { .api }
584
dispose(): void
585
```
586
587
Cleans up all backend resources and stored tensor data.
588
589
**Example:**
590
```typescript { .api }
591
const backend = new MathBackendCPU();
592
593
// Use backend for operations...
594
const dataId = backend.write(new Float32Array([1, 2, 3]), [3], 'float32');
595
596
// Clean up when done
597
backend.dispose();
598
599
console.log(backend.numDataIds()); // 0 (all data cleaned up)
600
```
601
602
## Advanced Usage Examples
603
604
### Custom Kernel Implementation
605
606
```typescript { .api }
607
import { KernelConfig, KernelFunc } from '@tensorflow/tfjs-core';
608
import { MathBackendCPU } from '@tensorflow/tfjs-backend-cpu/base';
609
610
// Custom kernel that squares all values
611
const squareKernel: KernelFunc = ({ inputs, backend }) => {
612
const { x } = inputs;
613
const cpuBackend = backend as MathBackendCPU;
614
615
const values = cpuBackend.readSync(x.dataId) as Float32Array;
616
const squaredValues = new Float32Array(values.length);
617
618
for (let i = 0; i < values.length; i++) {
619
squaredValues[i] = values[i] * values[i];
620
}
621
622
return cpuBackend.makeOutput(squaredValues, x.shape, x.dtype);
623
};
624
625
// Register the kernel
626
const squareConfig: KernelConfig = {
627
kernelName: 'Square',
628
backendName: 'cpu',
629
kernelFunc: squareKernel
630
};
631
```
632
633
### Memory Pool Management
634
635
```typescript { .api }
636
class ManagedBackend {
637
private backend: MathBackendCPU;
638
private activeDataIds: Set<DataId>;
639
640
constructor() {
641
this.backend = new MathBackendCPU();
642
this.activeDataIds = new Set();
643
}
644
645
createTensor(values: BackendValues, shape: number[], dtype: DataType): DataId {
646
const dataId = this.backend.write(values, shape, dtype);
647
this.activeDataIds.add(dataId);
648
return dataId;
649
}
650
651
cloneData(dataId: DataId): DataId {
652
this.backend.incRef(dataId);
653
return dataId;
654
}
655
656
cleanup(): void {
657
// Dispose all managed tensors
658
for (const dataId of this.activeDataIds) {
659
while (this.backend.refCount(dataId) > 0) {
660
this.backend.decRef(dataId);
661
}
662
this.backend.disposeData(dataId, true);
663
}
664
this.activeDataIds.clear();
665
}
666
}
667
```
668
669
### Performance Monitoring
670
671
```typescript { .api }
672
class PerformanceMonitor {
673
private backend: MathBackendCPU;
674
private operationCounts: Map<string, number> = new Map();
675
private totalTime: number = 0;
676
677
constructor(backend: MathBackendCPU) {
678
this.backend = backend;
679
}
680
681
async timeOperation<T>(name: string, operation: () => T): Promise<T> {
682
const startTime = performance.now();
683
684
const timingInfo = await this.backend.time(() => {
685
const result = operation();
686
return result;
687
});
688
689
const endTime = performance.now();
690
691
// Update statistics
692
this.operationCounts.set(name, (this.operationCounts.get(name) || 0) + 1);
693
this.totalTime += timingInfo.kernelMs;
694
695
console.log(`${name}: ${timingInfo.kernelMs}ms (Total: ${endTime - startTime}ms)`);
696
697
return operation();
698
}
699
700
getStats() {
701
return {
702
operations: Object.fromEntries(this.operationCounts),
703
totalKernelTime: this.totalTime,
704
memoryInfo: this.backend.memory()
705
};
706
}
707
}
708
```