@mineproness/tensorloop 2.1.68 → 2.1.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +3 -1
- package/package.json +1 -1
- package/src/Model/index.js +2 -1
- package/src/RMSNorm/index.d.ts +5 -0
- package/src/RMSNorm/index.js +45 -0
- package/src/TransformerBlock/index.js +63 -36
- package/src/shaders/LB.wgsl +2 -2
- package/src/shaders/Norm/rmsBackward.wgsl +35 -0
- package/src/shaders/Norm/rmsForward.wgsl +19 -0
- package/src/shaders/Norm/sumSquare.wgsl +37 -0
package/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 { Model as m } from "./src/Model/index.js";
|
|
10
10
|
import {PositionEmbedding as PM } from './src/PositionEmbedding/index.js'
|
|
11
|
+
import { RMSNorm as RM } from "./src/RMSNorm/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 Model = m;
|
|
20
|
-
export const PositionEmbedding = PM;
|
|
21
|
+
export const PositionEmbedding = PM;
|
|
22
|
+
export const RMSNorm = RM
|
package/package.json
CHANGED
package/src/Model/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Embedding, Linear, Softmax, TransformerBlock, Tokenizer, PositionEmbedding } from '../../index.js'
|
|
1
|
+
import { Embedding, Linear, Softmax, TransformerBlock, Tokenizer, PositionEmbedding, RMSNorm } from '../../index.js'
|
|
2
2
|
import { join } from 'path'
|
|
3
3
|
import fs from 'fs'
|
|
4
4
|
import { OperationManager } from '../OperationManager.js'
|
|
@@ -16,6 +16,7 @@ export class Model {
|
|
|
16
16
|
tokenizerName;
|
|
17
17
|
op;
|
|
18
18
|
tokens;
|
|
19
|
+
rmsnorm
|
|
19
20
|
constructor(device, embeddingSize = 64, configs) {
|
|
20
21
|
this.device = device;
|
|
21
22
|
this.dimSize = embeddingSize;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OperationManager } from '../OperationManager.js'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
|
|
4
|
+
export class RMSNorm {
|
|
5
|
+
embeddingSize;
|
|
6
|
+
reductionShader;
|
|
7
|
+
forwardShader;
|
|
8
|
+
backwardShader;
|
|
9
|
+
op;
|
|
10
|
+
constructor(device, embeddingSize) {
|
|
11
|
+
this.op = new OperationManager(device);
|
|
12
|
+
this.embeddingSize = embeddingSize;
|
|
13
|
+
this.reductionShader = this.op.getShaderPipline("./src/shaders/Norm/sumSquare.wgsl")
|
|
14
|
+
this.forwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsForward.wgsl")
|
|
15
|
+
this.backwardShader = this.op.getShaderPipline("./src/shaders/Norm/rmsBackward.wgsl")
|
|
16
|
+
}
|
|
17
|
+
async forward(input) {
|
|
18
|
+
const outputReduce = await this.op.createBuffer(4 * 1);
|
|
19
|
+
const output = await this.op.createBuffer(input.size);
|
|
20
|
+
const bindGroup = await this.op.createBindGroup(this.reductionShader, 0, [input, outputReduce])
|
|
21
|
+
const encoder = await this.op.CreateEncoder()
|
|
22
|
+
await this.op.RunPipline(encoder, this.reductionShader, bindGroup, Math.ceil((input.size / 4) / 64))
|
|
23
|
+
const bindGroup1 = await this.op.createBindGroup(this.forwardShader, 0, [outputReduce, input, output])
|
|
24
|
+
await this.op.RunPipline(encoder, this.forwardShader, bindGroup1, Math.ceil((input.size / 4) / 64));
|
|
25
|
+
await this.op.submitQueue(encoder);
|
|
26
|
+
if (this.rms) this.rms.destroy()
|
|
27
|
+
this.rms = outputReduce
|
|
28
|
+
if (this.input) this.input.destroy()
|
|
29
|
+
this.input = input;
|
|
30
|
+
if (this.outputPre) this.outputPre.destroy()
|
|
31
|
+
this.outputPre = output
|
|
32
|
+
return output
|
|
33
|
+
}
|
|
34
|
+
async backward(outputGradient) {
|
|
35
|
+
const output = await this.op.createBuffer(outputGradient.size);
|
|
36
|
+
const bindGroup = await this.op.createBindGroup(this.backwardShader, 0, [this.input, outputGradient, this.rms, output]);
|
|
37
|
+
const encoder = await this.op.CreateEncoder()
|
|
38
|
+
await this.op.RunPipline(encoder, this.backwardShader, bindGroup, Math.ceil((this.input.size / 4) / 64))
|
|
39
|
+
await this.op.submitQueue(encoder)
|
|
40
|
+
if (this.prevOut) this.prevOut.destroy()
|
|
41
|
+
this.prevOut = outputGradient
|
|
42
|
+
return output
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
@@ -1,47 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
|
|
2
|
+
import { SelfAttention } from '../SelfAttention/index.js';
|
|
3
|
+
import { FFN } from '../FFN/index.js';
|
|
4
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
5
|
+
import { RMSNorm } from '../../index.js';
|
|
6
|
+
import { OperationManager } from '../OperationManager.js';
|
|
7
|
+
|
|
8
|
+
export class TransformerBlock {
|
|
6
9
|
attention;
|
|
7
10
|
ffn;
|
|
8
11
|
gpu;
|
|
9
12
|
size;
|
|
10
|
-
|
|
13
|
+
rmsnorm;
|
|
14
|
+
rmsnorm2;
|
|
15
|
+
|
|
16
|
+
constructor(device, embeddingSize, configs) {
|
|
11
17
|
this.size = embeddingSize;
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
|
|
18
|
+
|
|
19
|
+
this.rmsnorm = new RMSNorm(device, embeddingSize);
|
|
20
|
+
this.rmsnorm2 = new RMSNorm(device, embeddingSize);
|
|
21
|
+
|
|
22
|
+
if (!existsSync(configs.dirname)) {
|
|
23
|
+
mkdirSync(configs.dirname, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.attention = new SelfAttention(
|
|
27
|
+
device, embeddingSize, configs
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
this.ffn = new FFN(device, embeddingSize, configs);
|
|
31
|
+
this.gpu = new OperationManager(device);
|
|
16
32
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
|
|
34
|
+
async forward(input) {
|
|
35
|
+
const count = input.size / 4;
|
|
36
|
+
const norm1 = await this.rmsnorm.forward(input);
|
|
37
|
+
const att = await this.attention.forward(norm1);
|
|
38
|
+
const h = await this.gpu.add(input, att, count);
|
|
39
|
+
const norm2 = await this.rmsnorm2.forward(h);
|
|
40
|
+
const f = await this.ffn.forward(norm2);
|
|
41
|
+
const y = await this.gpu.add(h, f, count);
|
|
42
|
+
norm1.destroy();
|
|
43
|
+
att.destroy();
|
|
44
|
+
f.destroy();
|
|
45
|
+
return y;
|
|
26
46
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
|
|
48
|
+
async backward(outGradient, lr) {
|
|
49
|
+
const count = outGradient.size / 4;
|
|
50
|
+
const dNorm2 = await this.ffn.backward(outGradient, lr);
|
|
51
|
+
const dHFromFFN = await this.rmsnorm2.backward(dNorm2);
|
|
52
|
+
const dH = await this.gpu.add(outGradient, dHFromFFN, count);
|
|
53
|
+
const dNorm1 = await this.attention.backward(dH, lr);
|
|
54
|
+
const dInputFromAttention = await this.rmsnorm.backward(dNorm1);
|
|
55
|
+
const dInput = await this.gpu.add(dH, dInputFromAttention, count);
|
|
56
|
+
dNorm2.destroy();
|
|
57
|
+
dHFromFFN.destroy();
|
|
58
|
+
dH.destroy();
|
|
59
|
+
dNorm1.destroy();
|
|
60
|
+
dInputFromAttention.destroy();
|
|
61
|
+
dInputFromAttention.destroy();
|
|
62
|
+
return dInput;
|
|
38
63
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await this.
|
|
64
|
+
|
|
65
|
+
async ClearInputCache() {
|
|
66
|
+
await this.ffn.ClearInputCache();
|
|
67
|
+
await this.attention.ClearInputCache();
|
|
42
68
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await this.
|
|
69
|
+
|
|
70
|
+
async Save() {
|
|
71
|
+
await this.ffn.Save();
|
|
72
|
+
await this.attention.Save();
|
|
46
73
|
}
|
|
47
74
|
}
|
package/src/shaders/LB.wgsl
CHANGED
|
@@ -42,14 +42,14 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
|
42
42
|
let inputValue = input[token * u32(params.inputSize) + inputIndex];
|
|
43
43
|
let gradient = outGradient[token * u32(params.vocabSize) + outputIndex];
|
|
44
44
|
let dW = inputValue * gradient;
|
|
45
|
-
dWeights +=
|
|
45
|
+
dWeights += dW;
|
|
46
46
|
}
|
|
47
47
|
let vClap = weight[index] - params.lr * dWeights;
|
|
48
48
|
weight[index] = vClap;
|
|
49
49
|
if (inputIndex == 0u) {
|
|
50
50
|
var dBias = 0.0;
|
|
51
51
|
for (var token = 0u; token < u32(params.tokenCount); token++) {
|
|
52
|
-
dBias +=
|
|
52
|
+
dBias += outGradient[token * u32(params.vocabSize) + outputIndex];
|
|
53
53
|
}
|
|
54
54
|
bias[outputIndex] = bias[outputIndex] - params.lr * dBias;
|
|
55
55
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
@group(0) @binding(0)
|
|
3
|
+
var<storage, read> input: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
var<storage, read> gradOutput: array<f32>;
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(2)
|
|
9
|
+
var<storage, read> rms: array<f32>;
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(3)
|
|
12
|
+
var<storage, read_write> gradInput: array<f32>;
|
|
13
|
+
|
|
14
|
+
var<workgroup> partial: array<f32, 64>;
|
|
15
|
+
|
|
16
|
+
@compute @workgroup_size(64)
|
|
17
|
+
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
18
|
+
let D = arrayLength(&input);
|
|
19
|
+
partial[lid] = gradOutput[lid] * input[lid];
|
|
20
|
+
workgroupBarrier();
|
|
21
|
+
var stride = 32u;
|
|
22
|
+
loop {
|
|
23
|
+
if (stride == 0u) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
if (lid < stride) {
|
|
27
|
+
partial[lid] += partial[lid + stride];
|
|
28
|
+
}
|
|
29
|
+
workgroupBarrier();
|
|
30
|
+
stride = stride / 2u;
|
|
31
|
+
}
|
|
32
|
+
let dot = partial[0];
|
|
33
|
+
let r = rms[0];
|
|
34
|
+
gradInput[lid] = gradOutput[lid] / r - input[lid] * dot / (f32(D) * r * r * r);
|
|
35
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
|
|
3
|
+
var <storage, read> reduce: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
|
|
7
|
+
var <storage, read> vector: array<f32>;
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(2)
|
|
10
|
+
|
|
11
|
+
var <storage, read_write> output : array<f32>;
|
|
12
|
+
|
|
13
|
+
@compute @workgroup_size(64)
|
|
14
|
+
|
|
15
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
16
|
+
let x = id.x;
|
|
17
|
+
let rms = sqrt(reduce[0u] / f32(arrayLength(&vector)) + 1e-6);
|
|
18
|
+
output[x] = vector[x] / rms;
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
@group(0) @binding(0)
|
|
3
|
+
var<storage, read> input: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
var<storage, read_write> out: array<f32>;
|
|
7
|
+
|
|
8
|
+
var<workgroup> partial: array<f32, 64>;
|
|
9
|
+
|
|
10
|
+
@compute @workgroup_size(64)
|
|
11
|
+
fn main(@builtin(local_invocation_index) lid: u32) {
|
|
12
|
+
var sum = 0.0;
|
|
13
|
+
var i = lid;
|
|
14
|
+
while (i < arrayLength(&input)) {
|
|
15
|
+
sum += input[i] * input[i];
|
|
16
|
+
i += 64u;
|
|
17
|
+
}
|
|
18
|
+
partial[lid] = sum;
|
|
19
|
+
workgroupBarrier();
|
|
20
|
+
var stride = 32u;
|
|
21
|
+
|
|
22
|
+
loop {
|
|
23
|
+
if (stride == 0u) {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (lid < stride) {
|
|
28
|
+
partial[lid] += partial[lid + stride];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
workgroupBarrier();
|
|
32
|
+
stride = stride / 2u;
|
|
33
|
+
}
|
|
34
|
+
if (lid == 0u) {
|
|
35
|
+
out[0] = partial[0];
|
|
36
|
+
}
|
|
37
|
+
}
|