@mineproness/tensorloop 2.1.66 → 2.1.69
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 +7 -1
- package/package.json +1 -1
- package/src/Embedding/index.js +2 -1
- package/src/FFN/index.js +2 -1
- package/src/Linear/index.js +2 -1
- package/src/Model/index.d.ts +15 -0
- package/src/Model/index.js +95 -0
- package/src/OperationManager.js +21 -2
- package/src/PositionEmbedding/index.d.ts +10 -0
- package/src/PositionEmbedding/index.js +70 -0
- package/src/RMSNorm/index.d.ts +5 -0
- package/src/RMSNorm/index.js +45 -0
- package/src/SelfAttention/index.js +2 -1
- package/src/Softmax/index.js +1 -0
- package/src/Tokenizer/index.js +9 -5
- package/src/TransformerBlock/index.js +65 -22
- package/src/gpu.js +0 -0
- package/src/shaders/CalculateLoss.wgsl +1 -1
- package/src/shaders/LB.wgsl +4 -4
- package/src/shaders/Norm/rmsBackward.wgsl +35 -0
- package/src/shaders/Norm/rmsForward.wgsl +19 -0
- package/src/shaders/Norm/sumSquare.wgsl +37 -0
- package/src/shaders/PB.wgsl +25 -0
- package/src/shaders/PF.wgsl +21 -0
- package/src/shaders/add.wgsl +30 -0
package/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import { FFN as ffn } from "./src/FFN/index.js";
|
|
|
6
6
|
import { Tokenizer as to } from './src/Tokenizer/index.js'
|
|
7
7
|
import {SelfAttention as ST} from './src/SelfAttention/index.js'
|
|
8
8
|
import {TransformerBlock as TT} from './src/TransformerBlock/index.js'
|
|
9
|
+
import { Model as m } from "./src/Model/index.js";
|
|
10
|
+
import {PositionEmbedding as PM } from './src/PositionEmbedding/index.js'
|
|
11
|
+
import { RMSNorm as RM } from "./src/RMSNorm/index.js";
|
|
9
12
|
export const Embedding = E
|
|
10
13
|
export const Linear = L
|
|
11
14
|
export const Softmax = S;
|
|
@@ -13,4 +16,7 @@ export const RELU = r
|
|
|
13
16
|
export const FFN = ffn
|
|
14
17
|
export const Tokenizer = to;
|
|
15
18
|
export const SelfAttention = ST
|
|
16
|
-
export const TransformerBlock = TT;
|
|
19
|
+
export const TransformerBlock = TT;
|
|
20
|
+
export const Model = m;
|
|
21
|
+
export const PositionEmbedding = PM;
|
|
22
|
+
export const RMSNorm = RM
|
package/package.json
CHANGED
package/src/Embedding/index.js
CHANGED
|
@@ -134,6 +134,7 @@ export class Embedding {
|
|
|
134
134
|
await this.gpu.WriteBuffer(this.tokenBuffer, new Uint32Array(token));
|
|
135
135
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.embeddingSize * token.length) / 256))
|
|
136
136
|
this.device.queue.submit([encoder.finish()])
|
|
137
|
-
|
|
137
|
+
if(this.prevGra) this.prevGra.destroy()
|
|
138
|
+
this.prevGra = inputGradient;
|
|
138
139
|
}
|
|
139
140
|
}
|
package/src/FFN/index.js
CHANGED
|
@@ -29,10 +29,11 @@ export class FFN {
|
|
|
29
29
|
return final
|
|
30
30
|
}
|
|
31
31
|
async backward(inputGradient, lr) {
|
|
32
|
+
if(this.prevOUTGR) await this.prevOUTGR.destroy()
|
|
33
|
+
this.prevOUTGR = inputGradient;
|
|
32
34
|
const logit2 = await this.linear2.backward(inputGradient, lr)
|
|
33
35
|
const hidden = await this.hiddenLayer.backward(logit2)
|
|
34
36
|
const final = await this.linear1.backward(hidden, lr)
|
|
35
|
-
inputGradient.destroy()
|
|
36
37
|
return final
|
|
37
38
|
}
|
|
38
39
|
async Save(){
|
package/src/Linear/index.js
CHANGED
|
@@ -113,6 +113,8 @@ export class Linear {
|
|
|
113
113
|
return outputBuffer
|
|
114
114
|
}
|
|
115
115
|
async backward(dOutput, learningRate) {
|
|
116
|
+
if(this.pdOutput) await this.pdOutput.destroy();
|
|
117
|
+
this.pdOutput = dOutput
|
|
116
118
|
const encoder = this.device.createCommandEncoder()
|
|
117
119
|
const tokenCount = dOutput.size / (this.vocabSize * 4)
|
|
118
120
|
if (!this.oldParamb) {
|
|
@@ -173,7 +175,6 @@ export class Linear {
|
|
|
173
175
|
await this.gpu.RunPipline(encoder, this.dInputBackward, bind2, Math.ceil((this.embeddingSize * tokenCount) / 256));
|
|
174
176
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.vocabSize * tokenCount) / 256));
|
|
175
177
|
await this.device.queue.submit([encoder.finish()])
|
|
176
|
-
await dOutput.destroy()
|
|
177
178
|
this.input.destroy()
|
|
178
179
|
return outputBuffer
|
|
179
180
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class Model {
|
|
2
|
+
async forward(input: Number[], buffer: boolean): Promise<Float32Array | GPUBuffer>;
|
|
3
|
+
async backward(output: GPUBuffer, target: number[], lr: number): Promise<{ acc: number, loss: number }>
|
|
4
|
+
TrainTokenizer(dataset: string): void;
|
|
5
|
+
constructor(device :GPUAdapter, embeddingSize: number, configs: {
|
|
6
|
+
tokenizerName: string
|
|
7
|
+
blockSize: number,
|
|
8
|
+
dirname: string,
|
|
9
|
+
contextSize: number,
|
|
10
|
+
gpuName: string
|
|
11
|
+
|
|
12
|
+
})
|
|
13
|
+
async Save() : Promise<void>
|
|
14
|
+
async CreateContext()
|
|
15
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Embedding, Linear, Softmax, TransformerBlock, Tokenizer, PositionEmbedding, RMSNorm } from '../../index.js'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
import { OperationManager } from '../OperationManager.js'
|
|
5
|
+
export class Model {
|
|
6
|
+
embedding;
|
|
7
|
+
posEmbedding;
|
|
8
|
+
linear;
|
|
9
|
+
softmax;
|
|
10
|
+
blocks = [];
|
|
11
|
+
blockSize;
|
|
12
|
+
dimSize;
|
|
13
|
+
tokenizer;
|
|
14
|
+
device;
|
|
15
|
+
configs;
|
|
16
|
+
tokenizerName;
|
|
17
|
+
op;
|
|
18
|
+
tokens;
|
|
19
|
+
rmsnorm
|
|
20
|
+
constructor(device, embeddingSize = 64, configs) {
|
|
21
|
+
this.device = device;
|
|
22
|
+
this.dimSize = embeddingSize;
|
|
23
|
+
this.blockSize = configs.blockSize;
|
|
24
|
+
this.configs = configs
|
|
25
|
+
this.tokenizer = new Tokenizer(configs.tokenizerName)
|
|
26
|
+
this.tokenizerName = configs.tokenizerName
|
|
27
|
+
this.op = new OperationManager(device)
|
|
28
|
+
}
|
|
29
|
+
async CreateContext() {
|
|
30
|
+
this.embedding = new Embedding(this.device, this.dimSize, this.tokenizer.vocabSize, {
|
|
31
|
+
save: {
|
|
32
|
+
filename: join(this.configs.dirname, "./vec.bin")
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
this.linear = new Linear(this.device, this.dimSize, this.tokenizer.vocabSize, {
|
|
36
|
+
save: {
|
|
37
|
+
filename: [join(this.configs.dirname, "weights.bin"), join(this.configs.dirname, "bias.bin")]
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
this.softmax = new Softmax(this.device, this.dimSize, this.tokenizer.vocabSize);
|
|
41
|
+
for (let a = 0; a < this.blockSize; a++) {
|
|
42
|
+
console.log(`Load the Transfomer Block ${a + 1}...`)
|
|
43
|
+
if (!fs.existsSync(join(this.configs.dirname, `block-${a}`))) fs.mkdirSync(join(this.configs.dirname, `block-${a}`));
|
|
44
|
+
this.blocks[a] = new TransformerBlock(this.device, this.dimSize, {
|
|
45
|
+
dirname: join(this.configs.dirname, `block-${a}`)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
this.posEmbedding = new PositionEmbedding(this.device, this.dimSize, this.configs.contextSize, {
|
|
49
|
+
save:{
|
|
50
|
+
filename: join(this.configs.dirname, "posVec.bin")
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
TrainTokenizer(text = "", mergeSize = 5) {
|
|
55
|
+
this.tokenizer.trainTokenizer(text, mergeSize, this.tokenizerName)
|
|
56
|
+
}
|
|
57
|
+
async ClearInputCache() {
|
|
58
|
+
await this.linear.ClearInputCache()
|
|
59
|
+
for (let a = 0; a < this.blockSize; a++) {
|
|
60
|
+
await this.blocks[a].ClearInputCache()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async forward(input, readBack) {
|
|
64
|
+
if(this.configs.contextSize < input.length) throw new Error("The Input is larger then contextSize")
|
|
65
|
+
this.tokens = input;
|
|
66
|
+
await this.ClearInputCache()
|
|
67
|
+
let vec = await this.embedding.forward(input)
|
|
68
|
+
vec = await this.posEmbedding.forward(vec)
|
|
69
|
+
for (let a = 0; a < this.blockSize; a++) {
|
|
70
|
+
vec = await this.blocks[a].forward(vec)
|
|
71
|
+
}
|
|
72
|
+
let logits = await this.linear.forward(vec);
|
|
73
|
+
let probs = await this.softmax.forward(logits, readBack)
|
|
74
|
+
return probs
|
|
75
|
+
}
|
|
76
|
+
async backward(outputGradient, target, lr = 0.02) {
|
|
77
|
+
const loss = await this.softmax.crossEntropy(outputGradient, target)
|
|
78
|
+
const dLogits = await this.softmax.backward(outputGradient, target);
|
|
79
|
+
let DInput = await this.linear.backward(dLogits, lr);
|
|
80
|
+
for (let a = this.blockSize - 1; a !== 0; a--) {
|
|
81
|
+
DInput = await this.blocks[a].backward(DInput, lr);
|
|
82
|
+
}
|
|
83
|
+
this.embedding.backward(this.tokens, DInput, lr);
|
|
84
|
+
this.posEmbedding.backward(DInput, lr)
|
|
85
|
+
return loss
|
|
86
|
+
}
|
|
87
|
+
async Save() {
|
|
88
|
+
await this.embedding.Save()
|
|
89
|
+
await this.linear.Save()
|
|
90
|
+
for (let a = this.blockSize - 1; a !== 0; a--) {
|
|
91
|
+
await this.blocks[a].Save();
|
|
92
|
+
}
|
|
93
|
+
await this.posEmbedding.Save()
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/OperationManager.js
CHANGED
|
@@ -8,9 +8,10 @@ export class OperationManager {
|
|
|
8
8
|
device;
|
|
9
9
|
matrixMatSHhaders;
|
|
10
10
|
params;
|
|
11
|
-
|
|
11
|
+
addShader;
|
|
12
12
|
constructor(device) {
|
|
13
13
|
this.device = device;
|
|
14
|
+
this.addShader = this.getShaderPipline("./src/shaders/add.wgsl")
|
|
14
15
|
}
|
|
15
16
|
async createBuffer(size) {
|
|
16
17
|
return this.device.createBuffer({
|
|
@@ -71,18 +72,21 @@ export class OperationManager {
|
|
|
71
72
|
pass.end()
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
async MakeACopyBuffer(
|
|
75
|
+
async MakeACopyBuffer(encoder2, sourceBuffer) {
|
|
76
|
+
const encoder = encoder2 ? encoder2 : await this.CreateEncoder()
|
|
75
77
|
const buffer = this.device.createBuffer({
|
|
76
78
|
size: sourceBuffer.size,
|
|
77
79
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
78
80
|
})
|
|
79
81
|
encoder.copyBufferToBuffer(sourceBuffer, 0, buffer, 0, sourceBuffer.size);
|
|
82
|
+
if(!encoder2) await this.submitQueue(encoder)
|
|
80
83
|
return buffer
|
|
81
84
|
}
|
|
82
85
|
CreateEncoder() {
|
|
83
86
|
return this.device.createCommandEncoder()
|
|
84
87
|
}
|
|
85
88
|
createBindGroup(shader, groupNum, ent) {
|
|
89
|
+
|
|
86
90
|
return this.device.createBindGroup({
|
|
87
91
|
layout: shader.getBindGroupLayout(groupNum),
|
|
88
92
|
entries: ent.map((e, x) => {
|
|
@@ -96,5 +100,20 @@ export class OperationManager {
|
|
|
96
100
|
async submitQueue(encoder) {
|
|
97
101
|
this.device.queue.submit([encoder.finish()])
|
|
98
102
|
}
|
|
103
|
+
async add(a, b, size) {
|
|
104
|
+
if (!this.params) {
|
|
105
|
+
this.params = await this.createUniFormBuffer(4 * 4)
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
const encoder = await this.CreateEncoder()
|
|
109
|
+
const output = await this.createBuffer(a.size);
|
|
110
|
+
const bind = await this.createBindGroup(this.addShader, 0, [a, b, output, this.params]);
|
|
111
|
+
await this.WriteBuffer(this.params, new Uint32Array([size, 0]))
|
|
112
|
+
await this.RunPipline(encoder, this.addShader, bind, Math.ceil(size / 64));
|
|
113
|
+
await this.submitQueue(encoder)
|
|
114
|
+
// a.destroy()
|
|
115
|
+
// b.destroy()
|
|
116
|
+
return output
|
|
117
|
+
}
|
|
99
118
|
|
|
100
119
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export class PositionEmbedding{
|
|
2
|
+
constructor(device: GPUBuffer ,embedding : number, contextSize: number, config:{
|
|
3
|
+
save: {
|
|
4
|
+
filename: string
|
|
5
|
+
}
|
|
6
|
+
});
|
|
7
|
+
async forward(input: GPUBuffer) : Promise<GPUBuffer>
|
|
8
|
+
async Save() : Promise<GPUBuffer>
|
|
9
|
+
async backward(inputGradient: GPUBuffer, lr: number) : Promise<void>
|
|
10
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OperationManager } from "../OperationManager.js"
|
|
2
|
+
import { getVector, SaveVector } from "../getVec.js"
|
|
3
|
+
function GenerateVectors(embeddingSize, contextSize) {
|
|
4
|
+
const vec = new Float32Array(embeddingSize * contextSize).map(() => (Math.random() * 2 - 1) * 0.02)
|
|
5
|
+
return vec
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class PositionEmbedding {
|
|
9
|
+
vectors;
|
|
10
|
+
vecBuffer;
|
|
11
|
+
gpu;
|
|
12
|
+
embeddingSize;
|
|
13
|
+
contextSize;
|
|
14
|
+
params;
|
|
15
|
+
forwardShader;
|
|
16
|
+
backwardShader;
|
|
17
|
+
configs;
|
|
18
|
+
constructor(device, embeddingSize, contextSize, configs) {
|
|
19
|
+
this.embeddingSize = embeddingSize;
|
|
20
|
+
const total = embeddingSize * contextSize;
|
|
21
|
+
this.configs = configs;
|
|
22
|
+
this.contextSize = contextSize;
|
|
23
|
+
if (configs && configs.save) {
|
|
24
|
+
const vec = getVector(configs.save.filename, total);
|
|
25
|
+
if (vec) {
|
|
26
|
+
this.vectors = vec;
|
|
27
|
+
|
|
28
|
+
} else {
|
|
29
|
+
this.vectors = GenerateVectors(embeddingSize, contextSize)
|
|
30
|
+
SaveVector(this.configs.save.filename, this.vectors)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
} else {
|
|
34
|
+
this.vectors = GenerateVectors(embeddingSize, contextSize)
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
this.gpu = new OperationManager(device)
|
|
38
|
+
this.forwardShader = this.gpu.getShaderPipline("./src/shaders/PF.wgsl")
|
|
39
|
+
this.backwardShader = this.gpu.getShaderPipline("./src/shaders/PB.wgsl")
|
|
40
|
+
}
|
|
41
|
+
async forward(input) {
|
|
42
|
+
const encoder = this.gpu.CreateEncoder()
|
|
43
|
+
if (!this.params) this.params = await this.gpu.createUniFormBuffer(4 * 4)
|
|
44
|
+
if (!this.vecBuffer) {
|
|
45
|
+
this.vecBuffer = await this.gpu.createBuffer(Float32Array.BYTES_PER_ELEMENT * this.contextSize * this.embeddingSize);
|
|
46
|
+
await this.gpu.WriteBuffer(this.vecBuffer, this.vectors)
|
|
47
|
+
}
|
|
48
|
+
const output = await this.gpu.createBuffer(input.size);
|
|
49
|
+
const size = Math.ceil((input.size / 4) / 64);
|
|
50
|
+
const bindGroup = await this.gpu.createBindGroup(this.forwardShader, 0, [this.vecBuffer, input, output])
|
|
51
|
+
if (this.prevVec) this.prevVec.destroy();
|
|
52
|
+
this.prevVec = input;
|
|
53
|
+
await this.gpu.RunPipline(encoder, this.forwardShader, bindGroup, size);
|
|
54
|
+
await this.gpu.submitQueue(encoder);
|
|
55
|
+
return output
|
|
56
|
+
}
|
|
57
|
+
async backward(outputGradient, lr){
|
|
58
|
+
const encoder = await this.gpu.CreateEncoder()
|
|
59
|
+
await this.gpu.WriteBuffer(this.params, new Float32Array([lr,0]))
|
|
60
|
+
const bindGroup = await this.gpu.createBindGroup(this.backwardShader, 0, [this.vecBuffer, outputGradient, this.params])
|
|
61
|
+
if(this.prevGradient) await this.prevGradient.destroy()
|
|
62
|
+
this.prevGradient = outputGradient;
|
|
63
|
+
await this.gpu.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((outputGradient.size / 4) / 64))
|
|
64
|
+
await this.gpu.submitQueue(encoder);
|
|
65
|
+
}
|
|
66
|
+
async Save() {
|
|
67
|
+
const vec = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.contextSize * this.embeddingSize, this.vecBuffer)
|
|
68
|
+
SaveVector(this.configs.save.filename, vec)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OperationManager } from '../OperationManager.js'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
|
|
4
|
+
export class RMSNorm {
|
|
5
|
+
embeddingSize;
|
|
6
|
+
reductionShader;
|
|
7
|
+
forwardShader;
|
|
8
|
+
backwardShader;
|
|
9
|
+
op;
|
|
10
|
+
constructor(device, embeddingSize) {
|
|
11
|
+
this.op = new OperationManager(device);
|
|
12
|
+
this.embeddingSize = embeddingSize;
|
|
13
|
+
this.reductionShader = this.op.getShaderPipline("./src/shaders/Norm/sumSquare.wgsl")
|
|
14
|
+
this.forwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsForward.wgsl")
|
|
15
|
+
this.backwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsBackward.wgsl")
|
|
16
|
+
}
|
|
17
|
+
async forward(input) {
|
|
18
|
+
const outputReduce = await this.op.createBuffer(4 * 1);
|
|
19
|
+
const output = await this.op.createBuffer(input.size);
|
|
20
|
+
const bindGroup = await this.op.createBindGroup(this.reductionShader, 0, [input, outputReduce])
|
|
21
|
+
const encoder = await this.op.CreateEncoder()
|
|
22
|
+
await this.op.RunPipline(encoder, this.reductionShader, bindGroup, Math.ceil((input.size / 4) / 64))
|
|
23
|
+
const bindGroup1 = await this.op.createBindGroup(this.forwardShader, 0, [outputReduce, input, output])
|
|
24
|
+
await this.op.RunPipline(encoder, this.forwardShader, bindGroup1, Math.ceil((input.size / 4) / 64));
|
|
25
|
+
await this.op.submitQueue(encoder);
|
|
26
|
+
if (this.rms) this.rms.destroy()
|
|
27
|
+
this.rms = outputReduce
|
|
28
|
+
if (this.input) this.input.destroy()
|
|
29
|
+
this.input = input;
|
|
30
|
+
if (this.outputPre) this.outputPre.destroy()
|
|
31
|
+
this.outputPre = output
|
|
32
|
+
return output
|
|
33
|
+
}
|
|
34
|
+
async backward(outputGradient) {
|
|
35
|
+
const output = await this.op.createBuffer(outputGradient.size);
|
|
36
|
+
const bindGroup = await this.op.createBindGroup(this.backwardShader, 0, [this.input, outputGradient, this.rms, output]);
|
|
37
|
+
const encoder = await this.op.CreateEncoder()
|
|
38
|
+
await this.op.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((this.input.size / 4) / 64))
|
|
39
|
+
await this.op.submitQueue(encoder)
|
|
40
|
+
if (this.prevOut) this.prevOut.destroy()
|
|
41
|
+
this.prevOut = outputGradient
|
|
42
|
+
return output
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
package/src/Softmax/index.js
CHANGED
package/src/Tokenizer/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export class Tokenizer {
|
|
|
9
9
|
IdtoWord = {};
|
|
10
10
|
WordtoID = {};
|
|
11
11
|
EOSToken = 2
|
|
12
|
-
constructor(filename="") {
|
|
12
|
+
constructor(filename = "") {
|
|
13
13
|
if (fs.existsSync(filename)) {
|
|
14
14
|
console.log("Warning: Tokenizer is loaded with a Custom Vocab File!")
|
|
15
15
|
console.log("")
|
|
@@ -22,7 +22,7 @@ export class Tokenizer {
|
|
|
22
22
|
this.WordtoID = Object.fromEntries(this.vocabs.map((e, idx) => [e, idx]))
|
|
23
23
|
}
|
|
24
24
|
encoder(text = "") {
|
|
25
|
-
const AddSpaces = text.toLocaleLowerCase().replaceAll(/([,.;'{}!`~\|":><?])/g, " $1 ").replaceAll("<"
|
|
25
|
+
const AddSpaces = text.toLocaleLowerCase().replaceAll(/([,.;'{}!`~\|":><?])/g, " $1 ").replaceAll("<", " < ")
|
|
26
26
|
const splitedWords = AddSpaces.split(/\s+/).filter(e => e.length > 0)
|
|
27
27
|
const output = []
|
|
28
28
|
for (let a = 0; a < splitedWords.length; a++) {
|
|
@@ -145,8 +145,8 @@ export class Tokenizer {
|
|
|
145
145
|
]
|
|
146
146
|
const uniArr = [...new Set([...arrText, ...specal, ...prevVocab])];
|
|
147
147
|
const output = []
|
|
148
|
-
for(let a = 0
|
|
149
|
-
let text = uniArr[a].match(reg).filter((e)=> e.length > 0);
|
|
148
|
+
for (let a = 0; a < uniArr.length; a++) {
|
|
149
|
+
let text = uniArr[a].match(reg).filter((e) => e.length > 0);
|
|
150
150
|
output.push(...text)
|
|
151
151
|
}
|
|
152
152
|
let finalOutput = [...new Set([...output])]
|
|
@@ -155,6 +155,10 @@ export class Tokenizer {
|
|
|
155
155
|
console.log(`New VocabSize : ${finalOutput.length - prevVocab.length}`);
|
|
156
156
|
console.log("_________________________________")
|
|
157
157
|
console.log("Operation Completed!")
|
|
158
|
-
|
|
158
|
+
this.vocabs = finalOutput;
|
|
159
|
+
this.vocabSize = finalOutput.length;
|
|
160
|
+
this.IdtoWord = Object.fromEntries(this.vocabs.map((e, idx) => [idx, e]))
|
|
161
|
+
this.WordtoID = Object.fromEntries(this.vocabs.map((e, idx) => [e, idx]))
|
|
162
|
+
|
|
159
163
|
}
|
|
160
164
|
}
|
|
@@ -1,31 +1,74 @@
|
|
|
1
|
-
import {SelfAttention} from '../SelfAttention/index.js'
|
|
2
|
-
import {FFN} from '../FFN/index.js'
|
|
3
|
-
import {existsSync, mkdirSync} from 'fs'
|
|
4
1
|
|
|
5
|
-
|
|
2
|
+
import { SelfAttention } from '../SelfAttention/index.js';
|
|
3
|
+
import { FFN } from '../FFN/index.js';
|
|
4
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
5
|
+
import { RMSNorm } from '../../index.js';
|
|
6
|
+
import { OperationManager } from '../OperationManager.js';
|
|
7
|
+
|
|
8
|
+
export class TransformerBlock {
|
|
6
9
|
attention;
|
|
7
10
|
ffn;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
gpu;
|
|
12
|
+
size;
|
|
13
|
+
rmsnorm;
|
|
14
|
+
rmsnorm2;
|
|
15
|
+
|
|
16
|
+
constructor(device, embeddingSize, configs) {
|
|
17
|
+
this.size = embeddingSize;
|
|
18
|
+
|
|
19
|
+
this.rmsnorm = new RMSNorm(device, embeddingSize);
|
|
20
|
+
this.rmsnorm2 = new RMSNorm(device, embeddingSize);
|
|
21
|
+
|
|
22
|
+
if (!existsSync(configs.dirname)) {
|
|
23
|
+
mkdirSync(configs.dirname, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.attention = new SelfAttention(
|
|
27
|
+
device, embeddingSize, configs
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
this.ffn = new FFN(device, embeddingSize, configs);
|
|
31
|
+
this.gpu = new OperationManager(device);
|
|
12
32
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
33
|
+
|
|
34
|
+
async forward(input) {
|
|
35
|
+
const count = input.size / 4;
|
|
36
|
+
const norm1 = await this.rmsnorm.forward(input);
|
|
37
|
+
const att = await this.attention.forward(norm1);
|
|
38
|
+
const h = await this.gpu.add(input, att, count);
|
|
39
|
+
const norm2 = await this.rmsnorm2.forward(h);
|
|
40
|
+
const f = await this.ffn.forward(norm2);
|
|
41
|
+
const y = await this.gpu.add(h, f, count);
|
|
42
|
+
norm1.destroy();
|
|
43
|
+
att.destroy();
|
|
44
|
+
f.destroy();
|
|
45
|
+
return y;
|
|
17
46
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
47
|
+
|
|
48
|
+
async backward(outGradient, lr) {
|
|
49
|
+
const count = outGradient.size / 4;
|
|
50
|
+
const dNorm2 = await this.ffn.backward(outGradient, lr);
|
|
51
|
+
const dHFromFFN = await this.rmsnorm2.backward(dNorm2);
|
|
52
|
+
const dH = await this.gpu.add(outGradient, dHFromFFN, count);
|
|
53
|
+
const dNorm1 = await this.attention.backward(dH, lr);
|
|
54
|
+
const dInputFromAttention = await this.rmsnorm.backward(dNorm1);
|
|
55
|
+
const dInput = await this.gpu.add(dH, dInputFromAttention, count);
|
|
56
|
+
dNorm2.destroy();
|
|
57
|
+
dHFromFFN.destroy();
|
|
58
|
+
dH.destroy();
|
|
59
|
+
dNorm1.destroy();
|
|
60
|
+
dInputFromAttention.destroy();
|
|
61
|
+
dInputFromAttention.destroy();
|
|
62
|
+
return dInput;
|
|
22
63
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await this.
|
|
64
|
+
|
|
65
|
+
async ClearInputCache() {
|
|
66
|
+
await this.ffn.ClearInputCache();
|
|
67
|
+
await this.attention.ClearInputCache();
|
|
26
68
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
await this.
|
|
69
|
+
|
|
70
|
+
async Save() {
|
|
71
|
+
await this.ffn.Save();
|
|
72
|
+
await this.attention.Save();
|
|
30
73
|
}
|
|
31
74
|
}
|
package/src/gpu.js
ADDED
|
File without changes
|
package/src/shaders/LB.wgsl
CHANGED
|
@@ -42,16 +42,16 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
42
42
|
let inputValue = input[token * u32(params.inputSize) + inputIndex];
|
|
43
43
|
let gradient = outGradient[token * u32(params.vocabSize) + outputIndex];
|
|
44
44
|
let dW = inputValue * gradient;
|
|
45
|
-
dWeights +=
|
|
45
|
+
dWeights += dW;
|
|
46
46
|
}
|
|
47
|
-
let vClap = weight[index] - params.lr *
|
|
47
|
+
let vClap = weight[index] - params.lr * dWeights;
|
|
48
48
|
weight[index] = vClap;
|
|
49
49
|
if (inputIndex == 0u) {
|
|
50
50
|
var dBias = 0.0;
|
|
51
51
|
for (var token = 0u; token < u32(params.tokenCount); token++) {
|
|
52
|
-
dBias +=
|
|
52
|
+
dBias += outGradient[token * u32(params.vocabSize) + outputIndex];
|
|
53
53
|
}
|
|
54
|
-
bias[outputIndex] = bias[outputIndex] - params.lr *
|
|
54
|
+
bias[outputIndex] = bias[outputIndex] - params.lr * dBias;
|
|
55
55
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
@group(0) @binding(0)
|
|
3
|
+
var<storage, read> input: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
var<storage, read> gradOutput: array<f32>;
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(2)
|
|
9
|
+
var<storage, read> rms: array<f32>;
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(3)
|
|
12
|
+
var<storage, read_write> gradInput: array<f32>;
|
|
13
|
+
|
|
14
|
+
var<workgroup> partial: array<f32, 64>;
|
|
15
|
+
|
|
16
|
+
@compute @workgroup_size(64)
|
|
17
|
+
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
18
|
+
let D = arrayLength(&input);
|
|
19
|
+
partial[lid] = gradOutput[lid] * input[lid];
|
|
20
|
+
workgroupBarrier();
|
|
21
|
+
var stride = 32u;
|
|
22
|
+
loop {
|
|
23
|
+
if (stride == 0u) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
if (lid < stride) {
|
|
27
|
+
partial[lid] += partial[lid + stride];
|
|
28
|
+
}
|
|
29
|
+
workgroupBarrier();
|
|
30
|
+
stride = stride / 2u;
|
|
31
|
+
}
|
|
32
|
+
let dot = partial[0];
|
|
33
|
+
let r = rms[0];
|
|
34
|
+
gradInput[lid] = gradOutput[lid] / r - input[lid] * dot / (f32(D) * r * r * r);
|
|
35
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
|
|
3
|
+
var <storage, read> reduce: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
|
|
7
|
+
var <storage, read> vector: array<f32>;
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(2)
|
|
10
|
+
|
|
11
|
+
var <storage, read_write> output : array<f32>;
|
|
12
|
+
|
|
13
|
+
@compute @workgroup_size(64)
|
|
14
|
+
|
|
15
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
16
|
+
let x = id.x;
|
|
17
|
+
let rms = sqrt(reduce[0u] / f32(arrayLength(&vector)) + 1e-6);
|
|
18
|
+
output[x] = vector[x] / rms;
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
@group(0) @binding(0)
|
|
3
|
+
var<storage, read> input: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
var<storage, read_write> out: array<f32>;
|
|
7
|
+
|
|
8
|
+
var<workgroup> partial: array<f32, 64>;
|
|
9
|
+
|
|
10
|
+
@compute @workgroup_size(64)
|
|
11
|
+
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
12
|
+
var sum = 0.0;
|
|
13
|
+
var i = lid;
|
|
14
|
+
while (i < arrayLength(&input)) {
|
|
15
|
+
sum += input[i] * input[i];
|
|
16
|
+
i += 64u;
|
|
17
|
+
}
|
|
18
|
+
partial[lid] = sum;
|
|
19
|
+
workgroupBarrier();
|
|
20
|
+
var stride = 32u;
|
|
21
|
+
|
|
22
|
+
loop {
|
|
23
|
+
if (stride == 0u) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (lid < stride) {
|
|
28
|
+
partial[lid] += partial[lid + stride];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
workgroupBarrier();
|
|
32
|
+
stride = stride / 2u;
|
|
33
|
+
}
|
|
34
|
+
if (lid == 0u) {
|
|
35
|
+
out[0] = partial[0];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
struct Params{
|
|
2
|
+
lr : f32
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(0)
|
|
6
|
+
var <storage, read_write> posVec: array<f32>;
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(1)
|
|
9
|
+
|
|
10
|
+
var <storage, read> outputGradient : array<f32>;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(2)
|
|
14
|
+
|
|
15
|
+
var <uniform> params: Params;
|
|
16
|
+
|
|
17
|
+
@compute @workgroup_size(64)
|
|
18
|
+
|
|
19
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
20
|
+
let x = id.x;
|
|
21
|
+
if(x >= arrayLength(&outputGradient)){
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
posVec[x] -= params.lr * outputGradient[x];
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
var <storage, read> posVec: array<f32>;
|
|
3
|
+
|
|
4
|
+
@group(0) @binding(1)
|
|
5
|
+
|
|
6
|
+
var <storage, read> vecs : array<f32>;
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(2)
|
|
9
|
+
|
|
10
|
+
var <storage, read_write> output: array<f32>;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@compute @workgroup_size(64)
|
|
14
|
+
|
|
15
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
16
|
+
let x = id.x;
|
|
17
|
+
if(x >= arrayLength(&vecs)){
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
output[x] = vecs[x] + posVec[x];
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
struct Params{
|
|
2
|
+
size: u32
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(0)
|
|
6
|
+
|
|
7
|
+
var <storage, read> a : array<f32>;
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(1)
|
|
10
|
+
|
|
11
|
+
var <storage, read> b : array<f32>;
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(2)
|
|
14
|
+
|
|
15
|
+
var <storage, read_write> output : array<f32>;
|
|
16
|
+
@group(0) @binding(3)
|
|
17
|
+
|
|
18
|
+
var <uniform> params : Params;
|
|
19
|
+
|
|
20
|
+
@compute @workgroup_size(64)
|
|
21
|
+
|
|
22
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
23
|
+
let index = id.x;
|
|
24
|
+
if(index >= params.size){
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let mainOut = a[index] + b[index];
|
|
28
|
+
output[index] = mainOut;
|
|
29
|
+
}
|
|
30
|
+
|