@imaduddin/fastbrain 0.0.0-stage → 1.0.0
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 +20 -0
- package/package.json +29 -6
- package/readme.md +959 -0
- package/src/Embedding/index.d.ts +21 -0
- package/src/Embedding/index.js +141 -0
- package/src/FFN/index.d.ts +23 -0
- package/src/FFN/index.js +45 -0
- package/src/Linear/index.d.ts +31 -0
- package/src/Linear/index.js +198 -0
- package/src/OperationManager.js +169 -0
- package/src/PositionEmbedding/index.d.ts +30 -0
- package/src/PositionEmbedding/index.js +65 -0
- package/src/RMSNorm/index.d.ts +30 -0
- package/src/RMSNorm/index.js +96 -0
- package/src/Relu/index.d.ts +25 -0
- package/src/Relu/index.js +110 -0
- package/src/SelfAttention/index.d.ts +28 -0
- package/src/SelfAttention/index.js +138 -0
- package/src/Softmax/index.d.ts +26 -0
- package/src/Softmax/index.js +225 -0
- package/src/Tokenizer/index.d.ts +12 -0
- package/src/Tokenizer/index.js +164 -0
- package/src/Tokenizer/vocabs.json +19618 -0
- package/src/TransformerBlock/index.d.ts +28 -0
- package/src/TransformerBlock/index.js +78 -0
- package/src/getVec.js +30 -0
- package/src/gpu.js +0 -0
- package/src/residualConnection/index.js +32 -0
- package/src/shaders/CalculateAcc.wgsl +50 -0
- package/src/shaders/CalculateLoss.wgsl +30 -0
- package/src/shaders/ComputeDInput.wgsl +32 -0
- package/src/shaders/EB.wgsl +33 -0
- package/src/shaders/EF.wgsl +25 -0
- package/src/shaders/LB.wgsl +75 -0
- package/src/shaders/LF.wgsl +60 -0
- package/src/shaders/Norm/rmsBackward.wgsl +65 -0
- package/src/shaders/Norm/rmsForward.wgsl +30 -0
- package/src/shaders/Norm/sumSquare.wgsl +38 -0
- package/src/shaders/Norm/updateGamma.wgsl +52 -0
- package/src/shaders/PB.wgsl +25 -0
- package/src/shaders/PF.wgsl +19 -0
- package/src/shaders/RB.wgsl +37 -0
- package/src/shaders/RF.wgsl +33 -0
- package/src/shaders/ReductionFunction.wgsl +28 -0
- package/src/shaders/SB.wgsl +36 -0
- package/src/shaders/SF.wgsl +75 -0
- package/src/shaders/SoftmaxBackward.wgsl +31 -0
- package/src/shaders/add.wgsl +30 -0
- package/src/shaders/attentionShader/CompueFinalForwardOutput.wgsl +29 -0
- package/src/shaders/attentionShader/ComputeDA.wgsl +30 -0
- package/src/shaders/attentionShader/ComputeDV.wgsl +37 -0
- package/src/shaders/attentionShader/ComputeK.wgsl +30 -0
- package/src/shaders/attentionShader/ComputedQ.wgsl +31 -0
- package/src/shaders/attentionShader/attentionSocres.wgsl +40 -0
- package/src/shaders/attentionShader/sumGradient.wgsl +24 -0
- package/src/shaders/calculateTotal.wgsl +26 -0
- package/README.md +0 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export class TransformerBlock{
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number, configs: {
|
|
3
|
+
dirname: string
|
|
4
|
+
})
|
|
5
|
+
async forward(input : {
|
|
6
|
+
read: function(): Promise<Float32Array>,
|
|
7
|
+
mainBuffer: GPUBuffer,
|
|
8
|
+
isDestroyed: function(): Boolean,
|
|
9
|
+
destroy: function(): void
|
|
10
|
+
}) : Promise<{
|
|
11
|
+
read: function(): Promise<Float32Array>,
|
|
12
|
+
mainBuffer: GPUBuffer,
|
|
13
|
+
isDestroyed: function(): Boolean,
|
|
14
|
+
destroy: function(): void
|
|
15
|
+
}>
|
|
16
|
+
async backward(outInput : {
|
|
17
|
+
read: function(): Promise<Float32Array>,
|
|
18
|
+
mainBuffer: GPUBuffer,
|
|
19
|
+
isDestroyed: function(): Boolean,
|
|
20
|
+
destroy: function(): void
|
|
21
|
+
}, lr : number) : Promise<{
|
|
22
|
+
read: function(): Promise<Float32Array>,
|
|
23
|
+
mainBuffer: GPUBuffer,
|
|
24
|
+
isDestroyed: function(): Boolean,
|
|
25
|
+
destroy: function(): void
|
|
26
|
+
}>
|
|
27
|
+
async Save() : Promise<void>
|
|
28
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
import path, { join } from 'path';
|
|
8
|
+
import { residualConnection } from '../residualConnection/index.js'
|
|
9
|
+
|
|
10
|
+
export class TransformerBlock {
|
|
11
|
+
attention;
|
|
12
|
+
ffn;
|
|
13
|
+
gpu;
|
|
14
|
+
size;
|
|
15
|
+
rmsnorm;
|
|
16
|
+
rmsnorm2;
|
|
17
|
+
|
|
18
|
+
constructor(device, embeddingSize, configs) {
|
|
19
|
+
this.size = embeddingSize;
|
|
20
|
+
if (!existsSync(configs.dirname)) {
|
|
21
|
+
mkdirSync(configs.dirname, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
this.rmsnorm = new RMSNorm(device, embeddingSize, {
|
|
24
|
+
save: {
|
|
25
|
+
filename: join(configs.dirname, "LAYERNORM-1.bin")
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
this.rmsnorm2 = new RMSNorm(device, embeddingSize, {
|
|
29
|
+
save: {
|
|
30
|
+
filename: join(configs.dirname, "LAYERNORM-2.bin")
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
this.attention = new SelfAttention(
|
|
36
|
+
device, embeddingSize, configs
|
|
37
|
+
);
|
|
38
|
+
this.rFor1 = new residualConnection(device)
|
|
39
|
+
this.rFor2 = new residualConnection(device)
|
|
40
|
+
this.rback1 = new residualConnection(device)
|
|
41
|
+
this.rback2 = new residualConnection(device)
|
|
42
|
+
this.ffn = new FFN(device, embeddingSize, configs);
|
|
43
|
+
this.gpu = new OperationManager(device);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async forward(input, encoderMain) {
|
|
47
|
+
const count = input.size / 4;
|
|
48
|
+
const norm1 = await this.rmsnorm.forward(input);
|
|
49
|
+
const att = await this.attention.forward(norm1, encoderMain)
|
|
50
|
+
const residual1 = await this.rFor1.add(att, input, encoderMain)
|
|
51
|
+
const norm2 = await this.rmsnorm2.forward(residual1)
|
|
52
|
+
const f = await this.ffn.forward(norm2, encoderMain)
|
|
53
|
+
const residual2 = await this.rFor2.add(f, residual1, encoderMain)
|
|
54
|
+
return residual2;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async backward(outGradient, lr, encoderMain) {
|
|
58
|
+
const dAtt = await this.ffn.backward(outGradient, lr, encoderMain);
|
|
59
|
+
const dNorm2 = await this.rmsnorm2.backward(dAtt, lr)
|
|
60
|
+
const dResidual1 = await this.rback2.add(outGradient, dNorm2, encoderMain)
|
|
61
|
+
const dFF = await this.attention.backward(dResidual1, lr, encoderMain)
|
|
62
|
+
const dNorm = await this.rmsnorm.backward(dFF, lr)
|
|
63
|
+
const dResidual2 = await this.rback1.add(dNorm, dResidual1, encoderMain)
|
|
64
|
+
return dResidual2;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async ClearInputCache() {
|
|
68
|
+
await this.ffn.ClearInputCache();
|
|
69
|
+
await this.attention.ClearInputCache();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async Save() {
|
|
73
|
+
await this.ffn.Save();
|
|
74
|
+
await this.attention.Save();
|
|
75
|
+
await this.rmsnorm.Save()
|
|
76
|
+
await this.rmsnorm2.Save()
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/getVec.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export function getVector(filename, size, bias) {
|
|
5
|
+
if (!fs.existsSync(filename)) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const buffer = fs.readFileSync(filename);
|
|
9
|
+
const r = new Float32Array(
|
|
10
|
+
buffer.buffer,
|
|
11
|
+
buffer.byteOffset,
|
|
12
|
+
buffer.byteLength / 4
|
|
13
|
+
);
|
|
14
|
+
if (r.length >= size) {
|
|
15
|
+
return r;
|
|
16
|
+
}
|
|
17
|
+
const output = new Float32Array(size);
|
|
18
|
+
output.set(r);
|
|
19
|
+
if (!bias) {
|
|
20
|
+
for (let i = r.length; i < size; i++) {
|
|
21
|
+
output[i] = (Math.random() * 2 - 1) * 0.02;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return output;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function SaveVector(filename, vectors) {
|
|
28
|
+
const buffer = Buffer.from(vectors.buffer)
|
|
29
|
+
fs.writeFileSync(filename, buffer)
|
|
30
|
+
}
|
package/src/gpu.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { OperationManager } from "../OperationManager.js";
|
|
2
|
+
|
|
3
|
+
export class residualConnection {
|
|
4
|
+
gpu;
|
|
5
|
+
addShader;
|
|
6
|
+
a;
|
|
7
|
+
b;
|
|
8
|
+
output;
|
|
9
|
+
constructor(device) {
|
|
10
|
+
this.gpu = new OperationManager(device)
|
|
11
|
+
this.addShader = this.gpu.getShaderPipline("./src/shaders/add.wgsl")
|
|
12
|
+
}
|
|
13
|
+
async add(a, b, encoderMain) {
|
|
14
|
+
if (!this.params) {
|
|
15
|
+
this.params = await this.gpu.createUniFormBuffer(4 * 4)
|
|
16
|
+
}
|
|
17
|
+
const encoder = encoderMain ? encoderMain : await this.gpu.CreateEncoder()
|
|
18
|
+
if (!this.output) {
|
|
19
|
+
this.output = await this.gpu.ManageBuffer(a.size);
|
|
20
|
+
}
|
|
21
|
+
if (this.output.size !== a.size || this.output.size == 0 || this.output.isDestroyed()) {
|
|
22
|
+
this.output.destroy()
|
|
23
|
+
this.output = await this.gpu.ManageBuffer(a.size);
|
|
24
|
+
}
|
|
25
|
+
await this.output.count()
|
|
26
|
+
const bind = await this.gpu.createBindGroup(this.addShader, 0, [a.mainBuffer, b.mainBuffer, this.output.mainBuffer, this.params]);
|
|
27
|
+
await this.gpu.WriteBuffer(this.params, new Uint32Array([(a.size / 4), 0]))
|
|
28
|
+
await this.gpu.RunPipline(encoder, this.addShader, bind, Math.ceil((a.size / 4) / 64));
|
|
29
|
+
if(!encoderMain) await this.gpu.submitQueue(encoder)
|
|
30
|
+
return this.output
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
struct Params{
|
|
2
|
+
vocabSize: u32,
|
|
3
|
+
tokenCount: u32
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
@group(0) @binding(0)
|
|
7
|
+
|
|
8
|
+
var <uniform> params : Params;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(1)
|
|
12
|
+
|
|
13
|
+
var <storage, read_write> probs : array<f32>;
|
|
14
|
+
|
|
15
|
+
@group(0) @binding(3)
|
|
16
|
+
|
|
17
|
+
var <storage, read_write> tToken : array<u32>;
|
|
18
|
+
|
|
19
|
+
@group(0) @binding(2)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
var <storage, read_write> result : array<f32>;
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@compute @workgroup_size(1)
|
|
26
|
+
|
|
27
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
28
|
+
let x = id.x;
|
|
29
|
+
|
|
30
|
+
var correct = 0.0;
|
|
31
|
+
for(var a = 0u; a < params.tokenCount; a++){
|
|
32
|
+
var bestVal = - 3.402823e38;
|
|
33
|
+
var maxToken = 0u;
|
|
34
|
+
var start = a * params.vocabSize;
|
|
35
|
+
let end = start + params.vocabSize;
|
|
36
|
+
for(var t = start; t < end; t++){
|
|
37
|
+
let val = probs[t];
|
|
38
|
+
if(bestVal < val){
|
|
39
|
+
bestVal = val;
|
|
40
|
+
maxToken = t - start;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if(maxToken == tToken[a]){
|
|
44
|
+
correct += 1.0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
correct /= f32(params.tokenCount);
|
|
49
|
+
result[x] = correct;
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
struct Params {
|
|
2
|
+
vocabSize: u32,
|
|
3
|
+
tokenCount: u32,
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
@group(0) @binding(0)
|
|
7
|
+
|
|
8
|
+
var <storage, read> probs : array<f32>;
|
|
9
|
+
|
|
10
|
+
@group(0) @binding(1)
|
|
11
|
+
|
|
12
|
+
var <storage, read> targetToken : array<u32>;
|
|
13
|
+
|
|
14
|
+
@group(0) @binding(2)
|
|
15
|
+
|
|
16
|
+
var <storage, read_write> loss : array<f32>;
|
|
17
|
+
|
|
18
|
+
@group(0) @binding(3)
|
|
19
|
+
|
|
20
|
+
var <uniform> params: Params;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@compute @workgroup_size(4)
|
|
24
|
+
|
|
25
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>) {
|
|
26
|
+
let index = id.x;
|
|
27
|
+
var targetIndex = targetToken[index];
|
|
28
|
+
let probalitils = probs[index * params.vocabSize + u32(targetIndex)];
|
|
29
|
+
loss[index] = -log(probalitils + 1e-15);
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
struct Params {
|
|
2
|
+
vocabSize: u32,
|
|
3
|
+
tokenCount: u32,
|
|
4
|
+
lr: f32,
|
|
5
|
+
inputSize: u32,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(0)
|
|
9
|
+
var<storage, read_write> weight: array<f32>;
|
|
10
|
+
@group(0) @binding(1)
|
|
11
|
+
var<storage, read> outGradient: array<f32>;
|
|
12
|
+
@group(0) @binding(3)
|
|
13
|
+
var<uniform> params: Params;
|
|
14
|
+
@group(0) @binding(4)
|
|
15
|
+
var<storage, read_write> dInput: array<f32>;
|
|
16
|
+
@compute @workgroup_size(256)
|
|
17
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
18
|
+
let index = id.x;
|
|
19
|
+
let total = params.tokenCount * params.inputSize;
|
|
20
|
+
if (index >= u32(total)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let token =index / u32(params.inputSize);
|
|
24
|
+
let inputIndex = index % u32(params.inputSize);
|
|
25
|
+
var gradInput = 0.0;
|
|
26
|
+
for (var i = 0u; i < u32(params.vocabSize); i++) {
|
|
27
|
+
let w = weight[i * u32(params.inputSize) + inputIndex];
|
|
28
|
+
let grad = outGradient[token * u32(params.vocabSize) + i];
|
|
29
|
+
gradInput += grad * w;
|
|
30
|
+
}
|
|
31
|
+
dInput[index] = gradInput;
|
|
32
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
struct Params {
|
|
2
|
+
lr: f32
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(0)
|
|
6
|
+
|
|
7
|
+
var<storage, read_write> embeddings: array<f32>;
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(1)
|
|
10
|
+
|
|
11
|
+
var<storage, read_write> outputGradient: array<f32>;
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(2)
|
|
14
|
+
|
|
15
|
+
var<storage, read_write> tokens: array<u32>;
|
|
16
|
+
|
|
17
|
+
@group(0) @binding(3)
|
|
18
|
+
var<uniform> params: Params;
|
|
19
|
+
|
|
20
|
+
const embeddingSize = %embeddingSize%u;
|
|
21
|
+
|
|
22
|
+
@compute @workgroup_size(256)
|
|
23
|
+
|
|
24
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
25
|
+
let dim = id.x % embeddingSize;
|
|
26
|
+
if (id.x >= arrayLength(&outputGradient)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
let tokenIndex = id.x / embeddingSize;
|
|
30
|
+
let tokenID = tokens[tokenIndex];
|
|
31
|
+
let embeddingIDx = tokenID * embeddingSize + dim;
|
|
32
|
+
embeddings[embeddingIDx] -= params.lr * outputGradient[id.x];
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
|
|
3
|
+
var <storage, read_write> embeddings: array<f32>;
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(1)
|
|
6
|
+
|
|
7
|
+
var <storage, read_write> output: array<f32>;
|
|
8
|
+
|
|
9
|
+
@group(0) @binding(2)
|
|
10
|
+
|
|
11
|
+
var <storage, read_write> tokens: array<u32>;
|
|
12
|
+
|
|
13
|
+
const embeddingSize = %embeddingSize%u;
|
|
14
|
+
|
|
15
|
+
@compute @workgroup_size(256)
|
|
16
|
+
|
|
17
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
18
|
+
let dim = id.x % embeddingSize;
|
|
19
|
+
let tokenIndex = id.x / embeddingSize;
|
|
20
|
+
|
|
21
|
+
let tokenID = tokens[tokenIndex];
|
|
22
|
+
|
|
23
|
+
let embeddingIDx = tokenID * embeddingSize + dim;
|
|
24
|
+
output[id.x] = embeddings[embeddingIDx];
|
|
25
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
struct Params {
|
|
2
|
+
vocabSize: u32,
|
|
3
|
+
tokenCount: u32,
|
|
4
|
+
lr: f32,
|
|
5
|
+
inputSize: u32,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(0)
|
|
9
|
+
var<storage, read_write> bias: array<f32>;
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(1)
|
|
12
|
+
var<storage, read_write> weight: array<f32>;
|
|
13
|
+
|
|
14
|
+
@group(0) @binding(2)
|
|
15
|
+
var<storage, read> outGradient: array<f32>;
|
|
16
|
+
|
|
17
|
+
@group(0) @binding(3)
|
|
18
|
+
var<storage, read> input: array<f32>;
|
|
19
|
+
|
|
20
|
+
@group(0) @binding(4)
|
|
21
|
+
var<uniform> params: Params;
|
|
22
|
+
|
|
23
|
+
var<workgroup> sharedBias: array<f32, 256>;
|
|
24
|
+
|
|
25
|
+
@compute @workgroup_size(256)
|
|
26
|
+
fn main(
|
|
27
|
+
@builtin(workgroup_id) wid: vec3<u32>,
|
|
28
|
+
@builtin(local_invocation_id) lid: vec3<u32>
|
|
29
|
+
) {
|
|
30
|
+
let outputIndex = wid.x;
|
|
31
|
+
let tid = lid.x;
|
|
32
|
+
|
|
33
|
+
let vocab = params.vocabSize;
|
|
34
|
+
let tokens = params.tokenCount;
|
|
35
|
+
let inputSize = params.inputSize;
|
|
36
|
+
|
|
37
|
+
for (
|
|
38
|
+
var inputIndex = tid;
|
|
39
|
+
inputIndex < inputSize;
|
|
40
|
+
inputIndex += 256u
|
|
41
|
+
) {
|
|
42
|
+
var grad = 0.0;
|
|
43
|
+
|
|
44
|
+
for (var t = 0u; t < tokens; t++) {
|
|
45
|
+
grad += input[t * inputSize + inputIndex]
|
|
46
|
+
* outGradient[t * vocab + outputIndex];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (tokens > 0u) {
|
|
50
|
+
weight[outputIndex * inputSize + inputIndex] -=
|
|
51
|
+
params.lr * grad / f32(tokens);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var biasGrad = 0.0;
|
|
56
|
+
|
|
57
|
+
for (var t = tid; t < tokens; t += 256u) {
|
|
58
|
+
biasGrad += outGradient[t * vocab + outputIndex];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sharedBias[tid] = biasGrad;
|
|
62
|
+
workgroupBarrier();
|
|
63
|
+
|
|
64
|
+
for (var stride = 128u; stride > 0u; stride >>= 1u) {
|
|
65
|
+
if (tid < stride) {
|
|
66
|
+
sharedBias[tid] += sharedBias[tid + stride];
|
|
67
|
+
}
|
|
68
|
+
workgroupBarrier();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (tid == 0u && tokens > 0u) {
|
|
72
|
+
bias[outputIndex] -=
|
|
73
|
+
params.lr * sharedBias[0] / f32(tokens);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
|
|
2
|
+
struct Params {
|
|
3
|
+
inputSize: u32,
|
|
4
|
+
outputSize: u32,
|
|
5
|
+
tokenCount: u32,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(0)
|
|
9
|
+
var<storage, read> weights: array<f32>;
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(1)
|
|
12
|
+
var<storage, read_write> output: array<f32>;
|
|
13
|
+
|
|
14
|
+
@group(0) @binding(2)
|
|
15
|
+
var<storage, read> input: array<f32>;
|
|
16
|
+
|
|
17
|
+
@group(0) @binding(3)
|
|
18
|
+
var<storage, read> bias: array<f32>;
|
|
19
|
+
|
|
20
|
+
@group(0) @binding(4)
|
|
21
|
+
var<uniform> params: Params;
|
|
22
|
+
|
|
23
|
+
const TILE_OUT: u32 = 16u;
|
|
24
|
+
const TILE_TOKEN: u32 = 4u;
|
|
25
|
+
const TILE_K: u32 = 16u;
|
|
26
|
+
|
|
27
|
+
var<workgroup> tileInput: array<f32, 64>;
|
|
28
|
+
var<workgroup> tileWeights: array<f32, 256>;
|
|
29
|
+
|
|
30
|
+
@compute @workgroup_size(64)
|
|
31
|
+
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
32
|
+
let outFeature = wid.x * TILE_OUT + lid.x % TILE_OUT;
|
|
33
|
+
let token = wid.y * TILE_TOKEN + lid.x / TILE_OUT;
|
|
34
|
+
let localOut = lid.x % TILE_OUT;
|
|
35
|
+
let localToken = lid.x / TILE_OUT;
|
|
36
|
+
var sum = 0.0;
|
|
37
|
+
for (var baseK = 0u; baseK < params.inputSize; baseK += TILE_K) {
|
|
38
|
+
let loadIndex = lid.x;
|
|
39
|
+
let inputToken = wid.y * TILE_TOKEN + loadIndex / TILE_K;
|
|
40
|
+
let inputK = baseK + loadIndex % TILE_K;
|
|
41
|
+
if (loadIndex < TILE_TOKEN * TILE_K && inputToken < params.tokenCount && inputK < params.inputSize) {
|
|
42
|
+
tileInput[loadIndex] = input[inputToken * params.inputSize + inputK];
|
|
43
|
+
}
|
|
44
|
+
let weightFeature = wid.x * TILE_OUT + loadIndex / TILE_K;
|
|
45
|
+
let weightK = baseK + loadIndex % TILE_K;
|
|
46
|
+
if (loadIndex < TILE_OUT * TILE_K && weightFeature < params.outputSize && weightK < params.inputSize) {
|
|
47
|
+
tileWeights[loadIndex] = weights[weightFeature * params.inputSize + weightK];
|
|
48
|
+
}
|
|
49
|
+
workgroupBarrier();
|
|
50
|
+
for (var k = 0u; k < TILE_K; k++) {
|
|
51
|
+
let a = tileInput[localToken * TILE_K + k];
|
|
52
|
+
let b = tileWeights[localOut * TILE_K + k];
|
|
53
|
+
sum += a * b;
|
|
54
|
+
}
|
|
55
|
+
workgroupBarrier();
|
|
56
|
+
}
|
|
57
|
+
if (token < params.tokenCount && outFeature < params.outputSize) {
|
|
58
|
+
output[token * params.outputSize + outFeature] = sum + bias[outFeature];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
@group(0) @binding(2)
|
|
8
|
+
var<storage, read> sumSquares: array<f32>;
|
|
9
|
+
|
|
10
|
+
@group(0) @binding(3)
|
|
11
|
+
var<storage, read> gamma: array<f32>;
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(4)
|
|
14
|
+
var<storage, read_write> gradInput: array<f32>;
|
|
15
|
+
|
|
16
|
+
var<workgroup> partial: array<f32, 64>;
|
|
17
|
+
|
|
18
|
+
const D: u32 = %embeddingSize%u;
|
|
19
|
+
const EPSILON: f32 = 1e-6;
|
|
20
|
+
@compute @workgroup_size(64)
|
|
21
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
22
|
+
let token = wid.x;
|
|
23
|
+
if (token >= arrayLength(&sumSquares)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let base = token * D;
|
|
27
|
+
let r = sqrt(sumSquares[token] / f32(D) + EPSILON);
|
|
28
|
+
var localSum = 0.0;
|
|
29
|
+
var d = lid;
|
|
30
|
+
while (d < D) {
|
|
31
|
+
let idx = base + d;
|
|
32
|
+
localSum += gradOutput[idx] * gamma[d] * input[idx];
|
|
33
|
+
d += 64u;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
partial[lid] = localSum;
|
|
37
|
+
workgroupBarrier();
|
|
38
|
+
var stride = 32u;
|
|
39
|
+
loop {
|
|
40
|
+
if (stride == 0u) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (lid < stride) {
|
|
45
|
+
partial[lid] += partial[lid + stride];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
workgroupBarrier();
|
|
49
|
+
stride /= 2u;
|
|
50
|
+
}
|
|
51
|
+
let dot = partial[0];
|
|
52
|
+
d = lid;
|
|
53
|
+
while (d < D) {
|
|
54
|
+
let idx = base + d;
|
|
55
|
+
let x = input[idx];
|
|
56
|
+
let dy = gradOutput[idx];
|
|
57
|
+
let g = gamma[d];
|
|
58
|
+
|
|
59
|
+
gradInput[idx] =
|
|
60
|
+
(dy * g) / r
|
|
61
|
+
- (x * dot) / (f32(D) * r * r * r);
|
|
62
|
+
|
|
63
|
+
d += 64u;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@group(0) @binding(0)
|
|
2
|
+
var<storage, read> reduce: array<f32>;
|
|
3
|
+
|
|
4
|
+
@group(0) @binding(1)
|
|
5
|
+
var<storage, read> vector: array<f32>;
|
|
6
|
+
|
|
7
|
+
@group(0) @binding(2)
|
|
8
|
+
var<storage, read_write> output: array<f32>;
|
|
9
|
+
|
|
10
|
+
@group(0) @binding(3)
|
|
11
|
+
var<storage, read> gamma: array<f32>;
|
|
12
|
+
|
|
13
|
+
@compute @workgroup_size(64)
|
|
14
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
15
|
+
let x = id.x;
|
|
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];
|
|
30
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
const D: u32 = %embeddingSize%u;
|
|
10
|
+
@compute @workgroup_size(64)
|
|
11
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
12
|
+
let base = wid.x * D;
|
|
13
|
+
var sum = 0.0;
|
|
14
|
+
var d = lid;
|
|
15
|
+
while (d < D) {
|
|
16
|
+
let idx = base + d;
|
|
17
|
+
if (idx < arrayLength(&input)) {
|
|
18
|
+
sum += input[idx] * input[idx];
|
|
19
|
+
}
|
|
20
|
+
d += 64u;
|
|
21
|
+
}
|
|
22
|
+
partial[lid] = sum;
|
|
23
|
+
workgroupBarrier();
|
|
24
|
+
var stride = 32u;
|
|
25
|
+
loop {
|
|
26
|
+
if (stride == 0u) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
if (lid < stride) {
|
|
30
|
+
partial[lid] += partial[lid + stride];
|
|
31
|
+
}
|
|
32
|
+
workgroupBarrier();
|
|
33
|
+
stride /= 2u;
|
|
34
|
+
}
|
|
35
|
+
if (lid == 0u) {
|
|
36
|
+
out[wid.x] = partial[0];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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> sumSquares: array<f32>;
|
|
10
|
+
|
|
11
|
+
@group(0) @binding(3)
|
|
12
|
+
var<storage, read_write> gamma: array<f32>;
|
|
13
|
+
|
|
14
|
+
@group(0) @binding(4)
|
|
15
|
+
var<storage, read> params: array<f32>;
|
|
16
|
+
|
|
17
|
+
var<workgroup> partial: array<f32, 64>;
|
|
18
|
+
|
|
19
|
+
const D: u32 = %embeddingSize%u;
|
|
20
|
+
const EPSILON: f32 = 1e-6;
|
|
21
|
+
|
|
22
|
+
@compute @workgroup_size(64)
|
|
23
|
+
fn main(@builtin(local_invocation_index) lid: u32, @builtin(workgroup_id) wid: vec3<u32>) {
|
|
24
|
+
let dim = wid.x;
|
|
25
|
+
let T = arrayLength(&sumSquares);
|
|
26
|
+
var sum = 0.0;
|
|
27
|
+
if (dim < D) {
|
|
28
|
+
var token = lid;
|
|
29
|
+
while (token < T) {
|
|
30
|
+
let idx = token * D + dim;
|
|
31
|
+
let rms = sqrt(sumSquares[token] / f32(D) + EPSILON);
|
|
32
|
+
sum += gradOutput[idx] * input[idx] / rms;
|
|
33
|
+
token += 64u;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
partial[lid] = sum;
|
|
37
|
+
workgroupBarrier();
|
|
38
|
+
var stride = 32u;
|
|
39
|
+
loop {
|
|
40
|
+
if (stride == 0u) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
if (lid < stride) {
|
|
44
|
+
partial[lid] += partial[lid + stride];
|
|
45
|
+
}
|
|
46
|
+
workgroupBarrier();
|
|
47
|
+
stride /= 2u;
|
|
48
|
+
}
|
|
49
|
+
if (lid == 0u && dim < D) {
|
|
50
|
+
gamma[dim] -= params[0] * partial[0];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
struct Params{
|
|
2
|
+
lr : f32
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@group(0) @binding(0)
|
|
6
|
+
var <storage, read_write> posVec: array<f32>;
|
|
7
|
+
|
|
8
|
+
@group(0) @binding(1)
|
|
9
|
+
|
|
10
|
+
var <storage, read> outputGradient : array<f32>;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@group(0) @binding(2)
|
|
14
|
+
|
|
15
|
+
var <uniform> params: Params;
|
|
16
|
+
|
|
17
|
+
@compute @workgroup_size(64)
|
|
18
|
+
|
|
19
|
+
fn main(@builtin(global_invocation_id) id : vec3<u32>){
|
|
20
|
+
let x = id.x;
|
|
21
|
+
if(x >= arrayLength(&outputGradient)){
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
posVec[x] -= params.lr * outputGradient[x];
|
|
25
|
+
}
|