catniff 0.6.11 → 0.6.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 +1 -0
- package/dist/core.d.ts +2 -1
- package/dist/core.js +69 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,6 +132,7 @@ All available APIs are in [`./src/`](./src/) if you want to dig deeper.
|
|
|
132
132
|
|
|
133
133
|
* [Shakespeare-style text generator](https://github.com/nguyenphuminh/shakespeare-lm).
|
|
134
134
|
* [Simple neural net for XOR calculation](./examples/xornet.js).
|
|
135
|
+
* [N-th order derivative calculation](./examples/nthorder.js).
|
|
135
136
|
* [Tensors](./examples/tensors.js).
|
|
136
137
|
* [Optimizer](./examples/optim.js).
|
|
137
138
|
* [Simple quadratic equation](./examples/quadratic.js).
|
package/dist/core.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare class Tensor {
|
|
|
23
23
|
children: Tensor[];
|
|
24
24
|
device: string;
|
|
25
25
|
static training: boolean;
|
|
26
|
+
static noGrad: boolean;
|
|
27
|
+
static createGraph: boolean;
|
|
26
28
|
constructor(value: TensorValue, options?: TensorOptions);
|
|
27
29
|
static flattenValue(tensor: TensorValue): number[] | number;
|
|
28
30
|
static getShape(tensor: TensorValue): number[];
|
|
@@ -214,7 +216,6 @@ export declare class Tensor {
|
|
|
214
216
|
zeroGrad?: boolean;
|
|
215
217
|
}): void;
|
|
216
218
|
val(): TensorValue;
|
|
217
|
-
withGrad(requiresGrad: boolean): Tensor;
|
|
218
219
|
detach(): Tensor;
|
|
219
220
|
clone(): Tensor;
|
|
220
221
|
replace(other: Tensor | TensorValue, allowShapeMismatch?: boolean): Tensor;
|
package/dist/core.js
CHANGED
|
@@ -14,6 +14,8 @@ class Tensor {
|
|
|
14
14
|
children;
|
|
15
15
|
device;
|
|
16
16
|
static training = false;
|
|
17
|
+
static noGrad = false;
|
|
18
|
+
static createGraph = false;
|
|
17
19
|
constructor(value, options = {}) {
|
|
18
20
|
// Storage
|
|
19
21
|
this.value = Tensor.flattenValue(value);
|
|
@@ -183,14 +185,22 @@ class Tensor {
|
|
|
183
185
|
static elementWiseSelf(tA, op) {
|
|
184
186
|
if (typeof tA.value === "number")
|
|
185
187
|
return new Tensor(op(tA.value));
|
|
188
|
+
const contiguous = tA.isContiguous();
|
|
186
189
|
const outputShape = tA.shape;
|
|
187
|
-
const outputStrides = Tensor.getStrides(outputShape);
|
|
190
|
+
const outputStrides = contiguous ? tA.strides : Tensor.getStrides(outputShape);
|
|
188
191
|
const outputSize = tA.numel;
|
|
189
192
|
const outputValue = new Array(outputSize);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
if (contiguous) {
|
|
194
|
+
for (let index = 0; index < outputSize; index++) {
|
|
195
|
+
outputValue[index] = op(tA.value[index + tA.offset]);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
for (let index = 0; index < outputSize; index++) {
|
|
200
|
+
const outputCoords = Tensor.indexToCoords(index, outputStrides);
|
|
201
|
+
const originalIndex = tA.offset + Tensor.coordsToIndex(outputCoords, tA.strides);
|
|
202
|
+
outputValue[index] = op(tA.value[originalIndex]);
|
|
203
|
+
}
|
|
194
204
|
}
|
|
195
205
|
return new Tensor(outputValue, { shape: outputShape, strides: outputStrides, numel: tA.numel });
|
|
196
206
|
}
|
|
@@ -210,12 +220,12 @@ class Tensor {
|
|
|
210
220
|
out.gradFn = () => {
|
|
211
221
|
// Disable gradient collecting of gradients themselves
|
|
212
222
|
const outGrad = out.grad;
|
|
213
|
-
const
|
|
214
|
-
const
|
|
223
|
+
const selfWithGrad = Tensor.createGraph ? this : this.detach();
|
|
224
|
+
const otherWithGrad = Tensor.createGraph ? other : other.detach();
|
|
215
225
|
if (this.requiresGrad)
|
|
216
|
-
Tensor.addGrad(this, thisGrad(
|
|
226
|
+
Tensor.addGrad(this, thisGrad(selfWithGrad, otherWithGrad, outGrad));
|
|
217
227
|
if (other.requiresGrad)
|
|
218
|
-
Tensor.addGrad(other, otherGrad(
|
|
228
|
+
Tensor.addGrad(other, otherGrad(selfWithGrad, otherWithGrad, outGrad));
|
|
219
229
|
};
|
|
220
230
|
}
|
|
221
231
|
return out;
|
|
@@ -231,9 +241,9 @@ class Tensor {
|
|
|
231
241
|
out.gradFn = () => {
|
|
232
242
|
// Disable gradient collecting of gradients themselves
|
|
233
243
|
const outGrad = out.grad;
|
|
234
|
-
const
|
|
244
|
+
const selfWithGrad = Tensor.createGraph ? this : this.detach();
|
|
235
245
|
if (this.requiresGrad)
|
|
236
|
-
Tensor.addGrad(this, thisGrad(
|
|
246
|
+
Tensor.addGrad(this, thisGrad(selfWithGrad, outGrad));
|
|
237
247
|
};
|
|
238
248
|
}
|
|
239
249
|
return out;
|
|
@@ -289,9 +299,6 @@ class Tensor {
|
|
|
289
299
|
// Contiguity-related ops
|
|
290
300
|
isContiguous() {
|
|
291
301
|
const expectedStrides = Tensor.getStrides(this.shape);
|
|
292
|
-
if (expectedStrides.length !== this.strides.length) {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
302
|
for (let i = 0; i < this.strides.length; i++) {
|
|
296
303
|
if (this.strides[i] !== expectedStrides[i]) {
|
|
297
304
|
return false;
|
|
@@ -340,6 +347,7 @@ class Tensor {
|
|
|
340
347
|
const out = new Tensor(this.value, {
|
|
341
348
|
shape: newShape,
|
|
342
349
|
strides: outputStrides,
|
|
350
|
+
offset: this.offset,
|
|
343
351
|
numel: outputSize,
|
|
344
352
|
device: this.device
|
|
345
353
|
});
|
|
@@ -354,28 +362,7 @@ class Tensor {
|
|
|
354
362
|
return out;
|
|
355
363
|
}
|
|
356
364
|
reshape(newShape) {
|
|
357
|
-
|
|
358
|
-
const originalSize = this.numel;
|
|
359
|
-
const outputSize = Tensor.shapeToSize(newShape);
|
|
360
|
-
if (originalSize !== outputSize || typeof this.value === "number") {
|
|
361
|
-
throw new Error("Can not reshape: incompatible sizes");
|
|
362
|
-
}
|
|
363
|
-
// Create new tensor with forced compatibility (only contiguity for now)
|
|
364
|
-
const outputStrides = Tensor.getStrides(newShape);
|
|
365
|
-
const out = new Tensor(this.contiguous().value, {
|
|
366
|
-
shape: newShape,
|
|
367
|
-
strides: outputStrides,
|
|
368
|
-
numel: outputSize
|
|
369
|
-
});
|
|
370
|
-
// Gradient reshaped and flow back to the original tensor
|
|
371
|
-
if (this.requiresGrad) {
|
|
372
|
-
out.requiresGrad = true;
|
|
373
|
-
out.children.push(this);
|
|
374
|
-
out.gradFn = () => {
|
|
375
|
-
Tensor.addGrad(this, out.grad.reshape(this.shape));
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
return out;
|
|
365
|
+
return this.contiguous().view(newShape);
|
|
379
366
|
}
|
|
380
367
|
flatten(startDim = 0, endDim = -1) {
|
|
381
368
|
// Handle negative indices
|
|
@@ -550,7 +537,7 @@ class Tensor {
|
|
|
550
537
|
}
|
|
551
538
|
// Tensor indexing
|
|
552
539
|
index(indices) {
|
|
553
|
-
const tensorIndices = this.handleOther(indices).
|
|
540
|
+
const tensorIndices = this.handleOther(indices).clone();
|
|
554
541
|
if (typeof tensorIndices.value === "number") {
|
|
555
542
|
return this.indexWithArray([tensorIndices.value]).squeeze(0);
|
|
556
543
|
}
|
|
@@ -1353,12 +1340,12 @@ class Tensor {
|
|
|
1353
1340
|
out.gradFn = () => {
|
|
1354
1341
|
// Disable gradient collecting of gradients themselves
|
|
1355
1342
|
const outGrad = out.grad;
|
|
1356
|
-
const
|
|
1357
|
-
const
|
|
1343
|
+
const selfWithGrad = Tensor.createGraph ? this : this.detach();
|
|
1344
|
+
const otherWithGrad = Tensor.createGraph ? other : other.detach();
|
|
1358
1345
|
if (this.requiresGrad)
|
|
1359
|
-
Tensor.addGrad(this, outGrad.mm(
|
|
1346
|
+
Tensor.addGrad(this, outGrad.mm(otherWithGrad.t()));
|
|
1360
1347
|
if (other.requiresGrad)
|
|
1361
|
-
Tensor.addGrad(other,
|
|
1348
|
+
Tensor.addGrad(other, selfWithGrad.t().mm(outGrad));
|
|
1362
1349
|
};
|
|
1363
1350
|
}
|
|
1364
1351
|
return out;
|
|
@@ -1411,12 +1398,12 @@ class Tensor {
|
|
|
1411
1398
|
out.gradFn = () => {
|
|
1412
1399
|
// Disable gradient collecting of gradients themselves
|
|
1413
1400
|
const outGrad = out.grad;
|
|
1414
|
-
const
|
|
1415
|
-
const
|
|
1401
|
+
const selfWithGrad = Tensor.createGraph ? this : this.detach();
|
|
1402
|
+
const otherWithGrad = Tensor.createGraph ? other : other.detach();
|
|
1416
1403
|
if (this.requiresGrad)
|
|
1417
|
-
Tensor.addGrad(this, outGrad.bmm(
|
|
1404
|
+
Tensor.addGrad(this, outGrad.bmm(otherWithGrad.transpose(1, 2)));
|
|
1418
1405
|
if (other.requiresGrad)
|
|
1419
|
-
Tensor.addGrad(other,
|
|
1406
|
+
Tensor.addGrad(other, selfWithGrad.transpose(1, 2).bmm(outGrad));
|
|
1420
1407
|
};
|
|
1421
1408
|
}
|
|
1422
1409
|
return out;
|
|
@@ -1511,12 +1498,12 @@ class Tensor {
|
|
|
1511
1498
|
out.gradFn = () => {
|
|
1512
1499
|
other = other;
|
|
1513
1500
|
const outGrad = out.grad;
|
|
1514
|
-
const
|
|
1515
|
-
const
|
|
1501
|
+
const selfWithGrad = Tensor.createGraph ? self : self.detach();
|
|
1502
|
+
const otherWithGrad = Tensor.createGraph ? other : other.detach();
|
|
1516
1503
|
if (this.requiresGrad)
|
|
1517
|
-
Tensor.addGrad(this, outGrad.matmul(
|
|
1504
|
+
Tensor.addGrad(this, outGrad.matmul(otherWithGrad.transpose(-2, -1)));
|
|
1518
1505
|
if (other.requiresGrad)
|
|
1519
|
-
Tensor.addGrad(other,
|
|
1506
|
+
Tensor.addGrad(other, selfWithGrad.transpose(-2, -1).matmul(outGrad));
|
|
1520
1507
|
};
|
|
1521
1508
|
}
|
|
1522
1509
|
return out;
|
|
@@ -1801,7 +1788,7 @@ class Tensor {
|
|
|
1801
1788
|
const visited = new Set();
|
|
1802
1789
|
function build(node) {
|
|
1803
1790
|
// Only collects unvisited node and node that requires gradient
|
|
1804
|
-
if (!visited.has(node) && node.requiresGrad) {
|
|
1791
|
+
if (!visited.has(node) && node.requiresGrad && !Tensor.noGrad) {
|
|
1805
1792
|
visited.add(node);
|
|
1806
1793
|
// Reset grad to zeros if specified
|
|
1807
1794
|
if (zeroGrad) {
|
|
@@ -1841,17 +1828,6 @@ class Tensor {
|
|
|
1841
1828
|
}
|
|
1842
1829
|
return buildNested(this.value, this.shape, this.strides, this.offset);
|
|
1843
1830
|
}
|
|
1844
|
-
// Returns a view of the tensor with gradient turned on/off and detaches from autograd
|
|
1845
|
-
withGrad(requiresGrad) {
|
|
1846
|
-
return new Tensor(this.value, {
|
|
1847
|
-
shape: this.shape,
|
|
1848
|
-
strides: this.strides,
|
|
1849
|
-
offset: this.offset,
|
|
1850
|
-
numel: this.numel,
|
|
1851
|
-
device: this.device,
|
|
1852
|
-
requiresGrad
|
|
1853
|
-
});
|
|
1854
|
-
}
|
|
1855
1831
|
// Returns a view of the tensor with gradient turned off and detaches from autograd
|
|
1856
1832
|
detach() {
|
|
1857
1833
|
return new Tensor(this.value, {
|
|
@@ -1863,15 +1839,39 @@ class Tensor {
|
|
|
1863
1839
|
requiresGrad: false
|
|
1864
1840
|
});
|
|
1865
1841
|
}
|
|
1866
|
-
// Returns a copy of the tensor (with new data allocation) and
|
|
1842
|
+
// Returns a copy of the tensor (with new data allocation) and keeps grad connection
|
|
1867
1843
|
clone() {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1844
|
+
let out;
|
|
1845
|
+
if (typeof this.value === "number") {
|
|
1846
|
+
out = new Tensor(this.value);
|
|
1847
|
+
}
|
|
1848
|
+
else {
|
|
1849
|
+
const contiguous = this.isContiguous();
|
|
1850
|
+
const outputStrides = contiguous ? this.strides : Tensor.getStrides(this.shape);
|
|
1851
|
+
const outputSize = this.numel;
|
|
1852
|
+
const outputValue = new Array(outputSize);
|
|
1853
|
+
if (contiguous) {
|
|
1854
|
+
for (let index = 0; index < outputSize; index++) {
|
|
1855
|
+
outputValue[index] = this.value[this.offset + index];
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
else {
|
|
1859
|
+
for (let index = 0; index < outputSize; index++) {
|
|
1860
|
+
const outputCoords = Tensor.indexToCoords(index, outputStrides);
|
|
1861
|
+
const originalIndex = Tensor.coordsToIndex(outputCoords, this.strides);
|
|
1862
|
+
outputValue[index] = this.value[this.offset + originalIndex];
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
out = new Tensor(outputValue, { shape: this.shape, strides: outputStrides, numel: outputSize });
|
|
1866
|
+
}
|
|
1867
|
+
if (this.requiresGrad) {
|
|
1868
|
+
out.requiresGrad = true;
|
|
1869
|
+
out.children.push(this);
|
|
1870
|
+
out.gradFn = () => {
|
|
1871
|
+
Tensor.addGrad(this, out.grad);
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
return out;
|
|
1875
1875
|
}
|
|
1876
1876
|
// Returns this tensor with value replaced with the value of another tensor
|
|
1877
1877
|
replace(other, allowShapeMismatch = false) {
|