@dniskav/neuron 0.1.1 → 0.1.3

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,5 +1,8 @@
1
1
  # @dniskav/neuron
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@dniskav/neuron)](https://www.npmjs.com/package/@dniskav/neuron)
4
+ [![license](https://img.shields.io/npm/l/@dniskav/neuron)](LICENSE)
5
+
3
6
  A minimal, dependency-free neural network library built from scratch in TypeScript. Designed for learning and experimentation — every line of math is readable.
4
7
 
5
8
  ## What's inside
@@ -11,6 +14,8 @@ A minimal, dependency-free neural network library built from scratch in TypeScri
11
14
  | `Layer` | A group of `NeuronN` neurons that share the same inputs. |
12
15
  | `Network` | Two-layer network (hidden + output) with backpropagation. |
13
16
  | `NetworkN` | Deep network of arbitrary depth. Define your architecture as `[inputs, ...hidden, outputs]`. |
17
+ | `LSTMLayer` | Recurrent layer with persistent hidden and cell state. Learns sequences via BPTT. |
18
+ | `NetworkLSTM` | Wraps an `LSTMLayer` + dense layers. Maintains memory across steps within an episode. |
14
19
 
15
20
  ## Install
16
21
 
@@ -95,6 +100,47 @@ const [out1, out2] = net.predict([0.5, 0.3, 0.8]);
95
100
  net.trainWithDeltas(inputs, [0.4, -0.2], 0.05);
96
101
  ```
97
102
 
103
+ ### NetworkLSTM — recurrent network with memory
104
+
105
+ `NetworkLSTM` adds within-episode memory: the network can remember what happened in previous steps of the same sequence.
106
+
107
+ ```ts
108
+ import { NetworkLSTM } from "@dniskav/neuron";
109
+
110
+ // 1 input → LSTM(8 hidden) → Dense(4) → 1 output
111
+ const net = new NetworkLSTM(1, 8, [4, 1]);
112
+
113
+ // Task: predict 1 if we're past step 3 in the episode, else 0
114
+ // A feedforward net can't do this — it has no memory of step count.
115
+
116
+ for (let epoch = 0; epoch < 300; epoch++) {
117
+ net.resetState(); // clear memory at episode start
118
+
119
+ const targets: number[][] = [];
120
+ for (let step = 0; step < 6; step++) {
121
+ net.predict([1]); // same input every step
122
+ targets.push([step >= 3 ? 1 : 0]);
123
+ }
124
+
125
+ net.train(targets, 0.05); // BPTT across the full episode
126
+ }
127
+
128
+ // Run a fresh episode and check predictions
129
+ net.resetState();
130
+ for (let step = 0; step < 6; step++) {
131
+ const [out] = net.predict([1]);
132
+ console.log(`step ${step}: ${out.toFixed(2)} (expected: ${step >= 3 ? 1 : 0})`);
133
+ }
134
+ // step 0: 0.07 (expected: 0)
135
+ // step 1: 0.11 (expected: 0)
136
+ // step 2: 0.18 (expected: 0)
137
+ // step 3: 0.81 (expected: 1)
138
+ // step 4: 0.89 (expected: 1)
139
+ // step 5: 0.93 (expected: 1)
140
+ ```
141
+
142
+ The network learns to count steps using its hidden state — no external counter needed.
143
+
98
144
  ## How it works
99
145
 
100
146
  Every class uses **sigmoid** as its activation function and **gradient descent** to update weights:
package/dist/index.js CHANGED
@@ -372,7 +372,7 @@ var NetworkLSTM = class {
372
372
  const grad = denseGrads[l];
373
373
  const prevDeltas = layerIn.map((out, j) => {
374
374
  const errProp = layer.neurons.reduce((s, n, k) => s + deltas[k] * n.weights[j], 0);
375
- return errProp * out * (1 - out);
375
+ return l === 0 ? errProp : errProp * out * (1 - out);
376
376
  });
377
377
  layer.neurons.forEach((n, k) => {
378
378
  n.weights.forEach((_, j) => {
package/dist/index.mjs CHANGED
@@ -340,7 +340,7 @@ var NetworkLSTM = class {
340
340
  const grad = denseGrads[l];
341
341
  const prevDeltas = layerIn.map((out, j) => {
342
342
  const errProp = layer.neurons.reduce((s, n, k) => s + deltas[k] * n.weights[j], 0);
343
- return errProp * out * (1 - out);
343
+ return l === 0 ? errProp : errProp * out * (1 - out);
344
344
  });
345
345
  layer.neurons.forEach((n, k) => {
346
346
  n.weights.forEach((_, j) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dniskav/neuron",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Minimal neural network from scratch — neuron, layer, network, backpropagation. No dependencies.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -12,12 +12,19 @@
12
12
  "types": "./dist/index.d.ts"
13
13
  }
14
14
  },
15
- "files": ["dist"],
15
+ "files": [
16
+ "dist"
17
+ ],
16
18
  "scripts": {
17
19
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
18
20
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
19
21
  },
20
- "keywords": ["neural-network", "machine-learning", "backpropagation", "typescript"],
22
+ "keywords": [
23
+ "neural-network",
24
+ "machine-learning",
25
+ "backpropagation",
26
+ "typescript"
27
+ ],
21
28
  "author": "dniskav",
22
29
  "license": "MIT",
23
30
  "devDependencies": {