catniff 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/core.d.ts +13 -0
- package/dist/core.js +244 -28
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,6 +87,9 @@ I'm mostly just learning and playing with this currently, so there are no concre
|
|
|
87
87
|
* Proper documentation.
|
|
88
88
|
* GPU acceleration.
|
|
89
89
|
* Some general neural net APIs.
|
|
90
|
+
* Refactor code.
|
|
91
|
+
* Proper tests.
|
|
92
|
+
* Option to load more backends.
|
|
90
93
|
|
|
91
94
|
## Copyrights and License
|
|
92
95
|
|
package/dist/core.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export declare class Tensor {
|
|
|
41
41
|
sum(dims?: number[] | number, keepDims?: boolean): Tensor;
|
|
42
42
|
prod(dims?: number[] | number, keepDims?: boolean): Tensor;
|
|
43
43
|
mean(dims?: number[] | number, keepDims?: boolean): Tensor;
|
|
44
|
+
max(dims?: number[] | number, keepDims?: boolean): Tensor;
|
|
45
|
+
min(dims?: number[] | number, keepDims?: boolean): Tensor;
|
|
44
46
|
add(other: TensorValue | Tensor): Tensor;
|
|
45
47
|
sub(other: TensorValue | Tensor): Tensor;
|
|
46
48
|
subtract: (other: TensorValue | Tensor) => Tensor;
|
|
@@ -137,9 +139,20 @@ export declare class Tensor {
|
|
|
137
139
|
mm(other: TensorValue | Tensor): Tensor;
|
|
138
140
|
mv(other: TensorValue | Tensor): Tensor;
|
|
139
141
|
matmul(other: TensorValue | Tensor): Tensor;
|
|
142
|
+
static full(shape: number[], num: number, options?: TensorOptions): Tensor;
|
|
140
143
|
static fullLike(tensor: Tensor, num: number, options?: TensorOptions): Tensor;
|
|
144
|
+
static ones(shape?: number[], options?: TensorOptions): Tensor;
|
|
141
145
|
static onesLike(tensor: Tensor, options?: TensorOptions): Tensor;
|
|
146
|
+
static zeros(shape?: number[], options?: TensorOptions): Tensor;
|
|
142
147
|
static zerosLike(tensor: Tensor, options?: TensorOptions): Tensor;
|
|
148
|
+
static rand(shape?: number[], options?: TensorOptions): Tensor;
|
|
149
|
+
static randLike(tensor: Tensor, options?: TensorOptions): Tensor;
|
|
150
|
+
static randn(shape?: number[], options?: TensorOptions): Tensor;
|
|
151
|
+
static randnLike(tensor: Tensor, options?: TensorOptions): Tensor;
|
|
152
|
+
static randint(shape: number[], low: number, high: number, options?: TensorOptions): Tensor;
|
|
153
|
+
static randintLike(tensor: Tensor, low: number, high: number, options?: TensorOptions): Tensor;
|
|
154
|
+
static normal(shape: number[], mean: number, stdDev: number, options?: TensorOptions): Tensor;
|
|
155
|
+
static uniform(shape: number[], low: number, high: number, options?: TensorOptions): Tensor;
|
|
143
156
|
backward(): void;
|
|
144
157
|
val(): TensorValue;
|
|
145
158
|
withGrad(requiresGrad: boolean): Tensor;
|
package/dist/core.js
CHANGED
|
@@ -252,7 +252,7 @@ class Tensor {
|
|
|
252
252
|
// Tensor squeeze
|
|
253
253
|
squeeze(dims) {
|
|
254
254
|
if (typeof this.value === "number")
|
|
255
|
-
return
|
|
255
|
+
return this;
|
|
256
256
|
if (typeof dims === "number") {
|
|
257
257
|
dims = [dims];
|
|
258
258
|
}
|
|
@@ -300,10 +300,9 @@ class Tensor {
|
|
|
300
300
|
}
|
|
301
301
|
// Tensor unsqueeze - adds dimension of size 1 at specified position
|
|
302
302
|
unsqueeze(dim) {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
throw new Error(`Invalid dimension ${dim} for unsqueeze`);
|
|
303
|
+
let thisValue = this.value;
|
|
304
|
+
if (typeof thisValue === "number") {
|
|
305
|
+
thisValue = [thisValue];
|
|
307
306
|
}
|
|
308
307
|
// Insert size-1 dimension at specified position
|
|
309
308
|
const newShape = [...this.shape];
|
|
@@ -320,7 +319,7 @@ class Tensor {
|
|
|
320
319
|
newDimStride = this.strides[dim] * this.shape[dim];
|
|
321
320
|
}
|
|
322
321
|
newStrides.splice(dim, 0, newDimStride);
|
|
323
|
-
const out = new Tensor(
|
|
322
|
+
const out = new Tensor(thisValue, { shape: newShape, strides: newStrides });
|
|
324
323
|
// Set up gradient if needed
|
|
325
324
|
if (this.requiresGrad) {
|
|
326
325
|
out.requiresGrad = true;
|
|
@@ -334,7 +333,7 @@ class Tensor {
|
|
|
334
333
|
// Tensor sum reduction
|
|
335
334
|
sum(dims, keepDims = false) {
|
|
336
335
|
if (typeof this.value === "number")
|
|
337
|
-
return
|
|
336
|
+
return this;
|
|
338
337
|
if (typeof dims === "number") {
|
|
339
338
|
dims = [dims];
|
|
340
339
|
}
|
|
@@ -364,6 +363,7 @@ class Tensor {
|
|
|
364
363
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
365
364
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
366
365
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
366
|
+
// Add into sum
|
|
367
367
|
outputValue[outFlatIndex] += this.value[realFlatIndex];
|
|
368
368
|
// Mark for gradient if needed
|
|
369
369
|
if (this.requiresGrad) {
|
|
@@ -388,7 +388,7 @@ class Tensor {
|
|
|
388
388
|
// Tensor product reduction
|
|
389
389
|
prod(dims, keepDims = false) {
|
|
390
390
|
if (typeof this.value === "number")
|
|
391
|
-
return
|
|
391
|
+
return this;
|
|
392
392
|
if (typeof dims === "number") {
|
|
393
393
|
dims = [dims];
|
|
394
394
|
}
|
|
@@ -401,14 +401,6 @@ class Tensor {
|
|
|
401
401
|
const outputSize = Tensor.shapeToSize(outputShape);
|
|
402
402
|
const outputValue = new Array(outputSize).fill(1);
|
|
403
403
|
const originalSize = Tensor.shapeToSize(this.shape);
|
|
404
|
-
// Gradient data
|
|
405
|
-
let gradShape, gradStrides, gradValue = [];
|
|
406
|
-
// Allocate gradient data only when needed
|
|
407
|
-
if (this.requiresGrad) {
|
|
408
|
-
gradShape = this.shape;
|
|
409
|
-
gradStrides = this.strides;
|
|
410
|
-
gradValue = new Array(originalSize).fill(0);
|
|
411
|
-
}
|
|
412
404
|
// Calculate new value after multiplying
|
|
413
405
|
for (let index = 0; index < originalSize; index++) {
|
|
414
406
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
@@ -418,6 +410,7 @@ class Tensor {
|
|
|
418
410
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
419
411
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
420
412
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
413
|
+
// Multiply into product
|
|
421
414
|
outputValue[outFlatIndex] *= this.value[realFlatIndex];
|
|
422
415
|
}
|
|
423
416
|
const out = new Tensor(outputValue, {
|
|
@@ -426,7 +419,7 @@ class Tensor {
|
|
|
426
419
|
});
|
|
427
420
|
// Set up gradient if needed
|
|
428
421
|
if (this.requiresGrad) {
|
|
429
|
-
|
|
422
|
+
const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
|
|
430
423
|
for (let index = 0; index < originalSize; index++) {
|
|
431
424
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
432
425
|
// Force 0 on reduced axes to collapse into size-1 dims
|
|
@@ -435,7 +428,7 @@ class Tensor {
|
|
|
435
428
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
436
429
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
437
430
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
438
|
-
//
|
|
431
|
+
// Grad is the product of other elements of the same axis, which is product of all els divided by the current value
|
|
439
432
|
gradValue[realFlatIndex] = outputValue[outFlatIndex] / this.value[realFlatIndex];
|
|
440
433
|
}
|
|
441
434
|
out.requiresGrad = true;
|
|
@@ -450,7 +443,7 @@ class Tensor {
|
|
|
450
443
|
// Tensor mean reduction
|
|
451
444
|
mean(dims, keepDims = false) {
|
|
452
445
|
if (typeof this.value === "number")
|
|
453
|
-
return
|
|
446
|
+
return this;
|
|
454
447
|
if (typeof dims === "number") {
|
|
455
448
|
dims = [dims];
|
|
456
449
|
}
|
|
@@ -464,14 +457,6 @@ class Tensor {
|
|
|
464
457
|
const outputValue = new Array(outputSize).fill(0);
|
|
465
458
|
const outputFeeders = new Array(outputSize).fill(0);
|
|
466
459
|
const originalSize = Tensor.shapeToSize(this.shape);
|
|
467
|
-
// Gradient data
|
|
468
|
-
let gradShape, gradStrides, gradValue = [];
|
|
469
|
-
// Allocate gradient data only when needed
|
|
470
|
-
if (this.requiresGrad) {
|
|
471
|
-
gradShape = this.shape;
|
|
472
|
-
gradStrides = this.strides;
|
|
473
|
-
gradValue = new Array(originalSize).fill(0);
|
|
474
|
-
}
|
|
475
460
|
// Calculate sums and how many elements contribute to specific positions
|
|
476
461
|
for (let index = 0; index < originalSize; index++) {
|
|
477
462
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
@@ -481,6 +466,7 @@ class Tensor {
|
|
|
481
466
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
482
467
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
483
468
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
469
|
+
// Calculate sum and contributors to the sum
|
|
484
470
|
outputValue[outFlatIndex] += this.value[realFlatIndex];
|
|
485
471
|
outputFeeders[outFlatIndex]++;
|
|
486
472
|
}
|
|
@@ -494,7 +480,8 @@ class Tensor {
|
|
|
494
480
|
});
|
|
495
481
|
// Set up gradient if needed
|
|
496
482
|
if (this.requiresGrad) {
|
|
497
|
-
|
|
483
|
+
const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
|
|
484
|
+
// Calculate grad by assigning 1 divided by the number of contributors to the position
|
|
498
485
|
for (let index = 0; index < originalSize; index++) {
|
|
499
486
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
500
487
|
// Force 0 on reduced axes to collapse into size-1 dims
|
|
@@ -515,6 +502,120 @@ class Tensor {
|
|
|
515
502
|
}
|
|
516
503
|
return keepDims ? out : out.squeeze(dims);
|
|
517
504
|
}
|
|
505
|
+
// Tensor maximum reduction
|
|
506
|
+
max(dims, keepDims = false) {
|
|
507
|
+
if (typeof this.value === "number")
|
|
508
|
+
return this;
|
|
509
|
+
if (typeof dims === "number") {
|
|
510
|
+
dims = [dims];
|
|
511
|
+
}
|
|
512
|
+
if (typeof dims === "undefined") {
|
|
513
|
+
dims = Array.from({ length: this.shape.length }, (_, index) => index);
|
|
514
|
+
}
|
|
515
|
+
// Dims that are reduced now have size-1
|
|
516
|
+
const outputShape = this.shape.map((dim, i) => dims.includes(i) ? 1 : dim);
|
|
517
|
+
const outputStrides = Tensor.getStrides(outputShape);
|
|
518
|
+
const outputSize = Tensor.shapeToSize(outputShape);
|
|
519
|
+
const outputValue = new Array(outputSize).fill(-Infinity);
|
|
520
|
+
const originalSize = Tensor.shapeToSize(this.shape);
|
|
521
|
+
// Calculate maximum values of axes
|
|
522
|
+
for (let index = 0; index < originalSize; index++) {
|
|
523
|
+
const coords = Tensor.indexToCoords(index, this.strides);
|
|
524
|
+
// Force 0 on reduced axes to collapse into size-1 dims
|
|
525
|
+
const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
|
|
526
|
+
// Convert output coordinates to flat index
|
|
527
|
+
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
528
|
+
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
529
|
+
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
530
|
+
// Get max over time
|
|
531
|
+
if (this.value[realFlatIndex] > outputValue[outFlatIndex]) {
|
|
532
|
+
outputValue[outFlatIndex] = this.value[realFlatIndex];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const out = new Tensor(outputValue, {
|
|
536
|
+
shape: outputShape,
|
|
537
|
+
strides: outputStrides
|
|
538
|
+
});
|
|
539
|
+
// Set up gradient if needed
|
|
540
|
+
if (this.requiresGrad) {
|
|
541
|
+
const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
|
|
542
|
+
for (let index = 0; index < originalSize; index++) {
|
|
543
|
+
const coords = Tensor.indexToCoords(index, this.strides);
|
|
544
|
+
// Force 0 on reduced axes to collapse into size-1 dims
|
|
545
|
+
const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
|
|
546
|
+
// Convert output coordinates to flat index
|
|
547
|
+
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
548
|
+
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
549
|
+
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
550
|
+
// Calculate grad by checking if a positon holds a value equal to the max value
|
|
551
|
+
gradValue[realFlatIndex] = outputValue[outFlatIndex] === this.value[realFlatIndex] ? 1 : 0;
|
|
552
|
+
}
|
|
553
|
+
out.requiresGrad = true;
|
|
554
|
+
out.children.push(this);
|
|
555
|
+
out.gradFn = () => {
|
|
556
|
+
const localGrad = new Tensor(gradValue, { shape: gradShape, strides: gradStrides });
|
|
557
|
+
Tensor.addGrad(this, out.grad.withGrad(false).mul(localGrad));
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
return keepDims ? out : out.squeeze(dims);
|
|
561
|
+
}
|
|
562
|
+
// Tensor minimum reduction
|
|
563
|
+
min(dims, keepDims = false) {
|
|
564
|
+
if (typeof this.value === "number")
|
|
565
|
+
return this;
|
|
566
|
+
if (typeof dims === "number") {
|
|
567
|
+
dims = [dims];
|
|
568
|
+
}
|
|
569
|
+
if (typeof dims === "undefined") {
|
|
570
|
+
dims = Array.from({ length: this.shape.length }, (_, index) => index);
|
|
571
|
+
}
|
|
572
|
+
// Dims that are reduced now have size-1
|
|
573
|
+
const outputShape = this.shape.map((dim, i) => dims.includes(i) ? 1 : dim);
|
|
574
|
+
const outputStrides = Tensor.getStrides(outputShape);
|
|
575
|
+
const outputSize = Tensor.shapeToSize(outputShape);
|
|
576
|
+
const outputValue = new Array(outputSize).fill(Infinity);
|
|
577
|
+
const originalSize = Tensor.shapeToSize(this.shape);
|
|
578
|
+
// Calculate minimum values of axes
|
|
579
|
+
for (let index = 0; index < originalSize; index++) {
|
|
580
|
+
const coords = Tensor.indexToCoords(index, this.strides);
|
|
581
|
+
// Force 0 on reduced axes to collapse into size-1 dims
|
|
582
|
+
const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
|
|
583
|
+
// Convert output coordinates to flat index
|
|
584
|
+
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
585
|
+
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
586
|
+
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
587
|
+
// Get min over time
|
|
588
|
+
if (this.value[realFlatIndex] < outputValue[outFlatIndex]) {
|
|
589
|
+
outputValue[outFlatIndex] = this.value[realFlatIndex];
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const out = new Tensor(outputValue, {
|
|
593
|
+
shape: outputShape,
|
|
594
|
+
strides: outputStrides
|
|
595
|
+
});
|
|
596
|
+
// Set up gradient if needed
|
|
597
|
+
if (this.requiresGrad) {
|
|
598
|
+
const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
|
|
599
|
+
for (let index = 0; index < originalSize; index++) {
|
|
600
|
+
const coords = Tensor.indexToCoords(index, this.strides);
|
|
601
|
+
// Force 0 on reduced axes to collapse into size-1 dims
|
|
602
|
+
const outCoords = coords.map((val, i) => dims.includes(i) ? 0 : val);
|
|
603
|
+
// Convert output coordinates to flat index
|
|
604
|
+
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
605
|
+
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
606
|
+
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
607
|
+
// Calculate grad by checking if a positon holds a value equal to the min value
|
|
608
|
+
gradValue[realFlatIndex] = outputValue[outFlatIndex] === this.value[realFlatIndex] ? 1 : 0;
|
|
609
|
+
}
|
|
610
|
+
out.requiresGrad = true;
|
|
611
|
+
out.children.push(this);
|
|
612
|
+
out.gradFn = () => {
|
|
613
|
+
const localGrad = new Tensor(gradValue, { shape: gradShape, strides: gradStrides });
|
|
614
|
+
Tensor.addGrad(this, out.grad.withGrad(false).mul(localGrad));
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
return keepDims ? out : out.squeeze(dims);
|
|
618
|
+
}
|
|
518
619
|
// Tensor element-wise addition
|
|
519
620
|
add(other) {
|
|
520
621
|
return this.elementWiseABDAG(other, (a, b) => a + b, (self, other, outGrad) => outGrad, (self, other, outGrad) => outGrad);
|
|
@@ -1000,24 +1101,139 @@ class Tensor {
|
|
|
1000
1101
|
// Too lazy for batched matmul
|
|
1001
1102
|
throw new Error(`Shapes [${this.shape}] and [${other.shape}] are not supported`);
|
|
1002
1103
|
}
|
|
1104
|
+
// Utility to create a new tensor filled with a number
|
|
1105
|
+
static full(shape, num, options = {}) {
|
|
1106
|
+
if (shape.length === 0)
|
|
1107
|
+
return new Tensor(num, options);
|
|
1108
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1109
|
+
const outputValue = new Array(outputSize).fill(num);
|
|
1110
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1111
|
+
}
|
|
1003
1112
|
// Utility to create a new tensor with shape of another tensor, filled with a number
|
|
1004
1113
|
static fullLike(tensor, num, options = {}) {
|
|
1005
1114
|
if (typeof tensor.value === "number")
|
|
1006
1115
|
return new Tensor(num, options);
|
|
1007
1116
|
return new Tensor(new Array(tensor.value.length).fill(num), { shape: tensor.shape, strides: tensor.strides, ...options });
|
|
1008
1117
|
}
|
|
1118
|
+
// Utility to create a new tensor filled with 1
|
|
1119
|
+
static ones(shape, options = {}) {
|
|
1120
|
+
if (typeof shape === "undefined" || shape.length === 0)
|
|
1121
|
+
return new Tensor(1, options);
|
|
1122
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1123
|
+
const outputValue = new Array(outputSize).fill(1);
|
|
1124
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1125
|
+
}
|
|
1009
1126
|
// Utility to create a new tensor with shape of another tensor, filled with 1
|
|
1010
1127
|
static onesLike(tensor, options = {}) {
|
|
1011
1128
|
if (typeof tensor.value === "number")
|
|
1012
1129
|
return new Tensor(1, options);
|
|
1013
1130
|
return new Tensor(new Array(tensor.value.length).fill(1), { shape: tensor.shape, strides: tensor.strides, ...options });
|
|
1014
1131
|
}
|
|
1132
|
+
// Utility to create a new tensor filled with 0
|
|
1133
|
+
static zeros(shape, options = {}) {
|
|
1134
|
+
if (typeof shape === "undefined" || shape.length === 0)
|
|
1135
|
+
return new Tensor(0, options);
|
|
1136
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1137
|
+
const outputValue = new Array(outputSize).fill(0);
|
|
1138
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1139
|
+
}
|
|
1015
1140
|
// Utility to create a new tensor with shape of another tensor, filled with 0
|
|
1016
1141
|
static zerosLike(tensor, options = {}) {
|
|
1017
1142
|
if (typeof tensor.value === "number")
|
|
1018
1143
|
return new Tensor(0, options);
|
|
1019
1144
|
return new Tensor(new Array(tensor.value.length).fill(0), { shape: tensor.shape, strides: tensor.strides, ...options });
|
|
1020
1145
|
}
|
|
1146
|
+
// Utility to create a new tensor filled with a random number with uniform distribution from 0 to 1
|
|
1147
|
+
static rand(shape, options = {}) {
|
|
1148
|
+
if (typeof shape === "undefined" || shape.length === 0)
|
|
1149
|
+
return new Tensor((0, utils_1.randUniform)(), options);
|
|
1150
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1151
|
+
const outputValue = new Array(outputSize);
|
|
1152
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1153
|
+
outputValue[index] = (0, utils_1.randUniform)();
|
|
1154
|
+
}
|
|
1155
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1156
|
+
}
|
|
1157
|
+
// Utility to create a new tensor with shape of another tensor, filled with a random number with uniform distribution from 0 to 1
|
|
1158
|
+
static randLike(tensor, options = {}) {
|
|
1159
|
+
if (typeof tensor.value === "number")
|
|
1160
|
+
return new Tensor((0, utils_1.randUniform)(), options);
|
|
1161
|
+
const outputValue = new Array(tensor.value.length);
|
|
1162
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1163
|
+
outputValue[index] = (0, utils_1.randUniform)();
|
|
1164
|
+
}
|
|
1165
|
+
return new Tensor(outputValue, {
|
|
1166
|
+
shape: tensor.shape, strides: tensor.strides, ...options
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
// Utility to create a new tensor filled with a random number with normal distribution of mean=0 and stddev=1
|
|
1170
|
+
static randn(shape, options = {}) {
|
|
1171
|
+
if (typeof shape === "undefined" || shape.length === 0)
|
|
1172
|
+
return new Tensor((0, utils_1.randNormal)(), options);
|
|
1173
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1174
|
+
const outputValue = new Array(outputSize);
|
|
1175
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1176
|
+
outputValue[index] = (0, utils_1.randNormal)();
|
|
1177
|
+
}
|
|
1178
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1179
|
+
}
|
|
1180
|
+
// Utility to create a new tensor with shape of another tensor, filled with a random number with normal distribution of mean=0 and stddev=1
|
|
1181
|
+
static randnLike(tensor, options = {}) {
|
|
1182
|
+
if (typeof tensor.value === "number")
|
|
1183
|
+
return new Tensor((0, utils_1.randNormal)(), options);
|
|
1184
|
+
const outputValue = new Array(tensor.value.length);
|
|
1185
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1186
|
+
outputValue[index] = (0, utils_1.randNormal)();
|
|
1187
|
+
}
|
|
1188
|
+
return new Tensor(outputValue, {
|
|
1189
|
+
shape: tensor.shape, strides: tensor.strides, ...options
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
// Utility to create a new tensor filled with a random integer between low and high
|
|
1193
|
+
static randint(shape, low, high, options = {}) {
|
|
1194
|
+
if (shape.length === 0)
|
|
1195
|
+
return new Tensor((0, utils_1.randInt)(low, high), options);
|
|
1196
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1197
|
+
const outputValue = new Array(outputSize);
|
|
1198
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1199
|
+
outputValue[index] = (0, utils_1.randInt)(low, high);
|
|
1200
|
+
}
|
|
1201
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1202
|
+
}
|
|
1203
|
+
// Utility to create a new tensor with shape of another tensor, filled with a random integer between low and high
|
|
1204
|
+
static randintLike(tensor, low, high, options = {}) {
|
|
1205
|
+
if (typeof tensor.value === "number")
|
|
1206
|
+
return new Tensor((0, utils_1.randInt)(low, high), options);
|
|
1207
|
+
const outputValue = new Array(tensor.value.length);
|
|
1208
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1209
|
+
outputValue[index] = (0, utils_1.randInt)(low, high);
|
|
1210
|
+
}
|
|
1211
|
+
return new Tensor(outputValue, {
|
|
1212
|
+
shape: tensor.shape, strides: tensor.strides, ...options
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
// Utility to create a new tensor filled with a random number with normal distribution of custom mean and stddev
|
|
1216
|
+
static normal(shape, mean, stdDev, options = {}) {
|
|
1217
|
+
if (shape.length === 0)
|
|
1218
|
+
return new Tensor((0, utils_1.randNormal)(mean, stdDev), options);
|
|
1219
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1220
|
+
const outputValue = new Array(outputSize);
|
|
1221
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1222
|
+
outputValue[index] = (0, utils_1.randNormal)(mean, stdDev);
|
|
1223
|
+
}
|
|
1224
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1225
|
+
}
|
|
1226
|
+
// Utility to create a new tensor filled with a random number with uniform distribution from low to high
|
|
1227
|
+
static uniform(shape, low, high, options = {}) {
|
|
1228
|
+
if (shape.length === 0)
|
|
1229
|
+
return new Tensor((0, utils_1.randUniform)(low, high), options);
|
|
1230
|
+
const outputSize = Tensor.shapeToSize(shape);
|
|
1231
|
+
const outputValue = new Array(outputSize);
|
|
1232
|
+
for (let index = 0; index < outputValue.length; index++) {
|
|
1233
|
+
outputValue[index] = (0, utils_1.randUniform)(low, high);
|
|
1234
|
+
}
|
|
1235
|
+
return new Tensor(outputValue, { shape, ...options });
|
|
1236
|
+
}
|
|
1021
1237
|
// Reverse-mode autodiff call
|
|
1022
1238
|
backward() {
|
|
1023
1239
|
// Build topological order
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export declare function erf(x: number): number;
|
|
2
2
|
export declare function erfc(x: number): number;
|
|
3
3
|
export declare function erfinv(x: number): number;
|
|
4
|
+
export declare function randUniform(low?: number, high?: number): number;
|
|
5
|
+
export declare function randNormal(mean?: number, stdDev?: number): number;
|
|
6
|
+
export declare function randInt(low: number, high: number): number;
|
package/dist/utils.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.erf = erf;
|
|
4
4
|
exports.erfc = erfc;
|
|
5
5
|
exports.erfinv = erfinv;
|
|
6
|
+
exports.randUniform = randUniform;
|
|
7
|
+
exports.randNormal = randNormal;
|
|
8
|
+
exports.randInt = randInt;
|
|
6
9
|
// Error function using Abramowitz and Stegun approximation
|
|
7
10
|
function erf(x) {
|
|
8
11
|
const a1 = 0.254829592;
|
|
@@ -33,3 +36,15 @@ function erfinv(x) {
|
|
|
33
36
|
const sign = x >= 0 ? 1 : -1;
|
|
34
37
|
return sign * Math.sqrt(-part1 + Math.sqrt(part1 * part1 - part2));
|
|
35
38
|
}
|
|
39
|
+
function randUniform(low = 0, high = 1) {
|
|
40
|
+
return Math.random() * (high - low) + low;
|
|
41
|
+
}
|
|
42
|
+
function randNormal(mean = 0, stdDev = 1) {
|
|
43
|
+
const u = 1 - Math.random();
|
|
44
|
+
const v = 1 - Math.random();
|
|
45
|
+
const z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
|
46
|
+
return z * stdDev + mean;
|
|
47
|
+
}
|
|
48
|
+
function randInt(low, high) {
|
|
49
|
+
return Math.floor(Math.random() * (high - low) + low);
|
|
50
|
+
}
|