@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,21 @@
|
|
|
1
|
+
export class Embedding {
|
|
2
|
+
constructor(device: GPUBuffer, embedding: number, vocabSize: number, config: {
|
|
3
|
+
cpuReadBack: boolean,
|
|
4
|
+
save: {
|
|
5
|
+
filename: string
|
|
6
|
+
}
|
|
7
|
+
})
|
|
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>
|
|
21
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { config } from "process";
|
|
2
|
+
|
|
3
|
+
import { SaveVector, getVector } from '../getVec.js'
|
|
4
|
+
import { OperationManager } from "../OperationManager.js";
|
|
5
|
+
|
|
6
|
+
function GenerateVectors(embeddingSize, vocabSize) {
|
|
7
|
+
const vec = new Float32Array(embeddingSize * vocabSize).map(() => (Math.random() * 2 - 1) * 0.02)
|
|
8
|
+
return vec
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Embedding {
|
|
12
|
+
embeddingSize;
|
|
13
|
+
vocabSize;
|
|
14
|
+
gpu;
|
|
15
|
+
firstTrue;
|
|
16
|
+
vectors;
|
|
17
|
+
configs;
|
|
18
|
+
vectorsBuffer;
|
|
19
|
+
forwardPipline;
|
|
20
|
+
constructor(device, embeddingSize, vocabSize, configs) {
|
|
21
|
+
this.configs = configs
|
|
22
|
+
this.embeddingSize = embeddingSize;
|
|
23
|
+
this.vocabSize = vocabSize;
|
|
24
|
+
this.device = device
|
|
25
|
+
let total = embeddingSize * vocabSize;
|
|
26
|
+
if (configs && configs.save) {
|
|
27
|
+
const vec = getVector(configs.save.filename, total);
|
|
28
|
+
if (vec) {
|
|
29
|
+
this.vectors = vec;
|
|
30
|
+
|
|
31
|
+
} else {
|
|
32
|
+
this.vectors = GenerateVectors(embeddingSize, vocabSize)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
} else {
|
|
36
|
+
this.vectors = GenerateVectors(embeddingSize, vocabSize)
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
this.gpu = new OperationManager(device)
|
|
40
|
+
this.forwardPipline = this.gpu.getShaderPipline("./src/shaders/EF.wgsl", {
|
|
41
|
+
embeddingSize: embeddingSize
|
|
42
|
+
})
|
|
43
|
+
this.backwardPipline = this.gpu.getShaderPipline("./src/shaders/EB.wgsl", {
|
|
44
|
+
embeddingSize: embeddingSize
|
|
45
|
+
})
|
|
46
|
+
SaveVector(this.configs.save.filename, this.vectors)
|
|
47
|
+
}
|
|
48
|
+
async forward(input, encoderMain) {
|
|
49
|
+
const encoder = encoderMain ? encoderMain : this.device.createCommandEncoder()
|
|
50
|
+
if (!this.vectorsBuffer) {
|
|
51
|
+
this.vectorsBuffer = await this.gpu.createBuffer(Float32Array.BYTES_PER_ELEMENT * this.vocabSize * this.embeddingSize);
|
|
52
|
+
await this.gpu.WriteBuffer(this.vectorsBuffer, this.vectors)
|
|
53
|
+
}
|
|
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
|
+
}
|
|
66
|
+
await this.outputBuffer.count()
|
|
67
|
+
const bind = await this.device.createBindGroup({
|
|
68
|
+
layout: await this.forwardPipline.getBindGroupLayout(0),
|
|
69
|
+
entries: [
|
|
70
|
+
{
|
|
71
|
+
binding: 0,
|
|
72
|
+
resource: {
|
|
73
|
+
buffer: this.vectorsBuffer
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
binding: 1,
|
|
78
|
+
resource: {
|
|
79
|
+
buffer: this.outputBuffer.mainBuffer
|
|
80
|
+
}
|
|
81
|
+
}, {
|
|
82
|
+
binding: 2,
|
|
83
|
+
resource: {
|
|
84
|
+
buffer: this.tokenBuffer
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
})
|
|
89
|
+
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil((this.embeddingSize * input.length) / 256))
|
|
90
|
+
if(!encoderMain) this.device.queue.submit([encoder.finish()])
|
|
91
|
+
return this.outputBuffer
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
async Save() {
|
|
95
|
+
const vec = await this.gpu.readBuffer(Float32Array.BYTES_PER_ELEMENT * this.vocabSize * this.embeddingSize, this.vectorsBuffer)
|
|
96
|
+
SaveVector(this.configs.save.filename, vec)
|
|
97
|
+
}
|
|
98
|
+
async backward(inputGradient, lr, encoderMain) {
|
|
99
|
+
const encoder = encoderMain ? encoderMain : this.device.createCommandEncoder()
|
|
100
|
+
if (!this.oldParam) {
|
|
101
|
+
this.oldParam = new Float32Array([0, 0]);
|
|
102
|
+
this.param = await this.gpu.createUniFormBuffer(this.oldParam.byteLength);
|
|
103
|
+
}
|
|
104
|
+
if (this.oldParam[0] !== lr) {
|
|
105
|
+
this.oldParam = new Float32Array([lr, 0]);
|
|
106
|
+
this.gpu.WriteBuffer(this.param, this.oldParam)
|
|
107
|
+
}
|
|
108
|
+
const bind = await this.device.createBindGroup({
|
|
109
|
+
layout: await this.backwardPipline.getBindGroupLayout(0),
|
|
110
|
+
entries: [
|
|
111
|
+
{
|
|
112
|
+
binding: 0,
|
|
113
|
+
resource: {
|
|
114
|
+
buffer: this.vectorsBuffer
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
binding: 1,
|
|
119
|
+
resource: {
|
|
120
|
+
buffer: inputGradient.mainBuffer
|
|
121
|
+
}
|
|
122
|
+
}, {
|
|
123
|
+
binding: 2,
|
|
124
|
+
resource: {
|
|
125
|
+
buffer: this.tokenBuffer
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
}, {
|
|
129
|
+
binding: 3,
|
|
130
|
+
resource: {
|
|
131
|
+
buffer: this.param
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
})
|
|
137
|
+
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil((this.embeddingSize * (this.tokenBuffer.size / 4)) / 256))
|
|
138
|
+
if(!encoderMain) this.device.queue.submit([encoder.finish()])
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class FFN {
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number, configs: {
|
|
3
|
+
dirname: string
|
|
4
|
+
})
|
|
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(inputGradient: {
|
|
12
|
+
read: function(): Promise<Float32Array>,
|
|
13
|
+
mainBuffer: GPUBuffer,
|
|
14
|
+
isDestroyed: function(): Boolean,
|
|
15
|
+
destroy: function(): void
|
|
16
|
+
}, lr: number): Promise<{
|
|
17
|
+
read: function(): Promise<Float32Array>,
|
|
18
|
+
mainBuffer: GPUBuffer,
|
|
19
|
+
isDestroyed: function(): Boolean,
|
|
20
|
+
destroy: function(): void
|
|
21
|
+
}>
|
|
22
|
+
async Save(): Promise<void>
|
|
23
|
+
}
|
package/src/FFN/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RELU, Linear } from "../../index.js";
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { OperationManager } from "../OperationManager.js";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class FFN {
|
|
7
|
+
linear1;
|
|
8
|
+
linear2;
|
|
9
|
+
hiddenLayer;
|
|
10
|
+
Op
|
|
11
|
+
constructor(device, embeddingSize, configs) {
|
|
12
|
+
this.Op = new OperationManager(device)
|
|
13
|
+
this.linear1 = new Linear(device, embeddingSize, embeddingSize * 4, {
|
|
14
|
+
save: {
|
|
15
|
+
filename: [join(configs.dirname, "FFN_weights1.bin"), join(configs.dirname, "FFN_bias1.bin")]
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
this.hiddenLayer = new RELU(device, embeddingSize * 4);
|
|
19
|
+
this.linear2 = new Linear(device, embeddingSize * 4, embeddingSize, {
|
|
20
|
+
save: {
|
|
21
|
+
filename: [join(configs.dirname, "FFN_weights2.bin"), join(configs.dirname, "FFN_bias2.bin")]
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
async forward(vec, encoderMain) {
|
|
26
|
+
const logit1 = await this.linear1.forward(vec, encoderMain)
|
|
27
|
+
const hidden = await this.hiddenLayer.forward(logit1, encoderMain)
|
|
28
|
+
const final = await this.linear2.forward(hidden, encoderMain)
|
|
29
|
+
return final
|
|
30
|
+
}
|
|
31
|
+
async backward(inputGradient, lr, encoderMain) {
|
|
32
|
+
const logit2 = await this.linear2.backward(inputGradient, lr, encoderMain)
|
|
33
|
+
const hidden = await this.hiddenLayer.backward(logit2, encoderMain)
|
|
34
|
+
const final = await this.linear1.backward(hidden, lr, encoderMain)
|
|
35
|
+
return final
|
|
36
|
+
}
|
|
37
|
+
async Save() {
|
|
38
|
+
await this.linear1.Save()
|
|
39
|
+
await this.linear2.Save()
|
|
40
|
+
}
|
|
41
|
+
async ClearInputCache() {
|
|
42
|
+
this.linear1.ClearInputCache()
|
|
43
|
+
this.linear2.ClearInputCache()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export class Linear {
|
|
2
|
+
constructor(device: GPUAdapter, embeddingSize: number, vocabSize: number, configs: {
|
|
3
|
+
save: {
|
|
4
|
+
filename: string[]
|
|
5
|
+
}
|
|
6
|
+
})
|
|
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
|
+
}>
|
|
29
|
+
async Save(): Promise<void>
|
|
30
|
+
|
|
31
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import { buffer } from "stream/consumers";
|
|
4
|
+
import { SaveVector, getVector } from '../getVec.js'
|
|
5
|
+
import { OperationManager } from "../OperationManager.js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
function GenerateVectors(embeddingSize, vocabSize) {
|
|
10
|
+
const vec = new Float32Array(embeddingSize * vocabSize).map(() => (Math.random() * 2 - 1) * 0.02)
|
|
11
|
+
return vec
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function GenerateBias(vocabSize) {
|
|
15
|
+
const vec = new Float32Array(vocabSize)
|
|
16
|
+
return vec
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class Linear {
|
|
20
|
+
device;
|
|
21
|
+
embeddingSize;
|
|
22
|
+
vocabSize;
|
|
23
|
+
configs;
|
|
24
|
+
bias;
|
|
25
|
+
weights;
|
|
26
|
+
forwardPipline;
|
|
27
|
+
configs;
|
|
28
|
+
input;
|
|
29
|
+
wBuffer;
|
|
30
|
+
bBuffer;
|
|
31
|
+
gpu;
|
|
32
|
+
paramForward;
|
|
33
|
+
oldParam;
|
|
34
|
+
constructor(device, embeddingSize, vocabSize, configs) {
|
|
35
|
+
this.configs = configs
|
|
36
|
+
this.embeddingSize = embeddingSize;
|
|
37
|
+
this.vocabSize = vocabSize;
|
|
38
|
+
this.configs = configs;
|
|
39
|
+
this.device = device
|
|
40
|
+
let total = embeddingSize * vocabSize;
|
|
41
|
+
if (configs && configs.save) {
|
|
42
|
+
const w = getVector(configs.save.filename[0], total);
|
|
43
|
+
const b = getVector(configs.save.filename[1], vocabSize, true)
|
|
44
|
+
if (!w && !b) {
|
|
45
|
+
this.bias = GenerateBias(vocabSize)
|
|
46
|
+
this.weights = GenerateVectors(embeddingSize, vocabSize)
|
|
47
|
+
SaveVector(configs.save.filename[0], this.weights)
|
|
48
|
+
SaveVector(configs.save.filename[1], this.bias)
|
|
49
|
+
} else {
|
|
50
|
+
this.bias = b;
|
|
51
|
+
this.weights = w;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
this.bias = GenerateBias(vocabSize)
|
|
55
|
+
this.weights = GenerateVectors(embeddingSize, vocabSize)
|
|
56
|
+
}
|
|
57
|
+
this.gpu = new OperationManager(device);
|
|
58
|
+
this.forwardPipline = this.gpu.getShaderPipline("./src/shaders/LF.wgsl")
|
|
59
|
+
this.backwardPipline = this.gpu.getShaderPipline("./src/shaders/LB.wgsl")
|
|
60
|
+
this.dInputBackward = this.gpu.getShaderPipline("./src/shaders/ComputeDInput.wgsl")
|
|
61
|
+
}
|
|
62
|
+
async forward(vec, encoderMain) {
|
|
63
|
+
const encoder = encoderMain ? encoderMain : this.device.createCommandEncoder()
|
|
64
|
+
const tokenCount = vec.mainBuffer.size / (this.embeddingSize * 4)
|
|
65
|
+
if (!this.wBuffer) {
|
|
66
|
+
|
|
67
|
+
this.wBuffer = await this.gpu.createBuffer(this.embeddingSize * this.vocabSize * 4)
|
|
68
|
+
await this.gpu.WriteBuffer(this.wBuffer, this.weights)
|
|
69
|
+
this.bBuffer = await this.gpu.createBuffer(this.vocabSize * 4)
|
|
70
|
+
await this.gpu.WriteBuffer(this.bBuffer, this.bias)
|
|
71
|
+
this.paramForward = await this.gpu.createUniFormBuffer(4 * 4)
|
|
72
|
+
this.paramBackward = await this.gpu.createUniFormBuffer(16)
|
|
73
|
+
}
|
|
74
|
+
if (!this.oldParam) {
|
|
75
|
+
this.oldParam = new Uint32Array([this.embeddingSize, this.vocabSize, 0, 0])
|
|
76
|
+
}
|
|
77
|
+
if (this.oldParam[2] !== tokenCount) {
|
|
78
|
+
await this.gpu.WriteBuffer(this.paramForward, new Uint32Array([this.embeddingSize, this.vocabSize, tokenCount, 0]))
|
|
79
|
+
this.oldParam = new Uint32Array([this.embeddingSize, this.vocabSize, tokenCount, 0]);
|
|
80
|
+
}
|
|
81
|
+
if (!this.outputBuffer) this.outputBuffer = await this.gpu.ManageBuffer(4 * this.vocabSize * tokenCount)
|
|
82
|
+
if (this.outputBuffer.mainBuffer.size !== 4 * this.vocabSize * tokenCount || this.outputBuffer.isDestroyed()) {
|
|
83
|
+
this.outputBuffer.destroy()
|
|
84
|
+
this.outputBuffer = await this.gpu.ManageBuffer(4 * this.vocabSize * tokenCount)
|
|
85
|
+
}
|
|
86
|
+
await this.outputBuffer.count()
|
|
87
|
+
const bind = await this.device.createBindGroup({
|
|
88
|
+
layout: await this.forwardPipline.getBindGroupLayout(0),
|
|
89
|
+
entries: [
|
|
90
|
+
{
|
|
91
|
+
binding: 0,
|
|
92
|
+
resource: this.wBuffer
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
binding: 1,
|
|
96
|
+
resource: this.outputBuffer.mainBuffer
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
binding: 2,
|
|
100
|
+
resource: vec.mainBuffer
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
binding: 3,
|
|
104
|
+
resource: this.bBuffer
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
binding: 4,
|
|
108
|
+
resource: this.paramForward
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
})
|
|
112
|
+
await this.gpu.RunPipline(encoder, this.forwardPipline, bind, Math.ceil(this.vocabSize / 16), Math.ceil(tokenCount / 4))
|
|
113
|
+
|
|
114
|
+
if (!encoderMain) this.device.queue.submit([encoder.finish()])
|
|
115
|
+
this.input = vec;
|
|
116
|
+
return this.outputBuffer
|
|
117
|
+
}
|
|
118
|
+
async backward(dOutput, learningRate, encoderMain) {
|
|
119
|
+
const encoder = encoderMain ? encoderMain : this.device.createCommandEncoder()
|
|
120
|
+
const tokenCount = dOutput.size / (this.vocabSize * 4)
|
|
121
|
+
const data = new ArrayBuffer(16);
|
|
122
|
+
const view = new DataView(data);
|
|
123
|
+
view.setUint32(0, this.vocabSize, true);
|
|
124
|
+
view.setUint32(4, tokenCount, true);
|
|
125
|
+
view.setFloat32(8, learningRate, true);
|
|
126
|
+
view.setUint32(12, this.embeddingSize, true);
|
|
127
|
+
await this.gpu.WriteBuffer(this.paramBackward, data);
|
|
128
|
+
|
|
129
|
+
|
|
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
|
+
}
|
|
136
|
+
await this.gradientBuffer.count()
|
|
137
|
+
const bind = await this.device.createBindGroup({
|
|
138
|
+
layout: await this.backwardPipline.getBindGroupLayout(0),
|
|
139
|
+
entries: [
|
|
140
|
+
{
|
|
141
|
+
binding: 0,
|
|
142
|
+
resource: this.bBuffer
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
binding: 1,
|
|
146
|
+
resource: this.wBuffer
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
binding: 2,
|
|
150
|
+
resource: dOutput.mainBuffer
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
binding: 3,
|
|
154
|
+
resource: this.input.mainBuffer
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
binding: 4,
|
|
158
|
+
resource: this.paramBackward
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
const bind2 = await this.device.createBindGroup({
|
|
163
|
+
layout: await this.dInputBackward.getBindGroupLayout(0),
|
|
164
|
+
entries: [
|
|
165
|
+
{
|
|
166
|
+
binding: 0,
|
|
167
|
+
resource: this.wBuffer
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
binding: 1,
|
|
171
|
+
resource: dOutput.mainBuffer
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
binding: 3,
|
|
175
|
+
resource: this.paramBackward
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
binding: 4,
|
|
179
|
+
resource: this.gradientBuffer.mainBuffer
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
})
|
|
183
|
+
// console.log((await this.gpu.readBuffer(this.input.size, this.input))[0])
|
|
184
|
+
await this.gpu.RunPipline(encoder, this.dInputBackward, bind2, Math.ceil((this.embeddingSize * tokenCount) / 256));
|
|
185
|
+
await this.gpu.RunPipline(encoder, this.backwardPipline, bind, Math.ceil(this.vocabSize));
|
|
186
|
+
if (!encoderMain) await this.device.queue.submit([encoder.finish()])
|
|
187
|
+
return this.gradientBuffer
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
async Save() {
|
|
191
|
+
const b = await this.gpu.readBuffer(this.bBuffer.size, this.bBuffer);
|
|
192
|
+
const w = await this.gpu.readBuffer(this.wBuffer.size, this.wBuffer);
|
|
193
|
+
SaveVector(this.configs.save.filename[0], w)
|
|
194
|
+
SaveVector(this.configs.save.filename[1], b)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path, { join, dirname, format } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
|
|
7
|
+
export class OperationManager {
|
|
8
|
+
device;
|
|
9
|
+
matrixMatSHhaders;
|
|
10
|
+
params;
|
|
11
|
+
addShader;
|
|
12
|
+
constructor(device) {
|
|
13
|
+
this.device = device;
|
|
14
|
+
this.addShader = this.getShaderPipline("./src/shaders/add.wgsl")
|
|
15
|
+
}
|
|
16
|
+
async createBuffer(size) {
|
|
17
|
+
return this.device.createBuffer({
|
|
18
|
+
size: size,
|
|
19
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
async createUniFormBuffer(size) {
|
|
23
|
+
return this.device.createBuffer({
|
|
24
|
+
size,
|
|
25
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.UNIFORM
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
async readBuffer(size, buffer) {
|
|
29
|
+
const readBuffer = this.device.createBuffer({
|
|
30
|
+
size: size,
|
|
31
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
32
|
+
})
|
|
33
|
+
const encoder = this.device.createCommandEncoder()
|
|
34
|
+
encoder.copyBufferToBuffer(buffer, 0, readBuffer, 0, size);
|
|
35
|
+
this.device.queue.submit([await encoder.finish()])
|
|
36
|
+
await readBuffer.mapAsync(GPUMapMode.READ);
|
|
37
|
+
const mapped = readBuffer.getMappedRange();
|
|
38
|
+
const result = new Float32Array(
|
|
39
|
+
mapped.slice(0)
|
|
40
|
+
);
|
|
41
|
+
readBuffer.unmap()
|
|
42
|
+
readBuffer.destroy()
|
|
43
|
+
return result
|
|
44
|
+
}
|
|
45
|
+
getShaderPipline(filename, value = { "embedding": 123 }, entryPoint = "main") {
|
|
46
|
+
let readShaderCode = fs.readFileSync(path.join(__dirname, `../${filename}`), "utf-8");
|
|
47
|
+
if (value) {
|
|
48
|
+
for (const a in value) {
|
|
49
|
+
readShaderCode = readShaderCode.replaceAll(`%${a}%`, value[a])
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const compiledKernel = this.device.createShaderModule({
|
|
53
|
+
code: readShaderCode
|
|
54
|
+
});
|
|
55
|
+
const compiledPipLine = this.device.createComputePipeline({
|
|
56
|
+
layout: "auto",
|
|
57
|
+
compute: {
|
|
58
|
+
module: compiledKernel,
|
|
59
|
+
entryPoint: entryPoint
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return compiledPipLine;
|
|
63
|
+
}
|
|
64
|
+
async WriteBuffer(buffer, data) {
|
|
65
|
+
this.device.queue.writeBuffer(buffer, 0, data)
|
|
66
|
+
}
|
|
67
|
+
async RunPipline(encoder, pipline, binding, dispatchWorkgroups, y = 1, z = 1) {
|
|
68
|
+
const pass = encoder.beginComputePass();
|
|
69
|
+
pass.setPipeline(pipline)
|
|
70
|
+
pass.setBindGroup(0, binding)
|
|
71
|
+
pass.dispatchWorkgroups(dispatchWorkgroups, y, z)
|
|
72
|
+
pass.end()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async MakeACopyBuffer(encoder2, sourceBuffer) {
|
|
76
|
+
const encoder = encoder2 ? encoder2 : await this.CreateEncoder()
|
|
77
|
+
const buffer = this.device.createBuffer({
|
|
78
|
+
size: sourceBuffer.size,
|
|
79
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
80
|
+
})
|
|
81
|
+
encoder.copyBufferToBuffer(sourceBuffer, 0, buffer, 0, sourceBuffer.size);
|
|
82
|
+
if (!encoder2) await this.submitQueue(encoder)
|
|
83
|
+
return buffer
|
|
84
|
+
}
|
|
85
|
+
CreateEncoder() {
|
|
86
|
+
return this.device.createCommandEncoder()
|
|
87
|
+
}
|
|
88
|
+
createBindGroup(shader, groupNum, ent) {
|
|
89
|
+
|
|
90
|
+
return this.device.createBindGroup({
|
|
91
|
+
layout: shader.getBindGroupLayout(groupNum),
|
|
92
|
+
entries: ent.map((e, x) => {
|
|
93
|
+
return {
|
|
94
|
+
binding: x,
|
|
95
|
+
resource: { buffer: e}
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
async submitQueue(encoder) {
|
|
101
|
+
this.device.queue.submit([encoder.finish()])
|
|
102
|
+
}
|
|
103
|
+
async add(a, b, size) {
|
|
104
|
+
if (!this.params) {
|
|
105
|
+
this.params = await this.createUniFormBuffer(4 * 4)
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
const encoder = await this.CreateEncoder()
|
|
109
|
+
const output = await this.ManageBuffer(a.size);
|
|
110
|
+
const bind = await this.createBindGroup(this.addShader, 0, [a, b, output.mainBuffer, this.params]);
|
|
111
|
+
await this.WriteBuffer(this.params, new Uint32Array([size, 0]))
|
|
112
|
+
await this.RunPipline(encoder, this.addShader, bind, Math.ceil(size / 64));
|
|
113
|
+
await this.submitQueue(encoder)
|
|
114
|
+
// a.destroy()
|
|
115
|
+
// b.destroy()
|
|
116
|
+
return output
|
|
117
|
+
}
|
|
118
|
+
ManageBuffer(size) {
|
|
119
|
+
let buffer = this.device.createBuffer({
|
|
120
|
+
size,
|
|
121
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
122
|
+
})
|
|
123
|
+
let isDestroy = false;
|
|
124
|
+
let ret = {
|
|
125
|
+
id: Math.floor(Math.random() * 9999),
|
|
126
|
+
mainBuffer: buffer,
|
|
127
|
+
reuse: 0,
|
|
128
|
+
destroy: function () {
|
|
129
|
+
isDestroy = true
|
|
130
|
+
this.mainBuffer.destroy()
|
|
131
|
+
},
|
|
132
|
+
isDestroyed: function () {
|
|
133
|
+
return isDestroy
|
|
134
|
+
},
|
|
135
|
+
read: async () => {
|
|
136
|
+
return await this.readBuffer(buffer.size, buffer)
|
|
137
|
+
},
|
|
138
|
+
write: async (data) => {
|
|
139
|
+
if (ret.reuse == 1000) {
|
|
140
|
+
await ret.mainBuffer.destroy()
|
|
141
|
+
ret.mainBuffer = this.device.createBuffer({
|
|
142
|
+
size: ret.size,
|
|
143
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
144
|
+
})
|
|
145
|
+
ret.reuse = 0;
|
|
146
|
+
}
|
|
147
|
+
await this.WriteBuffer(buffer, data)
|
|
148
|
+
ret.reuse++;
|
|
149
|
+
|
|
150
|
+
},
|
|
151
|
+
size: size,
|
|
152
|
+
count: async () => {
|
|
153
|
+
if (ret.reuse == 1000) {
|
|
154
|
+
await ret.mainBuffer.destroy()
|
|
155
|
+
ret.mainBuffer = this.device.createBuffer({
|
|
156
|
+
size: ret.size,
|
|
157
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
|
|
158
|
+
})
|
|
159
|
+
ret.reuse = 0;
|
|
160
|
+
}
|
|
161
|
+
ret.reuse++;
|
|
162
|
+
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
}
|
|
166
|
+
return ret
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class PositionEmbedding {
|
|
2
|
+
constructor(device: GPUBuffer, embedding: number, contextSize: number, config: {
|
|
3
|
+
save: {
|
|
4
|
+
filename: string
|
|
5
|
+
}
|
|
6
|
+
});
|
|
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
|
+
}>
|
|
30
|
+
}
|