@mineproness/tensorloop 2.1.0 → 2.1.3
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/SelfAttention/index.js +13 -76
- package/src/gpiInit.js +125 -4
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Softmax } from '../../index.js';
|
|
2
|
+
import { GPUAttention } from '../gpiInit.js';
|
|
2
3
|
import { Linear } from '../Linear/index.js'
|
|
3
4
|
|
|
4
5
|
export class SelfAttention {
|
|
@@ -13,6 +14,7 @@ export class SelfAttention {
|
|
|
13
14
|
score;
|
|
14
15
|
softmax;
|
|
15
16
|
weights;
|
|
17
|
+
gpu;
|
|
16
18
|
constructor(embeddingSize, configs) {
|
|
17
19
|
this.configs = configs
|
|
18
20
|
this.softmax = new Softmax()
|
|
@@ -22,99 +24,34 @@ export class SelfAttention {
|
|
|
22
24
|
this.value = new Linear(embeddingSize, embeddingSize, { save: { filename: [`${configs.dirname}/value.bin`, `${configs.dirname}/valueBias.bin`] } })
|
|
23
25
|
}
|
|
24
26
|
forward(vectors) {
|
|
27
|
+
if(!this.gpu) this.gpu = new GPUAttention(vectors[0].length, vectors.length);
|
|
25
28
|
this.q = this.query.forward(vectors)
|
|
26
29
|
this.v = this.value.forward(vectors)
|
|
27
30
|
this.k = this.key.forward(vectors)
|
|
28
|
-
const attentionSocres =
|
|
29
|
-
for (let i = 0; i < this.q.length; i++) {
|
|
30
|
-
attentionSocres[i] = new Float32Array(this.k.length);
|
|
31
|
-
|
|
32
|
-
for (let j = 0; j < this.k.length; j++) {
|
|
33
|
-
if (j > i) {
|
|
34
|
-
attentionSocres[i][j] = -1e9; // mask future
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let dot = 0;
|
|
39
|
-
|
|
40
|
-
for (let d = 0; d < this.q[i].length; d++) {
|
|
41
|
-
dot += this.q[i][d] * this.k[j][d];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
attentionSocres[i][j] = dot / this.score;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
31
|
+
const attentionSocres = this.gpu.attentionScores(this.q, this.k, this.score);
|
|
48
32
|
const weights = this.softmax.forward(attentionSocres)
|
|
49
33
|
this.weights = weights
|
|
50
|
-
const output =
|
|
51
|
-
|
|
52
|
-
for (let i = 0; i < weights.length; i++) {
|
|
53
|
-
output[i] = new Float32Array(this.v[0].length);
|
|
54
|
-
|
|
55
|
-
for (let j = 0; j < this.v.length; j++) {
|
|
56
|
-
for (let d = 0; d < this.v[j].length; d++) {
|
|
57
|
-
output[i][d] += weights[i][j] * this.v[j][d];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
34
|
+
const output = this.gpu.attentionOutput(weights, this.v)
|
|
62
35
|
return output;
|
|
63
36
|
}
|
|
64
|
-
softmaxBack(probs, dOut) {
|
|
65
|
-
const dIn = new Float32Array(probs.length);
|
|
66
37
|
|
|
67
|
-
for (let i = 0; i < probs.length; i++) {
|
|
68
|
-
let sum = 0;
|
|
69
|
-
for (let j = 0; j < probs.length; j++) {
|
|
70
|
-
const jacobian =
|
|
71
|
-
i === j
|
|
72
|
-
? probs[i] * (1 - probs[i])
|
|
73
|
-
: -probs[i] * probs[j];
|
|
74
|
-
|
|
75
|
-
sum += jacobian * dOut[j];
|
|
76
|
-
}
|
|
77
|
-
dIn[i] = sum;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return dIn;
|
|
81
|
-
}
|
|
82
38
|
backward(dOutput, learningRate) {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
for (let r = 0; r < this.v[j].length; r++) {
|
|
89
|
-
dWeights[a][j] += dOutput[a][r] * this.v[j][r]
|
|
90
|
-
dV[j][r] += dOutput[a][r] * this.weights[a][j]
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const dScores = []
|
|
95
|
-
for (let t = 0; t < dWeights.length; t++) {
|
|
96
|
-
dScores[t] = this.softmaxBack(this.weights[t], dWeights[t])
|
|
97
|
-
}
|
|
98
|
-
const dQ = this.q.map(q => new Float32Array(q.length));
|
|
99
|
-
const dK = this.k.map(k => new Float32Array(k.length));
|
|
100
|
-
for (let a = 0; a < this.q.length; a++) {
|
|
101
|
-
for (let j = 0; j < this.k.length; j++) {
|
|
102
|
-
if (j > a) continue;
|
|
103
|
-
for (let r = 0; r < this.q[a].length; r++) {
|
|
104
|
-
dQ[a][r] += dScores[a][j] * this.k[j][r] / this.score;
|
|
105
|
-
dK[j][r] += dScores[a][j] * this.q[a][r] / this.score;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
39
|
+
const dWeights = this.gpu.dWeightsKernel(dOutput, this.v)
|
|
40
|
+
const dV = this.gpu.dVKernel(dOutput, this.weights);
|
|
41
|
+
const dScores = this.gpu.softmaxBackKernel(this.weights, dWeights)
|
|
42
|
+
const dQ = this.gpu.dQKernel(dScores, this.k, this.score)
|
|
43
|
+
const dK = this.gpu.dKKernel(dScores, this.q, this.score)
|
|
109
44
|
const dInput = this.q.map(() => new Float32Array(this.q[0].length))
|
|
110
45
|
const dq = this.query.backward(dQ, learningRate)
|
|
111
46
|
const dk = this.key.backward(dK, learningRate)
|
|
112
47
|
const dv = this.value.backward(dV, learningRate)
|
|
113
48
|
for (let a = 0; a < this.q.length; a++) {
|
|
114
|
-
for (let b = 0; b < dq.length; b++) {
|
|
49
|
+
for (let b = 0; b < dq[a].length; b++) {
|
|
115
50
|
dInput[a][b] = dq[a][b] + dk[a][b] + dv[a][b]
|
|
116
51
|
}
|
|
117
52
|
}
|
|
53
|
+
dWeights.delete()
|
|
54
|
+
dScores.delete()
|
|
118
55
|
return dInput
|
|
119
56
|
}
|
|
120
57
|
Save() {
|
package/src/gpiInit.js
CHANGED
|
@@ -261,12 +261,14 @@ export class GPUSoftmax {
|
|
|
261
261
|
const maxLogits = this.cacheMaxCache(logits)
|
|
262
262
|
const sumes = this.cacheSumCalculate(maxLogits, logits)
|
|
263
263
|
const splitedLogits = split2DByColumns(logits)
|
|
264
|
-
const result = Array.from({ length: this.contextSize }, () => [])
|
|
264
|
+
const result = Array.from({ length: this.contextSize }, () => new Float32Array(logits[0].length))
|
|
265
|
+
let offset = 0
|
|
265
266
|
for (let i = 0; i < splitedLogits.length; i++) {
|
|
266
267
|
const out = this.cacheSF[i](splitedLogits[i], sumes, maxLogits)
|
|
267
268
|
for (let a = 0; a < this.contextSize; a++) {
|
|
268
|
-
result[a].
|
|
269
|
+
result[a].set(out[a] , offset)
|
|
269
270
|
}
|
|
271
|
+
offset += out[0].length
|
|
270
272
|
}
|
|
271
273
|
maxLogits.delete()
|
|
272
274
|
sumes.delete()
|
|
@@ -274,12 +276,14 @@ export class GPUSoftmax {
|
|
|
274
276
|
}
|
|
275
277
|
backward(probs, target) {
|
|
276
278
|
const splitedProbs = split2DByColumns(probs)
|
|
277
|
-
const result = Array.from({ length: this.contextSize }, () => [])
|
|
279
|
+
const result = Array.from({ length: this.contextSize }, () => new Float32Array(probs[0].length))
|
|
280
|
+
let offset = 0;
|
|
278
281
|
for (let i = 0; i < this.cacheSB.length; i++) {
|
|
279
282
|
const out = this.cacheSB[i](splitedProbs[i], target)
|
|
280
283
|
for (let a = 0; a < this.contextSize; a++) {
|
|
281
|
-
result[a].
|
|
284
|
+
result[a].set(out[a], offset)
|
|
282
285
|
}
|
|
286
|
+
offset += out[0].length
|
|
283
287
|
}
|
|
284
288
|
return result
|
|
285
289
|
}
|
|
@@ -601,4 +605,121 @@ export class GELUGPU {
|
|
|
601
605
|
backward(dOutput, input) {
|
|
602
606
|
return this.cacheGB(input, dOutput)
|
|
603
607
|
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export class GPUAttention {
|
|
611
|
+
attentionScores;
|
|
612
|
+
attentionOutput;
|
|
613
|
+
dWeightsKernel;
|
|
614
|
+
dVKernel;
|
|
615
|
+
softmaxBackKernel;
|
|
616
|
+
dQKernel;
|
|
617
|
+
dKKernel;
|
|
618
|
+
constructor(embeddingSize, contextSize) {
|
|
619
|
+
this.attentionScores = gpu.createKernel(function (q, k, scale) {
|
|
620
|
+
const i = this.thread.y;
|
|
621
|
+
const j = this.thread.x;
|
|
622
|
+
if (j > i) {
|
|
623
|
+
return -1e9;
|
|
624
|
+
}
|
|
625
|
+
let sum = 0;
|
|
626
|
+
for (let d = 0; d < this.constants.D; d++) {
|
|
627
|
+
sum += q[i][d] * k[j][d];
|
|
628
|
+
}
|
|
629
|
+
return sum / scale;
|
|
630
|
+
}, {
|
|
631
|
+
output: [contextSize, contextSize],
|
|
632
|
+
constants: {
|
|
633
|
+
D: embeddingSize
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
this.attentionOutput = gpu.createKernel(function (weights, v) {
|
|
637
|
+
const i = this.thread.y;
|
|
638
|
+
const d = this.thread.x;
|
|
639
|
+
let sum = 0;
|
|
640
|
+
for (let j = 0; j < this.constants.CONTEXT; j++) {
|
|
641
|
+
sum += weights[i][j] * v[j][d];
|
|
642
|
+
}
|
|
643
|
+
return sum;
|
|
644
|
+
}, {
|
|
645
|
+
output: [embeddingSize, contextSize],
|
|
646
|
+
constants: {
|
|
647
|
+
CONTEXT: contextSize
|
|
648
|
+
},
|
|
649
|
+
});
|
|
650
|
+
this.dWeightsKernel = gpu.createKernel(function (dOutput, v) {
|
|
651
|
+
const a = this.thread.y;
|
|
652
|
+
const j = this.thread.x;
|
|
653
|
+
let sum = 0;
|
|
654
|
+
for (let r = 0; r < this.constants.D; r++) {
|
|
655
|
+
sum += dOutput[a][r] * v[j][r];
|
|
656
|
+
}
|
|
657
|
+
return sum;
|
|
658
|
+
}, {
|
|
659
|
+
output: [contextSize, contextSize],
|
|
660
|
+
pipeline: true,
|
|
661
|
+
immutable: true,
|
|
662
|
+
constants: {
|
|
663
|
+
D: embeddingSize
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
this.dVKernel = gpu.createKernel(function (dOutput, weights) {
|
|
667
|
+
const j = this.thread.y;
|
|
668
|
+
const r = this.thread.x;
|
|
669
|
+
let sum = 0;
|
|
670
|
+
for (let a = 0; a < this.constants.C; a++) {
|
|
671
|
+
sum += weights[a][j] * dOutput[a][r];
|
|
672
|
+
}
|
|
673
|
+
return sum;
|
|
674
|
+
}, {
|
|
675
|
+
output: [embeddingSize, contextSize],
|
|
676
|
+
|
|
677
|
+
constants: {
|
|
678
|
+
C: contextSize
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
this.softmaxBackKernel = gpu.createKernel(function (probs, dOut) {
|
|
682
|
+
const a = this.thread.y;
|
|
683
|
+
const i = this.thread.x;
|
|
684
|
+
let dot = 0;
|
|
685
|
+
for (let j = 0; j < this.constants.C; j++) {
|
|
686
|
+
dot += probs[a][j] * dOut[a][j];
|
|
687
|
+
}
|
|
688
|
+
return probs[a][i] * (dOut[a][i] - dot);
|
|
689
|
+
}, {
|
|
690
|
+
output: [contextSize, contextSize],
|
|
691
|
+
pipeline: true,
|
|
692
|
+
immutable: true,
|
|
693
|
+
constants: {
|
|
694
|
+
C: contextSize
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
this.dQKernel = gpu.createKernel(function (dScores, k, scale) {
|
|
698
|
+
const a = this.thread.y;
|
|
699
|
+
const r = this.thread.x;
|
|
700
|
+
let sum = 0;
|
|
701
|
+
for (let j = 0; j <= a; j++) {
|
|
702
|
+
sum += dScores[a][j] * k[j][r];
|
|
703
|
+
}
|
|
704
|
+
return sum / scale;
|
|
705
|
+
}, {
|
|
706
|
+
output: [embeddingSize, contextSize],
|
|
707
|
+
|
|
708
|
+
});
|
|
709
|
+
this.dKKernel = gpu.createKernel(function (dScores, q, scale) {
|
|
710
|
+
const j = this.thread.y;
|
|
711
|
+
const r = this.thread.x;
|
|
712
|
+
let sum = 0;
|
|
713
|
+
for (let a = j; a < this.constants.C; a++) {
|
|
714
|
+
sum += dScores[a][j] * q[a][r];
|
|
715
|
+
}
|
|
716
|
+
return sum / scale;
|
|
717
|
+
}, {
|
|
718
|
+
output: [embeddingSize, contextSize],
|
|
719
|
+
|
|
720
|
+
constants: {
|
|
721
|
+
C: contextSize
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
}
|
|
604
725
|
}
|