@imaduddin/fastbrain 1.0.2 → 1.0.4
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 +3 -1
- package/package.json +1 -1
- package/src/Embedding/index.js +6 -6
- package/src/FFN/index.js +4 -4
- package/src/Linear/index.js +4 -5
- package/src/PositionEmbedding/index.js +6 -6
- package/src/RMSNorm/index.js +11 -15
- package/src/Relu/index.js +6 -6
- package/src/SelfAttention/index.js +12 -12
- package/src/Softmax/index.js +19 -9
- package/src/TransformerBlock/index.js +7 -7
- package/src/model/index.d.ts +43 -0
- package/src/model/index.js +87 -0
- package/src/residualConnection/index.js +3 -4
- package/src/shaders/ComputeDInput.wgsl +25 -11
- package/src/shaders/LB.wgsl +20 -24
- package/src/shaders/Norm/updateGamma.wgsl +5 -3
- package/src/shaders/SB.wgsl +7 -2
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {SelfAttention as ST} from './src/SelfAttention/index.js'
|
|
|
8
8
|
import {TransformerBlock as TT} from './src/TransformerBlock/index.js'
|
|
9
9
|
import {PositionEmbedding as PM } from './src/PositionEmbedding/index.js'
|
|
10
10
|
import { RMSNorm as RM } from "./src/RMSNorm/index.js";
|
|
11
|
+
import {model as M} from './src/model/index.js'
|
|
11
12
|
export const Embedding = E
|
|
12
13
|
export const Linear = L
|
|
13
14
|
export const Softmax = S;
|
|
@@ -17,4 +18,5 @@ export const Tokenizer = to;
|
|
|
17
18
|
export const SelfAttention = ST
|
|
18
19
|
export const TransformerBlock = TT;
|
|
19
20
|
export const PositionEmbedding = PM;
|
|
20
|
-
export const RMSNorm = RM
|
|
21
|
+
export const RMSNorm = RM
|
|
22
|
+
export const model = M
|
package/package.json
CHANGED
package/src/Embedding/index.js
CHANGED
|
@@ -45,8 +45,8 @@ export class Embedding {
|
|
|
45
45
|
})
|
|
46
46
|
SaveVector(this.configs.save.filename, this.vectors)
|
|
47
47
|
}
|
|
48
|
-
async forward(input,
|
|
49
|
-
const encoder =
|
|
48
|
+
async forward(input, encoder2) {
|
|
49
|
+
const encoder = encoder2 ? encoder2 : this.device.createCommandEncoder()
|
|
50
50
|
if (!this.vectorsBuffer) {
|
|
51
51
|
this.vectorsBuffer = await this.gpu.createBuffer(Float32Array.BYTES_PER_ELEMENT * this.vocabSize * this.embeddingSize);
|
|
52
52
|
await this.gpu.WriteBuffer(this.vectorsBuffer, this.vectors)
|
|
@@ -86,7 +86,7 @@ export class Embedding {
|
|
|
86
86
|
]
|
|
87
87
|
})
|
|
88
88
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((this.embeddingSize * input.length) / 256))
|
|
89
|
-
if(!
|
|
89
|
+
if(!encoder2) await this.device.queue.submit([encoder.finish()])
|
|
90
90
|
return this.outputBuffer
|
|
91
91
|
|
|
92
92
|
}
|
|
@@ -94,8 +94,8 @@ export class Embedding {
|
|
|
94
94
|
const vec = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.vocabSize * this.embeddingSize, this.vectorsBuffer)
|
|
95
95
|
SaveVector(this.configs.save.filename, vec)
|
|
96
96
|
}
|
|
97
|
-
async backward(inputGradient, lr,
|
|
98
|
-
const encoder =
|
|
97
|
+
async backward(inputGradient, lr, en2) {
|
|
98
|
+
const encoder = en2 ? en2 : this.device.createCommandEncoder()
|
|
99
99
|
if (!this.oldParam) {
|
|
100
100
|
this.oldParam = new Float32Array([0, 0]);
|
|
101
101
|
this.param = await this.gpu.createUniFormBuffer(this.oldParam.byteLength);
|
|
@@ -134,7 +134,7 @@ export class Embedding {
|
|
|
134
134
|
]
|
|
135
135
|
})
|
|
136
136
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.embeddingSize * (this.tokenBuffer.size / 4)) / 256))
|
|
137
|
-
if(!
|
|
137
|
+
if(!en2) this.device.queue.submit([encoder.finish()])
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
}
|
package/src/FFN/index.js
CHANGED
|
@@ -28,10 +28,10 @@ export class FFN {
|
|
|
28
28
|
const final = await this.linear2.forward(hidden, encoderMain)
|
|
29
29
|
return final
|
|
30
30
|
}
|
|
31
|
-
async backward(inputGradient, lr,
|
|
32
|
-
const logit2 = await this.linear2.backward(inputGradient, lr,
|
|
33
|
-
const hidden = await this.hiddenLayer.backward(logit2,
|
|
34
|
-
const final = await this.linear1.backward(hidden, lr,
|
|
31
|
+
async backward(inputGradient, lr, encoder) {
|
|
32
|
+
const logit2 = await this.linear2.backward(inputGradient, lr, encoder)
|
|
33
|
+
const hidden = await this.hiddenLayer.backward(logit2,encoder)
|
|
34
|
+
const final = await this.linear1.backward(hidden, lr, encoder)
|
|
35
35
|
return final
|
|
36
36
|
}
|
|
37
37
|
async Save() {
|
package/src/Linear/index.js
CHANGED
|
@@ -110,7 +110,7 @@ export class Linear {
|
|
|
110
110
|
})
|
|
111
111
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil(this.vocabSize / 16), Math.ceil(tokenCount / 4))
|
|
112
112
|
|
|
113
|
-
if
|
|
113
|
+
if(!encoderMain) this.device.queue.submit([encoder.finish()])
|
|
114
114
|
this.input = vec;
|
|
115
115
|
return this.outputBuffer
|
|
116
116
|
}
|
|
@@ -179,10 +179,9 @@ export class Linear {
|
|
|
179
179
|
}
|
|
180
180
|
]
|
|
181
181
|
})
|
|
182
|
-
|
|
183
|
-
await this.gpu.RunPipline(encoder, this.
|
|
184
|
-
await this.
|
|
185
|
-
if (!encoderMain) await this.device.queue.submit([encoder.finish()])
|
|
182
|
+
await this.gpu.RunPipline(encoder, this.dInputBackward, bind2, Math.ceil((this.embeddingSize * tokenCount) / 64));
|
|
183
|
+
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, this.vocabSize);
|
|
184
|
+
if(!encoderMain) await this.device.queue.submit([encoder.finish()])
|
|
186
185
|
return this.gradientBuffer
|
|
187
186
|
|
|
188
187
|
}
|
|
@@ -38,8 +38,8 @@ export class PositionEmbedding {
|
|
|
38
38
|
this.forwardShader = this.gpu.getShaderPipline("./src/shaders/PF.wgsl")
|
|
39
39
|
this.backwardShader = this.gpu.getShaderPipline("./src/shaders/PB.wgsl")
|
|
40
40
|
}
|
|
41
|
-
async forward(input,
|
|
42
|
-
const encoder =
|
|
41
|
+
async forward(input, en2) {
|
|
42
|
+
const encoder = en2 ? en2 : this.gpu.CreateEncoder()
|
|
43
43
|
if (!this.params) this.params = await this.gpu.createUniFormBuffer(4 * 4)
|
|
44
44
|
if (!this.vecBuffer) {
|
|
45
45
|
this.vecBuffer = await this.gpu.createBuffer(Float32Array.BYTES_PER_ELEMENT * this.contextSize * this.embeddingSize);
|
|
@@ -48,15 +48,15 @@ export class PositionEmbedding {
|
|
|
48
48
|
const size = Math.ceil((input.size / 4) / 64);
|
|
49
49
|
const bindGroup = await this.gpu.createBindGroup(this.forwardShader, 0, [this.vecBuffer, input.mainBuffer])
|
|
50
50
|
await this.gpu.RunPipline(encoder, this.forwardShader, bindGroup, size);
|
|
51
|
-
if(!
|
|
51
|
+
if(!en2) await this.gpu.submitQueue(encoder);
|
|
52
52
|
return input
|
|
53
53
|
}
|
|
54
|
-
async backward(outputGradient, lr,
|
|
55
|
-
const encoder =
|
|
54
|
+
async backward(outputGradient, lr, en2){
|
|
55
|
+
const encoder = en2 ? en2 : await this.gpu.CreateEncoder()
|
|
56
56
|
await this.gpu.WriteBuffer(this.params, new Float32Array([lr,0]))
|
|
57
57
|
const bindGroup = await this.gpu.createBindGroup(this.backwardShader, 0, [this.vecBuffer, outputGradient.mainBuffer, this.params])
|
|
58
58
|
await this.gpu.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((outputGradient.size / 4) / 64))
|
|
59
|
-
if(!
|
|
59
|
+
if(!en2) await this.gpu.submitQueue(encoder);
|
|
60
60
|
}
|
|
61
61
|
async Save() {
|
|
62
62
|
const vec = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.contextSize * this.embeddingSize, this.vecBuffer)
|
package/src/RMSNorm/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export class RMSNorm {
|
|
|
45
45
|
this.gamma = new Float32Array(embeddingSize).fill(1)
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
async forward(vec,
|
|
48
|
+
async forward(vec, en) {
|
|
49
49
|
if (!this.gammabuffer) {
|
|
50
50
|
this.gammabuffer = await this.op.createBuffer(this.embeddingSize * 4);
|
|
51
51
|
await this.op.WriteBuffer(this.gammabuffer, this.gamma);
|
|
@@ -57,34 +57,30 @@ export class RMSNorm {
|
|
|
57
57
|
this.rmsReduction.destroy()
|
|
58
58
|
this.rmsReduction = await this.op.createBuffer(4 * context)
|
|
59
59
|
}
|
|
60
|
-
if (this.output
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
const encoder = encoderMain ? encoderMain : await this.op.CreateEncoder()
|
|
60
|
+
if (this.output) this.output.destroy();
|
|
61
|
+
this.output = await this.op.ManageBuffer(vec.size)
|
|
62
|
+
const encoder = en ? en : await this.op.CreateEncoder()
|
|
65
63
|
const bind1 = await this.op.createBindGroup(this.reductionShader, 0, [vec.mainBuffer, this.rmsReduction])
|
|
66
64
|
const bind2 = await this.op.createBindGroup(this.forwardShader, 0, [this.rmsReduction, vec.mainBuffer, this.output.mainBuffer, this.gammabuffer])
|
|
67
65
|
await this.op.RunPipline(encoder, this.reductionShader, bind1, context)
|
|
68
66
|
await this.op.RunPipline(encoder, this.forwardShader, bind2, Math.ceil((this.embeddingSize * context) / 64))
|
|
69
|
-
if
|
|
67
|
+
if(!en) await this.op.submitQueue(encoder);
|
|
70
68
|
this.input = vec;
|
|
71
69
|
return this.output
|
|
72
70
|
|
|
73
71
|
}
|
|
74
|
-
async backward(outGradient, lr,
|
|
72
|
+
async backward(outGradient, lr, en) {
|
|
75
73
|
const contextSize = outGradient.size / (this.embeddingSize * 4);
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
if (!this.params) this.params = await this.op.createBuffer(4 * 2);
|
|
74
|
+
if (this.gradientOutput) this.gradientOutput.destroy()
|
|
75
|
+
this.gradientOutput = await this.op.ManageBuffer(this.embeddingSize * 4 * contextSize)
|
|
76
|
+
if (!this.params) this.params = await this.op.createUniFormBuffer(4 * 2);
|
|
81
77
|
await this.op.WriteBuffer(this.params, new Float32Array([lr, 0]))
|
|
82
|
-
const encoder =
|
|
78
|
+
const encoder = en ? en : this.op.CreateEncoder()
|
|
83
79
|
const bind1 = await this.op.createBindGroup(this.backwardShader, 0, [this.input.mainBuffer, outGradient.mainBuffer, this.rmsReduction, this.gammabuffer, this.gradientOutput.mainBuffer])
|
|
84
80
|
await this.op.RunPipline(encoder, this.backwardShader, bind1, contextSize);
|
|
85
81
|
const bind2 = await this.op.createBindGroup(this.updateGamma, 0, [this.input.mainBuffer, outGradient.mainBuffer, this.rmsReduction, this.gammabuffer, this.params])
|
|
86
82
|
await this.op.RunPipline(encoder, this.updateGamma, bind2, this.embeddingSize);
|
|
87
|
-
if
|
|
83
|
+
if(!en) this.op.submitQueue(encoder);
|
|
88
84
|
return this.gradientOutput
|
|
89
85
|
}
|
|
90
86
|
async Save() {
|
package/src/Relu/index.js
CHANGED
|
@@ -15,8 +15,8 @@ export class Relu {
|
|
|
15
15
|
this.forwardPipline = this.gpu.getShaderPipline("./src/shaders/RF.wgsl")
|
|
16
16
|
this.backwardPipline = this.gpu.getShaderPipline("./src/shaders/RB.wgsl")
|
|
17
17
|
}
|
|
18
|
-
async forward(input,
|
|
19
|
-
const encoder =
|
|
18
|
+
async forward(input, en) {
|
|
19
|
+
const encoder = en ? en : this.device.createCommandEncoder()
|
|
20
20
|
const tokenCount = input.mainBuffer.size / (this.embeddingSize * 4)
|
|
21
21
|
if (!this.oldParam) {
|
|
22
22
|
this.oldParam = new Uint32Array([0, 0, 0]);
|
|
@@ -54,12 +54,12 @@ export class Relu {
|
|
|
54
54
|
]
|
|
55
55
|
})
|
|
56
56
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
57
|
-
if(!
|
|
57
|
+
if(!en) this.device.queue.submit([encoder.finish()])
|
|
58
58
|
this.input = input
|
|
59
59
|
return this.output
|
|
60
60
|
}
|
|
61
|
-
async backward(inputGradient,
|
|
62
|
-
const encoder =
|
|
61
|
+
async backward(inputGradient,en) {
|
|
62
|
+
const encoder = en ? en : this.device.createCommandEncoder()
|
|
63
63
|
const tokenCount = inputGradient.size / (this.embeddingSize * 4)
|
|
64
64
|
if (!this.oldParam) {
|
|
65
65
|
this.oldParam = new Uint32Array([0, 0, 0]);
|
|
@@ -102,7 +102,7 @@ export class Relu {
|
|
|
102
102
|
]
|
|
103
103
|
})
|
|
104
104
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
105
|
-
if(!
|
|
105
|
+
if(!en) await this.device.queue.submit([encoder.finish()])
|
|
106
106
|
return this.gradOut
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -38,12 +38,12 @@ export class SelfAttention {
|
|
|
38
38
|
this.dKShader = this.gpu.getShaderPipline("./src/shaders/attentionShader/ComputeK.wgsl")
|
|
39
39
|
this.sumShader = this.gpu.getShaderPipline("./src/shaders/attentionShader/sumGradient.wgsl")
|
|
40
40
|
}
|
|
41
|
-
async forward(vec,
|
|
41
|
+
async forward(vec, encoder2) {
|
|
42
42
|
this.input = vec.mainBuffer;
|
|
43
43
|
const tokenCount = vec.mainBuffer.size / (this.embeddingSize * 4)
|
|
44
44
|
if (!this.asParams) this.asParams = await this.gpu.createUniFormBuffer(4 * 3);
|
|
45
45
|
if (!this.softmaxParams) this.softmaxParams = await this.gpu.createUniFormBuffer(4 * 3);
|
|
46
|
-
const encoder =
|
|
46
|
+
const encoder = encoder2 ? encoder2 : await this.gpu.CreateEncoder()
|
|
47
47
|
if (!this.scroes) {
|
|
48
48
|
this.scroes = await this.gpu.createBuffer(tokenCount * tokenCount * 4)
|
|
49
49
|
}
|
|
@@ -53,9 +53,9 @@ export class SelfAttention {
|
|
|
53
53
|
}
|
|
54
54
|
await this.gpu.WriteBuffer(this.asParams, new Uint32Array([tokenCount, this.embeddingSize, 0]))
|
|
55
55
|
await this.gpu.WriteBuffer(this.softmaxParams, new Uint32Array([tokenCount, tokenCount, 0]))
|
|
56
|
-
this.query = await this.q.forward(vec,
|
|
57
|
-
this.key = await this.k.forward(vec,
|
|
58
|
-
this.value = await this.v.forward(vec,
|
|
56
|
+
this.query = await this.q.forward(vec, encoder)
|
|
57
|
+
this.key = await this.k.forward(vec, encoder)
|
|
58
|
+
this.value = await this.v.forward(vec, encoder)
|
|
59
59
|
const bindAttention = await this.gpu.createBindGroup(this.attentionscoresShader, 0, [this.query.mainBuffer, this.key.mainBuffer, this.scroes, this.asParams])
|
|
60
60
|
await this.gpu.RunPipline(encoder, this.attentionscoresShader, bindAttention, Math.ceil(tokenCount / 16), Math.ceil(tokenCount / 16))
|
|
61
61
|
if (this.weights) this.weights.destroy()
|
|
@@ -71,12 +71,12 @@ export class SelfAttention {
|
|
|
71
71
|
await this.finalOutput.count()
|
|
72
72
|
const outputBind = await this.gpu.createBindGroup(this.outputForward, 0, [this.weights, this.value.mainBuffer, this.finalOutput.mainBuffer, this.asParams]);
|
|
73
73
|
await this.gpu.RunPipline(encoder, this.outputForward, outputBind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
74
|
-
if(!
|
|
74
|
+
if(!encoder2) await this.gpu.submitQueue(encoder)
|
|
75
75
|
return this.finalOutput
|
|
76
76
|
}
|
|
77
|
-
async backward(dO, lr,
|
|
77
|
+
async backward(dO, lr,encoder2) {
|
|
78
78
|
const tokenCount = dO.size / (this.embeddingSize * 4);
|
|
79
|
-
const encoder =
|
|
79
|
+
const encoder = encoder2 ? encoder2 : await this.gpu.CreateEncoder();
|
|
80
80
|
if (!this.dV) this.dV = await this.gpu.createBuffer(dO.size);
|
|
81
81
|
if (!this.dA) this.dA = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
82
82
|
if (!this.dS) this.dS = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
@@ -112,9 +112,9 @@ export class SelfAttention {
|
|
|
112
112
|
await this.gpu.RunPipline(encoder, this.dQshader, dQbind, Math.ceil(tokenCount / 16), Math.ceil(this.embeddingSize / 16))
|
|
113
113
|
const dKbind = await this.gpu.createBindGroup(this.dKShader, 0, [this.dS, this.query.mainBuffer, this.dK, this.asParams]);
|
|
114
114
|
await this.gpu.RunPipline(encoder, this.dKShader, dKbind, Math.ceil(tokenCount / 16), Math.ceil(this.embeddingSize / 16))
|
|
115
|
-
const dq = await this.q.backward({ mainBuffer: this.dQ, size: this.dQ.size}, lr,
|
|
116
|
-
const dk = await this.k.backward({ mainBuffer: this.dK, size: this.dK.size}, lr,
|
|
117
|
-
const dv = await this.v.backward({ mainBuffer: this.dV, size: this.dV.size}, lr,
|
|
115
|
+
const dq = await this.q.backward({ mainBuffer: this.dQ, size: this.dQ.size}, lr, encoder)
|
|
116
|
+
const dk = await this.k.backward({ mainBuffer: this.dK, size: this.dK.size}, lr, encoder)
|
|
117
|
+
const dv = await this.v.backward({ mainBuffer: this.dV, size: this.dV.size}, lr, encoder)
|
|
118
118
|
if(!this.gradOut) this.gradOut = await this.gpu.ManageBuffer(tokenCount * this.embeddingSize * 4)
|
|
119
119
|
if(this.gradOut.size !== tokenCount * 4 * this.embeddingSize || this.gradOut.isDestroyed() || this.gradOut.size == 0){
|
|
120
120
|
this.gradOut.destroy()
|
|
@@ -126,7 +126,7 @@ export class SelfAttention {
|
|
|
126
126
|
}
|
|
127
127
|
const outputBind = await this.gpu.createBindGroup(this.sumShader, 0, [dq.mainBuffer, dk.mainBuffer, dv.mainBuffer, this.gradOut.mainBuffer, this.asParams]);
|
|
128
128
|
await this.gpu.RunPipline(encoder, this.sumShader, outputBind, Math.ceil((tokenCount * this.embeddingSize / 256)));
|
|
129
|
-
if(!
|
|
129
|
+
if(!encoder2) await this.gpu.submitQueue(encoder)
|
|
130
130
|
return this.gradOut
|
|
131
131
|
|
|
132
132
|
}
|
package/src/Softmax/index.js
CHANGED
|
@@ -26,8 +26,8 @@ export class Softmax {
|
|
|
26
26
|
this.reduceFn = this.gpu.getShaderPipline("./src/shaders/ReductionFunction.wgsl")
|
|
27
27
|
this.totalCalculate = this.gpu.getShaderPipline('./src/shaders/calculateTotal.wgsl')
|
|
28
28
|
}
|
|
29
|
-
async forward(logits,
|
|
30
|
-
const encoder =
|
|
29
|
+
async forward(logits, en) {
|
|
30
|
+
const encoder = en ? en : this.device.createCommandEncoder()
|
|
31
31
|
const tokenCount = logits.size / (this.vocabSize * 4)
|
|
32
32
|
if (!this.paramsForward) {
|
|
33
33
|
this.paramsForward = await this.gpu.createUniFormBuffer(4 * 3)
|
|
@@ -65,13 +65,12 @@ export class Softmax {
|
|
|
65
65
|
]
|
|
66
66
|
})
|
|
67
67
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, tokenCount)
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
}
|
|
68
|
+
if(!en) await this.device.queue.submit([encoder.finish()])
|
|
69
|
+
|
|
71
70
|
return this.output
|
|
72
71
|
}
|
|
73
|
-
async backward(probs, target,
|
|
74
|
-
const encoder =
|
|
72
|
+
async backward(probs, target,encoder2) {
|
|
73
|
+
const encoder = encoder2 ? encoder2 : this.device.createCommandEncoder()
|
|
75
74
|
const tokenCount = probs.size / (this.vocabSize * 4)
|
|
76
75
|
if (!this.paramsForward) {
|
|
77
76
|
this.paramsForward = await this.gpu.createUniFormBuffer(4 * 3)
|
|
@@ -88,6 +87,11 @@ export class Softmax {
|
|
|
88
87
|
this.targetBuffer.destroy()
|
|
89
88
|
this.targetBuffer = await this.gpu.createBuffer(target.length * Float32Array.BYTES_PER_ELEMENT)
|
|
90
89
|
}
|
|
90
|
+
if (!this.dLogits) this.dLogits = await this.gpu.ManageBuffer(probs.size);
|
|
91
|
+
if (this.dLogits.size !== probs.size) {
|
|
92
|
+
this.dLogits.destroy()
|
|
93
|
+
this.dLogits = await this.gpu.ManageBuffer(probs.size);
|
|
94
|
+
}
|
|
91
95
|
await this.gpu.WriteBuffer(this.targetBuffer, new Float32Array(target))
|
|
92
96
|
const bind = await this.device.createBindGroup({
|
|
93
97
|
layout: await this.backwardPipline.getBindGroupLayout(0),
|
|
@@ -107,12 +111,18 @@ export class Softmax {
|
|
|
107
111
|
resource: {
|
|
108
112
|
buffer: this.paramsForward
|
|
109
113
|
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
binding: 4,
|
|
117
|
+
resource: {
|
|
118
|
+
buffer: this.dLogits.mainBuffer
|
|
119
|
+
}
|
|
110
120
|
}
|
|
111
121
|
]
|
|
112
122
|
})
|
|
113
123
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((tokenCount * this.vocabSize) / 256))
|
|
114
|
-
if
|
|
115
|
-
return
|
|
124
|
+
if(!encoder2) await this.gpu.submitQueue(encoder)
|
|
125
|
+
return this.dLogits
|
|
116
126
|
}
|
|
117
127
|
async crossEntropy(probs, target, encoderMain) {
|
|
118
128
|
const encoder = encoderMain ? encoderMain : this.device.createCommandEncoder();
|
|
@@ -54,13 +54,13 @@ export class TransformerBlock {
|
|
|
54
54
|
return residual2;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
async backward(outGradient, lr,
|
|
58
|
-
const dAtt = await this.ffn.backward(outGradient, lr,
|
|
59
|
-
const dNorm2 = await this.rmsnorm2.backward(dAtt, lr)
|
|
60
|
-
const dResidual1 = await this.rback2.add(outGradient, dNorm2,
|
|
61
|
-
const dFF = await this.attention.backward(dResidual1, lr,
|
|
62
|
-
const dNorm = await this.rmsnorm.backward(dFF, lr)
|
|
63
|
-
const dResidual2 = await this.rback1.add(dNorm, dResidual1,
|
|
57
|
+
async backward(outGradient, lr, encoder) {
|
|
58
|
+
const dAtt = await this.ffn.backward(outGradient, lr, encoder);
|
|
59
|
+
const dNorm2 = await this.rmsnorm2.backward(dAtt, lr, encoder)
|
|
60
|
+
const dResidual1 = await this.rback2.add(outGradient, dNorm2, encoder)
|
|
61
|
+
const dFF = await this.attention.backward(dResidual1, lr, encoder)
|
|
62
|
+
const dNorm = await this.rmsnorm.backward(dFF, lr, encoder)
|
|
63
|
+
const dResidual2 = await this.rback1.add(dNorm, dResidual1 ,encoder)
|
|
64
64
|
return dResidual2;
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Embedding } from '../Embedding/index.ts'
|
|
2
|
+
import { Linear } from '../Linear/index.ts'
|
|
3
|
+
import { PositionEmbedding } from '../PositionEmbedding/index.ts'
|
|
4
|
+
import { TransformerBlock } from '../TransformerBlock/index.ts'
|
|
5
|
+
import { Softmax } from '../Softmax/index.ts'
|
|
6
|
+
import { Tokenizer } from '../Tokenizer/index.ts'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class model {
|
|
11
|
+
tokenizer: Tokenizer
|
|
12
|
+
embedding: Embedding
|
|
13
|
+
linear: Linear
|
|
14
|
+
PosEmbedding: PositionEmbedding
|
|
15
|
+
blocks: TransformerBlock[]
|
|
16
|
+
softmax: Softmax
|
|
17
|
+
embeddingSize: number
|
|
18
|
+
loopSize: number
|
|
19
|
+
contextSize: number
|
|
20
|
+
constructor(device: GPUAdapter, configs: {
|
|
21
|
+
embeddingSize: number,
|
|
22
|
+
contextSize: number,
|
|
23
|
+
blockSize: number,
|
|
24
|
+
dirname: string,
|
|
25
|
+
vocabFile: string
|
|
26
|
+
})
|
|
27
|
+
getLoss : Function
|
|
28
|
+
getAcc: Function
|
|
29
|
+
clearLoss : Function
|
|
30
|
+
async forward(input: number[], target: number[]): Promise<{
|
|
31
|
+
read: function(): Promise<Float32Array>,
|
|
32
|
+
mainBuffer: GPUBuffer,
|
|
33
|
+
isDestroyed: function(): Boolean,
|
|
34
|
+
destroy: function(): void
|
|
35
|
+
}>
|
|
36
|
+
async backward(x: {
|
|
37
|
+
read: function(): Promise<Float32Array>,
|
|
38
|
+
mainBuffer: GPUBuffer,
|
|
39
|
+
isDestroyed: function(): Boolean,
|
|
40
|
+
destroy: function(): void
|
|
41
|
+
}, target: number[], lr : number)
|
|
42
|
+
async Save() : Promise<void>
|
|
43
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Embedding } from "../Embedding/index.js"
|
|
2
|
+
import { Linear } from "../Linear/index.js"
|
|
3
|
+
import { PositionEmbedding } from "../PositionEmbedding/index.js"
|
|
4
|
+
import { Softmax } from "../Softmax/index.js"
|
|
5
|
+
import { Tokenizer } from "../Tokenizer/index.js"
|
|
6
|
+
import { join } from 'path'
|
|
7
|
+
import { TransformerBlock } from "../TransformerBlock/index.js"
|
|
8
|
+
import { OperationManager } from '../OperationManager.js'
|
|
9
|
+
export class model {
|
|
10
|
+
tokenizer
|
|
11
|
+
embedding
|
|
12
|
+
linear
|
|
13
|
+
PosEmbedding
|
|
14
|
+
blocks = []
|
|
15
|
+
softmax
|
|
16
|
+
embeddingSize
|
|
17
|
+
contextSize
|
|
18
|
+
op;
|
|
19
|
+
clearLoss;
|
|
20
|
+
getLoss;
|
|
21
|
+
getAcc;
|
|
22
|
+
constructor(device, configs) {
|
|
23
|
+
this.contextSize = configs.contextSize
|
|
24
|
+
this.embeddingSize = configs.embeddingSize;
|
|
25
|
+
this.tokenizer = new Tokenizer(configs.vocabFile)
|
|
26
|
+
this.op = new OperationManager(device)
|
|
27
|
+
this.embedding = new Embedding(device, this.embeddingSize, this.tokenizer.vocabSize, {
|
|
28
|
+
save: {
|
|
29
|
+
filename: join(configs.dirname, "vec.bin")
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
this.softmax = new Softmax(device, this.embeddingSize, this.tokenizer.vocabSize);
|
|
33
|
+
this.PosEmbedding = new PositionEmbedding(device, this.embeddingSize, configs.contextSize, {
|
|
34
|
+
save: {
|
|
35
|
+
filename: join(configs.dirname, "posVec.bin")
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
this.linear = new Linear(device, this.embeddingSize, this.tokenizer.vocabSize, {
|
|
39
|
+
save: {
|
|
40
|
+
filename: [join(configs.dirname, "w.bin"), join(configs.dirname, "b.bin")]
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
for (let a = 0; a < configs.blockSize; a++) {
|
|
44
|
+
this.blocks[a] = new TransformerBlock(device, this.embeddingSize, {
|
|
45
|
+
dirname: join(configs.dirname, `block-${a + 1}`)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async forward(input, target) {
|
|
50
|
+
const encoder = await this.op.CreateEncoder()
|
|
51
|
+
if (input.length > this.contextSize) throw new Error("The input get large then ContextSize")
|
|
52
|
+
let vec = await this.embedding.forward(input, encoder)
|
|
53
|
+
vec = await this.PosEmbedding.forward(vec, encoder)
|
|
54
|
+
for (let i = 0; i < this.blocks.length; i++) {
|
|
55
|
+
vec = await this.blocks[i].forward(vec, encoder)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let logits = await this.linear.forward(vec, encoder)
|
|
59
|
+
let probs = await this.softmax.forward(logits, encoder)
|
|
60
|
+
await this.op.submitQueue(encoder)
|
|
61
|
+
const { acc, clear, loss } = await this.softmax.crossEntropy(probs, target)
|
|
62
|
+
this.getAcc = acc;
|
|
63
|
+
this.getLoss = loss;
|
|
64
|
+
this.clearLoss = clear;
|
|
65
|
+
return probs
|
|
66
|
+
}
|
|
67
|
+
async backward(x, target, lr) {
|
|
68
|
+
const encoder = await this.op.CreateEncoder()
|
|
69
|
+
let dLogits = await this.softmax.backward(x, target, encoder)
|
|
70
|
+
let dInput = await this.linear.backward(dLogits, lr, encoder)
|
|
71
|
+
for (let i = this.blocks.length - 1; i >= 0; i--) {
|
|
72
|
+
dInput = await this.blocks[i].backward(dInput, lr, encoder)
|
|
73
|
+
};
|
|
74
|
+
await this.embedding.backward(dInput, lr)
|
|
75
|
+
await this.PosEmbedding.backward(dInput, lr)
|
|
76
|
+
await this.op.submitQueue(encoder)
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
async Save() {
|
|
80
|
+
await this.PosEmbedding.Save()
|
|
81
|
+
await this.embedding.Save()
|
|
82
|
+
await this.linear.Save()
|
|
83
|
+
for (let i = this.blocks.length - 1; i >= 0; i--) {
|
|
84
|
+
await this.blocks[i].Save()
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -10,11 +10,11 @@ export class residualConnection {
|
|
|
10
10
|
this.gpu = new OperationManager(device)
|
|
11
11
|
this.addShader = this.gpu.getShaderPipline("./src/shaders/add.wgsl")
|
|
12
12
|
}
|
|
13
|
-
async add(a, b,
|
|
13
|
+
async add(a, b, en) {
|
|
14
14
|
if (!this.params) {
|
|
15
15
|
this.params = await this.gpu.createUniFormBuffer(4 * 4)
|
|
16
16
|
}
|
|
17
|
-
const encoder =
|
|
17
|
+
const encoder = en ? en : await this.gpu.CreateEncoder()
|
|
18
18
|
if (!this.output) {
|
|
19
19
|
this.output = await this.gpu.ManageBuffer(a.size);
|
|
20
20
|
}
|
|
@@ -22,11 +22,10 @@ export class residualConnection {
|
|
|
22
22
|
this.output.destroy()
|
|
23
23
|
this.output = await this.gpu.ManageBuffer(a.size);
|
|
24
24
|
}
|
|
25
|
-
await this.output.count()
|
|
26
25
|
const bind = await this.gpu.createBindGroup(this.addShader, 0, [a.mainBuffer, b.mainBuffer, this.output.mainBuffer, this.params]);
|
|
27
26
|
await this.gpu.WriteBuffer(this.params, new Uint32Array([(a.size / 4), 0]))
|
|
28
27
|
await this.gpu.RunPipline(encoder, this.addShader, bind, Math.ceil((a.size / 4) / 64));
|
|
29
|
-
if(!
|
|
28
|
+
if(!en) await this.gpu.submitQueue(encoder)
|
|
30
29
|
return this.output
|
|
31
30
|
}
|
|
32
31
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
struct Params {
|
|
2
3
|
vocabSize: u32,
|
|
3
4
|
tokenCount: u32,
|
|
@@ -6,27 +7,40 @@ struct Params {
|
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
@group(0) @binding(0)
|
|
9
|
-
var<storage,
|
|
10
|
+
var<storage, read> weight: array<f32>;
|
|
11
|
+
|
|
10
12
|
@group(0) @binding(1)
|
|
11
13
|
var<storage, read> outGradient: array<f32>;
|
|
14
|
+
|
|
12
15
|
@group(0) @binding(3)
|
|
13
16
|
var<uniform> params: Params;
|
|
17
|
+
|
|
14
18
|
@group(0) @binding(4)
|
|
15
19
|
var<storage, read_write> dInput: array<f32>;
|
|
20
|
+
|
|
16
21
|
@compute @workgroup_size(256)
|
|
17
22
|
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
18
23
|
let index = id.x;
|
|
19
24
|
let total = params.tokenCount * params.inputSize;
|
|
20
|
-
|
|
25
|
+
|
|
26
|
+
if (index >= total) {
|
|
21
27
|
return;
|
|
22
28
|
}
|
|
23
|
-
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
let inputSize = params.inputSize;
|
|
31
|
+
let vocabSize = params.vocabSize;
|
|
32
|
+
|
|
33
|
+
let token = index / inputSize;
|
|
34
|
+
let inputIndex = index % inputSize;
|
|
35
|
+
|
|
36
|
+
let weightBase = inputIndex;
|
|
37
|
+
let gradBase = token * vocabSize;
|
|
38
|
+
var sum = 0.0;
|
|
39
|
+
|
|
40
|
+
for (var i = 0u; i < vocabSize; i++) {
|
|
41
|
+
let wIndex = i * inputSize + weightBase;
|
|
42
|
+
let gIndex = gradBase + i;
|
|
43
|
+
sum += outGradient[gIndex] * weight[wIndex];
|
|
30
44
|
}
|
|
31
|
-
dInput[index] =
|
|
32
|
-
}
|
|
45
|
+
dInput[index] = sum;
|
|
46
|
+
}
|
package/src/shaders/LB.wgsl
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
struct Params {
|
|
2
3
|
vocabSize: u32,
|
|
3
4
|
tokenCount: u32,
|
|
@@ -20,48 +21,44 @@ var<storage, read> input: array<f32>;
|
|
|
20
21
|
@group(0) @binding(4)
|
|
21
22
|
var<uniform> params: Params;
|
|
22
23
|
|
|
24
|
+
const WG_SIZE: u32 = 256u;
|
|
25
|
+
|
|
23
26
|
var<workgroup> sharedBias: array<f32, 256>;
|
|
24
27
|
|
|
25
28
|
@compute @workgroup_size(256)
|
|
26
|
-
fn main(
|
|
27
|
-
@builtin(workgroup_id) wid: vec3<u32>,
|
|
28
|
-
@builtin(local_invocation_id) lid: vec3<u32>
|
|
29
|
-
) {
|
|
29
|
+
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
30
30
|
let outputIndex = wid.x;
|
|
31
31
|
let tid = lid.x;
|
|
32
|
-
|
|
33
32
|
let vocab = params.vocabSize;
|
|
34
33
|
let tokens = params.tokenCount;
|
|
35
34
|
let inputSize = params.inputSize;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
) {
|
|
35
|
+
if (outputIndex >= vocab) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let gradBase = outputIndex;
|
|
39
|
+
let weightBase = outputIndex * inputSize;
|
|
40
|
+
for (var j = tid; j < inputSize; j += WG_SIZE) {
|
|
42
41
|
var grad = 0.0;
|
|
43
|
-
|
|
44
42
|
for (var t = 0u; t < tokens; t++) {
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
let inputIndex = t * inputSize + j;
|
|
44
|
+
let outputGradIndex = t * vocab + gradBase;
|
|
45
|
+
grad += input[inputIndex] * outGradient[outputGradIndex];
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
if (tokens > 0u) {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
let idx = weightBase + j;
|
|
50
|
+
weight[idx] -= params.lr * (grad / f32(tokens));
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
var biasGrad = 0.0;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
biasGrad += outGradient[t * vocab + outputIndex];
|
|
55
|
+
for (var t = tid; t < tokens; t += WG_SIZE) {
|
|
56
|
+
biasGrad += outGradient[t * vocab + gradBase];
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
sharedBias[tid] = biasGrad;
|
|
62
60
|
workgroupBarrier();
|
|
63
|
-
|
|
64
|
-
for (var stride = 128u; stride > 0u; stride >>= 1u) {
|
|
61
|
+
for (var stride = WG_SIZE / 2u; stride > 0u; stride >>= 1u) {
|
|
65
62
|
if (tid < stride) {
|
|
66
63
|
sharedBias[tid] += sharedBias[tid + stride];
|
|
67
64
|
}
|
|
@@ -69,7 +66,6 @@ fn main(
|
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
if (tid == 0u && tokens > 0u) {
|
|
72
|
-
bias[outputIndex] -=
|
|
73
|
-
params.lr * sharedBias[0] / f32(tokens);
|
|
69
|
+
bias[outputIndex] -= params.lr * (sharedBias[0] / f32(tokens));
|
|
74
70
|
}
|
|
75
|
-
}
|
|
71
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
struct Params{
|
|
2
|
+
lr: f32
|
|
3
|
+
}
|
|
2
4
|
@group(0) @binding(0)
|
|
3
5
|
var<storage, read> input: array<f32>;
|
|
4
6
|
|
|
@@ -12,7 +14,7 @@ var<storage, read> sumSquares: array<f32>;
|
|
|
12
14
|
var<storage, read_write> gamma: array<f32>;
|
|
13
15
|
|
|
14
16
|
@group(0) @binding(4)
|
|
15
|
-
var<
|
|
17
|
+
var<uniform> params: Params;
|
|
16
18
|
|
|
17
19
|
var<workgroup> partial: array<f32, 64>;
|
|
18
20
|
|
|
@@ -47,6 +49,6 @@ fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: v
|
|
|
47
49
|
stride /= 2u;
|
|
48
50
|
}
|
|
49
51
|
if (lid == 0u && dim < D) {
|
|
50
|
-
gamma[dim] -= params
|
|
52
|
+
gamma[dim] -= params.lr * partial[0];
|
|
51
53
|
}
|
|
52
54
|
}
|
package/src/shaders/SB.wgsl
CHANGED
|
@@ -16,6 +16,11 @@ var<storage, read_write> targetToken: array<f32>;
|
|
|
16
16
|
|
|
17
17
|
var<uniform> params: Params;
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
@group(0) @binding(4)
|
|
21
|
+
|
|
22
|
+
var<storage, read_write> dLogits: array<f32>;
|
|
23
|
+
|
|
19
24
|
@compute @workgroup_size(256)
|
|
20
25
|
|
|
21
26
|
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
@@ -29,8 +34,8 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
29
34
|
return;
|
|
30
35
|
}
|
|
31
36
|
var targetIndex = targetToken[token];
|
|
32
|
-
|
|
37
|
+
dLogits[index] = probs[index];
|
|
33
38
|
if(vocabIndex == u32(targetIndex)){
|
|
34
|
-
|
|
39
|
+
dLogits[index] -= 1;
|
|
35
40
|
}
|
|
36
41
|
}
|