@mineproness/tensorloop 2.1.81 → 2.2.1
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/package.json +1 -1
- package/src/Embedding/index.d.ts +15 -5
- package/src/Embedding/index.js +30 -20
- package/src/FFN/index.js +0 -2
- package/src/Linear/index.d.ts +23 -4
- package/src/Linear/index.js +24 -17
- package/src/OperationManager.js +25 -3
- package/src/PositionEmbedding/index.d.ts +25 -5
- package/src/PositionEmbedding/index.js +3 -8
- package/src/RMSNorm/index.d.ts +26 -6
- package/src/RMSNorm/index.js +25 -21
- package/src/Relu/index.d.ts +24 -4
- package/src/Relu/index.js +18 -13
- package/src/SelfAttention/index.d.ts +11 -6
- package/src/SelfAttention/index.js +68 -48
- package/src/Softmax/index.d.ts +24 -4
- package/src/Softmax/index.js +20 -25
- package/src/TransformerBlock/index.js +9 -23
- package/src/shaders/LB.wgsl +2 -2
- package/src/shaders/PF.wgsl +2 -4
- package/src/shaders/RB.wgsl +1 -1
- package/src/shaders/RF.wgsl +1 -1
- package/src/shaders/SB.wgsl +3 -6
- package/src/Model/index.d.ts +0 -15
- package/src/Model/index.js +0 -95
package/package.json
CHANGED
package/src/Embedding/index.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
export class Embedding{
|
|
2
|
-
constructor(device: GPUBuffer
|
|
1
|
+
export class Embedding {
|
|
2
|
+
constructor(device: GPUBuffer, embedding: number, vocabSize: number, config: {
|
|
3
3
|
cpuReadBack: boolean,
|
|
4
4
|
save: {
|
|
5
5
|
filename: string
|
|
6
6
|
}
|
|
7
7
|
})
|
|
8
|
-
async forward(tokens: number[])
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
async forward(tokens: number[]): Promise<{
|
|
9
|
+
read: function(): Promise<Float32Array>,
|
|
10
|
+
mainBuffer: GPUBuffer,
|
|
11
|
+
isDestroyed: function(): Boolean,
|
|
12
|
+
destroy: function(): void
|
|
13
|
+
}>
|
|
14
|
+
async Save(): void
|
|
15
|
+
async backward(inputGradient: {
|
|
16
|
+
read: function(): Promise<Float32Array>,
|
|
17
|
+
mainBuffer: GPUBuffer,
|
|
18
|
+
isDestroyed: function(): Boolean,
|
|
19
|
+
destroy: function(): void
|
|
20
|
+
}, lr: number): Promise<void>
|
|
11
21
|
}
|
package/src/Embedding/index.js
CHANGED
|
@@ -51,9 +51,18 @@ export class Embedding {
|
|
|
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)
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
if (!this.tokenBuffer) this.tokenBuffer = await this.gpu.createBuffer(Uint32Array.BYTES_PER_ELEMENT * input.length);
|
|
55
|
+
if (this.tokenBuffer.size !== Uint32Array.BYTES_PER_ELEMENT * input.length) {
|
|
56
|
+
this.tokenBuffer.destroy()
|
|
57
|
+
this.tokenBuffer = await this.gpu.createBuffer(Uint32Array.BYTES_PER_ELEMENT * input.length);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await this.gpu.WriteBuffer(this.tokenBuffer, new Uint32Array(input))
|
|
61
|
+
if (!this.outputBuffer) this.outputBuffer = await this.gpu.ManageBuffer(Float32Array.BYTES_PER_ELEMENT * this.embeddingSize * input.length)
|
|
62
|
+
if (this.outputBuffer.mainBuffer.size !== Float32Array.BYTES_PER_ELEMENT * this.embeddingSize * input.length || this.outputBuffer.isDestroyed()) {
|
|
63
|
+
this.outputBuffer.destroy()
|
|
64
|
+
this.outputBuffer = await this.gpu.ManageBuffer(Float32Array.BYTES_PER_ELEMENT * this.embeddingSize * input.length);
|
|
65
|
+
}
|
|
57
66
|
const bind = await this.device.createBindGroup({
|
|
58
67
|
layout: await this.forwardPipline.getBindGroupLayout(0),
|
|
59
68
|
entries: [
|
|
@@ -66,37 +75,30 @@ export class Embedding {
|
|
|
66
75
|
{
|
|
67
76
|
binding: 1,
|
|
68
77
|
resource: {
|
|
69
|
-
buffer: outputBuffer
|
|
78
|
+
buffer: this.outputBuffer.mainBuffer
|
|
70
79
|
}
|
|
71
80
|
}, {
|
|
72
81
|
binding: 2,
|
|
73
82
|
resource: {
|
|
74
|
-
buffer: tokenBuffer
|
|
83
|
+
buffer: this.tokenBuffer
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
]
|
|
78
87
|
})
|
|
79
|
-
await this.gpu.RunPipline(encoder,this.forwardPipline, bind, Math.ceil((this.embeddingSize * input.length) / 256))
|
|
88
|
+
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((this.embeddingSize * input.length) / 256))
|
|
80
89
|
this.device.queue.submit([encoder.finish()])
|
|
81
|
-
|
|
82
|
-
if (this.configs.cpuReadBack) {
|
|
83
|
-
const output = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.embeddingSize * input.length, outputBuffer);
|
|
84
|
-
outputBuffer.destroy()
|
|
85
|
-
return output
|
|
86
|
-
}
|
|
87
|
-
return outputBuffer
|
|
90
|
+
return this.outputBuffer
|
|
88
91
|
|
|
89
92
|
}
|
|
90
93
|
async Save() {
|
|
91
94
|
const vec = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.vocabSize * this.embeddingSize, this.vectorsBuffer)
|
|
92
95
|
SaveVector(this.configs.save.filename, vec)
|
|
93
96
|
}
|
|
94
|
-
async backward(
|
|
97
|
+
async backward(inputGradient, lr) {
|
|
95
98
|
const encoder = this.device.createCommandEncoder()
|
|
96
99
|
if (!this.oldParam) {
|
|
97
100
|
this.oldParam = new Float32Array([0, 0]);
|
|
98
101
|
this.param = await this.gpu.createUniFormBuffer(this.oldParam.byteLength);
|
|
99
|
-
this.tokenBuffer = await this.gpu.createBuffer(4 * token.length)
|
|
100
102
|
}
|
|
101
103
|
if (this.oldParam[0] !== lr) {
|
|
102
104
|
this.oldParam = new Float32Array([lr, 0]);
|
|
@@ -114,7 +116,7 @@ export class Embedding {
|
|
|
114
116
|
{
|
|
115
117
|
binding: 1,
|
|
116
118
|
resource: {
|
|
117
|
-
buffer: inputGradient
|
|
119
|
+
buffer: inputGradient.mainBuffer
|
|
118
120
|
}
|
|
119
121
|
}, {
|
|
120
122
|
binding: 2,
|
|
@@ -131,10 +133,18 @@ export class Embedding {
|
|
|
131
133
|
}
|
|
132
134
|
]
|
|
133
135
|
})
|
|
134
|
-
await this.gpu.
|
|
135
|
-
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.embeddingSize * token.length) / 256))
|
|
136
|
+
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.embeddingSize * (this.tokenBuffer.size / 4)) / 256))
|
|
136
137
|
this.device.queue.submit([encoder.finish()])
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
}
|
|
139
|
+
destroy() {
|
|
140
|
+
this.vectorsBuffer?.destroy();
|
|
141
|
+
this.tokenBuffer?.destroy();
|
|
142
|
+
this.outputBuffer?.destroy();
|
|
143
|
+
this.param?.destroy();
|
|
144
|
+
|
|
145
|
+
this.vectorsBuffer = null;
|
|
146
|
+
this.tokenBuffer = null;
|
|
147
|
+
this.outputBuffer = null;
|
|
148
|
+
this.param = null;
|
|
139
149
|
}
|
|
140
150
|
}
|
package/src/FFN/index.js
CHANGED
|
@@ -29,8 +29,6 @@ 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;
|
|
34
32
|
const logit2 = await this.linear2.backward(inputGradient, lr)
|
|
35
33
|
const hidden = await this.hiddenLayer.backward(logit2)
|
|
36
34
|
const final = await this.linear1.backward(hidden, lr)
|
package/src/Linear/index.d.ts
CHANGED
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
export class Linear {
|
|
2
2
|
constructor(device: GPUAdapter, embeddingSize: number, vocabSize: number, configs: {
|
|
3
|
-
cpuReadBack: boolean,
|
|
4
3
|
save: {
|
|
5
4
|
filename: string[]
|
|
6
5
|
}
|
|
7
6
|
})
|
|
8
|
-
async forward(vec:
|
|
9
|
-
|
|
7
|
+
async forward(vec: {
|
|
8
|
+
read: function(): Promise<Float32Array>,
|
|
9
|
+
mainBuffer: GPUBuffer,
|
|
10
|
+
isDestroyed: function(): Boolean,
|
|
11
|
+
destroy: function(): void
|
|
12
|
+
}): Promise<{
|
|
13
|
+
read: function(): Promise<Float32Array>,
|
|
14
|
+
mainBuffer: GPUBuffer,
|
|
15
|
+
isDestroyed: function(): Boolean,
|
|
16
|
+
destroy: function(): void
|
|
17
|
+
}>
|
|
18
|
+
async backward(dOutput: {
|
|
19
|
+
read: function(): Promise<Float32Array>,
|
|
20
|
+
mainBuffer: GPUBuffer,
|
|
21
|
+
isDestroyed: function(): Boolean,
|
|
22
|
+
destroy: function(): void
|
|
23
|
+
}, lr: number): Promise<{
|
|
24
|
+
read: function(): Promise<Float32Array>,
|
|
25
|
+
mainBuffer: GPUBuffer,
|
|
26
|
+
isDestroyed: function(): Boolean,
|
|
27
|
+
destroy: function(): void
|
|
28
|
+
}>
|
|
10
29
|
async Save(): Promise<void>
|
|
11
|
-
async ClearInputCache()
|
|
30
|
+
async ClearInputCache(): Promise<void>
|
|
12
31
|
}
|
package/src/Linear/index.js
CHANGED
|
@@ -63,7 +63,7 @@ export class Linear {
|
|
|
63
63
|
}
|
|
64
64
|
async forward(vec) {
|
|
65
65
|
const encoder = this.device.createCommandEncoder()
|
|
66
|
-
const tokenCount = vec.size / (this.embeddingSize * 4)
|
|
66
|
+
const tokenCount = vec.mainBuffer.size / (this.embeddingSize * 4)
|
|
67
67
|
if (!this.wBuffer) {
|
|
68
68
|
|
|
69
69
|
this.wBuffer = await this.gpu.createBuffer(this.embeddingSize * this.vocabSize * 4)
|
|
@@ -80,7 +80,12 @@ export class Linear {
|
|
|
80
80
|
await this.gpu.WriteBuffer(this.paramForward, new Uint32Array([this.embeddingSize, this.vocabSize, tokenCount, 0]))
|
|
81
81
|
this.oldParam = new Uint32Array([this.embeddingSize, this.vocabSize, tokenCount, 0]);
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
if (!this.outputBuffer) this.outputBuffer = await this.gpu.ManageBuffer(4 * this.vocabSize * tokenCount)
|
|
84
|
+
if (this.outputBuffer.mainBuffer.size !== 4 * this.vocabSize * tokenCount || this.outputBuffer.isDestroyed()) {
|
|
85
|
+
this.outputBuffer.destroy()
|
|
86
|
+
this.outputBuffer = await this.gpu.ManageBuffer(4 * this.vocabSize * tokenCount)
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
const bind = await this.device.createBindGroup({
|
|
85
90
|
layout: await this.forwardPipline.getBindGroupLayout(0),
|
|
86
91
|
entries: [
|
|
@@ -90,11 +95,11 @@ export class Linear {
|
|
|
90
95
|
},
|
|
91
96
|
{
|
|
92
97
|
binding: 1,
|
|
93
|
-
resource: outputBuffer
|
|
98
|
+
resource: this.outputBuffer.mainBuffer
|
|
94
99
|
},
|
|
95
100
|
{
|
|
96
101
|
binding: 2,
|
|
97
|
-
resource: vec
|
|
102
|
+
resource: vec.mainBuffer
|
|
98
103
|
},
|
|
99
104
|
{
|
|
100
105
|
binding: 3,
|
|
@@ -107,14 +112,12 @@ export class Linear {
|
|
|
107
112
|
]
|
|
108
113
|
})
|
|
109
114
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((this.vocabSize * tokenCount) / 256))
|
|
110
|
-
|
|
111
|
-
this.input = await this.gpu.MakeACopyBuffer(encoder, vec);
|
|
115
|
+
|
|
112
116
|
this.device.queue.submit([encoder.finish()])
|
|
113
|
-
|
|
117
|
+
this.input = vec;
|
|
118
|
+
return this.outputBuffer
|
|
114
119
|
}
|
|
115
120
|
async backward(dOutput, learningRate) {
|
|
116
|
-
if(this.pdOutput) await this.pdOutput.destroy();
|
|
117
|
-
this.pdOutput = dOutput
|
|
118
121
|
const encoder = this.device.createCommandEncoder()
|
|
119
122
|
const tokenCount = dOutput.size / (this.vocabSize * 4)
|
|
120
123
|
if (!this.oldParamb) {
|
|
@@ -124,7 +127,12 @@ export class Linear {
|
|
|
124
127
|
await this.gpu.WriteBuffer(this.paramBackward, new Float32Array([this.vocabSize, tokenCount, learningRate, this.embeddingSize, 0]));
|
|
125
128
|
this.oldParamb = new Float32Array([this.vocabSize, tokenCount, learningRate, this.embeddingSize, 0]);
|
|
126
129
|
}
|
|
127
|
-
|
|
130
|
+
if(!this.gradientBuffer) this.gradientBuffer = await this.gpu.ManageBuffer(this.embeddingSize * tokenCount * 4);
|
|
131
|
+
if(this.gradientBuffer.size !== 4 * this.embeddingSize * tokenCount || this.gradientBuffer.isDestroyed()){
|
|
132
|
+
this.gradientBuffer.destroy()
|
|
133
|
+
this.gradientBuffer = await this.gpu.ManageBuffer(this.embeddingSize * tokenCount * 4)
|
|
134
|
+
|
|
135
|
+
}
|
|
128
136
|
const bind = await this.device.createBindGroup({
|
|
129
137
|
layout: await this.backwardPipline.getBindGroupLayout(0),
|
|
130
138
|
entries: [
|
|
@@ -138,11 +146,11 @@ export class Linear {
|
|
|
138
146
|
},
|
|
139
147
|
{
|
|
140
148
|
binding: 2,
|
|
141
|
-
resource: dOutput
|
|
149
|
+
resource: dOutput.mainBuffer
|
|
142
150
|
},
|
|
143
151
|
{
|
|
144
152
|
binding: 3,
|
|
145
|
-
resource: this.input
|
|
153
|
+
resource: this.input.mainBuffer
|
|
146
154
|
},
|
|
147
155
|
{
|
|
148
156
|
binding: 4,
|
|
@@ -159,7 +167,7 @@ export class Linear {
|
|
|
159
167
|
},
|
|
160
168
|
{
|
|
161
169
|
binding: 1,
|
|
162
|
-
resource: dOutput
|
|
170
|
+
resource: dOutput.mainBuffer
|
|
163
171
|
},
|
|
164
172
|
{
|
|
165
173
|
binding: 3,
|
|
@@ -167,7 +175,7 @@ export class Linear {
|
|
|
167
175
|
},
|
|
168
176
|
{
|
|
169
177
|
binding: 4,
|
|
170
|
-
resource:
|
|
178
|
+
resource: this.gradientBuffer.mainBuffer
|
|
171
179
|
}
|
|
172
180
|
]
|
|
173
181
|
})
|
|
@@ -175,8 +183,7 @@ export class Linear {
|
|
|
175
183
|
await this.gpu.RunPipline(encoder, this.dInputBackward, bind2, Math.ceil((this.embeddingSize * tokenCount) / 256));
|
|
176
184
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.vocabSize * tokenCount) / 256));
|
|
177
185
|
await this.device.queue.submit([encoder.finish()])
|
|
178
|
-
this.
|
|
179
|
-
return outputBuffer
|
|
186
|
+
return this.gradientBuffer
|
|
180
187
|
|
|
181
188
|
}
|
|
182
189
|
async Save() {
|
|
@@ -186,7 +193,7 @@ export class Linear {
|
|
|
186
193
|
SaveVector(this.configs.save.filename[1], b)
|
|
187
194
|
}
|
|
188
195
|
async ClearInputCache() {
|
|
189
|
-
|
|
196
|
+
|
|
190
197
|
}
|
|
191
198
|
|
|
192
199
|
}
|
package/src/OperationManager.js
CHANGED
|
@@ -15,7 +15,7 @@ export class OperationManager {
|
|
|
15
15
|
}
|
|
16
16
|
async createBuffer(size) {
|
|
17
17
|
return this.device.createBuffer({
|
|
18
|
-
size,
|
|
18
|
+
size: size,
|
|
19
19
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
20
20
|
})
|
|
21
21
|
}
|
|
@@ -106,8 +106,8 @@ export class OperationManager {
|
|
|
106
106
|
|
|
107
107
|
}
|
|
108
108
|
const encoder = await this.CreateEncoder()
|
|
109
|
-
const output = await this.
|
|
110
|
-
const bind = await this.createBindGroup(this.addShader, 0, [a, b, output, this.params]);
|
|
109
|
+
const output = await this.ManageBuffer(a.size);
|
|
110
|
+
const bind = await this.createBindGroup(this.addShader, 0, [a, b, output.mainBuffer, this.params]);
|
|
111
111
|
await this.WriteBuffer(this.params, new Uint32Array([size, 0]))
|
|
112
112
|
await this.RunPipline(encoder, this.addShader, bind, Math.ceil(size / 64));
|
|
113
113
|
await this.submitQueue(encoder)
|
|
@@ -115,5 +115,27 @@ export class OperationManager {
|
|
|
115
115
|
// b.destroy()
|
|
116
116
|
return output
|
|
117
117
|
}
|
|
118
|
+
async ManageBuffer(size){
|
|
119
|
+
const buffer = await this.device.createBuffer({
|
|
120
|
+
size,
|
|
121
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
122
|
+
})
|
|
123
|
+
let isDestroy = false;
|
|
124
|
+
return {
|
|
125
|
+
mainBuffer: buffer,
|
|
126
|
+
destroy: function(){
|
|
127
|
+
isDestroy = true
|
|
128
|
+
this.mainBuffer.destroy()
|
|
129
|
+
},
|
|
130
|
+
isDestroyed: function(){
|
|
131
|
+
return isDestroy
|
|
132
|
+
},
|
|
133
|
+
read: async ()=>{
|
|
134
|
+
return await this.readBuffer(buffer.size, buffer)
|
|
135
|
+
},
|
|
136
|
+
size: size
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
}
|
|
118
140
|
|
|
119
141
|
}
|
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
export class PositionEmbedding{
|
|
2
|
-
constructor(device: GPUBuffer
|
|
1
|
+
export class PositionEmbedding {
|
|
2
|
+
constructor(device: GPUBuffer, embedding: number, contextSize: number, config: {
|
|
3
3
|
save: {
|
|
4
4
|
filename: string
|
|
5
5
|
}
|
|
6
6
|
});
|
|
7
|
-
async forward(input:
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
async forward(input: {
|
|
8
|
+
read: function(): Promise<Float32Array>,
|
|
9
|
+
mainBuffer: GPUBuffer,
|
|
10
|
+
isDestroyed: function(): Boolean,
|
|
11
|
+
destroy: function(): void
|
|
12
|
+
}): Promise<{
|
|
13
|
+
read: function(): Promise<Float32Array>,
|
|
14
|
+
mainBuffer: GPUBuffer,
|
|
15
|
+
isDestroyed: function(): Boolean,
|
|
16
|
+
destroy: function(): void
|
|
17
|
+
}>
|
|
18
|
+
async Save(): Promise<void>
|
|
19
|
+
async backward(inputGradient: {
|
|
20
|
+
read: function(): Promise<Float32Array>,
|
|
21
|
+
mainBuffer: GPUBuffer,
|
|
22
|
+
isDestroyed: function(): Boolean,
|
|
23
|
+
destroy: function(): void
|
|
24
|
+
}, lr: number): Promise<{
|
|
25
|
+
read: function(): Promise<Float32Array>,
|
|
26
|
+
mainBuffer: GPUBuffer,
|
|
27
|
+
isDestroyed: function(): Boolean,
|
|
28
|
+
destroy: function(): void
|
|
29
|
+
}>
|
|
10
30
|
}
|
|
@@ -45,21 +45,16 @@ export class PositionEmbedding {
|
|
|
45
45
|
this.vecBuffer = await this.gpu.createBuffer(Float32Array.BYTES_PER_ELEMENT * this.contextSize * this.embeddingSize);
|
|
46
46
|
await this.gpu.WriteBuffer(this.vecBuffer, this.vectors)
|
|
47
47
|
}
|
|
48
|
-
const output = await this.gpu.createBuffer(input.size);
|
|
49
48
|
const size = Math.ceil((input.size / 4) / 64);
|
|
50
|
-
const bindGroup = await this.gpu.createBindGroup(this.forwardShader, 0, [this.vecBuffer, input
|
|
51
|
-
if (this.prevVec) this.prevVec.destroy();
|
|
52
|
-
this.prevVec = input;
|
|
49
|
+
const bindGroup = await this.gpu.createBindGroup(this.forwardShader, 0, [this.vecBuffer, input.mainBuffer])
|
|
53
50
|
await this.gpu.RunPipline(encoder, this.forwardShader, bindGroup, size);
|
|
54
51
|
await this.gpu.submitQueue(encoder);
|
|
55
|
-
return
|
|
52
|
+
return input
|
|
56
53
|
}
|
|
57
54
|
async backward(outputGradient, lr){
|
|
58
55
|
const encoder = await this.gpu.CreateEncoder()
|
|
59
56
|
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;
|
|
57
|
+
const bindGroup = await this.gpu.createBindGroup(this.backwardShader, 0, [this.vecBuffer, outputGradient.mainBuffer, this.params])
|
|
63
58
|
await this.gpu.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((outputGradient.size / 4) / 64))
|
|
64
59
|
await this.gpu.submitQueue(encoder);
|
|
65
60
|
}
|
package/src/RMSNorm/index.d.ts
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
export class RMSNorm{
|
|
2
|
-
constructor(device
|
|
3
|
-
save:{
|
|
1
|
+
export class RMSNorm {
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number, {
|
|
3
|
+
save: {
|
|
4
4
|
filename: string
|
|
5
5
|
}
|
|
6
6
|
});
|
|
7
|
-
async forward(input
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
async forward(input: {
|
|
8
|
+
read: function(): Promise<Float32Array>,
|
|
9
|
+
mainBuffer: GPUBuffer,
|
|
10
|
+
isDestroyed: function(): Boolean,
|
|
11
|
+
destroy: function(): void
|
|
12
|
+
}): Promise<{
|
|
13
|
+
read: function(): Promise<Float32Array>,
|
|
14
|
+
mainBuffer: GPUBuffer,
|
|
15
|
+
isDestroyed: function(): Boolean,
|
|
16
|
+
destroy: function(): void
|
|
17
|
+
}>
|
|
18
|
+
async backward(outputGradient: {
|
|
19
|
+
read: function(): Promise<Float32Array>,
|
|
20
|
+
mainBuffer: GPUBuffer,
|
|
21
|
+
isDestroyed: function(): Boolean,
|
|
22
|
+
destroy: function(): void
|
|
23
|
+
}): Promise<{
|
|
24
|
+
read: function(): Promise<Float32Array>,
|
|
25
|
+
mainBuffer: GPUBuffer,
|
|
26
|
+
isDestroyed: function(): Boolean,
|
|
27
|
+
destroy: function(): void
|
|
28
|
+
}>
|
|
29
|
+
async Save(): Promise<void>
|
|
10
30
|
}
|
package/src/RMSNorm/index.js
CHANGED
|
@@ -40,43 +40,47 @@ export class RMSNorm {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
async forward(input) {
|
|
43
|
+
this.input = input;
|
|
43
44
|
if (!this.gammabuffer) {
|
|
44
45
|
this.gammabuffer = await this.op.createBuffer(4 * this.embeddingSize);
|
|
45
46
|
await this.op.WriteBuffer(this.gammabuffer, this.gamma);
|
|
46
47
|
}
|
|
47
48
|
let context = input.size / (this.embeddingSize * 4)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
if (!this.rms) this.rms = await this.op.createBuffer(4 * context);
|
|
50
|
+
if (this.rms.size !== 4 * context * this.embeddingSize) {
|
|
51
|
+
this.rms.destroy()
|
|
52
|
+
this.rms = await this.op.createBuffer(4 * context);
|
|
53
|
+
}
|
|
54
|
+
if (!this.output) this.output = await this.op.ManageBuffer(input.size);
|
|
55
|
+
if (this.output.size !== 4 * context || this.output.isDestroyed()) {
|
|
56
|
+
this.output.destroy()
|
|
57
|
+
this.output = await this.op.ManageBuffer(input.size)
|
|
58
|
+
}
|
|
59
|
+
const bindGroup = await this.op.createBindGroup(this.reductionShader, 0, [input.mainBuffer, this.rms])
|
|
51
60
|
const encoder = await this.op.CreateEncoder()
|
|
52
61
|
await this.op.RunPipline(encoder, this.reductionShader, bindGroup, context)
|
|
53
|
-
const bindGroup1 = await this.op.createBindGroup(this.forwardShader, 0, [
|
|
62
|
+
const bindGroup1 = await this.op.createBindGroup(this.forwardShader, 0, [this.rms, input.mainBuffer, this.output.mainBuffer, this.gammabuffer])
|
|
54
63
|
await this.op.RunPipline(encoder, this.forwardShader, bindGroup1, Math.ceil((input.size / 4) / 64));
|
|
55
64
|
await this.op.submitQueue(encoder);
|
|
56
|
-
|
|
57
|
-
this.rms = outputReduce
|
|
58
|
-
if (this.input) this.input.destroy()
|
|
59
|
-
this.input = input;
|
|
60
|
-
if (this.outputPre) this.outputPre.destroy()
|
|
61
|
-
this.outputPre = output
|
|
62
|
-
return output
|
|
65
|
+
return this.output
|
|
63
66
|
}
|
|
64
67
|
async backward(outputGradient, lr) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
if(!this.gradOut) this.gradOut = await this.op.ManageBuffer(outputGradient.size);
|
|
69
|
+
if(this.gradOut.size !== outputGradient.size || this.gradOut.isDestroyed()){
|
|
70
|
+
this.gradOut.destroy()
|
|
71
|
+
this.gradOut = await this.op.ManageBuffer(outputGradient.size)
|
|
72
|
+
}
|
|
73
|
+
if(!this.params) this.params = await this.op.createBuffer(4 * 2)
|
|
74
|
+
await this.op.WriteBuffer(this.params, new Float32Array([lr, 0]))
|
|
75
|
+
const bindGroup = await this.op.createBindGroup(this.backwardShader, 0, [this.input.mainBuffer, outputGradient.mainBuffer, this.rms, this.gammabuffer, this.gradOut.mainBuffer]);
|
|
76
|
+
const bindGroup2 = await this.op.createBindGroup(this.updateGamma, 0, [this.input.mainBuffer, outputGradient.mainBuffer, this.rms, this.gammabuffer, this.params]);
|
|
70
77
|
const encoder = await this.op.CreateEncoder()
|
|
71
78
|
await this.op.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((this.input.size) / (this.embeddingSize * 4)))
|
|
72
79
|
await this.op.RunPipline(encoder, this.updateGamma, bindGroup2, Math.ceil(this.embeddingSize))
|
|
73
80
|
await this.op.submitQueue(encoder)
|
|
74
|
-
|
|
75
|
-
this.prevOut = outputGradient
|
|
76
|
-
params.destroy()
|
|
77
|
-
return output
|
|
81
|
+
return this.gradOut
|
|
78
82
|
}
|
|
79
|
-
async Save(){
|
|
83
|
+
async Save() {
|
|
80
84
|
const read = await this.op.readBuffer(4 * this.embeddingSize, this.gammabuffer);
|
|
81
85
|
SaveVector(this.configs.save.filename, read)
|
|
82
86
|
}
|
package/src/Relu/index.d.ts
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
export class Relu{
|
|
2
|
-
constructor(device
|
|
3
|
-
async forward(input:
|
|
4
|
-
|
|
1
|
+
export class Relu {
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number);
|
|
3
|
+
async forward(input: {
|
|
4
|
+
read: function(): Promise<Float32Array>,
|
|
5
|
+
mainBuffer: GPUBuffer,
|
|
6
|
+
isDestroyed: function(): Boolean,
|
|
7
|
+
destroy: function(): void
|
|
8
|
+
}): Promise<{
|
|
9
|
+
read: function(): Promise<Float32Array>,
|
|
10
|
+
mainBuffer: GPUBuffer,
|
|
11
|
+
isDestroyed: function(): Boolean,
|
|
12
|
+
destroy: function(): void
|
|
13
|
+
}>
|
|
14
|
+
async backward(outGradinet: {
|
|
15
|
+
read: function(): Promise<Float32Array>,
|
|
16
|
+
mainBuffer: GPUBuffer,
|
|
17
|
+
isDestroyed: function(): Boolean,
|
|
18
|
+
destroy: function(): void
|
|
19
|
+
}): Promise<{
|
|
20
|
+
read: function(): Promise<Float32Array>,
|
|
21
|
+
mainBuffer: GPUBuffer,
|
|
22
|
+
isDestroyed: function(): Boolean,
|
|
23
|
+
destroy: function(): void
|
|
24
|
+
}>
|
|
5
25
|
}
|
package/src/Relu/index.js
CHANGED
|
@@ -17,12 +17,16 @@ export class Relu {
|
|
|
17
17
|
}
|
|
18
18
|
async forward(input) {
|
|
19
19
|
const encoder = this.device.createCommandEncoder()
|
|
20
|
-
const tokenCount = input.size / (this.embeddingSize * 4)
|
|
20
|
+
const tokenCount = input.mainBuffer.size / (this.embeddingSize * 4)
|
|
21
21
|
if (!this.oldParam) {
|
|
22
22
|
this.oldParam = new Uint32Array([0, 0, 0]);
|
|
23
23
|
this.paramBuffer = await this.gpu.createUniFormBuffer(4 * 3);
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
if (!this.output) this.output = await this.gpu.ManageBuffer(input.mainBuffer.size);
|
|
26
|
+
if (this.output.mainBuffer.size !== input.mainBuffer.size || this.output.isDestroyed()) {
|
|
27
|
+
this.output.destroy()
|
|
28
|
+
this.output = await this.gpu.ManageBuffer(input.mainBuffer.size);
|
|
29
|
+
}
|
|
26
30
|
if (this.oldParam[1] !== tokenCount) {
|
|
27
31
|
this.oldParam = new Uint32Array([this.embeddingSize, tokenCount, 0])
|
|
28
32
|
await this.gpu.WriteBuffer(this.paramBuffer, this.oldParam)
|
|
@@ -33,7 +37,7 @@ export class Relu {
|
|
|
33
37
|
{
|
|
34
38
|
binding: 0,
|
|
35
39
|
resource: {
|
|
36
|
-
buffer: input
|
|
40
|
+
buffer: input.mainBuffer
|
|
37
41
|
}
|
|
38
42
|
},
|
|
39
43
|
{
|
|
@@ -44,16 +48,15 @@ export class Relu {
|
|
|
44
48
|
}, {
|
|
45
49
|
binding: 2,
|
|
46
50
|
resource: {
|
|
47
|
-
buffer: output
|
|
51
|
+
buffer: this.output.mainBuffer
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
54
|
]
|
|
51
55
|
})
|
|
52
56
|
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
53
57
|
this.device.queue.submit([encoder.finish()])
|
|
54
|
-
if(this.input) this.input.destroy()
|
|
55
58
|
this.input = input
|
|
56
|
-
return output
|
|
59
|
+
return this.output
|
|
57
60
|
}
|
|
58
61
|
async backward(inputGradient) {
|
|
59
62
|
const encoder = this.device.createCommandEncoder()
|
|
@@ -62,7 +65,11 @@ export class Relu {
|
|
|
62
65
|
this.oldParam = new Uint32Array([0, 0, 0]);
|
|
63
66
|
this.paramBuffer = await this.gpu.createUniFormBuffer(4 * 3);
|
|
64
67
|
}
|
|
65
|
-
|
|
68
|
+
if(!this.gradOut) this.gradOut = await this.gpu.ManageBuffer(inputGradient.size);
|
|
69
|
+
if(this.gradOut.size !== inputGradient.size || this.gradOut.isDestroyed()){
|
|
70
|
+
this.gradOut.destroy();
|
|
71
|
+
this.gradOut = await this.gpu.ManageBuffer(inputGradient.size)
|
|
72
|
+
}
|
|
66
73
|
if (this.oldParam[1] !== tokenCount) {
|
|
67
74
|
this.oldParam = new Uint32Array([this.embeddingSize, tokenCount, 0])
|
|
68
75
|
await this.gpu.WriteBuffer(this.paramBuffer, this.oldParam)
|
|
@@ -73,7 +80,7 @@ export class Relu {
|
|
|
73
80
|
{
|
|
74
81
|
binding: 0,
|
|
75
82
|
resource: {
|
|
76
|
-
buffer: this.input
|
|
83
|
+
buffer: this.input.mainBuffer
|
|
77
84
|
}
|
|
78
85
|
},
|
|
79
86
|
{
|
|
@@ -84,20 +91,18 @@ export class Relu {
|
|
|
84
91
|
}, {
|
|
85
92
|
binding: 2,
|
|
86
93
|
resource: {
|
|
87
|
-
buffer:
|
|
94
|
+
buffer: this.gradOut.mainBuffer
|
|
88
95
|
}
|
|
89
96
|
}, {
|
|
90
97
|
binding: 3,
|
|
91
98
|
resource: {
|
|
92
|
-
buffer: inputGradient
|
|
99
|
+
buffer: inputGradient.mainBuffer
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
]
|
|
96
103
|
})
|
|
97
104
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
98
105
|
await this.device.queue.submit([encoder.finish()])
|
|
99
|
-
this.
|
|
100
|
-
inputGradient.destroy()
|
|
101
|
-
return output
|
|
106
|
+
return this.gradOut
|
|
102
107
|
}
|
|
103
108
|
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
export class SelfAttention{
|
|
2
|
-
constructor(device
|
|
1
|
+
export class SelfAttention {
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number, configs: {
|
|
3
3
|
dirname: string
|
|
4
4
|
})
|
|
5
|
-
async forward(vec
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
async forward(vec: GPUBuffer): Promise<{
|
|
6
|
+
read: function(): Promise<Float32Array>,
|
|
7
|
+
mainBuffer: GPUBuffer,
|
|
8
|
+
isDestroyed: function(): Boolean,
|
|
9
|
+
destroy: function(): void
|
|
10
|
+
}>
|
|
11
|
+
async backward(dO: GPUBuffer, lr: number): Promise<GPUBuffer>
|
|
12
|
+
async ClearInputCache(): Promise<void>
|
|
13
|
+
async Save(): Promise<void>
|
|
9
14
|
}
|
|
@@ -39,82 +39,102 @@ export class SelfAttention {
|
|
|
39
39
|
this.sumShader = this.gpu.getShaderPipline("./src/shaders/attentionShader/sumGradient.wgsl")
|
|
40
40
|
}
|
|
41
41
|
async forward(vec) {
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
const tokenCount = vec.size / (this.embeddingSize * 4)
|
|
42
|
+
this.input = vec.mainBuffer;
|
|
43
|
+
const tokenCount = vec.mainBuffer.size / (this.embeddingSize * 4)
|
|
45
44
|
if (!this.asParams) this.asParams = await this.gpu.createUniFormBuffer(4 * 3);
|
|
46
45
|
if (!this.softmaxParams) this.softmaxParams = await this.gpu.createUniFormBuffer(4 * 3);
|
|
47
46
|
const encoder = await this.gpu.CreateEncoder()
|
|
48
|
-
|
|
47
|
+
if (!this.scroes) {
|
|
48
|
+
this.scroes = await this.gpu.createBuffer(tokenCount * tokenCount * 4)
|
|
49
|
+
}
|
|
50
|
+
if (this.scroes.size !== tokenCount * tokenCount * 4) {
|
|
51
|
+
this.scroes.destroy()
|
|
52
|
+
this.scroes = await this.gpu.createBuffer(tokenCount * tokenCount * 4)
|
|
53
|
+
}
|
|
49
54
|
await this.gpu.WriteBuffer(this.asParams, new Uint32Array([tokenCount, this.embeddingSize, 0]))
|
|
50
55
|
await this.gpu.WriteBuffer(this.softmaxParams, new Uint32Array([tokenCount, tokenCount, 0]))
|
|
51
|
-
if (this.query) this.query.destroy()
|
|
52
|
-
if (this.key) this.key.destroy()
|
|
53
|
-
if (this.value) this.value.destroy()
|
|
54
56
|
this.query = await this.q.forward(vec)
|
|
55
57
|
this.key = await this.k.forward(vec)
|
|
56
58
|
this.value = await this.v.forward(vec)
|
|
57
|
-
const bindAttention = await this.gpu.createBindGroup(this.attentionscoresShader, 0, [this.query, this.key, scroes, this.asParams])
|
|
59
|
+
const bindAttention = await this.gpu.createBindGroup(this.attentionscoresShader, 0, [this.query.mainBuffer, this.key.mainBuffer, this.scroes, this.asParams])
|
|
58
60
|
await this.gpu.RunPipline(encoder, this.attentionscoresShader, bindAttention, Math.ceil(tokenCount / 16), Math.ceil(tokenCount / 16))
|
|
59
61
|
if (this.weights) this.weights.destroy()
|
|
60
62
|
this.weights = await this.gpu.createBuffer(tokenCount * tokenCount * 4)
|
|
61
|
-
const bindSF = await this.gpu.createBindGroup(this.softmaxForward, 0, [scroes, this.weights, this.softmaxParams]);
|
|
63
|
+
const bindSF = await this.gpu.createBindGroup(this.softmaxForward, 0, [this.scroes, this.weights, this.softmaxParams]);
|
|
62
64
|
await this.gpu.RunPipline(encoder, this.softmaxForward, bindSF, tokenCount)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
if (!this.finalOutput) {
|
|
66
|
+
this.finalOutput = await this.gpu.ManageBuffer(tokenCount * this.embeddingSize * 4)
|
|
67
|
+
}
|
|
68
|
+
if (this.finalOutput.mainBuffer.size !== tokenCount * this.embeddingSize * 4 || this.finalOutput.isDestroyed()) {
|
|
69
|
+
this.finalOutput = await this.gpu.ManageBuffer(tokenCount * this.embeddingSize * 4)
|
|
70
|
+
}
|
|
71
|
+
const outputBind = await this.gpu.createBindGroup(this.outputForward, 0, [this.weights, this.value.mainBuffer, this.finalOutput.mainBuffer, this.asParams]);
|
|
65
72
|
await this.gpu.RunPipline(encoder, this.outputForward, outputBind, Math.ceil((tokenCount * this.embeddingSize) / 256))
|
|
66
73
|
await this.gpu.submitQueue(encoder)
|
|
67
|
-
|
|
68
|
-
return finalOutput
|
|
74
|
+
return this.finalOutput
|
|
69
75
|
}
|
|
70
76
|
async backward(dO, lr) {
|
|
71
77
|
const tokenCount = dO.size / (this.embeddingSize * 4);
|
|
72
78
|
const encoder = await this.gpu.CreateEncoder();
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
if (!this.dV) this.dV = await this.gpu.createBuffer(dO.size);
|
|
80
|
+
if (!this.dA) this.dA = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
81
|
+
if (!this.dS) this.dS = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
82
|
+
if (!this.dQ) this.dQ = await this.gpu.createBuffer(tokenCount * this.embeddingSize * 4);
|
|
83
|
+
if (!this.dK) this.dK = await this.gpu.createBuffer(this.embeddingSize * tokenCount * 4)
|
|
84
|
+
if (this.dV.size !== dO.size) {
|
|
85
|
+
this.dV.destroy()
|
|
86
|
+
this.dV = await this.gpu.createBuffer(dO.size);
|
|
87
|
+
}
|
|
88
|
+
if (this.dA.size !== tokenCount * tokenCount * 4) {
|
|
89
|
+
this.dA.destroy()
|
|
90
|
+
this.dA = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
91
|
+
}
|
|
92
|
+
if (this.dS.size !== tokenCount * tokenCount * 4) {
|
|
93
|
+
this.dS.destroy()
|
|
94
|
+
this.dS = await this.gpu.createBuffer(tokenCount * tokenCount * 4);
|
|
95
|
+
}
|
|
96
|
+
if (this.dQ.size !== tokenCount * this.embeddingSize * 4) {
|
|
97
|
+
this.dQ.destroy()
|
|
98
|
+
this.dQ = await this.gpu.createBuffer(tokenCount * this.embeddingSize * 4);
|
|
99
|
+
}
|
|
100
|
+
if (this.dK.size !== tokenCount * this.embeddingSize * 4) {
|
|
101
|
+
this.dK.destroy()
|
|
102
|
+
this.dK = await this.gpu.createBuffer(tokenCount * this.embeddingSize * 4);
|
|
103
|
+
}
|
|
104
|
+
const DvBind = await this.gpu.createBindGroup(this.dVShader, 0, [this.weights, dO.mainBuffer, this.dV, this.asParams]);
|
|
75
105
|
await this.gpu.RunPipline(encoder, this.dVShader, DvBind, Math.ceil(tokenCount / 16), Math.ceil(this.embeddingSize / 16));
|
|
76
|
-
const
|
|
77
|
-
const DaBind = await this.gpu.createBindGroup(this.dAshader, 0, [dO, this.value, dA, this.asParams]);
|
|
106
|
+
const DaBind = await this.gpu.createBindGroup(this.dAshader, 0, [dO.mainBuffer, this.value.mainBuffer, this.dA, this.asParams]);
|
|
78
107
|
await this.gpu.RunPipline(encoder, this.dAshader, DaBind, Math.ceil(tokenCount / 16), Math.ceil(tokenCount / 16))
|
|
79
|
-
const
|
|
80
|
-
const dSBind = await this.gpu.createBindGroup(this.softmaxBackward, 0, [this.weights, dA, dS, this.asParams])
|
|
108
|
+
const dSBind = await this.gpu.createBindGroup(this.softmaxBackward, 0, [this.weights, this.dA, this.dS, this.asParams])
|
|
81
109
|
await this.gpu.RunPipline(encoder, this.softmaxBackward, dSBind, Math.ceil((tokenCount * tokenCount) / 256))
|
|
82
|
-
const
|
|
83
|
-
const dQbind = await this.gpu.createBindGroup(this.dQshader, 0, [dS, this.key, dQ, this.asParams]);
|
|
110
|
+
const dQbind = await this.gpu.createBindGroup(this.dQshader, 0, [this.dS, this.key.mainBuffer, this.dQ, this.asParams]);
|
|
84
111
|
await this.gpu.RunPipline(encoder, this.dQshader, dQbind, Math.ceil(tokenCount / 16), Math.ceil(this.embeddingSize / 16))
|
|
85
|
-
const
|
|
86
|
-
const dKbind = await this.gpu.createBindGroup(this.dKShader, 0, [dS, this.query, dK, this.asParams]);
|
|
112
|
+
const dKbind = await this.gpu.createBindGroup(this.dKShader, 0, [this.dS, this.query.mainBuffer, this.dK, this.asParams]);
|
|
87
113
|
await this.gpu.RunPipline(encoder, this.dKShader, dKbind, Math.ceil(tokenCount / 16), Math.ceil(this.embeddingSize / 16))
|
|
88
114
|
await this.gpu.submitQueue(encoder);
|
|
89
|
-
const dq = await this.q.backward(dQ, lr)
|
|
90
|
-
const dk = await this.k.backward(dK, lr)
|
|
91
|
-
const dv = await this.v.backward(dV, lr)
|
|
92
|
-
|
|
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)
|
|
118
|
+
if(!this.gradOut) this.gradOut = await this.gpu.ManageBuffer(tokenCount * this.embeddingSize * 4)
|
|
119
|
+
if(this.gradOut.size !== tokenCount * 4 * this.embeddingSize || this.gradOut.isDestroyed()){
|
|
120
|
+
this.gradOut.destroy()
|
|
121
|
+
this.gradOut = this.gpu.ManageBuffer(tokenCount * 4 * this.embeddingSize)
|
|
122
|
+
}
|
|
93
123
|
const encode = this.gpu.CreateEncoder()
|
|
94
|
-
const outputBind = await this.gpu.createBindGroup(this.sumShader, 0
|
|
124
|
+
const outputBind = await this.gpu.createBindGroup(this.sumShader, 0, [dq.mainBuffer, dk.mainBuffer, dv.mainBuffer, this.gradOut.mainBuffer, this.asParams]);
|
|
95
125
|
await this.gpu.RunPipline(encode, this.sumShader, outputBind, Math.ceil((tokenCount * this.embeddingSize / 256)));
|
|
96
126
|
await this.gpu.submitQueue(encode)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
dq.destroy()
|
|
100
|
-
dk.destroy()
|
|
101
|
-
dv.destroy()
|
|
102
|
-
dK.destroy()
|
|
103
|
-
dQ.destroy()
|
|
104
|
-
dV.destroy()
|
|
105
|
-
if(this.prevdO) await this.prevdO.destroy()
|
|
106
|
-
this.prevdO = dO
|
|
107
|
-
return output
|
|
108
|
-
|
|
127
|
+
return this.gradOut
|
|
128
|
+
|
|
109
129
|
}
|
|
110
|
-
async ClearInputCache(){
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
async ClearInputCache() {
|
|
131
|
+
await this.q.ClearInputCache()
|
|
132
|
+
await this.k.ClearInputCache()
|
|
133
|
+
await this.v.ClearInputCache()
|
|
114
134
|
}
|
|
115
|
-
async Save(){
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
async Save() {
|
|
136
|
+
await this.q.Save()
|
|
137
|
+
await this.k.Save()
|
|
138
|
+
await this.v.Save()
|
|
119
139
|
}
|
|
120
140
|
}
|
package/src/Softmax/index.d.ts
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
export class Softmax{
|
|
1
|
+
export class Softmax {
|
|
2
2
|
constructor(device: GPUAdapter, embeddingSize: number, vocabSize: number);
|
|
3
|
-
async forward(logit:
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
async forward(logit: {
|
|
4
|
+
read: function(): Promise<Float32Array>,
|
|
5
|
+
mainBuffer: GPUBuffer,
|
|
6
|
+
isDestroyed: function(): Boolean,
|
|
7
|
+
destroy: function(): void
|
|
8
|
+
}, isCpuReadBack): Promise<{
|
|
9
|
+
read: function(): Promise<Float32Array>,
|
|
10
|
+
mainBuffer: GPUBuffer,
|
|
11
|
+
isDestroyed: function(): Boolean,
|
|
12
|
+
destroy: function(): void
|
|
13
|
+
}>;
|
|
14
|
+
async backward(probs: {
|
|
15
|
+
read: function(): Promise<Float32Array>,
|
|
16
|
+
mainBuffer: GPUBuffer,
|
|
17
|
+
isDestroyed: function(): Boolean,
|
|
18
|
+
destroy: function(): void
|
|
19
|
+
}, target: number[]): Promise<{
|
|
20
|
+
read: function(): Promise<Float32Array>,
|
|
21
|
+
mainBuffer: GPUBuffer,
|
|
22
|
+
isDestroyed: function(): Boolean,
|
|
23
|
+
destroy: function(): void
|
|
24
|
+
}>
|
|
25
|
+
async crossEntropy(probs: GPUBuffer, target: number[]): Promise<{ loss: Float32Array, acc: Float32Array }>
|
|
6
26
|
}
|
package/src/Softmax/index.js
CHANGED
|
@@ -33,20 +33,24 @@ export class Softmax {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
if (this.oldParam[1] !== tokenCount) { await this.gpu.WriteBuffer(this.paramsForward, new Uint32Array([this.vocabSize, tokenCount, 0])); this.oldParam = new Uint32Array([this.vocabSize, tokenCount, 0]); }
|
|
36
|
-
|
|
36
|
+
if (!this.output) this.output = await this.gpu.ManageBuffer(logits.size);
|
|
37
|
+
if (this.output.size !== 4 * tokenCount * this.vocabSize || this.output.isDestroyed()) {
|
|
38
|
+
this.output.destroy()
|
|
39
|
+
this.output = await this.gpu.ManageBuffer(logits.size)
|
|
40
|
+
}
|
|
37
41
|
const bind = await this.device.createBindGroup({
|
|
38
42
|
layout: await this.forwardPipline.getBindGroupLayout(0),
|
|
39
43
|
entries: [
|
|
40
44
|
{
|
|
41
45
|
binding: 0,
|
|
42
46
|
resource: {
|
|
43
|
-
buffer: logits
|
|
47
|
+
buffer: logits.mainBuffer
|
|
44
48
|
}
|
|
45
49
|
},
|
|
46
50
|
{
|
|
47
51
|
binding: 1,
|
|
48
52
|
resource: {
|
|
49
|
-
buffer: output
|
|
53
|
+
buffer: this.output.mainBuffer
|
|
50
54
|
}
|
|
51
55
|
}, {
|
|
52
56
|
binding: 2,
|
|
@@ -61,12 +65,7 @@ export class Softmax {
|
|
|
61
65
|
await this.device.queue.submit([encoder.finish()])
|
|
62
66
|
logits.destroy()
|
|
63
67
|
}
|
|
64
|
-
|
|
65
|
-
const outputCPU = await this.gpu.readBuffer(output.size, output);
|
|
66
|
-
logits.destroy()
|
|
67
|
-
return outputCPU
|
|
68
|
-
}
|
|
69
|
-
return output
|
|
68
|
+
return this.output
|
|
70
69
|
}
|
|
71
70
|
async backward(probs, target) {
|
|
72
71
|
const encoder = this.device.createCommandEncoder()
|
|
@@ -81,27 +80,24 @@ export class Softmax {
|
|
|
81
80
|
await this.gpu.WriteBuffer(this.paramsForward, new Uint32Array([this.vocabSize, tokenCount, 0]));
|
|
82
81
|
this.oldParam = new Uint32Array([this.vocabSize, tokenCount, 0]);
|
|
83
82
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
if (!this.targetBuffer) this.targetBuffer = await this.gpu.createBuffer(target.length * Float32Array.BYTES_PER_ELEMENT);
|
|
84
|
+
if (this.targetBuffer.size !== target.length * 4) {
|
|
85
|
+
this.targetBuffer.destroy()
|
|
86
|
+
this.targetBuffer = await this.gpu.createBuffer(target.length * Float32Array.BYTES_PER_ELEMENT)
|
|
87
|
+
}
|
|
88
|
+
await this.gpu.WriteBuffer(this.targetBuffer, new Float32Array(target))
|
|
87
89
|
const bind = await this.device.createBindGroup({
|
|
88
90
|
layout: await this.backwardPipline.getBindGroupLayout(0),
|
|
89
91
|
entries: [
|
|
90
92
|
{
|
|
91
93
|
binding: 0,
|
|
92
94
|
resource: {
|
|
93
|
-
buffer: probs
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
binding: 1,
|
|
98
|
-
resource: {
|
|
99
|
-
buffer: output
|
|
95
|
+
buffer: probs.mainBuffer
|
|
100
96
|
}
|
|
101
97
|
}, {
|
|
102
98
|
binding: 2,
|
|
103
99
|
resource: {
|
|
104
|
-
buffer: targetBuffer
|
|
100
|
+
buffer: this.targetBuffer
|
|
105
101
|
}
|
|
106
102
|
}, {
|
|
107
103
|
binding: 3,
|
|
@@ -113,9 +109,7 @@ export class Softmax {
|
|
|
113
109
|
})
|
|
114
110
|
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, tokenCount)
|
|
115
111
|
this.device.queue.submit([encoder.finish()])
|
|
116
|
-
probs
|
|
117
|
-
targetBuffer.destroy()
|
|
118
|
-
return output
|
|
112
|
+
return probs
|
|
119
113
|
}
|
|
120
114
|
async crossEntropy(probs, target) {
|
|
121
115
|
const encoder = this.device.createCommandEncoder()
|
|
@@ -131,7 +125,7 @@ export class Softmax {
|
|
|
131
125
|
{
|
|
132
126
|
binding: 0,
|
|
133
127
|
resource: {
|
|
134
|
-
buffer: probs
|
|
128
|
+
buffer: probs.mainBuffer
|
|
135
129
|
}
|
|
136
130
|
},
|
|
137
131
|
{
|
|
@@ -169,7 +163,7 @@ export class Softmax {
|
|
|
169
163
|
{
|
|
170
164
|
binding: 1,
|
|
171
165
|
resource: {
|
|
172
|
-
buffer: probs
|
|
166
|
+
buffer: probs.mainBuffer
|
|
173
167
|
}
|
|
174
168
|
}, {
|
|
175
169
|
binding: 3,
|
|
@@ -192,6 +186,7 @@ export class Softmax {
|
|
|
192
186
|
const lossCpu = await this.gpu.readBuffer(outputLoss.size, outputLoss)
|
|
193
187
|
const accCPU = await this.gpu.readBuffer(acc.size, acc)
|
|
194
188
|
acc.destroy()
|
|
189
|
+
outputLoss.destroy()
|
|
195
190
|
return { loss: lossCpu[0], acc: accCPU[0] }
|
|
196
191
|
}
|
|
197
192
|
|
|
@@ -43,32 +43,18 @@ export class TransformerBlock {
|
|
|
43
43
|
async forward(input) {
|
|
44
44
|
const count = input.size / 4;
|
|
45
45
|
const norm1 = await this.rmsnorm.forward(input);
|
|
46
|
-
const att = await this.attention.forward(norm1)
|
|
47
|
-
const
|
|
48
|
-
const norm2 = await this.rmsnorm2.forward(
|
|
49
|
-
|
|
50
|
-
const y = await this.gpu.add(h, f, count);
|
|
51
|
-
norm1.destroy();
|
|
52
|
-
att.destroy();
|
|
53
|
-
f.destroy();
|
|
54
|
-
return y;
|
|
46
|
+
const att = await this.attention.forward(norm1)
|
|
47
|
+
const f = await this.ffn.forward(att)
|
|
48
|
+
const norm2 = await this.rmsnorm2.forward(f)
|
|
49
|
+
return norm2;
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
async backward(outGradient, lr) {
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const dInputFromAttention = await this.rmsnorm.backward(dNorm1, lr);
|
|
64
|
-
const dInput = await this.gpu.add(dH, dInputFromAttention, count);
|
|
65
|
-
dNorm2.destroy();
|
|
66
|
-
dHFromFFN.destroy();
|
|
67
|
-
dH.destroy();
|
|
68
|
-
dNorm1.destroy();
|
|
69
|
-
dInputFromAttention.destroy();
|
|
70
|
-
dInputFromAttention.destroy();
|
|
71
|
-
return dInput;
|
|
53
|
+
const dNorm2 = await this.rmsnorm2.backward(outGradient, lr)
|
|
54
|
+
const dAtt = await this.ffn.backward(dNorm2, lr);
|
|
55
|
+
const dFF = await this.attention.backward(dAtt, lr)
|
|
56
|
+
const dNorm = await this.rmsnorm.backward(dFF, lr)
|
|
57
|
+
return dNorm;
|
|
72
58
|
}
|
|
73
59
|
|
|
74
60
|
async ClearInputCache() {
|
package/src/shaders/LB.wgsl
CHANGED
|
@@ -44,14 +44,14 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
44
44
|
let dW = inputValue * gradient;
|
|
45
45
|
dWeights += dW;
|
|
46
46
|
}
|
|
47
|
-
let vClap = weight[index] - params.lr * clamp(dWeights, -
|
|
47
|
+
let vClap = weight[index] - params.lr * clamp(dWeights, -8.0, 8.0);
|
|
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
52
|
dBias += outGradient[token * u32(params.vocabSize) + outputIndex];
|
|
53
53
|
}
|
|
54
|
-
bias[outputIndex] = bias[outputIndex] - params.lr * clamp(dBias, -
|
|
54
|
+
bias[outputIndex] = bias[outputIndex] - params.lr * clamp(dBias, -8.0, 8.0);
|
|
55
55
|
|
|
56
56
|
}
|
|
57
57
|
}
|
package/src/shaders/PF.wgsl
CHANGED
|
@@ -3,11 +3,9 @@ var <storage, read> posVec: array<f32>;
|
|
|
3
3
|
|
|
4
4
|
@group(0) @binding(1)
|
|
5
5
|
|
|
6
|
-
var <storage,
|
|
6
|
+
var <storage, read_write> vecs : array<f32>;
|
|
7
7
|
|
|
8
|
-
@group(0) @binding(2)
|
|
9
8
|
|
|
10
|
-
var <storage, read_write> output: array<f32>;
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
@compute @workgroup_size(64)
|
|
@@ -17,5 +15,5 @@ fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
|
17
15
|
if(x >= arrayLength(&vecs)){
|
|
18
16
|
return;
|
|
19
17
|
}
|
|
20
|
-
|
|
18
|
+
vecs[x] = vecs[x] + posVec[x];
|
|
21
19
|
}
|
package/src/shaders/RB.wgsl
CHANGED
package/src/shaders/RF.wgsl
CHANGED
package/src/shaders/SB.wgsl
CHANGED
|
@@ -5,11 +5,8 @@ struct Params {
|
|
|
5
5
|
|
|
6
6
|
@group(0) @binding(0)
|
|
7
7
|
|
|
8
|
-
var<storage,
|
|
8
|
+
var<storage, read_write> probs: array<f32>;
|
|
9
9
|
|
|
10
|
-
@group(0) @binding(1)
|
|
11
|
-
|
|
12
|
-
var<storage, read_write> output: array<f32>;
|
|
13
10
|
|
|
14
11
|
@group(0) @binding(2)
|
|
15
12
|
|
|
@@ -32,8 +29,8 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
32
29
|
return;
|
|
33
30
|
}
|
|
34
31
|
var targetIndex = targetToken[token];
|
|
35
|
-
|
|
32
|
+
probs[index] = probs[index];
|
|
36
33
|
if(vocabIndex == u32(targetIndex)){
|
|
37
|
-
|
|
34
|
+
probs[index] -= 1;
|
|
38
35
|
}
|
|
39
36
|
}
|
package/src/Model/index.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}
|
package/src/Model/index.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
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
|
-
}
|