@mineproness/tensorloop 1.0.0
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 +10 -0
- package/package.json +22 -0
- package/src/Embedding/index.d.ts +10 -0
- package/src/Embedding/index.js +48 -0
- package/src/GetConfigs.js +35 -0
- package/src/Linear/index.d.ts +11 -0
- package/src/Linear/index.js +69 -0
- package/src/ReLU/index.js +14 -0
- package/src/Softmax/index.d.ts +4 -0
- package/src/Softmax/index.js +13 -0
- package/src/Tokenizer/index.d.ts +11 -0
- package/src/Tokenizer/index.js +92 -0
- package/src/Tokenizer/vocabs.json +29000 -0
- package/src/crossEntropy/index.js +3 -0
package/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Tokenizer as tokenizer } from "./src/Tokenizer/index.js";
|
|
2
|
+
import { Embedding as embeddding2 } from "./src/Embedding/index.js";
|
|
3
|
+
import { Linear as li2 } from "./src/Linear/index.js";
|
|
4
|
+
import { Softmax as softmax2 } from "./src/Softmax/index.js";
|
|
5
|
+
import { crossEntropy } from "./src/crossEntropy/index.js";
|
|
6
|
+
export const Tokenizer = tokenizer
|
|
7
|
+
export const Embedding = embeddding2
|
|
8
|
+
export const Linear = li2
|
|
9
|
+
export const Softmax = softmax2
|
|
10
|
+
export const CrossEntropy = crossEntropy
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mineproness/tensorloop",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "The most powerfull Machine Learing Libeary for AI.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"llm",
|
|
8
|
+
"Large",
|
|
9
|
+
"Language",
|
|
10
|
+
"model",
|
|
11
|
+
"Small",
|
|
12
|
+
"Language",
|
|
13
|
+
"Model"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "mineproness",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "index.js",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export class Embedding{
|
|
2
|
+
vectors: Float32Array[]
|
|
3
|
+
constructor(embeddingSize: number, vocabSize: number, configs: {
|
|
4
|
+
save: {
|
|
5
|
+
filename: string
|
|
6
|
+
}
|
|
7
|
+
})
|
|
8
|
+
forward(token: number | number[]) : number[] | number[][]
|
|
9
|
+
backward(token: number , inputGradient: number[], learingRate: number) : void
|
|
10
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs, { existsSync } from 'fs'
|
|
2
|
+
import { GetVectors, SaveVectors } from '../GetConfigs.js'
|
|
3
|
+
// import { config } from 'process'
|
|
4
|
+
|
|
5
|
+
function GenerateVectors(embeddingSize, vocabSize) {
|
|
6
|
+
const vector = []
|
|
7
|
+
for (let token = 0; token < vocabSize; token++) {
|
|
8
|
+
vector[token] = new Float32Array(embeddingSize)
|
|
9
|
+
for (let a = 0; a < embeddingSize; a++) {
|
|
10
|
+
vector[token][a] = (Math.random() * 2 - 1) * 0.2
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return vector
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Embedding {
|
|
17
|
+
vectors = []
|
|
18
|
+
configs;
|
|
19
|
+
constructor(embeddingSize, vocabSize, configs) {
|
|
20
|
+
this.configs = configs
|
|
21
|
+
if (configs && configs.save) {
|
|
22
|
+
if (existsSync(configs.save.filename)) {
|
|
23
|
+
this.vectors = GetVectors(configs.save.filename, embeddingSize)
|
|
24
|
+
} else {
|
|
25
|
+
this.vectors = GenerateVectors(embeddingSize, vocabSize)
|
|
26
|
+
SaveVectors(configs.save.filename, this.vectors)
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
this.vectors = GenerateVectors(embeddingSize, vocabSize)
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
forward(token) {
|
|
34
|
+
if(Array.isArray(token)){
|
|
35
|
+
return token.map((e)=> this.vectors[e])
|
|
36
|
+
}else{
|
|
37
|
+
return this.vectors[token]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
backward(token, inputGradient, learingRate){
|
|
41
|
+
for(let a = 0; a < this.vectors[token].length; a++){
|
|
42
|
+
this.vectors[token][a] -= learingRate * inputGradient[a]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
Save(){
|
|
46
|
+
SaveVectors(this.configs.save.filename , this.vectors)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
4
|
+
export function SaveVectors (filename, vectors){
|
|
5
|
+
const sizeOfArray = vectors.length;
|
|
6
|
+
const sizeOfEmbedding = vectors[0].length;
|
|
7
|
+
const floatArray = vectors.map((e)=> Buffer.from(e.buffer))
|
|
8
|
+
const combinedBuffer = Buffer.concat(floatArray)
|
|
9
|
+
fs.writeFileSync(filename , combinedBuffer)
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function GetVectors(filename, embeddingSize){
|
|
14
|
+
const fileBuffer = fs.readFileSync(filename)
|
|
15
|
+
const ELEMENTS_PER_ARRAY= embeddingSize;
|
|
16
|
+
const BYTES_PER_ELEMENT= Float32Array.BYTES_PER_ELEMENT
|
|
17
|
+
const BYTES_PER_ARRAY = ELEMENTS_PER_ARRAY * BYTES_PER_ELEMENT
|
|
18
|
+
const totalArraySaved = fileBuffer.byteLength / BYTES_PER_ARRAY;
|
|
19
|
+
const totalArray = []
|
|
20
|
+
for(let i = 0; i < totalArraySaved; i++){
|
|
21
|
+
const currentOffset = fileBuffer.byteOffset + (i * BYTES_PER_ARRAY)
|
|
22
|
+
const f32 = new Float32Array(fileBuffer.buffer, currentOffset, ELEMENTS_PER_ARRAY)
|
|
23
|
+
totalArray.push(f32)
|
|
24
|
+
}
|
|
25
|
+
return totalArray
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function GetVector(filename){
|
|
29
|
+
const buffer = fs.readFileSync(filename)
|
|
30
|
+
return new Float32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Float32Array.BYTES_PER_ELEMENT)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function Save(filename, vector){
|
|
34
|
+
return fs.writeFileSync(filename, Buffer.from(vector.buffer))
|
|
35
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class Linear{
|
|
2
|
+
Weights : Float32Array[]
|
|
3
|
+
Bias: Float32Array
|
|
4
|
+
constructor(embeddingSize : number, vocabSize : number, configs: {
|
|
5
|
+
save: {
|
|
6
|
+
filename: string[]
|
|
7
|
+
}
|
|
8
|
+
})
|
|
9
|
+
forward(input : number[]) : number[]
|
|
10
|
+
backward(outGradient : number[] , learingRate: number) : number[]
|
|
11
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { GetVector, GetVectors, Save, SaveVectors } from '../GetConfigs.js'
|
|
2
|
+
import { existsSync } from 'fs'
|
|
3
|
+
function GenerateWeightsBias(embeddingSize, vocabSize) {
|
|
4
|
+
const vectors = []
|
|
5
|
+
const Bias = new Float32Array(vocabSize)
|
|
6
|
+
for (let a = 0; a < vocabSize; a++) {
|
|
7
|
+
vectors[a] = new Float32Array(embeddingSize)
|
|
8
|
+
for (let t = 0; t < embeddingSize; t++) {
|
|
9
|
+
vectors[a][t] = (Math.random() * 2 - 1) * 0.02
|
|
10
|
+
}
|
|
11
|
+
Bias[a] = 0
|
|
12
|
+
}
|
|
13
|
+
return { vectors, Bias }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Linear {
|
|
17
|
+
Weights = []
|
|
18
|
+
Bias = []
|
|
19
|
+
configs;
|
|
20
|
+
input = [];
|
|
21
|
+
constructor(embeddingSize, vocabSize, configs) {
|
|
22
|
+
if (configs && configs.save) {
|
|
23
|
+
this.configs = configs
|
|
24
|
+
if (existsSync(configs.save.filename[0]) && existsSync(configs.save.filename[1])) {
|
|
25
|
+
const Vectors = GetVectors(configs.save.filename[0], embeddingSize)
|
|
26
|
+
const Bias = GetVector(configs.save.filename[1])
|
|
27
|
+
this.Weights = Vectors;
|
|
28
|
+
this.Bias = Bias
|
|
29
|
+
} else {
|
|
30
|
+
const { vectors, Bias } = GenerateWeightsBias(embeddingSize, vocabSize)
|
|
31
|
+
this.Weights = vectors;
|
|
32
|
+
this.Bias = Bias;
|
|
33
|
+
SaveVectors(configs.save.filename[0], this.Weights)
|
|
34
|
+
Save(configs.save.filename[1], this.Bias)
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
const { vectors, Bias } = GenerateWeightsBias(embeddingSize, vocabSize)
|
|
38
|
+
this.Weights = vectors;
|
|
39
|
+
this.Bias = Bias;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
Save() {
|
|
43
|
+
SaveVectors(this.configs.save.filename[0], this.Weights)
|
|
44
|
+
Save(this.configs.save.filename[1], this.Bias)
|
|
45
|
+
}
|
|
46
|
+
forward(input) {
|
|
47
|
+
this.input = input
|
|
48
|
+
const output = []
|
|
49
|
+
for (let a = 0; a < this.Weights.length; a++) {
|
|
50
|
+
let sum = this.Bias[a]
|
|
51
|
+
for (let t = 0; t < input.length; t++) {
|
|
52
|
+
sum += input[t] * this.Weights[a][t]
|
|
53
|
+
}
|
|
54
|
+
output.push(sum)
|
|
55
|
+
}
|
|
56
|
+
return output
|
|
57
|
+
}
|
|
58
|
+
backward(outputGradient, learningRate) {
|
|
59
|
+
const inputGradient = new Float32Array(this.input.length)
|
|
60
|
+
for (let a = 0; a < this.Weights.length; a++) {
|
|
61
|
+
for (let at = 0; at < this.input.length; at++) {
|
|
62
|
+
inputGradient[at] += outputGradient[a] * this.Weights[a][at]
|
|
63
|
+
this.Weights[a][at] -= learningRate * this.input[at] * outputGradient[a]
|
|
64
|
+
}
|
|
65
|
+
this.Bias[a] -= learningRate * outputGradient[a]
|
|
66
|
+
}
|
|
67
|
+
return inputGradient
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class ReLU{
|
|
2
|
+
input;
|
|
3
|
+
forward(XLi){
|
|
4
|
+
this.input = XLi
|
|
5
|
+
return XLi.map((e)=> e > 0 ? e : 0)
|
|
6
|
+
}
|
|
7
|
+
backward(outputGradient){
|
|
8
|
+
const inputGradient = new Float32Array(this.input.length)
|
|
9
|
+
for(let i = 0; i < outputGradient.length; i++){
|
|
10
|
+
inputGradient[i] = this.input[i] > 0 ? outputGradient[i] : 0
|
|
11
|
+
}
|
|
12
|
+
return inputGradient
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class Softmax{
|
|
2
|
+
forward(xLi){
|
|
3
|
+
const max = Math.max(...xLi)
|
|
4
|
+
const exp = xLi.map((e)=> Math.exp(e - max))
|
|
5
|
+
const sum = exp.reduce((a,b)=> a + b , 0)
|
|
6
|
+
return exp.map((e)=> e / sum)
|
|
7
|
+
}
|
|
8
|
+
backward(probs , target){
|
|
9
|
+
const pro = [...probs]
|
|
10
|
+
pro[target] -= 1
|
|
11
|
+
return pro
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class Tokenizer{
|
|
2
|
+
vocabs : string[]
|
|
3
|
+
vocabSize: number
|
|
4
|
+
IdtoWord : Record<string, string>
|
|
5
|
+
WordtoID : Record<string , number>
|
|
6
|
+
encoder(text: string) : {
|
|
7
|
+
tokens: string[]
|
|
8
|
+
tokenIDs: number[]
|
|
9
|
+
}
|
|
10
|
+
decoder(tokens: number[] | number[][]) : string
|
|
11
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { readFileSync } from 'fs'
|
|
2
|
+
import { join, dirname, format } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
export class Tokenizer {
|
|
7
|
+
vocabs = [];
|
|
8
|
+
vocabSize = 0;
|
|
9
|
+
IdtoWord = {};
|
|
10
|
+
WordtoID = {};
|
|
11
|
+
constructor() {
|
|
12
|
+
this.vocabs = JSON.parse(readFileSync(join(__dirname, "vocabs.json"), "utf-8"))
|
|
13
|
+
this.vocabSize = this.vocabs.length
|
|
14
|
+
this.IdtoWord = Object.fromEntries(this.vocabs.map((e, idx) => [idx, e]))
|
|
15
|
+
this.WordtoID = Object.fromEntries(this.vocabs.map((e, idx) => [e, idx]))
|
|
16
|
+
}
|
|
17
|
+
encoder(text = "") {
|
|
18
|
+
const AddSpaces = text.toLocaleLowerCase().replaceAll(/([,.;'{}`~\|":><?])/g, " $1 ")
|
|
19
|
+
const splitedWords = AddSpaces.split(/\s+/).filter(e => e.length > 0)
|
|
20
|
+
const output = []
|
|
21
|
+
for (let a = 0; a < splitedWords.length; a++) {
|
|
22
|
+
const word = splitedWords[a]
|
|
23
|
+
if (this.WordtoID[word]) {
|
|
24
|
+
output.push(word)
|
|
25
|
+
} else {
|
|
26
|
+
let max = word.length
|
|
27
|
+
output.push("$12")
|
|
28
|
+
while (true) {
|
|
29
|
+
const regPatten = new RegExp(`.{0,${max}}`, "g")
|
|
30
|
+
const wordsliced = word.match(regPatten).filter((e) => e.length > 0)
|
|
31
|
+
const matched = wordsliced.flatMap(e => {
|
|
32
|
+
if (this.WordtoID[e]) {
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
return false
|
|
36
|
+
}).reduce((prev, curr) => prev && curr)
|
|
37
|
+
if (matched) {
|
|
38
|
+
wordsliced.map((e) => output.push(e))
|
|
39
|
+
output.push("$130")
|
|
40
|
+
break
|
|
41
|
+
} else {
|
|
42
|
+
max -= 1
|
|
43
|
+
// break
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { tokens: output, tokenIDs: output.map((e) => this.WordtoID[e]) }
|
|
50
|
+
}
|
|
51
|
+
decoder(tokens = [1, 2, 3]) {
|
|
52
|
+
const output = []
|
|
53
|
+
let isSpace = false
|
|
54
|
+
// let index = 0
|
|
55
|
+
for (let token of tokens) {
|
|
56
|
+
const formated = this.IdtoWord[String(token)]
|
|
57
|
+
if (formated == "$12") {
|
|
58
|
+
output[output.length] = ""
|
|
59
|
+
isSpace = true
|
|
60
|
+
} else if (formated == "$130") {
|
|
61
|
+
isSpace = false
|
|
62
|
+
} else {
|
|
63
|
+
if (isSpace) {
|
|
64
|
+
output[output.length - 1] += formated
|
|
65
|
+
} else {
|
|
66
|
+
output.push(formated)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return Validate(output).join(" ").replaceAll(/\s+([,.;'{}`~\|":><?])/g, "$1")
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function Validate(output = ["hello", "guys"]) {
|
|
76
|
+
const bestOutput = []
|
|
77
|
+
output.map((e, idx) => {
|
|
78
|
+
if (idx == 0) {
|
|
79
|
+
bestOutput[idx] = e[0].toLocaleUpperCase() + e.slice(1, e.length)
|
|
80
|
+
} else {
|
|
81
|
+
if (bestOutput[idx - 1] == ":" || bestOutput[idx - 1] == ".") {
|
|
82
|
+
|
|
83
|
+
bestOutput[idx] = e[0].toLocaleUpperCase() + e.slice(1, e.length)
|
|
84
|
+
} else {
|
|
85
|
+
bestOutput[idx] = e
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
})
|
|
91
|
+
return bestOutput
|
|
92
|
+
}
|