@mineproness/tensorloop 1.4.2 → 1.4.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/index.js +5 -1
- package/package.json +1 -1
- package/readme.md +88 -36
- package/src/FFN/index.d.ts +9 -0
- package/src/FFN/index.js +54 -0
- package/src/LayerNorm/index.d.ts +22 -0
- package/src/LayerNorm/index.js +82 -0
- package/src/TransformerBlock/index.d.ts +9 -0
- package/src/TransformerBlock/index.js +92 -0
package/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import {ReLU} from './src/ReLU/index.js'
|
|
|
8
8
|
import {PositionEmbedding as PE} from './src/PositionEmbedding/index.js'
|
|
9
9
|
import {SelfAttention as ST} from './src/SelfAttention/index.js'
|
|
10
10
|
import {GELU as GU} from './src/GELU/index.js'
|
|
11
|
+
import {FFN as ffn} from './src/FFN/index.js'
|
|
12
|
+
import {LayerNorm as LN} from './src/LayerNorm/index.js'
|
|
11
13
|
export const Tokenizer = tokenizer
|
|
12
14
|
export const Embedding = embeddding2
|
|
13
15
|
export const Linear = li2
|
|
@@ -17,4 +19,6 @@ export const Tools = tools
|
|
|
17
19
|
export const ReLu = ReLU
|
|
18
20
|
export const PositionEmbedding = PE
|
|
19
21
|
export const SelfAttention = ST
|
|
20
|
-
export const GELU = GU
|
|
22
|
+
export const GELU = GU
|
|
23
|
+
export const FFN = ffn
|
|
24
|
+
export const LayerNorm = LN
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,74 +1,126 @@
|
|
|
1
|
-
|
|
1
|
+
# TensorLoop ➰
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A high-performance JavaScript library that provides essential AI and Large Language Model (LLM) development utilities. Build, train, and run neural network components like Embeddings, Linear layers, Activations, and Tokenizers directly in JavaScript.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Linear Weights and Bias.
|
|
9
|
-
- Softmax forward and Backward.
|
|
10
|
-
- CrossEntroy for Loss Calculation.
|
|
11
|
-
- Relu and GELU for Stable Layer.
|
|
12
|
-
- Tokenizer for convert into tokens.
|
|
13
|
-
- Self attention
|
|
14
|
-
- Position Embedding
|
|
15
|
-
- PAD token is '<PAD>' and EOS token <EOS>
|
|
7
|
+
## 🚀 Features
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
- **Transformer Block**: Complete modular block managing full attention and forward/backward training passes.
|
|
10
|
+
- **Embedding Vectors**: High-speed lookup and embedding initialization.
|
|
11
|
+
- **Linear Layer**: Fully connected layers with manageable weights and biases.
|
|
12
|
+
- **Activations**: Forward and backward propagation for **Softmax**, **ReLU**, and **GELU**.
|
|
13
|
+
- **Loss Functions**: **CrossEntropy** loss calculation for training classification tasks.
|
|
14
|
+
- **Attention & Positioning**: Built-in **Self-Attention** and **Positional Embedding** matrices.
|
|
15
|
+
- **Text Processing**: Built-in **Tokenizer** to convert raw text into token IDs and back.
|
|
16
|
+
- **Special Tokens**: Native support for `<PAD>` and `<EOS>`.
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
---
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
import {Embedding , linear} from '@mineproness/tensorloop'
|
|
20
|
+
## 🏗 Core Architecture
|
|
23
21
|
|
|
22
|
+
### Transformer Block
|
|
23
|
+
The `TransformerBlock` encapsulates attention, layer normalization, and feed-forward networks into a single trainable module.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { TransformerBlock } from '@mineproness/tensorloop'
|
|
27
|
+
|
|
28
|
+
// Initialize the block with an embedding size and save directory
|
|
29
|
+
const transformer = new TransformerBlock(1024, {
|
|
30
|
+
dirname: "./model/transformer_layers"
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Forward Pass: Processes an array of typed float arrays
|
|
34
|
+
const output = transformer.forward(inputVectors)
|
|
35
|
+
|
|
36
|
+
// Backward Pass: Calculates gradients and updates weights using a learning rate
|
|
37
|
+
const dInput = transformer.backward(dOutput, 0.001)
|
|
38
|
+
|
|
39
|
+
// Clear cache to free up system memory after an iteration
|
|
40
|
+
transformer.clearInputCache()
|
|
41
|
+
|
|
42
|
+
// Persist the transformer block weights to disk
|
|
43
|
+
transformer.Save()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🛠 Configurations
|
|
49
|
+
|
|
50
|
+
You can configure saving mechanisms by passing a configuration object to the `Embedding` and `Linear` classes.
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { Embedding, Linear } from '@mineproness/tensorloop'
|
|
54
|
+
|
|
55
|
+
// Initialize an Embedding layer and auto-save the weights
|
|
24
56
|
const embedding = new Embedding(1024, 2000, {
|
|
25
57
|
save: {
|
|
26
58
|
filename: "./model/vectors.bin"
|
|
27
59
|
}
|
|
28
60
|
})
|
|
29
|
-
|
|
61
|
+
|
|
62
|
+
// Initialize a Linear layer (requires an array to save Weights and Biases separately)
|
|
63
|
+
const linear = new Linear(1024, 2000, {
|
|
30
64
|
save: {
|
|
31
|
-
filename: ["./model/Weights.bin"
|
|
65
|
+
filename: ["./model/Weights.bin", "./model/Bias.bin"]
|
|
32
66
|
}
|
|
33
67
|
})
|
|
34
68
|
```
|
|
35
69
|
|
|
36
|
-
Linear
|
|
70
|
+
> 📌 **Note:** The `Linear` layer requires a two-element filename array to separate the Weights and Bias files. Always use the `.bin` extension.
|
|
71
|
+
|
|
72
|
+
---
|
|
37
73
|
|
|
38
|
-
## Optimizations
|
|
74
|
+
## ⚡ Optimizations
|
|
39
75
|
|
|
40
|
-
|
|
41
|
-
|
|
76
|
+
- **Float32Array Powered**: Built on top of native typed arrays for maximum numerical performance and low memory overhead.
|
|
77
|
+
- **Heavy Workloads**: Easily handles large scaling operations, including dense 1024 embedding sizes.
|
|
78
|
+
- **Vanilla JavaScript**: Written entirely in raw JavaScript to eliminate bloated dependencies and optimize V8 execution.
|
|
42
79
|
|
|
43
|
-
|
|
80
|
+
---
|
|
44
81
|
|
|
45
|
-
|
|
82
|
+
## 🔤 Tokenizer
|
|
46
83
|
|
|
84
|
+
The tokenizer splits raw text strings into token IDs, which can then be fully decoded back into human-readable text.
|
|
47
85
|
|
|
48
|
-
|
|
86
|
+
### Example Usage:
|
|
49
87
|
|
|
50
88
|
```javascript
|
|
51
89
|
import { Tokenizer } from '@mineproness/tensorloop'
|
|
52
90
|
|
|
53
91
|
const tokenizer = new Tokenizer()
|
|
54
|
-
const text = "Hello,
|
|
92
|
+
const text = "Hello, Welcome to My Channel."
|
|
55
93
|
|
|
56
|
-
|
|
57
|
-
const
|
|
94
|
+
// Encode text to token IDs
|
|
95
|
+
const { tokenIDs } = tokenizer.encoder(text)
|
|
96
|
+
console.log(tokenIDs) // Output example: ["hello", "\$12", "well", "come", "\$130"...]
|
|
58
97
|
|
|
98
|
+
// Decode token IDs back to text
|
|
99
|
+
const decoded = tokenizer.decoder(tokenIDs)
|
|
100
|
+
console.log(decoded) // Output: "Hello, Welcome to My Channel."
|
|
59
101
|
```
|
|
60
|
-
## Suggestion
|
|
61
102
|
|
|
62
|
-
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 💡 Best Practices & Suggestions
|
|
63
106
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
107
|
+
### 1. Use TypeScript
|
|
108
|
+
We highly recommend using **TypeScript** with TensorLoop to enforce type safety and leverage IDE autocomplete features for all active classes and methods.
|
|
109
|
+
|
|
110
|
+
### 2. Pair with Native Tools
|
|
111
|
+
Maximize efficiency by processing your layers with our built-in `Tools` utility suite:
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
import { Tools } from '@mineproness/tensorloop'
|
|
67
115
|
|
|
68
116
|
const tools = new Tools()
|
|
69
117
|
|
|
70
|
-
|
|
118
|
+
// Optimize vector arrays for downstream tasks
|
|
119
|
+
console.log(tools.betterVector(embeddingVectors))
|
|
71
120
|
```
|
|
72
|
-
## Thanks for Visiting this Site
|
|
73
121
|
|
|
74
|
-
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## ⭐ Support the Project
|
|
125
|
+
|
|
126
|
+
Thank you for visiting! If you find this library useful for your AI or LLM workflows, please consider giving us a star on **[GitHub](https://github.com/mineproness-org/tensorloop)**!
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export class FFN{
|
|
2
|
+
constructor(embeddingSize: number, hiddenLayer: "gelu" | "relu" , configs: {
|
|
3
|
+
dirname: string
|
|
4
|
+
})
|
|
5
|
+
forward(input: Float32Array[]) : Float32Array[]
|
|
6
|
+
backward(dInput: Float32Array[], LearningRate: number) : Float32Array[]
|
|
7
|
+
Save() : void;
|
|
8
|
+
ClearInputCache() : void
|
|
9
|
+
}
|
package/src/FFN/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Linear } from '../Linear/index.js'
|
|
2
|
+
import { GELU } from '../GELU/index.js'
|
|
3
|
+
import { ReLU } from '../ReLU/index.js'
|
|
4
|
+
import { join } from 'path'
|
|
5
|
+
export class FFN {
|
|
6
|
+
linear1;
|
|
7
|
+
linear2;
|
|
8
|
+
hidden;
|
|
9
|
+
constructor(embeddingSize, hiddenLayer = "gelu", configs) {
|
|
10
|
+
this.hidden = hiddenLayer.toLocaleLowerCase() == "gelu" ? new GELU() : new ReLU()
|
|
11
|
+
if (configs) {
|
|
12
|
+
this.linear1 = new Linear(embeddingSize, 4 * embeddingSize, {
|
|
13
|
+
save: {
|
|
14
|
+
filename: [join(configs.dirname, "ffnWeights.bin"), join(configs.dirname, "ffnBias.bin")]
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
this.linear2 = new Linear(4 * embeddingSize, embeddingSize, {
|
|
18
|
+
save: {
|
|
19
|
+
filename: [join(configs.dirname, "ffnWeights1.bin"), join(configs.dirname, "ffnBias1.bin")]
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
} else {
|
|
23
|
+
this.linear1 = new Linear(embeddingSize, 4 * embeddingSize)
|
|
24
|
+
this.linear2 = new Linear(4 * embeddingSize, embeddingSize)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
forward(input){
|
|
28
|
+
const result = []
|
|
29
|
+
for(let a = 0; a < input.length; a++){
|
|
30
|
+
const out1 = this.linear1.forward(input[a])
|
|
31
|
+
const hidden = this.hidden.forward(out1, a)
|
|
32
|
+
result[a] = this.linear2.forward(hidden)
|
|
33
|
+
}
|
|
34
|
+
return result
|
|
35
|
+
}
|
|
36
|
+
backward(dInput, LearningRate){
|
|
37
|
+
const result = []
|
|
38
|
+
for(let a = 0; a < dInput.length; a++){
|
|
39
|
+
const out2 = this.linear2.backward(dInput[a] , LearningRate, a);
|
|
40
|
+
const dHidden = this.hidden.backward(out2, a)
|
|
41
|
+
result[a] = this.linear1.backward(dHidden, LearningRate, a)
|
|
42
|
+
}
|
|
43
|
+
return result
|
|
44
|
+
}
|
|
45
|
+
Save(){
|
|
46
|
+
this.linear1.Save()
|
|
47
|
+
this.linear2.Save()
|
|
48
|
+
}
|
|
49
|
+
ClearInputCache(){
|
|
50
|
+
this.linear1.ClearInputCache()
|
|
51
|
+
this.linear2.ClearInputCache()
|
|
52
|
+
this.hidden.ClearInputCache()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class LayerNorm {
|
|
2
|
+
gamma: Float32Array;
|
|
3
|
+
beta: Float32Array;
|
|
4
|
+
eps: number;
|
|
5
|
+
cache: Array<{
|
|
6
|
+
input: Float32Array;
|
|
7
|
+
mean: number;
|
|
8
|
+
invStd: number;
|
|
9
|
+
}>;
|
|
10
|
+
|
|
11
|
+
constructor(embeddingSize: number, eps?: number);
|
|
12
|
+
|
|
13
|
+
forward(input: Float32Array, index?: number): Float32Array;
|
|
14
|
+
|
|
15
|
+
backward(
|
|
16
|
+
dOutput: Float32Array,
|
|
17
|
+
learningRate: number,
|
|
18
|
+
index?: number
|
|
19
|
+
): Float32Array;
|
|
20
|
+
|
|
21
|
+
ClearInputCache(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export class LayerNorm {
|
|
2
|
+
gamma;
|
|
3
|
+
beta;
|
|
4
|
+
eps;
|
|
5
|
+
cache;
|
|
6
|
+
|
|
7
|
+
constructor(embeddingSize, eps = 1e-5) {
|
|
8
|
+
this.gamma = new Float32Array(embeddingSize);
|
|
9
|
+
this.beta = new Float32Array(embeddingSize);
|
|
10
|
+
|
|
11
|
+
this.gamma.fill(1);
|
|
12
|
+
this.beta.fill(0);
|
|
13
|
+
|
|
14
|
+
this.eps = eps;
|
|
15
|
+
this.cache = [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
forward(input, index = 0) {
|
|
19
|
+
const size = input.length;
|
|
20
|
+
let mean = 0;
|
|
21
|
+
for (let i = 0; i < size; i++) {
|
|
22
|
+
mean += input[i];
|
|
23
|
+
}
|
|
24
|
+
mean /= size;
|
|
25
|
+
let variance = 0;
|
|
26
|
+
for (let i = 0; i < size; i++) {
|
|
27
|
+
const diff = input[i] - mean;
|
|
28
|
+
variance += diff * diff;
|
|
29
|
+
}
|
|
30
|
+
variance /= size;
|
|
31
|
+
const invStd = 1 / Math.sqrt(variance + this.eps);
|
|
32
|
+
const output = new Float32Array(size);
|
|
33
|
+
for (let i = 0; i < size; i++) {
|
|
34
|
+
const normalized = (input[i] - mean) * invStd;
|
|
35
|
+
output[i] = normalized * this.gamma[i] + this.beta[i];
|
|
36
|
+
}
|
|
37
|
+
this.cache[index] = {
|
|
38
|
+
input: new Float32Array(input),
|
|
39
|
+
mean,
|
|
40
|
+
invStd
|
|
41
|
+
};
|
|
42
|
+
return output;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
backward(dOutput, learningRate, index = 0) {
|
|
46
|
+
const cache = this.cache[index];
|
|
47
|
+
const input = cache.input;
|
|
48
|
+
const mean = cache.mean;
|
|
49
|
+
const invStd = cache.invStd;
|
|
50
|
+
const size = input.length;
|
|
51
|
+
const dInput = new Float32Array(size);
|
|
52
|
+
let sumDNorm = 0;
|
|
53
|
+
let sumDNormX = 0;
|
|
54
|
+
const normalized = new Float32Array(size);
|
|
55
|
+
for (let i = 0; i < size; i++) {
|
|
56
|
+
normalized[i] = (input[i] - mean) * invStd;
|
|
57
|
+
const dNorm = dOutput[i] * this.gamma[i];
|
|
58
|
+
sumDNorm += dNorm;
|
|
59
|
+
sumDNormX += dNorm * normalized[i];
|
|
60
|
+
const dGamma = dOutput[i] * normalized[i];
|
|
61
|
+
const dBeta = dOutput[i];
|
|
62
|
+
|
|
63
|
+
this.gamma[i] -= learningRate * dGamma;
|
|
64
|
+
this.beta[i] -= learningRate * dBeta;
|
|
65
|
+
}
|
|
66
|
+
for (let i = 0; i < size; i++) {
|
|
67
|
+
const dNorm = dOutput[i] * this.gamma[i];
|
|
68
|
+
dInput[i] =
|
|
69
|
+
(invStd / size) *
|
|
70
|
+
(
|
|
71
|
+
size * dNorm -
|
|
72
|
+
sumDNorm -
|
|
73
|
+
normalized[i] * sumDNormX
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return dInput;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
ClearInputCache() {
|
|
80
|
+
this.cache = [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export class TransformerBlock{
|
|
2
|
+
constructor(embeddingSize: number, configs:{
|
|
3
|
+
dirname: string
|
|
4
|
+
})
|
|
5
|
+
Save(): void
|
|
6
|
+
clearInputCache() : void
|
|
7
|
+
forward(input: Float32Array[]) : Float32Array[]
|
|
8
|
+
backward(dOutput: Float32Array[], LearningRate: number) : Float32Array[]
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { SelfAttention } from '../SelfAttention/index.js'
|
|
2
|
+
import { FFN } from '../FFN/index.js'
|
|
3
|
+
import { LayerNorm } from '../LayerNorm/index.js'
|
|
4
|
+
export class TransformerBlock {
|
|
5
|
+
norm1;
|
|
6
|
+
norm2;
|
|
7
|
+
ffn;
|
|
8
|
+
selfAttention;
|
|
9
|
+
constructor(embeddingSize, configs) {
|
|
10
|
+
this.norm1 = new LayerNorm(embeddingSize)
|
|
11
|
+
this.norm2 = new LayerNorm(embeddingSize)
|
|
12
|
+
this.ffn = new FFN(embeddingSize, "gelu", configs)
|
|
13
|
+
this.selfAttention = new SelfAttention(embeddingSize, configs)
|
|
14
|
+
}
|
|
15
|
+
forward(input) {
|
|
16
|
+
const normal1 = []
|
|
17
|
+
for (let a = 0; a < input.length; a++) {
|
|
18
|
+
normal1[a] = this.norm1.forward(input[a], a)
|
|
19
|
+
}
|
|
20
|
+
const attention = this.selfAttention.forward(normal1)
|
|
21
|
+
const residual1 = []
|
|
22
|
+
for (let a = 0; a < input.length; a++) {
|
|
23
|
+
residual1[a] = new Float32Array(input[0].length)
|
|
24
|
+
for (let i = 0; i < input[0].length; i++) {
|
|
25
|
+
residual1[a][i] = input[a][i] + attention[a][i]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const normal2 = []
|
|
29
|
+
for (let a = 0; a < input.length; a++) {
|
|
30
|
+
normal2[a] = this.norm2.forward(residual1[a], a)
|
|
31
|
+
}
|
|
32
|
+
const ffnOutput = this.ffn.forward(normal2)
|
|
33
|
+
const output = []
|
|
34
|
+
for (let g = 0; g < residual1.length; g++) {
|
|
35
|
+
output[g] = new Float32Array(residual1[0].length)
|
|
36
|
+
for (let a = 0; a < output[0].length; a++) {
|
|
37
|
+
output[g][a] = residual1[g][a] + ffnOutput[g][a]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return output
|
|
41
|
+
}
|
|
42
|
+
backward(dOutput, learningRate) {
|
|
43
|
+
const dFFN = this.ffn.backward(
|
|
44
|
+
dOutput,
|
|
45
|
+
learningRate
|
|
46
|
+
)
|
|
47
|
+
const dResidual1 = []
|
|
48
|
+
|
|
49
|
+
for (let a = 0; a < dFFN.length; a++) {
|
|
50
|
+
dResidual1[a] = this.norm2.backward(
|
|
51
|
+
dFFN[a],
|
|
52
|
+
learningRate,
|
|
53
|
+
a
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
const dAttention = this.selfAttention.backward(
|
|
57
|
+
dResidual1,
|
|
58
|
+
learningRate
|
|
59
|
+
)
|
|
60
|
+
const dInputFromAttention = []
|
|
61
|
+
for (let a = 0; a < dAttention.length; a++) {
|
|
62
|
+
dInputFromAttention[a] = this.norm1.backward(
|
|
63
|
+
dAttention[a],
|
|
64
|
+
learningRate,
|
|
65
|
+
a
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
const dInput = []
|
|
69
|
+
for (let a = 0; a < dOutput.length; a++) {
|
|
70
|
+
dInput[a] = new Float32Array(dOutput[a].length)
|
|
71
|
+
for (let i = 0; i < dOutput[a].length; i++) {
|
|
72
|
+
dInput[a][i] =
|
|
73
|
+
dOutput[a][i] +
|
|
74
|
+
dInputFromAttention[a][i]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return dInput
|
|
79
|
+
}
|
|
80
|
+
clearInputCache() {
|
|
81
|
+
this.ffn.clearInputCache()
|
|
82
|
+
this.selfAttention.key.ClearInputCache()
|
|
83
|
+
this.selfAttention.query.ClearInputCache()
|
|
84
|
+
this.selfAttention.value.ClearInputCache()
|
|
85
|
+
this.norm1.ClearInputCache()
|
|
86
|
+
this.norm2.ClearInputCache()
|
|
87
|
+
}
|
|
88
|
+
Save() {
|
|
89
|
+
this.selfAttention.Save()
|
|
90
|
+
this.ffn.Save()
|
|
91
|
+
}
|
|
92
|
+
}
|