@mineproness/tensorloop 2.1.0 → 2.1.11
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 +11 -76
- package/src/gpiInit.js +117 -0
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,96 +24,29 @@ 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
|
}
|
package/src/gpiInit.js
CHANGED
|
@@ -601,4 +601,121 @@ export class GELUGPU {
|
|
|
601
601
|
backward(dOutput, input) {
|
|
602
602
|
return this.cacheGB(input, dOutput)
|
|
603
603
|
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export class GPUAttention {
|
|
607
|
+
attentionScores;
|
|
608
|
+
attentionOutput;
|
|
609
|
+
dWeightsKernel;
|
|
610
|
+
dVKernel;
|
|
611
|
+
softmaxBackKernel;
|
|
612
|
+
dQKernel;
|
|
613
|
+
dKKernel;
|
|
614
|
+
constructor(embeddingSize, contextSize) {
|
|
615
|
+
this.attentionScores = gpu.createKernel(function (q, k, scale) {
|
|
616
|
+
const i = this.thread.y;
|
|
617
|
+
const j = this.thread.x;
|
|
618
|
+
if (j > i) {
|
|
619
|
+
return -1e9;
|
|
620
|
+
}
|
|
621
|
+
let sum = 0;
|
|
622
|
+
for (let d = 0; d < this.constants.D; d++) {
|
|
623
|
+
sum += q[i][d] * k[j][d];
|
|
624
|
+
}
|
|
625
|
+
return sum / scale;
|
|
626
|
+
}, {
|
|
627
|
+
output: [contextSize, contextSize],
|
|
628
|
+
constants: {
|
|
629
|
+
D: embeddingSize
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
this.attentionOutput = gpu.createKernel(function (weights, v) {
|
|
633
|
+
const i = this.thread.y;
|
|
634
|
+
const d = this.thread.x;
|
|
635
|
+
let sum = 0;
|
|
636
|
+
for (let j = 0; j < this.constants.CONTEXT; j++) {
|
|
637
|
+
sum += weights[i][j] * v[j][d];
|
|
638
|
+
}
|
|
639
|
+
return sum;
|
|
640
|
+
}, {
|
|
641
|
+
output: [embeddingSize, contextSize],
|
|
642
|
+
constants: {
|
|
643
|
+
CONTEXT: contextSize
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
this.dWeightsKernel = gpu.createKernel(function (dOutput, v) {
|
|
647
|
+
const a = this.thread.y;
|
|
648
|
+
const j = this.thread.x;
|
|
649
|
+
let sum = 0;
|
|
650
|
+
for (let r = 0; r < this.constants.D; r++) {
|
|
651
|
+
sum += dOutput[a][r] * v[j][r];
|
|
652
|
+
}
|
|
653
|
+
return sum;
|
|
654
|
+
}, {
|
|
655
|
+
output: [contextSize, contextSize],
|
|
656
|
+
pipeline: true,
|
|
657
|
+
immutable: true,
|
|
658
|
+
constants: {
|
|
659
|
+
D: embeddingSize
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
this.dVKernel = gpu.createKernel(function (dOutput, weights) {
|
|
663
|
+
const j = this.thread.y;
|
|
664
|
+
const r = this.thread.x;
|
|
665
|
+
let sum = 0;
|
|
666
|
+
for (let a = 0; a < this.constants.C; a++) {
|
|
667
|
+
sum += weights[a][j] * dOutput[a][r];
|
|
668
|
+
}
|
|
669
|
+
return sum;
|
|
670
|
+
}, {
|
|
671
|
+
output: [embeddingSize, contextSize],
|
|
672
|
+
|
|
673
|
+
constants: {
|
|
674
|
+
C: contextSize
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
this.softmaxBackKernel = gpu.createKernel(function (probs, dOut) {
|
|
678
|
+
const a = this.thread.y;
|
|
679
|
+
const i = this.thread.x;
|
|
680
|
+
let dot = 0;
|
|
681
|
+
for (let j = 0; j < this.constants.C; j++) {
|
|
682
|
+
dot += probs[a][j] * dOut[a][j];
|
|
683
|
+
}
|
|
684
|
+
return probs[a][i] * (dOut[a][i] - dot);
|
|
685
|
+
}, {
|
|
686
|
+
output: [contextSize, contextSize],
|
|
687
|
+
pipeline: true,
|
|
688
|
+
immutable: true,
|
|
689
|
+
constants: {
|
|
690
|
+
C: contextSize
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
this.dQKernel = gpu.createKernel(function (dScores, k, scale) {
|
|
694
|
+
const a = this.thread.y;
|
|
695
|
+
const r = this.thread.x;
|
|
696
|
+
let sum = 0;
|
|
697
|
+
for (let j = 0; j <= a; j++) {
|
|
698
|
+
sum += dScores[a][j] * k[j][r];
|
|
699
|
+
}
|
|
700
|
+
return sum / scale;
|
|
701
|
+
}, {
|
|
702
|
+
output: [embeddingSize, contextSize],
|
|
703
|
+
|
|
704
|
+
});
|
|
705
|
+
this.dKKernel = gpu.createKernel(function (dScores, q, scale) {
|
|
706
|
+
const j = this.thread.y;
|
|
707
|
+
const r = this.thread.x;
|
|
708
|
+
let sum = 0;
|
|
709
|
+
for (let a = j; a < this.constants.C; a++) {
|
|
710
|
+
sum += dScores[a][j] * q[a][r];
|
|
711
|
+
}
|
|
712
|
+
return sum / scale;
|
|
713
|
+
}, {
|
|
714
|
+
output: [embeddingSize, contextSize],
|
|
715
|
+
|
|
716
|
+
constants: {
|
|
717
|
+
C: contextSize
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
604
721
|
}
|