@genai-fi/nanogpt 0.22.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 (38) hide show
  1. package/dist/{DatasetBuilder-Ctb425Id.js → DatasetBuilder-C0iJT29K.js} +145 -116
  2. package/dist/Generator.js +2 -2
  3. package/dist/TeachableLLM.js +1 -1
  4. package/dist/Trainer-DBsyWJ4s.js +228 -0
  5. package/dist/Trainer.d.ts +2 -1
  6. package/dist/Trainer.js +1 -1
  7. package/dist/data/stream.js +1 -1
  8. package/dist/data/textLoader.js +1 -1
  9. package/dist/{BaseTokeniser-C9TSv4th.js → eventemitter3-D_qV3Lof.js} +2 -132
  10. package/dist/loader/load.js +2 -2
  11. package/dist/loader/loadHF.js +1 -1
  12. package/dist/loader/loadTransformers.js +2 -2
  13. package/dist/loader/newZipLoad.js +1 -1
  14. package/dist/loader/oldZipLoad.js +1 -1
  15. package/dist/loader/save.js +1 -1
  16. package/dist/{main-Bgc7_9kb.js → main-BSaDGH7I.js} +2686 -2913
  17. package/dist/main.d.ts +1 -0
  18. package/dist/main.js +20 -18
  19. package/dist/models/NanoGPTV1.js +1 -1
  20. package/dist/models/NanoGPTV2.js +1 -1
  21. package/dist/models/factory.js +1 -1
  22. package/dist/models/model.js +1 -1
  23. package/dist/{stream-DKl3GTDL.js → stream-BjdpSNqB.js} +31 -22
  24. package/dist/tokeniser/BaseTokeniser.js +135 -2
  25. package/dist/tokeniser/CharTokeniser.js +3 -3
  26. package/dist/tokeniser/bpe.js +8 -8
  27. package/dist/training/DatasetBuilder.d.ts +17 -1
  28. package/dist/training/DatasetBuilder.js +2 -2
  29. package/dist/training/PreTrainer.js +1 -1
  30. package/dist/training/SFTTrainer.js +1 -1
  31. package/dist/training/tasks/Task.d.ts +13 -4
  32. package/dist/training/tasks/Task.js +22 -14
  33. package/dist/training/tasks/TokenStore.d.ts +46 -0
  34. package/dist/training/tasks/TokenStore.js +215 -0
  35. package/dist/training/tasks/splitter.js +1 -1
  36. package/dist/training/validation.d.ts +4 -2
  37. package/dist/training/validation.js +21 -2
  38. package/package.json +1 -1
@@ -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,4 +1,4 @@
1
- import { n as e } from "../../stream-DKl3GTDL.js";
1
+ import { n as e } from "../../stream-BjdpSNqB.js";
2
2
  import t from "./ConversationTask.js";
3
3
  //#region lib/training/tasks/splitter.ts
4
4
  async function n(n, r) {
@@ -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-Bgc7_9kb.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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genai-fi/nanogpt",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "type": "module",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",