@mineproness/tensorloop 2.0.0 → 2.1.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/src/gpiInit.js ADDED
@@ -0,0 +1,604 @@
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 }, () => [])
265
+ for (let i = 0; i < splitedLogits.length; i++) {
266
+ const out = this.cacheSF[i](splitedLogits[i], sumes, maxLogits)
267
+ for (let a = 0; a < this.contextSize; a++) {
268
+ result[a].push(...out[a])
269
+ }
270
+ }
271
+ maxLogits.delete()
272
+ sumes.delete()
273
+ return result
274
+ }
275
+ backward(probs, target) {
276
+ const splitedProbs = split2DByColumns(probs)
277
+ const result = Array.from({ length: this.contextSize }, () => [])
278
+ for (let i = 0; i < this.cacheSB.length; i++) {
279
+ const out = this.cacheSB[i](splitedProbs[i], target)
280
+ for (let a = 0; a < this.contextSize; a++) {
281
+ result[a].push(...out[a])
282
+ }
283
+ }
284
+ return result
285
+ }
286
+ crossEntropy(probs, target) {
287
+ const losses = this.calculateLoss(probs, target)
288
+ const loss = this.avgLoss(losses)
289
+ losses.delete()
290
+ return loss
291
+ }
292
+
293
+ }
294
+
295
+
296
+ export class GPUHiddenLayer {
297
+ cacheHF = [];
298
+ cacheHB = []
299
+ contextSize = 0;
300
+ input = [];
301
+ initKernel(probs, contextSize) {
302
+ const splitL = split2DByColumns(probs)
303
+ this.contextSize = contextSize;
304
+ for (let a = 0; a < splitL.length; a++) {
305
+ this.cacheHF[a] = gpu.createKernel(function (xs) {
306
+ const x = xs[this.thread.y][this.thread.x]
307
+ return x > 0 ? x : x * 0.02
308
+ }).setOutput([splitL[a].length, contextSize])
309
+ this.cacheHB[a] = gpu.createKernel(function (outputGradient, input) {
310
+ const grad = outputGradient[this.thread.y][this.thread.x]
311
+ const x = input[this.thread.y][this.thread.x]
312
+ return x > 0 ? grad : grad * 0.02
313
+ }, {
314
+ output: [splitL[a].length, contextSize]
315
+ })
316
+ }
317
+ }
318
+ forward(logits) {
319
+ if (this.cacheHF.length == 0) {
320
+ this.initKernel(logits, logits.length)
321
+ }
322
+ this.input = logits
323
+ const split = split2DByColumns(logits)
324
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(logits[0].length))
325
+ let offset = 0;
326
+ for (let a = 0; a < split.length; a++) {
327
+ const out = this.cacheHF[a](split[a])
328
+ for (let i = 0; i < this.contextSize; i++) {
329
+ result[i].set(out[i], offset)
330
+ }
331
+ offset += out[0].length
332
+ }
333
+ return result
334
+ }
335
+ backward(outputGradient) {
336
+ const splitOut = split2DByColumns(outputGradient)
337
+ const inputSp = split2DByColumns(this.input)
338
+ const result = Array.from({ length: this.contextSize }, () => new Float32Array(outputGradient[0].length))
339
+ let offset = 0;
340
+ for (let a = 0; a < splitOut.length; a++) {
341
+ const out = this.cacheHB[a](splitOut[a], inputSp[a])
342
+ for (let i = 0; i < this.contextSize; i++) {
343
+ result[i].set(out[i], offset)
344
+ }
345
+ offset += out[0].length
346
+ }
347
+ return result
348
+ }
349
+ ClearInputCache() {
350
+ this.input = []
351
+ }
352
+ }
353
+ export class GPUEmbedding {
354
+ vocabSize = 0;
355
+ embeddingSize = 0;
356
+ contextSize = 0;
357
+ chunkStarts = [];
358
+ chunkEnds = [];
359
+ vectors = [];
360
+
361
+ lookupKernels = [];
362
+ cacheEB = [];
363
+
364
+ indexes = [];
365
+ positions = [];
366
+
367
+ constructor(vectors, vocabSize, embeddingSize, contextSize) {
368
+ this.embeddingSize = embeddingSize;
369
+ this.contextSize = contextSize;
370
+ this.vocabSize = vocabSize;
371
+
372
+ const splitedVectors = spilt2DArray(vectors);
373
+ let start = 0;
374
+ process.stdout.write(
375
+ `\r[DEBUG] Saving Vectors in VRAM${".".repeat(Math.floor(Math.random() * 4))}`
376
+ );
377
+ for (let a = 0; a < splitedVectors.length; a++) {
378
+
379
+
380
+ const length = splitedVectors[a].length;
381
+
382
+ this.chunkStarts[a] = start;
383
+ this.chunkEnds[a] = start + length;
384
+
385
+ const vectorsK = gpu.createKernel(function (x) {
386
+ return x[this.thread.x][this.thread.y];
387
+ }, {
388
+ output: [length, embeddingSize],
389
+ pipeline: true,
390
+ immutable: true
391
+ });
392
+
393
+ this.vectors[a] = vectorsK(splitedVectors[a]);
394
+ vectorsK.destroy();
395
+
396
+ this.cacheEB[a] = gpu.createKernel(function (vectors, indexes, positions, outGradient, learningRate) {
397
+ const tokenIndex = this.thread.x;
398
+ const dim = this.thread.y;
399
+ let gradient = 0;
400
+
401
+ for (let p = 0; p < this.constants.contextSize; p++) {
402
+ const index = indexes[p];
403
+ const pos = positions[p];
404
+
405
+ if (index >= 0 && index == tokenIndex && pos >= 0) {
406
+ gradient += outGradient[pos][dim];
407
+ }
408
+ }
409
+
410
+ return vectors[tokenIndex][dim] - learningRate * gradient;
411
+ }, {
412
+ output: [length, embeddingSize],
413
+ immutable: true,
414
+ pipeline: true,
415
+ constants: {
416
+ contextSize: this.contextSize
417
+ }
418
+ });
419
+
420
+ start += length;
421
+
422
+ }
423
+ process.stdout.write(
424
+ `\n[DEBUG] Vectors are Saved in VRAM!`
425
+ );
426
+
427
+ process.stdout.write("\n");
428
+ }
429
+
430
+ getLookupKernel(count) {
431
+ if (!this.lookupKernels[count]) {
432
+ this.lookupKernels[count] = gpu.createKernel(function (vectors, indexes) {
433
+ const dim = this.thread.x;
434
+ const pos = this.thread.y;
435
+ const index = Math.floor(indexes[pos]);
436
+
437
+ return vectors[index][dim];
438
+ }, {
439
+ output: [
440
+ this.embeddingSize,
441
+ count
442
+ ]
443
+ });
444
+ }
445
+
446
+ return this.lookupKernels[count];
447
+ }
448
+
449
+ forward(tokens) {
450
+ const result = Array.from(
451
+ { length: this.contextSize },
452
+ () => new Float32Array(this.embeddingSize)
453
+ );
454
+
455
+ for (let i = 0; i < this.vectors.length; i++) {
456
+
457
+ const start = this.chunkStarts[i];
458
+ const end = this.chunkEnds[i];
459
+
460
+ const indexArray = new Float32Array(this.contextSize);
461
+ const positionArray = new Int32Array(this.contextSize);
462
+
463
+ for (let p = 0; p < this.contextSize; p++) {
464
+ indexArray[p] = -1;
465
+ positionArray[p] = -1;
466
+ }
467
+
468
+ let count = 0;
469
+
470
+ for (let pos = 0; pos < tokens.length && count < this.contextSize; pos++) {
471
+ const token = tokens[pos];
472
+ if (token >= start && token < end) {
473
+ indexArray[count] = token - start;
474
+ positionArray[count] = pos;
475
+ count++;
476
+ }
477
+ }
478
+ this.indexes[i] = indexArray;
479
+ this.positions[i] = positionArray;
480
+ if (count === 0) {
481
+ continue;
482
+ }
483
+ const compactIndexes = indexArray.subarray(0, count);
484
+ const lookup = this.getLookupKernel(count);
485
+ const out = lookup(
486
+ this.vectors[i],
487
+ compactIndexes
488
+ );
489
+
490
+ for (let j = 0; j < count; j++) {
491
+ const originalPosition = positionArray[j];
492
+ for (let dim = 0; dim < this.embeddingSize; dim++) {
493
+ result[originalPosition][dim] = out[j][dim];
494
+ }
495
+ }
496
+ }
497
+ return result;
498
+ }
499
+
500
+ backward(outGradient, learningRate) {
501
+ for (let a = 0; a < this.vectors.length; a++) {
502
+ if (!this.indexes[a]) {
503
+ continue;
504
+ }
505
+
506
+ let hasToken = false;
507
+
508
+ for (let p = 0; p < this.contextSize; p++) {
509
+ if (this.indexes[a][p] >= 0) {
510
+ hasToken = true;
511
+ break;
512
+ }
513
+ }
514
+
515
+ if (!hasToken) {
516
+ continue;
517
+ }
518
+
519
+ const oldVec = this.vectors[a];
520
+
521
+ this.vectors[a] = this.cacheEB[a](
522
+ oldVec,
523
+ this.indexes[a],
524
+ this.positions[a],
525
+ outGradient,
526
+ learningRate
527
+ );
528
+
529
+ if (oldVec && oldVec.delete) {
530
+ oldVec.delete();
531
+ }
532
+ }
533
+ }
534
+
535
+ destroy() {
536
+ for (const vector of this.vectors) {
537
+ if (vector && vector.delete) {
538
+ vector.delete();
539
+ }
540
+ }
541
+
542
+ for (const kernel of this.lookupKernels) {
543
+ if (kernel) {
544
+ kernel.destroy();
545
+ }
546
+ }
547
+
548
+ for (const kernel of this.cacheEB) {
549
+ if (kernel) {
550
+ kernel.destroy();
551
+ }
552
+ }
553
+
554
+ this.vectors = [];
555
+ this.lookupKernels = [];
556
+ this.cacheEB = [];
557
+ this.indexes = [];
558
+ this.positions = [];
559
+ this.chunkStarts = [];
560
+ this.chunkEnds = [];
561
+ }
562
+ }
563
+
564
+ export class GELUGPU {
565
+ cacheGF;
566
+ cacheGB;
567
+ constructor(embeddingSize, contextSize) {
568
+ this.cacheGF = gpu.createKernel(function (input) {
569
+ const k = this.constants.kVal;
570
+ const x = input[this.thread.y][this.thread.x]
571
+ const u = k * (x + 0.044715 * x * x * x)
572
+ return 0.5 * x * (1 + Math.tanh(u))
573
+ }, {
574
+ output: [embeddingSize, contextSize],
575
+ constants: {
576
+ kVal: Math.sqrt(2 / Math.PI)
577
+ }
578
+ })
579
+ this.cacheGB = gpu.createKernel(function (input, gradient) {
580
+ const x = input[this.thread.y][this.thread.x]
581
+ const k = this.constants.kVal;
582
+ const x3 = x * x * x;
583
+ const u = k * (x + 0.044715 * x3)
584
+ const t = Math.tanh(u)
585
+ const sech2 = 1 - t * t
586
+ const duDx = k * (1 + 3 * 0.044715 * x * x)
587
+ const geluGrad =
588
+ 0.5 * (1 + t) +
589
+ 0.5 * x * sech2 * duDx;
590
+ return gradient[this.thread.y][this.thread.x] * geluGrad
591
+ }, {
592
+ output: [embeddingSize, contextSize],
593
+ constants: {
594
+ kVal: Math.sqrt(2 / Math.PI)
595
+ }
596
+ })
597
+ }
598
+ forward(input) {
599
+ return this.cacheGF(input)
600
+ }
601
+ backward(dOutput, input) {
602
+ return this.cacheGB(input, dOutput)
603
+ }
604
+ }