catniff 0.2.10 → 0.2.12
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 +11 -0
- package/dist/core.js +184 -38
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +35 -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;
|
|
@@ -112,6 +114,12 @@ export declare class Tensor {
|
|
|
112
114
|
relu(): Tensor;
|
|
113
115
|
sigmoid(): Tensor;
|
|
114
116
|
tanh(): Tensor;
|
|
117
|
+
softplus(): Tensor;
|
|
118
|
+
softsign(): Tensor;
|
|
119
|
+
silu(): Tensor;
|
|
120
|
+
mish(): Tensor;
|
|
121
|
+
maximum(other: TensorValue | Tensor): Tensor;
|
|
122
|
+
minimum(other: TensorValue | Tensor): Tensor;
|
|
115
123
|
round(): Tensor;
|
|
116
124
|
floor(): Tensor;
|
|
117
125
|
ceil(): Tensor;
|
|
@@ -120,6 +128,9 @@ export declare class Tensor {
|
|
|
120
128
|
frac(): Tensor;
|
|
121
129
|
clip(min: number, max: number): Tensor;
|
|
122
130
|
clamp: (min: number, max: number) => Tensor;
|
|
131
|
+
erf(): Tensor;
|
|
132
|
+
erfc(): Tensor;
|
|
133
|
+
erfinv(): Tensor;
|
|
123
134
|
transpose(dim1: number, dim2: number): Tensor;
|
|
124
135
|
swapaxes: (dim1: number, dim2: number) => Tensor;
|
|
125
136
|
swapdims: (dim1: number, dim2: number) => Tensor;
|
package/dist/core.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Tensor = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
4
5
|
class Tensor {
|
|
5
6
|
value;
|
|
6
7
|
shape;
|
|
@@ -251,7 +252,7 @@ class Tensor {
|
|
|
251
252
|
// Tensor squeeze
|
|
252
253
|
squeeze(dims) {
|
|
253
254
|
if (typeof this.value === "number")
|
|
254
|
-
return
|
|
255
|
+
return this;
|
|
255
256
|
if (typeof dims === "number") {
|
|
256
257
|
dims = [dims];
|
|
257
258
|
}
|
|
@@ -299,10 +300,9 @@ class Tensor {
|
|
|
299
300
|
}
|
|
300
301
|
// Tensor unsqueeze - adds dimension of size 1 at specified position
|
|
301
302
|
unsqueeze(dim) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
throw new Error(`Invalid dimension ${dim} for unsqueeze`);
|
|
303
|
+
let thisValue = this.value;
|
|
304
|
+
if (typeof thisValue === "number") {
|
|
305
|
+
thisValue = [thisValue];
|
|
306
306
|
}
|
|
307
307
|
// Insert size-1 dimension at specified position
|
|
308
308
|
const newShape = [...this.shape];
|
|
@@ -319,7 +319,7 @@ class Tensor {
|
|
|
319
319
|
newDimStride = this.strides[dim] * this.shape[dim];
|
|
320
320
|
}
|
|
321
321
|
newStrides.splice(dim, 0, newDimStride);
|
|
322
|
-
const out = new Tensor(
|
|
322
|
+
const out = new Tensor(thisValue, { shape: newShape, strides: newStrides });
|
|
323
323
|
// Set up gradient if needed
|
|
324
324
|
if (this.requiresGrad) {
|
|
325
325
|
out.requiresGrad = true;
|
|
@@ -333,7 +333,7 @@ class Tensor {
|
|
|
333
333
|
// Tensor sum reduction
|
|
334
334
|
sum(dims, keepDims = false) {
|
|
335
335
|
if (typeof this.value === "number")
|
|
336
|
-
return
|
|
336
|
+
return this;
|
|
337
337
|
if (typeof dims === "number") {
|
|
338
338
|
dims = [dims];
|
|
339
339
|
}
|
|
@@ -363,6 +363,7 @@ class Tensor {
|
|
|
363
363
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
364
364
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
365
365
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
366
|
+
// Add into sum
|
|
366
367
|
outputValue[outFlatIndex] += this.value[realFlatIndex];
|
|
367
368
|
// Mark for gradient if needed
|
|
368
369
|
if (this.requiresGrad) {
|
|
@@ -387,7 +388,7 @@ class Tensor {
|
|
|
387
388
|
// Tensor product reduction
|
|
388
389
|
prod(dims, keepDims = false) {
|
|
389
390
|
if (typeof this.value === "number")
|
|
390
|
-
return
|
|
391
|
+
return this;
|
|
391
392
|
if (typeof dims === "number") {
|
|
392
393
|
dims = [dims];
|
|
393
394
|
}
|
|
@@ -400,14 +401,6 @@ class Tensor {
|
|
|
400
401
|
const outputSize = Tensor.shapeToSize(outputShape);
|
|
401
402
|
const outputValue = new Array(outputSize).fill(1);
|
|
402
403
|
const originalSize = Tensor.shapeToSize(this.shape);
|
|
403
|
-
// Gradient data
|
|
404
|
-
let gradShape, gradStrides, gradValue = [];
|
|
405
|
-
// Allocate gradient data only when needed
|
|
406
|
-
if (this.requiresGrad) {
|
|
407
|
-
gradShape = this.shape;
|
|
408
|
-
gradStrides = this.strides;
|
|
409
|
-
gradValue = new Array(originalSize).fill(0);
|
|
410
|
-
}
|
|
411
404
|
// Calculate new value after multiplying
|
|
412
405
|
for (let index = 0; index < originalSize; index++) {
|
|
413
406
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
@@ -417,6 +410,7 @@ class Tensor {
|
|
|
417
410
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
418
411
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
419
412
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
413
|
+
// Multiply into product
|
|
420
414
|
outputValue[outFlatIndex] *= this.value[realFlatIndex];
|
|
421
415
|
}
|
|
422
416
|
const out = new Tensor(outputValue, {
|
|
@@ -425,7 +419,7 @@ class Tensor {
|
|
|
425
419
|
});
|
|
426
420
|
// Set up gradient if needed
|
|
427
421
|
if (this.requiresGrad) {
|
|
428
|
-
|
|
422
|
+
const gradShape = this.shape, gradStrides = this.strides, gradValue = new Array(originalSize).fill(0);
|
|
429
423
|
for (let index = 0; index < originalSize; index++) {
|
|
430
424
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
431
425
|
// Force 0 on reduced axes to collapse into size-1 dims
|
|
@@ -434,7 +428,7 @@ class Tensor {
|
|
|
434
428
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
435
429
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
436
430
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
437
|
-
//
|
|
431
|
+
// Grad is the product of other elements of the same axis, which is product of all els divided by the current value
|
|
438
432
|
gradValue[realFlatIndex] = outputValue[outFlatIndex] / this.value[realFlatIndex];
|
|
439
433
|
}
|
|
440
434
|
out.requiresGrad = true;
|
|
@@ -449,7 +443,7 @@ class Tensor {
|
|
|
449
443
|
// Tensor mean reduction
|
|
450
444
|
mean(dims, keepDims = false) {
|
|
451
445
|
if (typeof this.value === "number")
|
|
452
|
-
return
|
|
446
|
+
return this;
|
|
453
447
|
if (typeof dims === "number") {
|
|
454
448
|
dims = [dims];
|
|
455
449
|
}
|
|
@@ -463,14 +457,6 @@ class Tensor {
|
|
|
463
457
|
const outputValue = new Array(outputSize).fill(0);
|
|
464
458
|
const outputFeeders = new Array(outputSize).fill(0);
|
|
465
459
|
const originalSize = Tensor.shapeToSize(this.shape);
|
|
466
|
-
// Gradient data
|
|
467
|
-
let gradShape, gradStrides, gradValue = [];
|
|
468
|
-
// Allocate gradient data only when needed
|
|
469
|
-
if (this.requiresGrad) {
|
|
470
|
-
gradShape = this.shape;
|
|
471
|
-
gradStrides = this.strides;
|
|
472
|
-
gradValue = new Array(originalSize).fill(0);
|
|
473
|
-
}
|
|
474
460
|
// Calculate sums and how many elements contribute to specific positions
|
|
475
461
|
for (let index = 0; index < originalSize; index++) {
|
|
476
462
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
@@ -480,6 +466,7 @@ class Tensor {
|
|
|
480
466
|
const outFlatIndex = Tensor.coordsToIndex(outCoords, outputStrides);
|
|
481
467
|
// Accumulate, outFlatIndex should match multiple realFlatIndexes
|
|
482
468
|
const realFlatIndex = Tensor.coordsToIndex(coords, this.strides);
|
|
469
|
+
// Calculate sum and contributors to the sum
|
|
483
470
|
outputValue[outFlatIndex] += this.value[realFlatIndex];
|
|
484
471
|
outputFeeders[outFlatIndex]++;
|
|
485
472
|
}
|
|
@@ -493,7 +480,8 @@ class Tensor {
|
|
|
493
480
|
});
|
|
494
481
|
// Set up gradient if needed
|
|
495
482
|
if (this.requiresGrad) {
|
|
496
|
-
|
|
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
|
|
497
485
|
for (let index = 0; index < originalSize; index++) {
|
|
498
486
|
const coords = Tensor.indexToCoords(index, this.strides);
|
|
499
487
|
// Force 0 on reduced axes to collapse into size-1 dims
|
|
@@ -514,6 +502,120 @@ class Tensor {
|
|
|
514
502
|
}
|
|
515
503
|
return keepDims ? out : out.squeeze(dims);
|
|
516
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
|
+
}
|
|
517
619
|
// Tensor element-wise addition
|
|
518
620
|
add(other) {
|
|
519
621
|
return this.elementWiseABDAG(other, (a, b) => a + b, (self, other, outGrad) => outGrad, (self, other, outGrad) => outGrad);
|
|
@@ -534,7 +636,7 @@ class Tensor {
|
|
|
534
636
|
}
|
|
535
637
|
// Tensor element-wise division
|
|
536
638
|
div(other) {
|
|
537
|
-
return this.elementWiseABDAG(other, (a, b) => a / b, (self, other, outGrad) => outGrad.div(other), (self, other, outGrad) => outGrad.mul(self.neg().div(other.
|
|
639
|
+
return this.elementWiseABDAG(other, (a, b) => a / b, (self, other, outGrad) => outGrad.div(other), (self, other, outGrad) => outGrad.mul(self.neg().div(other.square())));
|
|
538
640
|
}
|
|
539
641
|
divide = this.div;
|
|
540
642
|
// Tensor element-wise modulo
|
|
@@ -618,7 +720,7 @@ class Tensor {
|
|
|
618
720
|
negative = this.neg;
|
|
619
721
|
// Tensor element-wise reciprocal
|
|
620
722
|
reciprocal() {
|
|
621
|
-
return this.elementWiseSelfDAG((a) => 1 / a, (self, outGrad) => outGrad.mul(self.
|
|
723
|
+
return this.elementWiseSelfDAG((a) => 1 / a, (self, outGrad) => outGrad.mul(self.pow(-2).neg()));
|
|
622
724
|
}
|
|
623
725
|
// Tensor element-wise square
|
|
624
726
|
square() {
|
|
@@ -643,21 +745,21 @@ class Tensor {
|
|
|
643
745
|
}
|
|
644
746
|
// Tensor element-wise tan
|
|
645
747
|
tan() {
|
|
646
|
-
return this.elementWiseSelfDAG((a) => Math.tan(a), (self, outGrad) => outGrad.mul(self.tan().
|
|
748
|
+
return this.elementWiseSelfDAG((a) => Math.tan(a), (self, outGrad) => outGrad.mul(self.tan().square().add(1)));
|
|
647
749
|
}
|
|
648
750
|
// Tensor element-wise asin
|
|
649
751
|
asin() {
|
|
650
|
-
return this.elementWiseSelfDAG((a) => Math.asin(a), (self, outGrad) => outGrad.div(self.
|
|
752
|
+
return this.elementWiseSelfDAG((a) => Math.asin(a), (self, outGrad) => outGrad.div(self.square().neg().add(1).sqrt()));
|
|
651
753
|
}
|
|
652
754
|
arcsin = this.asin;
|
|
653
755
|
// Tensor element-wise acos
|
|
654
756
|
acos() {
|
|
655
|
-
return this.elementWiseSelfDAG((a) => Math.acos(a), (self, outGrad) => outGrad.div(self.
|
|
757
|
+
return this.elementWiseSelfDAG((a) => Math.acos(a), (self, outGrad) => outGrad.div(self.square().neg().add(1).sqrt()).neg());
|
|
656
758
|
}
|
|
657
759
|
arccos = this.acos;
|
|
658
760
|
// Tensor element-wise atan
|
|
659
761
|
atan() {
|
|
660
|
-
return this.elementWiseSelfDAG((a) => Math.atan(a), (self, outGrad) => outGrad.div(self.
|
|
762
|
+
return this.elementWiseSelfDAG((a) => Math.atan(a), (self, outGrad) => outGrad.div(self.square().add(1)));
|
|
661
763
|
}
|
|
662
764
|
arctan = this.atan;
|
|
663
765
|
// Tensor element-wise atan2
|
|
@@ -675,7 +777,7 @@ class Tensor {
|
|
|
675
777
|
}
|
|
676
778
|
// Tensor element-wise asinh
|
|
677
779
|
asinh() {
|
|
678
|
-
return this.elementWiseSelfDAG((a) => Math.asinh(a), (self, outGrad) => outGrad.div(self.
|
|
780
|
+
return this.elementWiseSelfDAG((a) => Math.asinh(a), (self, outGrad) => outGrad.div(self.square().add(1).sqrt()));
|
|
679
781
|
}
|
|
680
782
|
arcsinh = this.asinh;
|
|
681
783
|
// Tensor element-wise acosh
|
|
@@ -685,7 +787,7 @@ class Tensor {
|
|
|
685
787
|
arccosh = this.acosh;
|
|
686
788
|
// Tensor element-wise atanh
|
|
687
789
|
atanh() {
|
|
688
|
-
return this.elementWiseSelfDAG((a) => Math.atanh(a), (self, outGrad) => outGrad.div(self.
|
|
790
|
+
return this.elementWiseSelfDAG((a) => Math.atanh(a), (self, outGrad) => outGrad.div(self.square().neg().add(1)));
|
|
689
791
|
}
|
|
690
792
|
arctanh = this.atanh;
|
|
691
793
|
// Tensor element-wise degree to radian
|
|
@@ -734,7 +836,7 @@ class Tensor {
|
|
|
734
836
|
}
|
|
735
837
|
// Tensor element-wise relu
|
|
736
838
|
relu() {
|
|
737
|
-
return this.elementWiseSelfDAG((a) => Math.max(a, 0), (self, outGrad) => outGrad.mul(self.
|
|
839
|
+
return this.elementWiseSelfDAG((a) => Math.max(a, 0), (self, outGrad) => outGrad.mul(self.gt(0)));
|
|
738
840
|
}
|
|
739
841
|
// Tensor element-wise sigmoid
|
|
740
842
|
sigmoid() {
|
|
@@ -745,7 +847,39 @@ class Tensor {
|
|
|
745
847
|
}
|
|
746
848
|
// Tensor element-wise tanh
|
|
747
849
|
tanh() {
|
|
748
|
-
return this.elementWiseSelfDAG((a) => Math.tanh(a), (self, outGrad) => outGrad.mul(self.tanh().
|
|
850
|
+
return this.elementWiseSelfDAG((a) => Math.tanh(a), (self, outGrad) => outGrad.mul(self.tanh().square().neg().add(1)));
|
|
851
|
+
}
|
|
852
|
+
// Tensor element-wise softplus
|
|
853
|
+
softplus() {
|
|
854
|
+
return this.elementWiseSelfDAG((a) => Math.log1p(Math.exp(a)), (self, outGrad) => outGrad.mul(self.sigmoid()));
|
|
855
|
+
}
|
|
856
|
+
// Tensor element-wise softsign
|
|
857
|
+
softsign() {
|
|
858
|
+
return this.elementWiseSelfDAG((a) => a / (1 + Math.abs(a)), (self, outGrad) => outGrad.div(self.abs().add(1).square()));
|
|
859
|
+
}
|
|
860
|
+
// Tensor element-wise silu (swish)
|
|
861
|
+
silu() {
|
|
862
|
+
return this.elementWiseSelfDAG((a) => a / (1 + Math.exp(-a)), (self, outGrad) => {
|
|
863
|
+
const sig = self.sigmoid();
|
|
864
|
+
return outGrad.mul(sig.add(self.mul(sig).mul(sig.neg().add(1))));
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
// Tensor element-wise mish
|
|
868
|
+
mish() {
|
|
869
|
+
return this.elementWiseSelfDAG((a) => a * Math.tanh(Math.log1p(Math.exp(a))), (self, outGrad) => {
|
|
870
|
+
const tanhSoftPlus = self.exp().add(1).log().tanh();
|
|
871
|
+
// tanh(softplus(x)) + x * (1 - tanh²(softplus(x))) * sigmoid(x)
|
|
872
|
+
const derivative = tanhSoftPlus.add(self.mul(tanhSoftPlus.square().neg().add(1)).mul(self.sigmoid()));
|
|
873
|
+
return outGrad.mul(derivative);
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
// Tensor element-wise maximum
|
|
877
|
+
maximum(other) {
|
|
878
|
+
return this.elementWiseABDAG(other, (a, b) => Math.max(a, b), (self, other, outGrad) => outGrad.mul(self.gt(other).add(self.eq(other).mul(0.5))), (self, other, outGrad) => outGrad.mul(other.gt(self).add(other.eq(self).mul(0.5))));
|
|
879
|
+
}
|
|
880
|
+
// Tensor element-wise minimum
|
|
881
|
+
minimum(other) {
|
|
882
|
+
return this.elementWiseABDAG(other, (a, b) => Math.min(a, b), (self, other, outGrad) => outGrad.mul(self.lt(other).add(self.eq(other).mul(0.5))), (self, other, outGrad) => outGrad.mul(other.lt(self).add(other.eq(self).mul(0.5))));
|
|
749
883
|
}
|
|
750
884
|
// Tensor element-wise round
|
|
751
885
|
round() {
|
|
@@ -773,6 +907,18 @@ class Tensor {
|
|
|
773
907
|
return this.elementWiseSelfDAG((a) => Math.max(min, Math.min(max, a)), (self, outGrad) => outGrad.mul(self.ge(min).mul(self.le(max))));
|
|
774
908
|
}
|
|
775
909
|
clamp = this.clip;
|
|
910
|
+
// Tensor element-wise error function
|
|
911
|
+
erf() {
|
|
912
|
+
return this.elementWiseSelfDAG((a) => (0, utils_1.erf)(a), (self, outGrad) => outGrad.mul(self.square().neg().exp().mul(2 / Math.sqrt(Math.PI))));
|
|
913
|
+
}
|
|
914
|
+
// Tensor element-wise complementary error function
|
|
915
|
+
erfc() {
|
|
916
|
+
return this.elementWiseSelfDAG((a) => (0, utils_1.erfc)(a), (self, outGrad) => outGrad.mul(self.square().neg().exp().mul(2 / Math.sqrt(Math.PI)).neg()));
|
|
917
|
+
}
|
|
918
|
+
// Tensor element-wise inverse error function
|
|
919
|
+
erfinv() {
|
|
920
|
+
return this.elementWiseSelfDAG((a) => (0, utils_1.erfinv)(a), (self, outGrad) => outGrad.mul(self.erfinv().square().exp().mul(Math.sqrt(Math.PI) / 2)));
|
|
921
|
+
}
|
|
776
922
|
// Transpose
|
|
777
923
|
transpose(dim1, dim2) {
|
|
778
924
|
// If dimension out of bound, throw error
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.erf = erf;
|
|
4
|
+
exports.erfc = erfc;
|
|
5
|
+
exports.erfinv = erfinv;
|
|
6
|
+
// Error function using Abramowitz and Stegun approximation
|
|
7
|
+
function erf(x) {
|
|
8
|
+
const a1 = 0.254829592;
|
|
9
|
+
const a2 = -0.284496736;
|
|
10
|
+
const a3 = 1.421413741;
|
|
11
|
+
const a4 = -1.453152027;
|
|
12
|
+
const a5 = 1.061405429;
|
|
13
|
+
const p = 0.3275911;
|
|
14
|
+
const sign = x >= 0 ? 1 : -1;
|
|
15
|
+
x = Math.abs(x);
|
|
16
|
+
// Formula 7.1.26
|
|
17
|
+
const t = 1.0 / (1.0 + p * x);
|
|
18
|
+
const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
|
19
|
+
return sign * y;
|
|
20
|
+
}
|
|
21
|
+
// Complementary error function
|
|
22
|
+
function erfc(x) {
|
|
23
|
+
return 1 - erf(x);
|
|
24
|
+
}
|
|
25
|
+
// Inverse error function using Winitzki approximation
|
|
26
|
+
function erfinv(x) {
|
|
27
|
+
if (Math.abs(x) >= 1)
|
|
28
|
+
throw new Error("Input must be in range (-1, 1)");
|
|
29
|
+
const a = 0.147;
|
|
30
|
+
const ln = Math.log(1 - x * x);
|
|
31
|
+
const part1 = 2 / (Math.PI * a) + ln / 2;
|
|
32
|
+
const part2 = ln / a;
|
|
33
|
+
const sign = x >= 0 ? 1 : -1;
|
|
34
|
+
return sign * Math.sqrt(-part1 + Math.sqrt(part1 * part1 - part2));
|
|
35
|
+
}
|