catniff 0.2.13 → 0.2.14

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Catniff
2
2
 
3
- Catniff is an experimental tensor ops library and autograd engine made to be Torch-like (its name is a play on "catnip" and "differentiation"). This project is heavily under development currently, so keep in mind that APIs can be completely unstable and backwards-incompatible.
3
+ Catniff is a small deep learning framework for Javacript, built to be Torch-like, but more direct on tensors and autograd usage like Tinygrad. This project is under development currently, so keep in mind that APIs can be unstable and backwards-incompatible. On a side-note, the name is a play on "catnip" and "differentiation".
4
4
 
5
5
  ## Setup
6
6
 
@@ -80,14 +80,12 @@ All available APIs are in [`./src/core.ts`](./src/core.ts) if you want to dig de
80
80
 
81
81
  ## Todos
82
82
 
83
- I'm mostly just learning and playing with this currently, so there are no concrete plans yet, but here is what I currently have in mind:
84
-
85
- * Fix whatever is the problem right now (there are a lot of problems right now lol).
86
- * Add more tensor ops.
87
- * Proper documentation.
83
+ * Bug fixes.
84
+ * More tensor ops.
85
+ * More detailed documentation.
88
86
  * GPU acceleration.
89
87
  * Some general neural net APIs.
90
- * Refactor code.
88
+ * Code refactoring.
91
89
  * Proper tests.
92
90
  * Option to load more backends.
93
91
 
package/dist/core.d.ts CHANGED
@@ -137,6 +137,7 @@ export declare class Tensor {
137
137
  t(): Tensor;
138
138
  dot(other: TensorValue | Tensor): Tensor;
139
139
  mm(other: TensorValue | Tensor): Tensor;
140
+ bmm(other: TensorValue | Tensor): Tensor;
140
141
  mv(other: TensorValue | Tensor): Tensor;
141
142
  matmul(other: TensorValue | Tensor): Tensor;
142
143
  static full(shape: number[], num: number, options?: TensorOptions): Tensor;
package/dist/core.js CHANGED
@@ -1049,6 +1049,64 @@ class Tensor {
1049
1049
  }
1050
1050
  return out;
1051
1051
  }
1052
+ // Batched 3D tensor matmul
1053
+ bmm(other) {
1054
+ other = Tensor.forceTensor(other);
1055
+ // Verify 3D shape
1056
+ if (this.shape.length !== 3 || other.shape.length !== 3 || this.shape[0] !== other.shape[0]) {
1057
+ throw new Error("Inputs are not 3D tensors with the same first dim size");
1058
+ }
1059
+ // Simple matrix multiplication
1060
+ const batchA = this.value;
1061
+ const batchB = other.value;
1062
+ const batchAStrides = this.strides;
1063
+ const batchBStrides = other.strides;
1064
+ const batchSize = this.shape[0];
1065
+ const batchARows = this.shape[1];
1066
+ const batchACols = this.shape[2];
1067
+ const batchBRows = other.shape[1];
1068
+ const batchBCols = other.shape[2];
1069
+ if (batchACols !== batchBRows)
1070
+ throw new Error("Invalid matrices shape for multiplication");
1071
+ const batchCShape = [batchSize, batchARows, batchBCols];
1072
+ const batchCStrides = Tensor.getStrides(batchCShape);
1073
+ const batchCSize = Tensor.shapeToSize(batchCShape);
1074
+ const batchC = new Array(batchCSize).fill(0);
1075
+ for (let q = 0; q < batchSize; q++) {
1076
+ for (let i = 0; i < batchARows; i++) {
1077
+ for (let j = 0; j < batchBCols; j++) {
1078
+ for (let k = 0; k < batchACols; k++) {
1079
+ // Tensor values are 1D arrays so we have to get real index using strides
1080
+ batchC[q * batchCStrides[0] + i * batchCStrides[1] + j * batchCStrides[2]] +=
1081
+ batchA[q * batchAStrides[0] + i * batchAStrides[1] + k * batchAStrides[2]] *
1082
+ batchB[q * batchBStrides[0] + k * batchBStrides[1] + j * batchBStrides[2]];
1083
+ }
1084
+ }
1085
+ }
1086
+ }
1087
+ const out = new Tensor(batchC, { shape: batchCShape, strides: batchCStrides });
1088
+ if (this.requiresGrad) {
1089
+ out.requiresGrad = true;
1090
+ out.children.push(this);
1091
+ }
1092
+ if (other.requiresGrad) {
1093
+ out.requiresGrad = true;
1094
+ out.children.push(other);
1095
+ }
1096
+ if (out.requiresGrad) {
1097
+ out.gradFn = () => {
1098
+ // Disable gradient collecting of gradients themselves
1099
+ const outGrad = out.grad.withGrad(false);
1100
+ const selfNoGrad = this.withGrad(false);
1101
+ const otherNoGrad = other.withGrad(false);
1102
+ if (this.requiresGrad)
1103
+ Tensor.addGrad(this, outGrad.bmm(otherNoGrad.transpose(1, 2)));
1104
+ if (other.requiresGrad)
1105
+ Tensor.addGrad(other, selfNoGrad.transpose(1, 2).bmm(outGrad));
1106
+ };
1107
+ }
1108
+ return out;
1109
+ }
1052
1110
  // Convert right-side 1D tensor to a vector (nx1 tensor) to do matmul
1053
1111
  mv(other) {
1054
1112
  other = Tensor.forceTensor(other);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "catniff",
3
- "version": "0.2.13",
4
- "description": "A cute autograd engine for Javascript",
3
+ "version": "0.2.14",
4
+ "description": "A small Torch-like deep learning framework for Javascript with tensor and autograd support",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -11,7 +11,6 @@
11
11
  "url": "git+https://github.com/nguyenphuminh/catniff.git"
12
12
  },
13
13
  "keywords": [
14
- "cats",
15
14
  "catniff",
16
15
  "autograd",
17
16
  "autodiff",
@@ -27,6 +26,7 @@
27
26
  "machine-learning",
28
27
  "deep-learning",
29
28
  "micrograd",
29
+ "tinygrad",
30
30
  "torch",
31
31
  "pytorch"
32
32
  ],