@genai-fi/nanogpt 0.21.0 → 0.23.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.
Files changed (55) hide show
  1. package/dist/{DatasetBuilder-B9UGNQT5.js → DatasetBuilder-C0iJT29K.js} +122 -93
  2. package/dist/Generator.js +2 -2
  3. package/dist/TeachableLLM.d.ts +2 -1
  4. package/dist/TeachableLLM.js +1 -1
  5. package/dist/Trainer-DBsyWJ4s.js +228 -0
  6. package/dist/Trainer.d.ts +2 -1
  7. package/dist/Trainer.js +1 -1
  8. package/dist/data/stream.d.ts +24 -0
  9. package/dist/data/stream.js +2 -0
  10. package/dist/data/textLoader.d.ts +2 -2
  11. package/dist/data/textLoader.js +28 -67
  12. package/dist/{BaseTokeniser-C9TSv4th.js → eventemitter3-D_qV3Lof.js} +2 -132
  13. package/dist/loader/load.js +2 -2
  14. package/dist/loader/loadHF.js +1 -1
  15. package/dist/loader/loadTransformers.js +2 -2
  16. package/dist/loader/newZipLoad.js +1 -1
  17. package/dist/loader/oldZipLoad.js +1 -1
  18. package/dist/loader/save.js +1 -1
  19. package/dist/{main-DdsoTJAW.js → main-BSaDGH7I.js} +2686 -2912
  20. package/dist/main.d.ts +4 -0
  21. package/dist/main.js +20 -16
  22. package/dist/models/NanoGPTV1.js +1 -1
  23. package/dist/models/NanoGPTV2.js +1 -1
  24. package/dist/models/factory.js +1 -1
  25. package/dist/models/model.js +1 -1
  26. package/dist/stream-BjdpSNqB.js +2296 -0
  27. package/dist/tokeniser/BaseTokeniser.d.ts +2 -1
  28. package/dist/tokeniser/BaseTokeniser.js +135 -2
  29. package/dist/tokeniser/CharTokeniser.d.ts +2 -2
  30. package/dist/tokeniser/CharTokeniser.js +10 -14
  31. package/dist/tokeniser/bpe.d.ts +2 -2
  32. package/dist/tokeniser/bpe.js +23 -32
  33. package/dist/tokeniser/type.d.ts +3 -2
  34. package/dist/training/DatasetBuilder.d.ts +17 -1
  35. package/dist/training/DatasetBuilder.js +2 -2
  36. package/dist/training/PreTrainer.js +1 -1
  37. package/dist/training/SFTTrainer.js +1 -1
  38. package/dist/training/tasks/ConversationTask.d.ts +9 -10
  39. package/dist/training/tasks/ConversationTask.js +15 -24
  40. package/dist/training/tasks/PretrainingTask.d.ts +4 -4
  41. package/dist/training/tasks/PretrainingTask.js +2 -2
  42. package/dist/training/tasks/StartSentenceTask.d.ts +4 -4
  43. package/dist/training/tasks/StartSentenceTask.js +3 -3
  44. package/dist/training/tasks/Task.d.ts +19 -12
  45. package/dist/training/tasks/Task.js +25 -30
  46. package/dist/training/tasks/TokenStore.d.ts +46 -0
  47. package/dist/training/tasks/TokenStore.js +215 -0
  48. package/dist/training/tasks/splitter.d.ts +2 -2
  49. package/dist/training/tasks/splitter.js +11 -11
  50. package/dist/training/validation.d.ts +4 -2
  51. package/dist/training/validation.js +21 -2
  52. package/dist/utilities/tokens.d.ts +2 -0
  53. package/dist/utilities/tokens.js +40 -0
  54. package/dist/utilities/topP.js +6 -0
  55. package/package.json +2 -1
@@ -1,9 +1,10 @@
1
1
  import { yieldIfNeeded as e } from "../../utilities/yielder.js";
2
+ import { createTokenStore as t, deleteTokenStore as n } from "./TokenStore.js";
2
3
  //#region lib/training/tasks/Task.ts
