or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

backend-cpu.mdindex.mdshared-kernels.md

backend-cpu.mddocs/

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

```