@mineproness/tensorloop 2.0.0 → 2.1.2

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/src/gpiInit.js ADDED
@@ -0,0 +1,725 @@
1
+ import { GPU } from 'gpu.js'
2
+
3
+ const gpu = new GPU({ mode: "gpu" })
4
+ if (gpu.mode == "cpu") {
5
+ throw new Error("The tensorloop didn't have working GPU access.")
6
+ }
7
+
8
+ // ==========================
9
+ // Init all Things
10
+ // ==========================
11
+
12
+ const maxTexture = GetMaxTexture()
13
+
14
+ // ===========================
15
+ // UTILS FUNCITON
16
+ // ===========================
17
+ function GetMaxTexture() {
18
+ const dummyKernel = gpu.createKernel(function () {
19
+ return 1 + 1
20
+ }).setOutput([1])
21
+ dummyKernel()
22
+ const gl = dummyKernel.context;
23
+ return gl.getParameter(gl.MAX_TEXTURE_SIZE)
24
+ }
25
+
26
+ export function spilt2DArray(arr) {
27
+ const result = []
28
+ for (let a = 0; a < arr.length; a += maxTexture) {
29
+ result.push(arr.slice(a, a + maxTexture))
30
+ }
31
+ return result
32
+ }
33
+ function split2DByColumns(matrix, chunkSize = maxTexture) {
34
+ const chunks = [];
35
+ for (let start = 0; start < matrix[0].length; start += chunkSize) {
36
+ const end = Math.min(start + chunkSize, matrix[0].length);
37
+ const chunk = matrix.map(row =>
38
+ row.slice(start, end)
39
+ );
40
+ chunks.push(chunk);
41
+ }
42
+ return chunks;
43
+ }
44
+ // =======================
45
+ // Init all Classes
46
+ // =======================
47
+
48
+
49
+ export class GPULinear {
50
+ cacheLF = [];
51
+ cacheLInputGra = []
52
+ cacheLWeigths = []
53
+ cacheLBias = []
54
+ Weights = [];
55
+ Bias = [];
56
+ contextSize;
57
+ embeddingSize;
58
+ outputSize;
59
+ constructor(weights, bias, contextSize) {
60
+
61
+ this.contextSize = contextSize;
62
+ this.embeddingSize = weights[0].length;
63
+ this.outputSize = weights.length
64
+ const splitW = spilt2DArray(weights)
65
+ const splitB = spilt2DArray(bias)
66
+ process.stdout.write(`\r[DEBUG] Saving Weights in VRAM${".".repeat(Math.floor(Math.random() * 4))}`)
67
+ for (let i = 0; i < splitW.length; i++) {
68
+ const biasVram = gpu.createKernel(function (x) {
69
+ return x[this.thread.x]
70
+ }, {
71
+ output: [splitW[i].length],
72
+ immutable: true,
73
+ pipeline: true
74
+ })
75
+ const weightVram = gpu.createKernel(function (x) {
76
+ return x[this.thread.y][this.thread.x]
77
+ }, {
78
+ output: [this.embeddingSize, splitW[i].length],
79
+ immutable: true,
80
+ pipeline: true
81
+ })
82
+ this.Weights[i] = weightVram(splitW[i]);
83
+ this.Bias[i] = biasVram(splitB[i]);
84
+ this.cacheLF[i] = gpu.createKernel(function (weights, bias, x) {
85
+ let sum = bias[this.thread.x]
86
+ for (let i = 0; i < this.constants.inputSize; i++) {
87
+ sum += weights[this.thread.x][i] * x[this.thread.y][i]
88
+ }
89
+ return sum;
90
+ }).setOutput([splitW[i].length, contextSize]).setConstants({ inputSize: this.embeddingSize })
91
+ this.cacheLWeigths[i] = gpu.createKernel(function (weights, learningRate, out, input) {
92
+ let sum = 0;
93
+ for (let a = 0; a < this.constants.contextSize; a++) {
94
+ sum += out[a][this.thread.y] * input[a][this.thread.x]
95
+ }
96
+ return weights[this.thread.y][this.thread.x] - learningRate * sum
97
+
98
+ }, {
99
+ constants: {
100
+ contextSize
101
+ },
102
+ output: [this.embeddingSize, splitW[i].length],
103
+ pipeline: true,
104
+ immutable: true
105
+ })
106
+ this.cacheLBias[i] = gpu.createKernel(function (bias, learningRate, out) {
107
+ let sum = 0;
108
+ for (let a = 0; a < this.constants.contextSize; a++) {
109
+ sum += out[a][this.thread.x]
110
+ }
111
+ return bias[this.thread.x] - learningRate * sum
112
+
113
+ }, {
114
+ constants: {
115
+ contextSize
116
+ },
117
+ output: [splitW[i].length],
118
+ pipeline: true,
119
+ immutable: true
120
+ })
121
+ this.cacheLInputGra[i] = gpu.createKernel(function (weights, out) {
122
+ let sum = 0;
123
+ for (let a = 0; a < this.constants.outputSizes; a++) {
124
+ sum += out[this.thread.y][a] * weights[a][this.thread.x]
125
+ }
126
+ return sum
127
+
128
+ }, {
129
+ output: [this.embeddingSize, contextSize],
130
+ constants: {
131
+ outputSizes: splitW[i].length
132
+ }
133
+ })
134
+ process.stdout.write(
135
+ `\r[DEBUG] Weigths are Saved in VRAM!`
136
+ );
137
+ }
138
+ }
139
+ forward(input) {
140
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(this.outputSize))
141
+ let offset = 0;
142
+ for (let i = 0; i < this.cacheLF.length; i++) {
143
+ const out = this.cacheLF[i](this.Weights[i], this.Bias[i], input)
144
+ for (let a = 0; a < this.contextSize; a++) {
145
+ result[a].set(out[a], offset)
146
+ }
147
+ offset += out[0].length
148
+ }
149
+ return result
150
+ }
151
+ Save() {
152
+ const weights = []
153
+ const bias = []
154
+ for (let a = 0; a < this.Weights.length; a++) {
155
+ const chunkB = this.Bias[a]
156
+ const chunkW = this.Weights[a]
157
+ if (chunkB.toArray) {
158
+ bias.push(...chunkB.toArray())
159
+ weights.push(...chunkW.toArray())
160
+ } else {
161
+ bias.push(...chunkB)
162
+ weights.push(...chunkW)
163
+ }
164
+ }
165
+ return { weights, bias: new Float32Array(bias) }
166
+ }
167
+ backward(outGradient, input, learningRate) {
168
+ const splitOut = split2DByColumns(outGradient)
169
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(this.embeddingSize))
170
+ for (let i = 0; i < splitOut.length; i++) {
171
+ const oldW = this.Weights[i]
172
+ const oldB = this.Bias[i]
173
+ const out = this.cacheLInputGra[i](this.Weights[i], splitOut[i])
174
+ this.Weights[i] = this.cacheLWeigths[i](this.Weights[i], learningRate, splitOut[i], input)
175
+ this.Bias[i] = this.cacheLBias[i](this.Bias[i], learningRate, splitOut[i])
176
+ for (let a = 0; a < this.contextSize; a++) {
177
+ for (let g = 0; g < this.embeddingSize; g++) {
178
+ result[a][g] += out[a][g]
179
+ }
180
+ }
181
+ if (oldW.delete) {
182
+ oldW.delete()
183
+ oldB.delete()
184
+ }
185
+ }
186
+ return result
187
+ }
188
+ }
189
+
190
+
191
+ export class GPUSoftmax {
192
+ cacheSumCalculate;
193
+ cacheMaxCache;
194
+ cacheSF = [];
195
+ cacheSB = []
196
+ contextSize;
197
+ calculateLoss;
198
+ avgLoss;
199
+ constructor(logits, contextSize) {
200
+ this.contextSize = contextSize;
201
+ this.avgLoss = gpu.createKernel(function (losses) {
202
+ let sum = 0;
203
+ for (let i = 0; i < this.constants.contextSize; i++) {
204
+ sum += losses[i]
205
+ }
206
+ return sum / this.constants.contextSize
207
+ }, {
208
+ output: [1],
209
+ constants: { contextSize }
210
+ })
211
+ this.calculateLoss = gpu.createKernel(function (probs, target) {
212
+ return -Math.log(probs[this.thread.x][target[this.thread.x]] + 1e-9)
213
+ }, { output: [contextSize], immutable: true, pipeline: true })
214
+ this.cacheSumCalculate = gpu.createKernel(function (maxLogits, logits) {
215
+ const maxLogit = maxLogits[this.thread.x]
216
+ let sum = 0;
217
+ for (let i = 0; i < this.constants.logitSize; i++) {
218
+ sum += Math.exp(logits[this.thread.x][i] - maxLogit)
219
+ }
220
+ return sum
221
+ }, {
222
+ output: [contextSize],
223
+ constants: { logitSize: logits[0].length },
224
+ immutable: true,
225
+ pipeline: true
226
+ })
227
+ this.cacheMaxCache = gpu.createKernel(function (logits) {
228
+ let maxLogit = logits[this.thread.x][0]
229
+ for (let i = 0; i < this.constants.logitSize; i++) {
230
+ if (logits[this.thread.x][i] > maxLogit) {
231
+ maxLogit = logits[this.thread.x][i]
232
+ }
233
+ }
234
+ return maxLogit
235
+ }, {
236
+ output: [contextSize],
237
+ constants: { logitSize: logits[0].length },
238
+ immutable: true,
239
+ pipeline: true
240
+ })
241
+ const splited2d = split2DByColumns(logits)
242
+ let offset = 0;
243
+ for (let a = 0; a < splited2d.length; a++) {
244
+ this.cacheSF[a] = gpu.createKernel(function (logits, sum, maxLogit) {
245
+ return Math.exp(logits[this.thread.y][this.thread.x] - maxLogit[this.thread.y]) / sum[this.thread.y]
246
+ }, {
247
+ output: [splited2d[a][0].length, contextSize]
248
+ })
249
+ this.cacheSB[a] = gpu.createKernel(function (logits, targets) {
250
+ let logit = logits[this.thread.y][this.thread.x]
251
+ let globalIndex = this.constants.offset + this.thread.x
252
+ return globalIndex == targets[this.thread.y] ? logit - 1.0 : logit
253
+ }, {
254
+ output: [splited2d[a][0].length, contextSize],
255
+ constants: { offset: offset }
256
+ })
257
+ offset += splited2d[a][0].length
258
+ }
259
+ }
260
+ forward(logits) {
261
+ const maxLogits = this.cacheMaxCache(logits)
262
+ const sumes = this.cacheSumCalculate(maxLogits, logits)
263
+ const splitedLogits = split2DByColumns(logits)
264
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(logits[0].length))
265
+ let offset = 0
266
+ for (let i = 0; i < splitedLogits.length; i++) {
267
+ const out = this.cacheSF[i](splitedLogits[i], sumes, maxLogits)
268
+ for (let a = 0; a < this.contextSize; a++) {
269
+ result[a].set(out[a] , offset)
270
+ }
271
+ offset += out[0].length
272
+ }
273
+ maxLogits.delete()
274
+ sumes.delete()
275
+ return result
276
+ }
277
+ backward(probs, target) {
278
+ const splitedProbs = split2DByColumns(probs)
279
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(probs[0].length))
280
+ let offset = 0;
281
+ for (let i = 0; i < this.cacheSB.length; i++) {
282
+ const out = this.cacheSB[i](splitedProbs[i], target)
283
+ for (let a = 0; a < this.contextSize; a++) {
284
+ result[a].set(out[a], offset)
285
+ }
286
+ offset += out[0].length
287
+ }
288
+ return result
289
+ }
290
+ crossEntropy(probs, target) {
291
+ const losses = this.calculateLoss(probs, target)
292
+ const loss = this.avgLoss(losses)
293
+ losses.delete()
294
+ return loss
295
+ }
296
+
297
+ }
298
+
299
+
300
+ export class GPUHiddenLayer {
301
+ cacheHF = [];
302
+ cacheHB = []
303
+ contextSize = 0;
304
+ input = [];
305
+ initKernel(probs, contextSize) {
306
+ const splitL = split2DByColumns(probs)
307
+ this.contextSize = contextSize;
308
+ for (let a = 0; a < splitL.length; a++) {
309
+ this.cacheHF[a] = gpu.createKernel(function (xs) {
310
+ const x = xs[this.thread.y][this.thread.x]
311
+ return x > 0 ? x : x * 0.02
312
+ }).setOutput([splitL[a].length, contextSize])
313
+ this.cacheHB[a] = gpu.createKernel(function (outputGradient, input) {
314
+ const grad = outputGradient[this.thread.y][this.thread.x]
315
+ const x = input[this.thread.y][this.thread.x]
316
+ return x > 0 ? grad : grad * 0.02
317
+ }, {
318
+ output: [splitL[a].length, contextSize]
319
+ })
320
+ }
321
+ }
322
+ forward(logits) {
323
+ if (this.cacheHF.length == 0) {
324
+ this.initKernel(logits, logits.length)
325
+ }
326
+ this.input = logits
327
+ const split = split2DByColumns(logits)
328
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(logits[0].length))
329
+ let offset = 0;
330
+ for (let a = 0; a < split.length; a++) {
331
+ const out = this.cacheHF[a](split[a])
332
+ for (let i = 0; i < this.contextSize; i++) {
333
+ result[i].set(out[i], offset)
334
+ }
335
+ offset += out[0].length
336
+ }
337
+ return result
338
+ }
339
+ backward(outputGradient) {
340
+ const splitOut = split2DByColumns(outputGradient)
341
+ const inputSp = split2DByColumns(this.input)
342
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(outputGradient[0].length))
343
+ let offset = 0;
344
+ for (let a = 0; a < splitOut.length; a++) {
345
+ const out = this.cacheHB[a](splitOut[a], inputSp[a])
346
+ for (let i = 0; i < this.contextSize; i++) {
347
+ result[i].set(out[i], offset)
348
+ }
349
+ offset += out[0].length
350
+ }
351
+ return result
352
+ }
353
+ ClearInputCache() {
354
+ this.input = []
355
+ }
356
+ }
357
+ export class GPUEmbedding {
358
+ vocabSize = 0;
359
+ embeddingSize = 0;
360
+ contextSize = 0;
361
+ chunkStarts = [];
362
+ chunkEnds = [];
363
+ vectors = [];
364
+
365
+ lookupKernels = [];
366
+ cacheEB = [];
367
+
368
+ indexes = [];
369
+ positions = [];
370
+
371
+ constructor(vectors, vocabSize, embeddingSize, contextSize) {
372
+ this.embeddingSize = embeddingSize;
373
+ this.contextSize = contextSize;
374
+ this.vocabSize = vocabSize;
375
+
376
+ const splitedVectors = spilt2DArray(vectors);
377
+ let start = 0;
378
+ process.stdout.write(
379
+ `\r[DEBUG] Saving Vectors in VRAM${".".repeat(Math.floor(Math.random() * 4))}`
380
+ );
381
+ for (let a = 0; a < splitedVectors.length; a++) {
382
+
383
+
384
+ const length = splitedVectors[a].length;
385
+
386
+ this.chunkStarts[a] = start;
387
+ this.chunkEnds[a] = start + length;
388
+
389
+ const vectorsK = gpu.createKernel(function (x) {
390
+ return x[this.thread.x][this.thread.y];
391
+ }, {
392
+ output: [length, embeddingSize],
393
+ pipeline: true,
394
+ immutable: true
395
+ });
396
+
397
+ this.vectors[a] = vectorsK(splitedVectors[a]);
398
+ vectorsK.destroy();
399
+
400
+ this.cacheEB[a] = gpu.createKernel(function (vectors, indexes, positions, outGradient, learningRate) {
401
+ const tokenIndex = this.thread.x;
402
+ const dim = this.thread.y;
403
+ let gradient = 0;
404
+
405
+ for (let p = 0; p < this.constants.contextSize; p++) {
406
+ const index = indexes[p];
407
+ const pos = positions[p];
408
+
409
+ if (index >= 0 && index == tokenIndex && pos >= 0) {
410
+ gradient += outGradient[pos][dim];
411
+ }
412
+ }
413
+
414
+ return vectors[tokenIndex][dim] - learningRate * gradient;
415
+ }, {
416
+ output: [length, embeddingSize],
417
+ immutable: true,
418
+ pipeline: true,
419
+ constants: {
420
+ contextSize: this.contextSize
421
+ }
422
+ });
423
+
424
+ start += length;
425
+
426
+ }
427
+ process.stdout.write(
428
+ `\n[DEBUG] Vectors are Saved in VRAM!`
429
+ );
430
+
431
+ process.stdout.write("\n");
432
+ }
433
+
434
+ getLookupKernel(count) {
435
+ if (!this.lookupKernels[count]) {
436
+ this.lookupKernels[count] = gpu.createKernel(function (vectors, indexes) {
437
+ const dim = this.thread.x;
438
+ const pos = this.thread.y;
439
+ const index = Math.floor(indexes[pos]);
440
+
441
+ return vectors[index][dim];
442
+ }, {
443
+ output: [
444
+ this.embeddingSize,
445
+ count
446
+ ]
447
+ });
448
+ }
449
+
450
+ return this.lookupKernels[count];
451
+ }
452
+
453
+ forward(tokens) {
454
+ const result = Array.from(
455
+ { length: this.contextSize },
456
+ () => new Float32Array(this.embeddingSize)
457
+ );
458
+
459
+ for (let i = 0; i < this.vectors.length; i++) {
460
+
461
+ const start = this.chunkStarts[i];
462
+ const end = this.chunkEnds[i];
463
+
464
+ const indexArray = new Float32Array(this.contextSize);
465
+ const positionArray = new Int32Array(this.contextSize);
466
+
467
+ for (let p = 0; p < this.contextSize; p++) {
468
+ indexArray[p] = -1;
469
+ positionArray[p] = -1;
470
+ }
471
+
472
+ let count = 0;
473
+
474
+ for (let pos = 0; pos < tokens.length && count < this.contextSize; pos++) {
475
+ const token = tokens[pos];
476
+ if (token >= start && token < end) {
477
+ indexArray[count] = token - start;
478
+ positionArray[count] = pos;
479
+ count++;
480
+ }
481
+ }
482
+ this.indexes[i] = indexArray;
483
+ this.positions[i] = positionArray;
484
+ if (count === 0) {
485
+ continue;
486
+ }
487
+ const compactIndexes = indexArray.subarray(0, count);
488
+ const lookup = this.getLookupKernel(count);
489
+ const out = lookup(
490
+ this.vectors[i],
491
+ compactIndexes
492
+ );
493
+
494
+ for (let j = 0; j < count; j++) {
495
+ const originalPosition = positionArray[j];
496
+ for (let dim = 0; dim < this.embeddingSize; dim++) {
497
+ result[originalPosition][dim] = out[j][dim];
498
+ }
499
+ }
500
+ }
501
+ return result;
502
+ }
503
+
504
+ backward(outGradient, learningRate) {
505
+ for (let a = 0; a < this.vectors.length; a++) {
506
+ if (!this.indexes[a]) {
507
+ continue;
508
+ }
509
+
510
+ let hasToken = false;
511
+
512
+ for (let p = 0; p < this.contextSize; p++) {
513
+ if (this.indexes[a][p] >= 0) {
514
+ hasToken = true;
515
+ break;
516
+ }
517
+ }
518
+
519
+ if (!hasToken) {
520
+ continue;
521
+ }
522
+
523
+ const oldVec = this.vectors[a];
524
+
525
+ this.vectors[a] = this.cacheEB[a](
526
+ oldVec,
527
+ this.indexes[a],
528
+ this.positions[a],
529
+ outGradient,
530
+ learningRate
531
+ );
532
+
533
+ if (oldVec && oldVec.delete) {
534
+ oldVec.delete();
535
+ }
536
+ }
537
+ }
538
+
539
+ destroy() {
540
+ for (const vector of this.vectors) {
541
+ if (vector && vector.delete) {
542
+ vector.delete();
543
+ }
544
+ }
545
+
546
+ for (const kernel of this.lookupKernels) {
547
+ if (kernel) {
548
+ kernel.destroy();
549
+ }
550
+ }
551
+
552
+ for (const kernel of this.cacheEB) {
553
+ if (kernel) {
554
+ kernel.destroy();
555
+ }
556
+ }
557
+
558
+ this.vectors = [];
559
+ this.lookupKernels = [];
560
+ this.cacheEB = [];
561
+ this.indexes = [];
562
+ this.positions = [];
563
+ this.chunkStarts = [];
564
+ this.chunkEnds = [];
565
+ }
566
+ }
567
+
568
+ export class GELUGPU {
569
+ cacheGF;
570
+ cacheGB;
571
+ constructor(embeddingSize, contextSize) {
572
+ this.cacheGF = gpu.createKernel(function (input) {
573
+ const k = this.constants.kVal;
574
+ const x = input[this.thread.y][this.thread.x]
575
+ const u = k * (x + 0.044715 * x * x * x)
576
+ return 0.5 * x * (1 + Math.tanh(u))
577
+ }, {
578
+ output: [embeddingSize, contextSize],
579
+ constants: {
580
+ kVal: Math.sqrt(2 / Math.PI)
581
+ }
582
+ })
583
+ this.cacheGB = gpu.createKernel(function (input, gradient) {
584
+ const x = input[this.thread.y][this.thread.x]
585
+ const k = this.constants.kVal;
586
+ const x3 = x * x * x;
587
+ const u = k * (x + 0.044715 * x3)
588
+ const t = Math.tanh(u)
589
+ const sech2 = 1 - t * t
590
+ const duDx = k * (1 + 3 * 0.044715 * x * x)
591
+ const geluGrad =
592
+ 0.5 * (1 + t) +
593
+ 0.5 * x * sech2 * duDx;
594
+ return gradient[this.thread.y][this.thread.x] * geluGrad
595
+ }, {
596
+ output: [embeddingSize, contextSize],
597
+ constants: {
598
+ kVal: Math.sqrt(2 / Math.PI)
599
+ }
600
+ })
601
+ }
602
+ forward(input) {
603
+ return this.cacheGF(input)
604
+ }
605
+ backward(dOutput, input) {
606
+ return this.cacheGB(input, dOutput)
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
+ }
725
+ }