3
- var t = class {};
4
- function n(e, t, n, r, i, a) {
4
+ var r = class {};
5
+ async function i(e, t, n, r, i, a) {
5
6
  for (let o of e) {
6
- let e = o.nextTokens(n, a ? !0 : void 0);
7
+ let e = await o.nextTokens(n, a ? !0 : void 0);
7
8
  if (e) {
8
9
  let n = Array.isArray(e) ? e : e.tokens;
9
10
  r.total += n.length;
@@ -11,7 +12,9 @@ function n(e, t, n, r, i, a) {
11
12
  if (r.offset + n.length > o.length) {
12
13
  let c = o.length - r.offset;
13
14
  o.set(n.slice(0, c), r.offset);
14
- let l = n.length - c, u = new Uint16Array(Math.max(Math.floor(i * .1) + 100, l));
15
+ let l = n.length - c;
16
+ if (l > i) throw Error(`Estimated tokens (${i}) is too small for the next batch of tokens (${l}).`);
17
+ let u = new Uint16Array(i);
15
18
  if (u.set(n.slice(c), 0), t.push(u), a && s && !Array.isArray(e)) {
16
19
  s.set(e.mask.slice(0, c).map((e) => +!!e), r.offset);
17
20
  let t = new Uint8Array(u.length);
@@ -22,34 +25,26 @@ function n(e, t, n, r, i, a) {
22
25
  }
23
26
  }
24
27
  }
25
- async function r(t, r, i, a) {
26
- let o = Math.min((await Promise.all(t.map((e) => e.estimateTokens(r)))).reduce((e, t) => e + t, 0), r.vocabSize * 1e4), s = [new Uint16Array(o)], c = a ? [new Uint8Array(o)] : null, l = {
28
+ async function a(r, a, o) {
29
+ await n("training-tokens");
30
+ let s = await t("training-tokens", a.id, a.datasetID ?? "", o);
31
+ await n("validation-tokens");
32
+ let c = o?.validationSplit && o.validationSplit > 0 ? await t("validation-tokens", a.id, a.datasetID ?? "", o) : void 0, l = [new Uint16Array(s.shardSize)], u = o?.masking ? [new Uint8Array(s.shardSize)] : null, d = {
27
33
  offset: 0,
28
34
  total: 0
29
- }, u = performance.now();
30
- for (; l.offset < o && (n(t, s, r, l, o, c || void 0), !t.every((e) => !e.hasMoreConversations()));) u = await e(u, i, l.total);
31
- if (s.length === 1) return c ? {
32
- tokens: s[0].subarray(0, l.offset),
33
- mask: c[0].subarray(0, l.offset)
34
- } : s[0].subarray(0, l.offset);
35
- let d = s.reduce((e, t) => e + t.length, 0) - (s[s.length - 1].length - l.offset), f = new Uint16Array(d), p = 0;
36
- for (let e = 0; e < s.length; e++) {
37
- let t = s[e];
38
- e === s.length - 1 ? (f.set(t.subarray(0, l.offset), p), p += l.offset) : (f.set(t, p), p += t.length);
39
- }
40
- if (c) {
41
- let e = new Uint8Array(d);
42
- p = 0;
43
- for (let t = 0; t < c.length; t++) {
44
- let n = c[t];
45
- t === c.length - 1 ? (e.set(n.subarray(0, l.offset), p), p += l.offset) : (e.set(n, p), p += n.length);
46
- }
47
- return {
48
- tokens: f,
49
- mask: e
50
- };
35
+ }, f = o?.validationSplit && o.validationSplit > 0 ? [new Uint16Array(c.shardSize)] : void 0, p = o?.masking && f ? [new Uint8Array(c.shardSize)] : null, m = {
36
+ offset: 0,
37
+ total: 0
38
+ }, h = performance.now();
39
+ for (;;) {
40
+ let t = o?.validationSplit && o.validationSplit > 0 && Math.random() < o.validationSplit, n = t ? f : l, g = t ? m : d, _ = t ? p : u, v = t ? c : s;
41
+ if (await i(r, n, a, g, v.shardSize, _ || void 0), n.length > 1 && (v.appendShard(n[0], _ ? _[0] : void 0), n.shift(), _ && _.shift()), r.every((e) => !e.hasMoreConversations())) break;
42
+ h = await e(h, o?.cb, d.total);
51
43
  }
52
- return f;
44
+ return l.length === 1 && (l[0] = l[0].subarray(0, d.offset), await s.appendShard(l[0], u ? u[0].subarray(0, d.offset) : void 0)), f && f.length === 1 && (f[0] = f[0].subarray(0, m.offset), await c.appendShard(f[0], p ? p[0].subarray(0, m.offset) : void 0)), {
45
+ trainingTokens: s,
46
+ validationTokens: f ? c : void 0
47
+ };
53
48
  }
54
49
  //#endregion
55
- export { t as Task, r as tokensFromTasks };
50
+ export { r as Task, a as tokensFromTasks };
@@ -0,0 +1,46 @@
1
+ export declare class TokenStore {
2
+ readonly name: string;
3
+ readonly tokeniserId: string;
4
+ readonly datasetId: string;
5
+ private shards;
6
+ private masks?;
7
+ private shardCount;
8
+ private lastShardLength;
9
+ private _shardSize;
10
+ private dirHandle;
11
+ private opfsAvailable;
12
+ private lru;
13
+ private maxCachedShards;
14
+ constructor(tokeniserId: string, datasetId: string, name?: string, maxCachedShards?: number, shardSize?: number);
15
+ get shardSize(): number;
16
+ hasMask(): boolean;
17
+ getShardLength(index: number): number;
18
+ slice(start: number, end: number): Promise<Uint16Array>;
19
+ init(): Promise<void>;
20
+ private writeManifest;
21
+ private readManifest;
22
+ private shardFilename;
23
+ private maskFilename;
24
+ private writeShardToOPFS;
25
+ private writeMaskToOPFS;
26
+ private readShardFromOPFS;
27
+ private readMaskFromOPFS;
28
+ private touchLRU;
29
+ private evictIfNeeded;
30
+ getShard(index: number): Promise<Uint16Array>;
31
+ getMask(index: number): Promise<Uint8Array | undefined>;
32
+ getShardCount(): number;
33
+ getTokenCount(): number;
34
+ appendShard(shard: Uint16Array, mask?: Uint8Array): Promise<void>;
35
+ dispose(): Promise<void>;
36
+ clear(): Promise<void>;
37
+ }
38
+ export declare function getTokenStore(name: string, tokeniserId: string, datasetId: string): TokenStore | null;
39
+ export declare function deleteTokenStore(name: string): Promise<void>;
40
+ interface TokenStoreOptions {
41
+ maxCachedShards?: number;
42
+ shardSize?: number;
43
+ noOPFS?: boolean;
44
+ }
45
+ export declare function createTokenStore(name: string, tokeniserId: string, datasetId: string, options?: TokenStoreOptions): Promise<TokenStore>;
46
+ export {};
@@ -0,0 +1,215 @@
1
+ //#region lib/training/tasks/TokenStore.ts
2
+ var e = "llm-tokenstore", t = class {
3
+ name;
4
+ tokeniserId;
5
+ datasetId;
6
+ shards = [];
7
+ masks;
8
+ shardCount = 0;
9
+ lastShardLength = -1;
10
+ _shardSize = 4e3 * 1024;
11
+ dirHandle = null;
12
+ opfsAvailable = !1;
13
+ lru = /* @__PURE__ */ new Map();
14
+ maxCachedShards;
15
+ constructor(t, n, r, i = 8, a = 4e3 * 1024) {
16
+ this.tokeniserId = t, this.datasetId = n, this.maxCachedShards = Math.max(1, Math.trunc(i)), this._shardSize = Math.max(1, Math.trunc(a)), this.name = r ?? e;
17
+ }
18
+ get shardSize() {
19
+ return this._shardSize;
20
+ }
21
+ hasMask() {
22
+ return !!this.masks;
23
+ }
24
+ getShardLength(e) {
25
+ if (e < 0 || e >= this.shardCount) throw RangeError(`Shard index ${e} out of range`);
26
+ return e === this.shardCount - 1 ? this.lastShardLength : this._shardSize;
27
+ }
28
+ async slice(e, t) {
29
+ if (e < 0 || t > this.getTokenCount() || e >= t) throw RangeError(`Invalid slice range: ${e} to ${t}`);
30
+ let n = new Uint16Array(t - e), r = 0, i = Math.floor(e / this._shardSize), a = Math.floor((t - 1) / this._shardSize);
31
+ for (let o = i; o <= a; o++) {
32
+ let i = o * this._shardSize, a = i + this.getShardLength(o), s = Math.max(e, i), c = Math.min(t, a);
33
+ if (s < c) {
34
+ let e = await this.getShard(o), t = s - i, a = c - i;
35
+ n.set(e.subarray(t, a), r), r += a - t;
36
+ }
37
+ }
38
+ return n;
39
+ }
40
+ async init() {
41
+ try {
42
+ let e = globalThis.navigator;
43
+ if (!e?.storage?.getDirectory) {
44
+ this.opfsAvailable = !1;
45
+ return;
46
+ }
47
+ let t = await e.storage.getDirectory();
48
+ this.dirHandle = await t.getDirectoryHandle(this.name, { create: !0 }), this.opfsAvailable = !0;
49
+ try {
50
+ let e = await this.readManifest();
51
+ if (e && (e?.tokenizerId !== this.tokeniserId || e?.datasetId !== this.datasetId)) for await (let e of this.dirHandle.values()) {
52
+ let t = e.name;
53
+ if (t.startsWith("shard-") || t.startsWith("mask-") || t === "manifest.json") try {
54
+ await this.dirHandle.removeEntry(t);
55
+ } catch {}
56
+ }
57
+ else e && (this.shardCount = e.shardCount, this._shardSize = e.shardSize, this.lastShardLength = e.lastShardLength, this.shards = Array(this.shardCount).fill(null), e.maskExistsIndex && Array.isArray(e.maskExistsIndex) && (this.masks = Array(this.shardCount).fill(null)));
58
+ } catch {}
59
+ } catch {
60
+ this.opfsAvailable = !1, this.dirHandle = null, console.warn("TokenStore: OPFS initialization failed, falling back to memory-only storage");
61
+ }
62
+ }
63
+ async writeManifest() {
64
+ if (!this.opfsAvailable || !this.dirHandle) return;
65
+ let e = {
66
+ tokenizerId: this.tokeniserId,
67
+ datasetId: this.datasetId,
68
+ shardSize: this._shardSize,
69
+ shardCount: this.shardCount,
70
+ lastShardLength: this.lastShardLength,
71
+ maskExistsIndex: (this.masks || []).map((e) => !!e),
72
+ timestamp: Date.now()
73
+ }, t = await (await this.dirHandle.getFileHandle("manifest.json", { create: !0 })).createWritable({ keepExistingData: !1 });
74
+ await t.write(JSON.stringify(e)), await t.close();
75
+ }
76
+ async readManifest() {
77
+ if (!(!this.opfsAvailable || !this.dirHandle)) try {
78
+ let e = await (await (await this.dirHandle.getFileHandle("manifest.json")).getFile()).text();
79
+ return JSON.parse(e);
80
+ } catch {
81
+ return;
82
+ }
83
+ }
84
+ shardFilename(e) {
85
+ return `shard-${e}.bin`;
86
+ }
87
+ maskFilename(e) {
88
+ return `mask-${e}.bin`;
89
+ }
90
+ async writeShardToOPFS(e, t) {
91
+ if (!this.opfsAvailable || !this.dirHandle) return;
92
+ let n = this.shardFilename(e), r = await (await this.dirHandle.getFileHandle(n, { create: !0 })).createWritable();
93
+ await r.write(t.buffer), await r.close();
94
+ }
95
+ async writeMaskToOPFS(e, t) {
96
+ if (!this.opfsAvailable || !this.dirHandle) return;
97
+ let n = this.maskFilename(e), r = await (await this.dirHandle.getFileHandle(n, { create: !0 })).createWritable();
98
+ await r.write(t.buffer), await r.close();
99
+ }
100
+ async readShardFromOPFS(e) {
101
+ if (!(!this.opfsAvailable || !this.dirHandle)) try {
102
+ let t = await (await (await this.dirHandle.getFileHandle(this.shardFilename(e))).getFile()).arrayBuffer();
103
+ return new Uint16Array(t);
104
+ } catch {
105
+ return;
106
+ }
107
+ }
108
+ async readMaskFromOPFS(e) {
109
+ if (!(!this.opfsAvailable || !this.dirHandle)) try {
110
+ let t = await (await (await this.dirHandle.getFileHandle(this.maskFilename(e))).getFile()).arrayBuffer();
111
+ return new Uint8Array(t);
112
+ } catch {
113
+ return;
114
+ }
115
+ }
116
+ touchLRU(e) {
117
+ this.lru.delete(e), this.lru.set(e, !0);
118
+ }
119
+ evictIfNeeded() {
120
+ if (!(this.maxCachedShards <= 0)) for (; this.lru.size > this.maxCachedShards;) {
121
+ let e = this.lru.keys().next().value;
122
+ if (e === void 0) break;
123
+ this.lru.delete(e), this.shards[e] && (this.shards[e] = null), this.masks?.[e] && (this.masks[e] = null);
124
+ }
125
+ }
126
+ async getShard(e) {
127
+ if (!Number.isInteger(e) || e < 0 || e >= this.shards.length) throw RangeError(`Shard index ${e} out of range`);
128
+ let t = this.shards[e];
129
+ if (t) return this.touchLRU(e), t;
130
+ if (this.opfsAvailable) {
131
+ let t = await this.readShardFromOPFS(e);
132
+ if (t) return this.shards[e] = t, this.touchLRU(e), this.evictIfNeeded(), t;
133
+ }
134
+ throw Error(`Shard ${e} not available in memory or OPFS`);
135
+ }
136
+ async getMask(e) {
137
+ if (!Number.isInteger(e) || e < 0 || e >= this.shardCount || !this.masks) return;
138
+ let t = this.masks[e];
139
+ if (t) return this.touchLRU(e), t;
140
+ if (this.opfsAvailable) {
141
+ let t = await this.readMaskFromOPFS(e);
142
+ if (t) return this.masks[e] = t, this.touchLRU(e), this.evictIfNeeded(), t;
143
+ }
144
+ }
145
+ getShardCount() {
146
+ return this.shardCount;
147
+ }
148
+ getTokenCount() {
149
+ return this.shardCount === 0 ? 0 : (this.shardCount - 1) * this._shardSize + this.lastShardLength;
150
+ }
151
+ async appendShard(e, t) {
152
+ if (this.lastShardLength >= 0 && this.lastShardLength < this._shardSize) throw Error("Previous shard was not full");
153
+ let n = this.shards.length;
154
+ this.shards.push(e), !this.masks && t && (this.masks = Array(n).fill(null)), this.masks && this.masks.push(t ?? null), this.shardCount = this.shards.length, this.lastShardLength = e.length, this.touchLRU(n);
155
+ try {
156
+ this.opfsAvailable && this.dirHandle && (await this.writeShardToOPFS(n, e), t && await this.writeMaskToOPFS(n, t), await this.writeManifest());
157
+ } catch (e) {
158
+ console.error(e), this.maxCachedShards = 2 ** 53 - 1;
159
+ }
160
+ this.evictIfNeeded();
161
+ }
162
+ async dispose() {
163
+ if (this.opfsAvailable && this.dirHandle) try {
164
+ for await (let e of this.dirHandle.values()) {
165
+ let t = e.name;
166
+ try {
167
+ await this.dirHandle.removeEntry(t);
168
+ } catch {}
169
+ }
170
+ try {
171
+ let e = globalThis.navigator;
172
+ if (e?.storage?.getDirectory) {
173
+ let t = await e.storage.getDirectory();
174
+ t.removeEntry && await t.removeEntry(this.name, { recursive: !0 });
175
+ }
176
+ } catch {}
177
+ } catch {}
178
+ this.shards = [], this.masks = [], this.shardCount = 0, this.lastShardLength = -1, this.lru.clear(), this.dirHandle = null, this.opfsAvailable = !1;
179
+ }
180
+ async clear() {
181
+ if (this.shards = [], this.masks = [], this.shardCount = 0, this.lastShardLength = -1, this.lru.clear(), this.opfsAvailable && this.dirHandle) try {
182
+ for await (let e of this.dirHandle.values()) {
183
+ let t = e.name;
184
+ try {
185
+ await this.dirHandle.removeEntry(t);
186
+ } catch {}
187
+ }
188
+ await this.writeManifest();
189
+ } catch {}
190
+ }
191
+ }, n = /* @__PURE__ */ new Map();
192
+ function r(e, t, r) {
193
+ let i = n.get(e);
194
+ return i && i.tokeniserId === t && i.datasetId === r ? i : null;
195
+ }
196
+ async function i(e) {
197
+ let t = n.get(e);
198
+ if (t) await t.dispose(), n.delete(e);
199
+ else try {
200
+ let t = globalThis.navigator;
201
+ if (t?.storage?.getDirectory) {
202
+ let n = await t.storage.getDirectory();
203
+ n.removeEntry && await n.removeEntry(e, { recursive: !0 });
204
+ }
205
+ } catch {}
206
+ }
207
+ async function a(e, r, i, a) {
208
+ let o = n.get(e);
209
+ if (o && o.tokeniserId === r && o.datasetId === i) return o;
210
+ o && (await o.dispose(), n.delete(e));
211
+ let s = new t(r, i, e, a?.maxCachedShards ?? 8, a?.shardSize ?? 4e3 * 1024);
212
+ return a?.noOPFS || await s.init(), n.set(e, s), s;
213
+ }
214
+ //#endregion
215
+ export { t as TokenStore, a as createTokenStore, i as deleteTokenStore, r as getTokenStore };
@@ -1,5 +1,5 @@
1
1
  import { Task } from './Task';
2
- export default function splitValidation(tasks: Task[], validationSplit: number): {
2
+ export default function splitValidation(tasks: Task[], validationSplit: number): Promise<{
3
3
  training: Task;
4
4
  validation: Task;
5
- };
5
+ }>;
@@ -1,18 +1,18 @@
1
- import e from "./ConversationTask.js";
1
+ import { n as e } from "../../stream-BjdpSNqB.js";
2
+ import t from "./ConversationTask.js";
2
3
  //#region lib/training/tasks/splitter.ts
3
- function t(t, n) {
4
- if (n <= 0 || n >= 1) throw Error("validationSplit must be between 0 and 1");
5
- t.forEach((e) => e.shuffle());
6
- let r = [], i = [];
7
- for (let e of t) for (; e.hasMoreConversations();) {
8
- let t = e.nextConversation();
4
+ async function n(n, r) {
5
+ if (r <= 0 || r >= 1) throw Error("validationSplit must be between 0 and 1");
6
+ let i = [], a = [];
7
+ for (let e of n) for (; e.hasMoreConversations();) {
8
+ let t = await e.nextConversation();
9
9
  if (!t) break;
10
- Math.random() < n ? i.push(t) : r.push(t);
10
+ Math.random() < r ? a.push(t) : i.push(t);
11
11
  }
12
12
  return {
13
- training: new e(r),
14
- validation: new e(i)
13
+ training: new t([new e(i)]),
14
+ validation: new t([new e(a)])
15
15
  };
16
16
  }
17
17
  //#endregion
18
- export { t as default };
18
+ export { n as default };
@@ -1,8 +1,10 @@
1
- import { ITokeniser, Task } from '../../main';
1
+ import { ITokeniser } from '../../tokeniser/type';
2
2
  import { Tensor } from '@tensorflow/tfjs-core';
3
3
  import { Dataset } from '@tensorflow/tfjs-data';
4
4
  import { DatasetBuilder, DatasetState } from './DatasetBuilder';
5
- export declare function createTrainValidationSplit(tasks: Task[] | Uint16Array, tokeniser: ITokeniser, datasetBuilder: DatasetBuilder, batchSize: number, validationSplit?: number, masking?: boolean): Promise<{
5
+ import { TokenStore } from './tasks/TokenStore';
6
+ export declare function storeFromArray(tokens: Uint16Array[], tokenizer: ITokeniser): Promise<TokenStore>;
7
+ export declare function createTrainValidationDatasets(trainingTokens: Uint16Array[] | TokenStore, validationTokens: Uint16Array[] | TokenStore, tokeniser: ITokeniser, datasetBuilder: DatasetBuilder, batchSize: number): Promise<{
6
8
  trainDataset: Dataset<{
7
9
  xs: Tensor;
8
10
  ys: Tensor;
@@ -1,2 +1,21 @@
1
- import { o as e } from "../main-DdsoTJAW.js";
2
- export { e as createTrainValidationSplit };
1
+ import { TokenStore as e, createTokenStore as t } from "./tasks/TokenStore.js";
2
+ //#region lib/training/validation.ts
3
+ async function n(e, n) {
4
+ let r = await t("training-tokens", n.id, n.datasetID ?? ""), i = e.map((e) => r.appendShard(e));
5
+ return await Promise.all(i), r;
6
+ }
7
+ async function r(t, r, i, a, o) {
8
+ let s = t instanceof e ? t : await n(t, i), c = r instanceof e ? r : await n(r, i), l = s.getTokenCount(), { dataset: u, state: d } = await a.createTextDataset(s, { batchSize: o }), { dataset: f, state: p } = await a.createTextDataset(c, {
9
+ batchSize: o,
10
+ shuffleFirst: !0
11
+ });
12
+ return {
13
+ trainDataset: u,
14
+ validationDataset: f,
15
+ size: l,
16
+ validationState: p,
17
+ trainState: d
18
+ };
19
+ }
20
+ //#endregion
21
+ export { r as createTrainValidationDatasets, n as storeFromArray };
@@ -0,0 +1,2 @@
1
+ export declare function sliceUint16Shards(shards: readonly Uint16Array[], start: number, endExclusive: number, shardSize?: number): Uint16Array;
2
+ export declare function sliceUint8Shards(shards: readonly Uint8Array[], start: number, endExclusive: number, shardSize?: number): Uint8Array;
@@ -0,0 +1,40 @@
1
+ //#region lib/utilities/tokens.ts
2
+ function e(e, t, n, r = e[0]?.length ?? 0) {
3
+ if (e.length === 0) return new Uint16Array();
4
+ if (!Number.isInteger(t) || !Number.isInteger(n)) throw RangeError("start/endExclusive must be integers");
5
+ if (t < 0 || n < t) throw RangeError(`Invalid range [${t}, ${n})`);
6
+ if (r <= 0) throw RangeError("Invalid shardSize");
7
+ let i = e[e.length - 1], a = (e.length - 1) * r + i.length;
8
+ if (n > a) throw RangeError(`Slice end ${n} is out of bounds for total length ${a}`);
9
+ if (t === n) return new Uint16Array();
10
+ let o = new Uint16Array(n - t), s = 0, c = t;
11
+ for (; c < n;) {
12
+ let t = Math.floor(c / r), i = c - t * r, a = e[t], l = Math.min(n - c, a.length - i);
13
+ try {
14
+ o.set(a.subarray(i, i + l), s);
15
+ } catch (n) {
16
+ throw console.error(`Error slicing shards: shardIndex=${t}, shardOffset=${i}, take=${l}, writeOffset=${s}`), e.forEach((t, n) => {
17
+ t.length !== r && n !== e.length - 1 && console.error(`Shard ${n} has length ${t.length}, expected ${r}`);
18
+ }), n;
19
+ }
20
+ c += l, s += l;
21
+ }
22
+ return o;
23
+ }
24
+ function t(e, t, n, r = e[0]?.length ?? 0) {
25
+ if (e.length === 0) return new Uint8Array();
26
+ if (!Number.isInteger(t) || !Number.isInteger(n)) throw RangeError("start/endExclusive must be integers");
27
+ if (t < 0 || n < t) throw RangeError(`Invalid range [${t}, ${n})`);
28
+ if (r <= 0) throw RangeError("Invalid shardSize");
29
+ let i = e[e.length - 1], a = (e.length - 1) * r + i.length;
30
+ if (n > a) throw RangeError(`Slice end ${n} is out of bounds for total length ${a}`);
31
+ if (t === n) return new Uint8Array();
32
+ let o = new Uint8Array(n - t), s = 0, c = t;
33
+ for (; c < n;) {
34
+ let t = Math.floor(c / r), i = c - t * r, a = e[t], l = Math.min(n - c, a.length - i);
35
+ o.set(a.subarray(i, i + l), s), c += l, s += l;
36
+ }
37
+ return o;
38
+ }
39
+ //#endregion
40
+ export { e as sliceUint16Shards, t as sliceUint8Shards };
@@ -6,6 +6,12 @@ function e(e, t) {
6
6
  })).sort((e, t) => t.prob - e.prob), r = 0, i = Array(n.length).fill(0);
7
7
  for (let e of n) if (r += e.prob, i[e.index] = e.prob, r >= t) break;
8
8
  let a = i.reduce((e, t) => e + t, 0);
9
+ if (a === 0) {
10
+ let t = e[0], n = t.reduce((e, t) => e + t, 0);
11
+ if (n > 0) return t.map((e) => e / n);
12
+ let r = 1 / t.length;
13
+ return t.map(() => r);
14
+ }
9
15
  return i.map((e) => e / a);
10
16
  }
11
17
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genai-fi/nanogpt",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "type": "module",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",
@@ -52,6 +52,7 @@
52
52
  "dependencies": {
53
53
  "@tensorflow/tfjs": "^4.22.0",
54
54
  "@tensorflow/tfjs-backend-webgpu": "^4.22.0",
55
+ "@zip.js/zip.js": "^2.8.34",
55
56
  "eventemitter3": "^5.0.1",
56
57
  "jszip": "^3.10.1",
57
58
  "papaparse": "^5.5.3",