@mineproness/tensorloop 2.1.69 → 2.1.70
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/RMSNorm/index.d.ts +6 -1
- package/src/RMSNorm/index.js +47 -8
- package/src/TransformerBlock/index.js +15 -4
- package/src/shaders/Norm/rmsBackward.wgsl +17 -10
- package/src/shaders/Norm/rmsForward.wgsl +20 -9
- package/src/shaders/Norm/sumSquare.wgsl +10 -12
- package/src/shaders/Norm/updateGamma.wgsl +61 -0
package/package.json
CHANGED
package/src/RMSNorm/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export class RMSNorm{
|
|
2
|
-
constructor(device : GPUAdapter, embeddingSize : number
|
|
2
|
+
constructor(device : GPUAdapter, embeddingSize : number , {
|
|
3
|
+
save:{
|
|
4
|
+
filename: string
|
|
5
|
+
}
|
|
6
|
+
});
|
|
3
7
|
async forward(input : GPUBuffer) : Promise<GPUBuffer>
|
|
4
8
|
async backward(outputGradient : GPUBuffer) : Promise<GPUBuffer>
|
|
9
|
+
async Save() : Promise<void>
|
|
5
10
|
}
|
package/src/RMSNorm/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OperationManager } from '../OperationManager.js'
|
|
2
2
|
import fs from 'fs'
|
|
3
|
+
import { SaveVector, getVector } from '../getVec.js'
|
|
3
4
|
|
|
4
5
|
export class RMSNorm {
|
|
5
6
|
embeddingSize;
|
|
@@ -7,20 +8,49 @@ export class RMSNorm {
|
|
|
7
8
|
forwardShader;
|
|
8
9
|
backwardShader;
|
|
9
10
|
op;
|
|
10
|
-
|
|
11
|
+
gamma;
|
|
12
|
+
gammabuffer;
|
|
13
|
+
configs;
|
|
14
|
+
constructor(device, embeddingSize, configs) {
|
|
15
|
+
this.configs = configs
|
|
11
16
|
this.op = new OperationManager(device);
|
|
12
17
|
this.embeddingSize = embeddingSize;
|
|
13
|
-
this.reductionShader = this.op.getShaderPipline("./src/shaders/Norm/sumSquare.wgsl"
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
this.reductionShader = this.op.getShaderPipline("./src/shaders/Norm/sumSquare.wgsl", {
|
|
19
|
+
embeddingSize: embeddingSize,
|
|
20
|
+
})
|
|
21
|
+
this.forwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsForward.wgsl", {
|
|
22
|
+
embeddingSize: embeddingSize
|
|
23
|
+
})
|
|
24
|
+
this.backwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsBackward.wgsl", {
|
|
25
|
+
embeddingSize: embeddingSize
|
|
26
|
+
})
|
|
27
|
+
this.updateGamma = this.op.getShaderPipline("./src/shaders/Norm/updateGamma.wgsl", {
|
|
28
|
+
embeddingSize: embeddingSize
|
|
29
|
+
})
|
|
30
|
+
if (configs) {
|
|
31
|
+
const ga = getVector(configs.save.filename, embeddingSize);
|
|
32
|
+
if (!ga) {
|
|
33
|
+
this.gamma = new Float32Array(embeddingSize).fill(1);
|
|
34
|
+
SaveVector(configs.save.filename, this.gamma)
|
|
35
|
+
} else {
|
|
36
|
+
this.gamma = ga
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
this.gamma = new Float32Array(embeddingSize).fill(1)
|
|
40
|
+
}
|
|
16
41
|
}
|
|
17
42
|
async forward(input) {
|
|
18
|
-
|
|
43
|
+
if (!this.gammabuffer) {
|
|
44
|
+
this.gammabuffer = await this.op.createBuffer(4 * this.embeddingSize);
|
|
45
|
+
await this.op.WriteBuffer(this.gammabuffer, this.gamma);
|
|
46
|
+
}
|
|
47
|
+
let context = input.size / (this.embeddingSize * 4)
|
|
48
|
+
const outputReduce = await this.op.createBuffer(4 * context);
|
|
19
49
|
const output = await this.op.createBuffer(input.size);
|
|
20
50
|
const bindGroup = await this.op.createBindGroup(this.reductionShader, 0, [input, outputReduce])
|
|
21
51
|
const encoder = await this.op.CreateEncoder()
|
|
22
52
|
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])
|
|
53
|
+
const bindGroup1 = await this.op.createBindGroup(this.forwardShader, 0, [outputReduce, input, output, this.gammabuffer])
|
|
24
54
|
await this.op.RunPipline(encoder, this.forwardShader, bindGroup1, Math.ceil((input.size / 4) / 64));
|
|
25
55
|
await this.op.submitQueue(encoder);
|
|
26
56
|
if (this.rms) this.rms.destroy()
|
|
@@ -31,15 +61,24 @@ export class RMSNorm {
|
|
|
31
61
|
this.outputPre = output
|
|
32
62
|
return output
|
|
33
63
|
}
|
|
34
|
-
async backward(outputGradient) {
|
|
64
|
+
async backward(outputGradient, lr) {
|
|
35
65
|
const output = await this.op.createBuffer(outputGradient.size);
|
|
36
|
-
|
|
66
|
+
let params = await this.op.createBuffer(4 * 2)
|
|
67
|
+
await this.op.WriteBuffer(params, new Float32Array([lr, 0]))
|
|
68
|
+
const bindGroup = await this.op.createBindGroup(this.backwardShader, 0, [this.input, outputGradient, this.rms, this.gammabuffer, output]);
|
|
69
|
+
const bindGroup2 = await this.op.createBindGroup(this.updateGamma, 0, [this.input, outputGradient, this.rms, this.gammabuffer, params]);
|
|
37
70
|
const encoder = await this.op.CreateEncoder()
|
|
38
71
|
await this.op.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((this.input.size / 4) / 64))
|
|
72
|
+
await this.op.RunPipline(encoder, this.updateGamma, bindGroup2, this.embeddingSize)
|
|
39
73
|
await this.op.submitQueue(encoder)
|
|
40
74
|
if (this.prevOut) this.prevOut.destroy()
|
|
41
75
|
this.prevOut = outputGradient
|
|
76
|
+
params.destroy()
|
|
42
77
|
return output
|
|
43
78
|
}
|
|
79
|
+
async Save(){
|
|
80
|
+
const read = await this.op.readBuffer(4 * this.embeddingSize, this.gammabuffer);
|
|
81
|
+
SaveVector(this.configs.save.filename, read)
|
|
82
|
+
}
|
|
44
83
|
|
|
45
84
|
}
|
|
@@ -4,6 +4,7 @@ import { FFN } from '../FFN/index.js';
|
|
|
4
4
|
import { existsSync, mkdirSync } from 'fs';
|
|
5
5
|
import { RMSNorm } from '../../index.js';
|
|
6
6
|
import { OperationManager } from '../OperationManager.js';
|
|
7
|
+
import { join } from 'path';
|
|
7
8
|
|
|
8
9
|
export class TransformerBlock {
|
|
9
10
|
attention;
|
|
@@ -16,8 +17,16 @@ export class TransformerBlock {
|
|
|
16
17
|
constructor(device, embeddingSize, configs) {
|
|
17
18
|
this.size = embeddingSize;
|
|
18
19
|
|
|
19
|
-
this.rmsnorm = new RMSNorm(device, embeddingSize
|
|
20
|
-
|
|
20
|
+
this.rmsnorm = new RMSNorm(device, embeddingSize, {
|
|
21
|
+
save: {
|
|
22
|
+
filename: join(configs.dirname, "LAYERNORM-1.bin")
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
this.rmsnorm2 = new RMSNorm(device, embeddingSize, {
|
|
26
|
+
save: {
|
|
27
|
+
filename: join(configs.dirname, "LAYERNORM-2.bin")
|
|
28
|
+
}
|
|
29
|
+
});
|
|
21
30
|
|
|
22
31
|
if (!existsSync(configs.dirname)) {
|
|
23
32
|
mkdirSync(configs.dirname, { recursive: true });
|
|
@@ -48,10 +57,10 @@ export class TransformerBlock {
|
|
|
48
57
|
async backward(outGradient, lr) {
|
|
49
58
|
const count = outGradient.size / 4;
|
|
50
59
|
const dNorm2 = await this.ffn.backward(outGradient, lr);
|
|
51
|
-
const dHFromFFN = await this.rmsnorm2.backward(dNorm2);
|
|
60
|
+
const dHFromFFN = await this.rmsnorm2.backward(dNorm2 , lr);
|
|
52
61
|
const dH = await this.gpu.add(outGradient, dHFromFFN, count);
|
|
53
62
|
const dNorm1 = await this.attention.backward(dH, lr);
|
|
54
|
-
const dInputFromAttention = await this.rmsnorm.backward(dNorm1);
|
|
63
|
+
const dInputFromAttention = await this.rmsnorm.backward(dNorm1, lr);
|
|
55
64
|
const dInput = await this.gpu.add(dH, dInputFromAttention, count);
|
|
56
65
|
dNorm2.destroy();
|
|
57
66
|
dHFromFFN.destroy();
|
|
@@ -70,5 +79,7 @@ export class TransformerBlock {
|
|
|
70
79
|
async Save() {
|
|
71
80
|
await this.ffn.Save();
|
|
72
81
|
await this.attention.Save();
|
|
82
|
+
await tthis.rmsnorm.Save()
|
|
83
|
+
await this.rmsnorm2.Save()
|
|
73
84
|
}
|
|
74
85
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
@group(0) @binding(0)
|
|
3
2
|
var<storage, read> input: array<f32>;
|
|
4
3
|
|
|
@@ -9,16 +8,25 @@ var<storage, read> gradOutput: array<f32>;
|
|
|
9
8
|
var<storage, read> rms: array<f32>;
|
|
10
9
|
|
|
11
10
|
@group(0) @binding(3)
|
|
11
|
+
var<storage, read> gamma: array<f32>;
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(4)
|
|
12
14
|
var<storage, read_write> gradInput: array<f32>;
|
|
13
15
|
|
|
14
|
-
var<workgroup> partial: array<f32,
|
|
16
|
+
var<workgroup> partial: array<f32, %embeddingSize%>;
|
|
15
17
|
|
|
16
|
-
@compute @workgroup_size(
|
|
17
|
-
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
18
|
-
let D =
|
|
19
|
-
|
|
18
|
+
@compute @workgroup_size(%embeddingSize%)
|
|
19
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
20
|
+
let D = %embeddingSize%u;
|
|
21
|
+
let token = wid.x;
|
|
22
|
+
let idx = token * D + lid;
|
|
23
|
+
let x = input[idx];
|
|
24
|
+
let dy = gradOutput[idx];
|
|
25
|
+
let g = gamma[lid];
|
|
26
|
+
let r = rms[token];
|
|
27
|
+
partial[lid] = dy * g * x;
|
|
20
28
|
workgroupBarrier();
|
|
21
|
-
var stride =
|
|
29
|
+
var stride = D / 2u;
|
|
22
30
|
loop {
|
|
23
31
|
if (stride == 0u) {
|
|
24
32
|
break;
|
|
@@ -27,9 +35,8 @@ fn main(@builtin(local_invocation_index) lid: u32) {
|
|
|
27
35
|
partial[lid] += partial[lid + stride];
|
|
28
36
|
}
|
|
29
37
|
workgroupBarrier();
|
|
30
|
-
stride
|
|
38
|
+
stride /= 2u;
|
|
31
39
|
}
|
|
32
40
|
let dot = partial[0];
|
|
33
|
-
|
|
34
|
-
gradInput[lid] = gradOutput[lid] / r - input[lid] * dot / (f32(D) * r * r * r);
|
|
41
|
+
gradInput[idx] = (dy * g) / r - x * dot / (f32(D) * r * r * r);
|
|
35
42
|
}
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
@group(0) @binding(0)
|
|
2
|
-
|
|
3
|
-
var <storage, read> reduce: array<f32>;
|
|
2
|
+
var<storage, read> reduce: array<f32>;
|
|
4
3
|
|
|
5
4
|
@group(0) @binding(1)
|
|
6
|
-
|
|
7
|
-
var <storage, read> vector: array<f32>;
|
|
5
|
+
var<storage, read> vector: array<f32>;
|
|
8
6
|
|
|
9
7
|
@group(0) @binding(2)
|
|
8
|
+
var<storage, read_write> output: array<f32>;
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
@group(0) @binding(3)
|
|
11
|
+
var<storage, read> gamma: array<f32>;
|
|
12
12
|
|
|
13
13
|
@compute @workgroup_size(64)
|
|
14
|
-
|
|
15
|
-
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
14
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
16
15
|
let x = id.x;
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
if (x >= arrayLength(&vector)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let dim = %embeddingSize%u;
|
|
22
|
+
let token = x / dim;
|
|
23
|
+
let d = x % dim;
|
|
24
|
+
|
|
25
|
+
let rms = sqrt(
|
|
26
|
+
reduce[token] / f32(dim) + 1e-6
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
output[x] = (vector[x] / rms) * gamma[d];
|
|
19
30
|
}
|
|
@@ -1,37 +1,35 @@
|
|
|
1
|
-
|
|
2
1
|
@group(0) @binding(0)
|
|
3
2
|
var<storage, read> input: array<f32>;
|
|
4
3
|
|
|
5
4
|
@group(0) @binding(1)
|
|
6
5
|
var<storage, read_write> out: array<f32>;
|
|
7
6
|
|
|
8
|
-
var<workgroup> partial: array<f32, 64>;
|
|
9
7
|
|
|
8
|
+
var<workgroup> partial: array<f32, %embeddingSize%>;
|
|
9
|
+
|
|
10
|
+
const embeddingSize : u32 = %embeddingSize%u;
|
|
10
11
|
@compute @workgroup_size(64)
|
|
11
|
-
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
12
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
13
|
+
let dim = embeddingSize;
|
|
14
|
+
let index = wid.x * dim + lid;
|
|
12
15
|
var sum = 0.0;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
sum += input[i] * input[i];
|
|
16
|
-
i += 64u;
|
|
16
|
+
if (lid < dim && index < arrayLength(&input)) {
|
|
17
|
+
sum = input[index] * input[index];
|
|
17
18
|
}
|
|
18
19
|
partial[lid] = sum;
|
|
19
20
|
workgroupBarrier();
|
|
20
21
|
var stride = 32u;
|
|
21
|
-
|
|
22
22
|
loop {
|
|
23
23
|
if (stride == 0u) {
|
|
24
24
|
break;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
26
|
if (lid < stride) {
|
|
28
27
|
partial[lid] += partial[lid + stride];
|
|
29
28
|
}
|
|
30
|
-
|
|
31
29
|
workgroupBarrier();
|
|
32
|
-
stride
|
|
30
|
+
stride /= 2u;
|
|
33
31
|
}
|
|
34
32
|
if (lid == 0u) {
|
|
35
|
-
out[
|
|
33
|
+
out[wid.x] = partial[0];
|
|
36
34
|
}
|
|
37
35
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
var<storage, read> input: array<f32>;
|
|
3
|
+
|
|
4
|
+
@group(0) @binding(1)
|
|
5
|
+
var<storage, read> gradOutput: array<f32>;
|
|
6
|
+
|
|
7
|
+
@group(0) @binding(2)
|
|
8
|
+
var<storage, read> rms: array<f32>;
|
|
9
|
+
|
|
10
|
+
@group(0) @binding(3)
|
|
11
|
+
var<storage, read_write> gamma: array<f32>;
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(4)
|
|
14
|
+
var<storage, read> params: array<f32>;
|
|
15
|
+
|
|
16
|
+
var<workgroup> partial: array<f32, %embeddingSize%>;
|
|
17
|
+
|
|
18
|
+
@compute @workgroup_size(64)
|
|
19
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
20
|
+
let D = %embeddingSize%u;
|
|
21
|
+
let dim = wid.x;
|
|
22
|
+
|
|
23
|
+
if (dim >= D) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let T = arrayLength(&rms);
|
|
28
|
+
let lr = params[0];
|
|
29
|
+
|
|
30
|
+
var sum = 0.0;
|
|
31
|
+
var token = lid;
|
|
32
|
+
|
|
33
|
+
while (token < T) {
|
|
34
|
+
let idx = token * D + dim;
|
|
35
|
+
|
|
36
|
+
sum += gradOutput[idx] * input[idx] / rms[token];
|
|
37
|
+
|
|
38
|
+
token += 64u;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
partial[lid] = sum;
|
|
42
|
+
workgroupBarrier();
|
|
43
|
+
|
|
44
|
+
var stride = 32u;
|
|
45
|
+
loop {
|
|
46
|
+
if (stride == 0u) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (lid < stride) {
|
|
51
|
+
partial[lid] += partial[lid + stride];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
workgroupBarrier();
|
|
55
|
+
stride /= 2u;
|
|
56
|
+
}
|
|
57
|
+
if (lid == 0u) {
|
|
58
|
+
let gradGamma = partial[0];
|
|
59
|
+
gamma[dim] -= lr * gradGamma;
|
|
60
|
+
}
|
|
61
|
+
}
|