@genai-fi/nanogpt 0.22.0 → 0.24.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 (51) hide show
  1. package/dist/{DatasetBuilder-Ctb425Id.js → DatasetBuilder-DU1G1OKX.js} +143 -117
  2. package/dist/Generator.js +1 -1
  3. package/dist/TeachableLLM.d.ts +1 -2
  4. package/dist/TeachableLLM.js +1 -1
  5. package/dist/Trainer-Cr7csbTD.js +228 -0
  6. package/dist/Trainer.d.ts +3 -2
  7. package/dist/Trainer.js +1 -1
  8. package/dist/data/stream.d.ts +6 -6
  9. package/dist/data/stream.js +1 -1
  10. package/dist/data/textLoader.js +1 -1
  11. package/dist/{BaseTokeniser-C9TSv4th.js → eventemitter3-D_qV3Lof.js} +2 -132
  12. package/dist/loader/load.js +1 -1
  13. package/dist/loader/loadHF.js +1 -1
  14. package/dist/loader/loadTransformers.js +2 -2
  15. package/dist/loader/newZipLoad.js +1 -1
  16. package/dist/loader/oldZipLoad.js +1 -1
  17. package/dist/loader/save.js +1 -1
  18. package/dist/{main-Bgc7_9kb.js → main-Dz72vadm.js} +2742 -2976
  19. package/dist/main.d.ts +3 -10
  20. package/dist/main.js +12 -10
  21. package/dist/models/NanoGPTV1.js +1 -1
  22. package/dist/models/NanoGPTV2.js +1 -1
  23. package/dist/models/factory.js +1 -1
  24. package/dist/models/model.js +1 -1
  25. package/dist/{stream-DKl3GTDL.js → stream-BpAwcvHz.js} +563 -550
  26. package/dist/tokeniser/BaseTokeniser.js +135 -2
  27. package/dist/tokeniser/CharTokeniser.js +17 -19
  28. package/dist/tokeniser/bpe.js +16 -20
  29. package/dist/training/DatasetBuilder.d.ts +19 -3
  30. package/dist/training/DatasetBuilder.js +2 -2
  31. package/dist/training/PreTrainer.js +1 -1
  32. package/dist/training/SFTTrainer.js +1 -1
  33. package/dist/training/tasks/TokenStore.d.ts +47 -0
  34. package/dist/training/tasks/TokenStore.js +218 -0
  35. package/dist/training/tasks/tokenStream.d.ts +16 -0
  36. package/dist/training/tasks/tokenStream.js +46 -0
  37. package/dist/training/validation.d.ts +4 -2
  38. package/dist/training/validation.js +23 -2
  39. package/dist/utilities/random.d.ts +1 -0
  40. package/dist/utilities/random.js +19 -0
  41. package/package.json +1 -1
  42. package/dist/training/tasks/ConversationTask.d.ts +0 -17
  43. package/dist/training/tasks/ConversationTask.js +0 -29
  44. package/dist/training/tasks/PretrainingTask.d.ts +0 -17
  45. package/dist/training/tasks/PretrainingTask.js +0 -42
  46. package/dist/training/tasks/StartSentenceTask.d.ts +0 -18
  47. package/dist/training/tasks/StartSentenceTask.js +0 -45
  48. package/dist/training/tasks/Task.d.ts +0 -20
  49. package/dist/training/tasks/Task.js +0 -42
  50. package/dist/training/tasks/splitter.d.ts +0 -5
  51. package/dist/training/tasks/splitter.js +0 -18
@@ -1,2 +1,135 @@
1
- import { n as e, t } from "../BaseTokeniser-C9TSv4th.js";
2
- export { e as SPECIALS, t as default };
1
+ import { t as e } from "../eventemitter3-D_qV3Lof.js";
2
+ //#region lib/tokeniser/BaseTokeniser.ts
3
+ var t = [
4
+ "<eos>",
5
+ "<bos>",
6
+ "",
7
+ "<pad>",
8
+ "<|user_start|>",
9
+ "<|user_end|>",
10
+ "<|assistant_start|>",
11
+ "<|assistant_end|>",
12
+ "<|system_start|>",
13
+ "<|system_end|>"
14
+ ], n = class extends e {
15
+ id = "untrained";
16
+ datasetID;
17
+ specialTokens = /* @__PURE__ */ new Map();
18
+ specialTokenSet = /* @__PURE__ */ new Set();
19
+ isSpecialToken(e) {
20
+ return this.specialTokenSet.has(e);
21
+ }
22
+ addSpecialTokens() {
23
+ t.forEach((e, t) => {
24
+ this.addToken(e, t), this.specialTokens.set(e, t), this.specialTokenSet.add(t);
25
+ });
26
+ }
27
+ addSpecialToken(e, t) {
28
+ this.specialTokens.set(e, t), this.specialTokenSet.add(t);
29
+ }
30
+ generateID() {
31
+ let e = this.getVocab(), t = 2166136261, n = 2654435769;
32
+ if (e.length === 0) {
33
+ this.id = "untrained";
34
+ return;
35
+ }
36
+ for (let r = 0; r < e.length; r++) {
37
+ let i = e[r];
38
+ t ^= i.length, t = Math.imul(t, 16777619), n ^= r, n = Math.imul(n, 2246822507);
39
+ for (let e = 0; e < i.length; e++) {
40
+ let r = i.charCodeAt(e);
41
+ t ^= r, t = Math.imul(t, 16777619), n ^= r, n = Math.imul(n, 3266489909);
42
+ }
43
+ }
44
+ let r = (t >>> 0).toString(36), i = (n >>> 0).toString(36);
45
+ this.id = "tokeniser_" + r + "_" + i;
46
+ }
47
+ encodeSequence(e) {
48
+ let t = this.encode(e);
49
+ return [
50
+ this.bosToken,
51
+ ...t,
52
+ this.eosToken
53
+ ];
54
+ }
55
+ encodeAsSequence(e, t) {
56
+ let n = e.flatMap((e) => this.encode(e.content));
57
+ return t ? [
58
+ this.bosToken,
59
+ ...n,
60
+ this.eosToken,
61
+ this.bosToken
62
+ ] : [
63
+ this.bosToken,
64
+ ...n,
65
+ this.eosToken
66
+ ];
67
+ }
68
+ encodeConversation(e, t, n) {
69
+ let r = [[this.bosToken]], i;
70
+ n && (i = [[!1]]);
71
+ let a = [
72
+ this.getSpecialTokenIndex("<|user_start|>"),
73
+ this.getSpecialTokenIndex("<|assistant_start|>"),
74
+ this.getSpecialTokenIndex("<|system_start|>")
75
+ ], o = [
76
+ this.getSpecialTokenIndex("<|user_end|>"),
77
+ this.getSpecialTokenIndex("<|assistant_end|>"),
78
+ this.getSpecialTokenIndex("<|system_end|>")
79
+ ];
80
+ for (let t of e) {
81
+ let e = !1, s = this.encode(t.content);
82
+ switch (t.role) {
83
+ case "user":
84
+ r.push([a[0]]), e = !0;
85
+ break;
86
+ case "assistant":
87
+ r.push([a[1]]);
88
+ break;
89
+ case "system":
90
+ r.push([a[2]]), e = !0;
91
+ break;
92
+ }
93
+ switch (r.push(s), t.role) {
94
+ case "user":
95
+ r.push([o[0]]);
96
+ break;
97
+ case "assistant":
98
+ r.push([o[1]]);
99
+ break;
100
+ case "system":
101
+ r.push([o[2]]);
102
+ break;
103
+ }
104
+ n && i && e ? (i.push([!1]), i.push(s.map(() => !1)), i.push([!1])) : n && i && (i.push([!1]), i.push(s.map(() => !0)), i.push([!0]));
105
+ }
106
+ let s = r.flat();
107
+ return t ? (s.push(a[1]), n && i && i.push([!1])) : (s.push(this.eosToken), n && i && i.push([!0])), n && i ? {
108
+ tokens: s,
109
+ mask: i.flat()
110
+ } : s;
111
+ }
112
+ decodeConversation(e) {
113
+ let t = [], n = 0;
114
+ for (; n < e.length;) {
115
+ let r = e[n], i = null;
116
+ if (r === this.getSpecialTokenIndex("<|user_start|>") ? i = "user" : r === this.getSpecialTokenIndex("<|assistant_start|>") ? i = "assistant" : r === this.getSpecialTokenIndex("<|system_start|>") ? i = "system" : r === this.bosToken || (r === this.eosToken ? i = null : (i = "text", n--)), i) {
117
+ n++;
118
+ let r = [];
119
+ for (; n < e.length && e[n] !== this.getSpecialTokenIndex(`<|${i}_end|>`) && e[n] !== this.eosToken;) r.push(e[n]), n++;
120
+ let a = this.decode(r);
121
+ t.push({
122
+ role: i,
123
+ content: a
124
+ });
125
+ }
126
+ n++;
127
+ }
128
+ return t;
129
+ }
130
+ getSpecialTokenIndex(e) {
131
+ return this.specialTokens.get(e);
132
+ }
133
+ };
134
+ //#endregion
135
+ export { t as SPECIALS, n as default };
@@ -1,7 +1,6 @@
1
- import { yieldIfNeeded as e } from "../utilities/yielder.js";
2
- import { n as t, t as n } from "../BaseTokeniser-C9TSv4th.js";
1
+ import e, { SPECIALS as t } from "./BaseTokeniser.js";
3
2
  //#region lib/tokeniser/CharTokeniser.ts
4
- var r = ["<eos>", "<unk>"], i = class extends n {
3
+ var n = ["<eos>", "<unk>"], r = class extends e {
5
4
  vocabSize = 0;
6
5
  eosToken = 0;
7
6
  bosToken = 0;
@@ -35,22 +34,21 @@ var r = ["<eos>", "<unk>"], i = class extends n {
35
34
  destroy() {
36
35
  this.cache.clear(), this.vocab = [];
37
36
  }
38
- async train(t, n, i) {
39
- this.datasetID = i;
40
- let a = /* @__PURE__ */ new Set(), o = performance.now();
41
- for (let r of t) {
42
- let t = r.cursor(), i = await t.next();
43
- for (; i !== null;) i.forEach((e) => {
44
- for (let t of e.content) a.add(t);
45
- }), o = await e(o, n, 0), i = await t.next();
46
- }
47
- let s = Array.from(a), c = this.vocab.indexOf("", this.unkToken + 1), l = this.vocabSize - r.length;
48
- if (c === -1) return this.generateID(), this.vocabSize;
49
- if (this._trained = !0, s.length > l) throw Error("too_small_vocab");
50
- let u = c;
51
- if (u !== -1) {
37
+ async train(e, t, r) {
38
+ this.datasetID = r;
39
+ let i = /* @__PURE__ */ new Set();
40
+ for (let n of e) await n.begin((e) => {
41
+ e.forEach((e) => {
42
+ for (let t of e.content) i.add(t);
43
+ });
44
+ }, t ? () => t(i.size) : void 0);
45
+ let a = Array.from(i), o = this.vocab.indexOf("", this.unkToken + 1), s = this.vocabSize - n.length;
46
+ if (o === -1) return this.generateID(), this.vocabSize;
47
+ if (this._trained = !0, a.length > s) throw Error("too_small_vocab");
48
+ let c = o;
49
+ if (c !== -1) {
52
50
  let e = new Set(this.vocab);
53
- for (let t of s) if (!e.has(t) && (this.vocab[u] = t, e.add(t), u = this.vocab.indexOf("", u + 1), u === -1)) break;
51
+ for (let t of a) if (!e.has(t) && (this.vocab[c] = t, e.add(t), c = this.vocab.indexOf("", c + 1), c === -1)) break;
54
52
  }
55
53
  return this.cache.clear(), this.vocab.forEach((e, t) => {
56
54
  this.cache.set(e, t);
@@ -85,4 +83,4 @@ var r = ["<eos>", "<unk>"], i = class extends n {
85
83
  }
86
84
  };
87
85
  //#endregion
88
- export { i as default };
86
+ export { r as default };
@@ -1,5 +1,5 @@
1
- import { yieldIfNeeded as e } from "../utilities/yielder.js";
2
- import { n as t, t as n } from "../BaseTokeniser-C9TSv4th.js";
1
+ import e, { SPECIALS as t } from "./BaseTokeniser.js";
2
+ import { yieldIfNeeded as n } from "../utilities/yielder.js";
3
3
  import r from "../utilities/tokenParse.js";
4
4
  //#region lib/tokeniser/bpe.ts
5
5
  function i(e, t) {
@@ -58,7 +58,7 @@ function l(e, t) {
58
58
  e.tokens[n] = i;
59
59
  }), e.pairs.delete(i(t.a, t.b));
60
60
  }
61
- var u = class extends n {
61
+ var u = class extends e {
62
62
  targetSize;
63
63
  vocab = /* @__PURE__ */ new Set();
64
64
  vocabIndex = /* @__PURE__ */ new Map();
@@ -98,26 +98,22 @@ var u = class extends n {
98
98
  get unkToken() {
99
99
  return this.vocabIndex.get("") ?? 1;
100
100
  }
101
- async train(t = [], n, i) {
101
+ async train(e = [], t, i) {
102
102
  this.datasetID = i;
103
- let o = performance.now(), c = /* @__PURE__ */ new Set();
104
- for (let i of t) {
105
- let t = i.cursor(), a = await t.next();
106
- for (; a !== null;) {
107
- for (let e of a) {
108
- let t = r(e.content);
109
- for (let e of t) c.add(e);
110
- }
111
- o = await e(o, n, this.vocab.size), a = await t.next();
112
- }
113
- }
103
+ let o = /* @__PURE__ */ new Set();
114
104
  this.vocab = /* @__PURE__ */ new Set(), this.pretokenMap.clear(), this.merges = [], this.addSpecialTokens();
115
- let u = Array.from(c), d = u.map((e) => Array.from(e).map((e) => (this.vocab.add(e), e))), f = a(d);
116
- if (o = await e(o, n, this.vocab.size), this.vocab.size >= this.targetSize) throw console.warn("Initial vocab size is greater than or equal to target size. No merges will be performed.", this.vocab.size, this.targetSize), Error("too_small_vocab");
105
+ for (let n of e) await n.begin((e) => {
106
+ for (let t of e) {
107
+ let e = r(t.content);
108
+ for (let t of e) o.has(t) || (o.add(t), Array.from(t).forEach((e) => this.vocab.add(e)));
109
+ }
110
+ }, t ? () => t(this.vocab.size) : void 0);
111
+ let c = performance.now(), u = Array.from(o), d = u.map((e) => Array.from(e)), f = a(d);
112
+ if (c = await n(c, t, this.vocab.size), this.vocab.size >= this.targetSize) throw console.warn("Initial vocab size is greater than or equal to target size. No merges will be performed.", this.vocab.size, this.targetSize), Error("too_small_vocab");
117
113
  for (; this.vocab.size < this.targetSize && this.merges.length < this.targetSize;) {
118
- let t = s(f);
119
- if (!t) break;
120
- this.merges.push([t.a, t.b]), this.vocab.add(t.a + t.b), l(f, t), o = await e(o, n, this.vocab.size);
114
+ let e = s(f);
115
+ if (!e) break;
116
+ this.merges.push([e.a, e.b]), this.vocab.add(e.a + e.b), l(f, e), c = await n(c, t, this.vocab.size);
121
117
  }
122
118
  u.forEach((e, t) => {
123
119
  let n = d[t];
@@ -1,21 +1,36 @@
1
1
  import { Tensor } from '@tensorflow/tfjs-core';
2
2
  import { Conversation, ITokeniser } from '../tokeniser/type';
3
3
  import { Dataset } from '@tensorflow/tfjs-data';
4
+ import { TokenStore } from './tasks/TokenStore';
4
5
  export declare function flattenTokens(textData: Conversation[][], tokenizer: ITokeniser): Uint16Array;
5
6
  export declare function flattenTokensWithMask(textData: Conversation[][], tokenizer: ITokeniser): {
6
7
  tokens: Uint16Array;
7
8
  mask: Uint8Array;
8
9
  };
9
- export declare function shuffle(array: Uint32Array): Uint32Array;
10
+ export declare function shuffle(array: Uint32Array | Uint16Array): Uint32Array | Uint16Array;
10
11
  export interface DatasetState {
11
- shuffledIndexes: Uint32Array;
12
+ shuffledShards: Uint16Array;
13
+ shuffledIndexes: Uint16Array;
14
+ lastShardIndexes: Uint16Array;
15
+ currentShard: Uint16Array | null;
16
+ nextShard: Uint16Array | null;
17
+ currentMask: Uint8Array | null;
18
+ nextMask: Uint8Array | null;
19
+ shardIndex: number;
12
20
  step: number;
13
21
  }
22
+ export declare function moveToNext(state: DatasetState, store: TokenStore, noShuffle?: boolean): Promise<void>;
23
+ interface DatasetOptions {
24
+ batchSize: number;
25
+ noShuffle?: boolean;
26
+ ignoreIndex?: number;
27
+ shuffleFirst?: boolean;
28
+ }
14
29
  export declare class DatasetBuilder {
15
30
  tokenizer: ITokeniser;
16
31
  blockSize: number;
17
32
  constructor(tokenizer: ITokeniser, blockSize?: number);
18
- createTextDataset(flatTokens: Uint16Array[], batchSize?: number, indexes?: Uint32Array, mask?: Uint8Array[], ignoreIndex?: number): Promise<{
33
+ createTextDataset(store: TokenStore, options?: DatasetOptions): Promise<{
19
34
  dataset: Dataset<{
20
35
  xs: Tensor;
21
36
  ys: Tensor;
@@ -23,3 +38,4 @@ export declare class DatasetBuilder {
23
38
  state: DatasetState;
24
39
  }>;
25
40
  }
41
+ export {};
@@ -1,2 +1,2 @@
1
- import { i as e, n as t, r as n, t as r } from "../DatasetBuilder-Ctb425Id.js";
2
- export { r as DatasetBuilder, t as flattenTokens, n as flattenTokensWithMask, e as shuffle };
1
+ import { a as e, i as t, n, r, t as i } from "../DatasetBuilder-DU1G1OKX.js";
2
+ export { i as DatasetBuilder, n as flattenTokens, r as flattenTokensWithMask, t as moveToNext, e as shuffle };
@@ -1,4 +1,4 @@
1
- import { t as e } from "../DatasetBuilder-Ctb425Id.js";
1
+ import { t as e } from "../DatasetBuilder-DU1G1OKX.js";
2
2
  import t from "./BasicTrainer.js";
3
3
  //#region lib/training/PreTrainer.ts
4
4
  var n = {
@@ -1,4 +1,4 @@
1
- import { t as e } from "../DatasetBuilder-Ctb425Id.js";
1
+ import { t as e } from "../DatasetBuilder-DU1G1OKX.js";
2
2
  import t from "./BasicTrainer.js";
3
3
  //#region lib/training/SFTTrainer.ts
4
4
  var n = {
@@ -0,0 +1,47 @@
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
+ finish(): Promise<void>;
35
+ appendShard(shard: Uint16Array, mask?: Uint8Array): void;
36
+ dispose(): Promise<void>;
37
+ clear(): Promise<void>;
38
+ }
39
+ export declare function getTokenStore(name: string, tokeniserId: string, datasetId: string): TokenStore | null;
40
+ export declare function deleteTokenStore(name: string): Promise<void>;
41
+ interface TokenStoreOptions {
42
+ maxCachedShards?: number;
43
+ shardSize?: number;
44
+ noOPFS?: boolean;
45
+ }
46
+ export declare function createTokenStore(name: string, tokeniserId: string, datasetId: string, options?: TokenStoreOptions): Promise<TokenStore>;
47
+ export {};
@@ -0,0 +1,218 @@
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 = 8e3 * 1024;
11
+ dirHandle = null;
12
+ opfsAvailable = !1;
13
+ lru = /* @__PURE__ */ new Map();
14
+ maxCachedShards;
15
+ constructor(t, n, r, i = 2, a = 8e3 * 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 finish() {
152
+ await this.writeManifest();
153
+ }
154
+ appendShard(e, t) {
155
+ if (this.lastShardLength >= 0 && this.lastShardLength < this._shardSize) throw Error("Previous shard was not full");
156
+ let n = this.shards.length;
157
+ 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);
158
+ try {
159
+ this.opfsAvailable && this.dirHandle && (this.writeShardToOPFS(n, e), t && this.writeMaskToOPFS(n, t));
160
+ } catch (e) {
161
+ console.error(e), this.maxCachedShards = 2 ** 53 - 1;
162
+ }
163
+ this.evictIfNeeded();
164
+ }
165
+ async dispose() {
166
+ if (this.opfsAvailable && this.dirHandle) try {
167
+ for await (let e of this.dirHandle.values()) {
168
+ let t = e.name;
169
+ try {
170
+ await this.dirHandle.removeEntry(t);
171
+ } catch {}
172
+ }
173
+ try {
174
+ let e = globalThis.navigator;
175
+ if (e?.storage?.getDirectory) {
176
+ let t = await e.storage.getDirectory();
177
+ t.removeEntry && await t.removeEntry(this.name, { recursive: !0 });
178
+ }
179
+ } catch {}
180
+ } catch {}
181
+ this.shards = [], this.masks = [], this.shardCount = 0, this.lastShardLength = -1, this.lru.clear(), this.dirHandle = null, this.opfsAvailable = !1;
182
+ }
183
+ async clear() {
184
+ if (this.shards = [], this.masks = [], this.shardCount = 0, this.lastShardLength = -1, this.lru.clear(), this.opfsAvailable && this.dirHandle) try {
185
+ for await (let e of this.dirHandle.values()) {
186
+ let t = e.name;
187
+ try {
188
+ await this.dirHandle.removeEntry(t);
189
+ } catch {}
190
+ }
191
+ await this.writeManifest();
192
+ } catch {}
193
+ }
194
+ }, n = /* @__PURE__ */ new Map();
195
+ function r(e, t, r) {
196
+ let i = n.get(e);
197
+ return i && i.tokeniserId === t && i.datasetId === r ? i : null;
198
+ }
199
+ async function i(e) {
200
+ let t = n.get(e);
201
+ if (t) await t.dispose(), n.delete(e);
202
+ else try {
203
+ let t = globalThis.navigator;
204
+ if (t?.storage?.getDirectory) {
205
+ let n = await t.storage.getDirectory();
206
+ n.removeEntry && await n.removeEntry(e, { recursive: !0 });
207
+ }
208
+ } catch {}
209
+ }
210
+ async function a(e, r, i, a) {
211
+ let o = n.get(e);
212
+ if (o && o.tokeniserId === r && o.datasetId === i) return o;
213
+ o && (await o.dispose(), n.delete(e));
214
+ let s = new t(r, i, e, a?.maxCachedShards, a?.shardSize);
215
+ return a?.noOPFS || await s.init(), n.set(e, s), s;
216
+ }
217
+ //#endregion
218
+ export { t as TokenStore, a as createTokenStore, i as deleteTokenStore, r as getTokenStore };
@@ -0,0 +1,16 @@
1
+ import { ConversationStream, ITokeniser } from '../../../main';
2
+ import { TokenStore } from './TokenStore';
3
+ interface TokensFromTasksOptions {
4
+ masking?: boolean;
5
+ maxCachedShards?: number;
6
+ noOPFS?: boolean;
7
+ shardSize?: number;
8
+ validationSplit?: number;
9
+ validationSeed?: string | number;
10
+ cb?: (tokens: number) => void;
11
+ }
12
+ export declare function tokensFromStreams(tasks: ConversationStream[], tokenizer: ITokeniser, options?: TokensFromTasksOptions): Promise<{
13
+ trainingTokens: TokenStore;
14
+ validationTokens?: TokenStore;
15
+ }>;
16
+ export {};
@@ -0,0 +1,46 @@
1
+ import { createTokenStore as e, deleteTokenStore as t } from "./TokenStore.js";
2
+ import { seededRng as n } from "../../utilities/random.js";
3
+ //#region lib/training/tasks/tokenStream.ts
4
+ function r(e, t, n, r, i, a) {
5
+ let o = n.encodeConversation(e, !1, !!a);
6
+ if (o) {
7
+ let e = Array.isArray(o) ? o : o.tokens;
8
+ r.total += e.length;
9
+ let n = t[t.length - 1], s = a ? a[a.length - 1] : null;
10
+ if (r.offset + e.length > n.length) {
11
+ let c = n.length - r.offset;
12
+ n.set(e.slice(0, c), r.offset);
13
+ let l = e.length - c;
14
+ if (l > i) throw Error(`Estimated tokens (${i}) is too small for the next batch of tokens (${l}).`);
15
+ let u = new Uint16Array(i);
16
+ if (u.set(e.slice(c), 0), t.push(u), a && s && !Array.isArray(o)) {
17
+ s.set(o.mask.slice(0, c).map((e) => +!!e), r.offset);
18
+ let e = new Uint8Array(u.length);
19
+ e.set(o.mask.slice(c).map((e) => +!!e), 0), a.push(e);
20
+ }
21
+ r.offset = e.length - c;
22
+ } else n.set(e, r.offset), s && !Array.isArray(o) && s.set(o.mask.map((e) => +!!e), r.offset), r.offset += e.length;
23
+ }
24
+ }
25
+ async function i(i, a, o) {
26
+ await t("training-tokens");
27
+ let s = await e("training-tokens", a.id, a.datasetID ?? "", o);
28
+ await t("validation-tokens");
29
+ let c = o?.validationSplit && o.validationSplit > 0 ? await e("validation-tokens", a.id, a.datasetID ?? "", o) : void 0, l = [new Uint16Array(s.shardSize)], u = o?.masking ? [new Uint8Array(s.shardSize)] : null, d = {
30
+ offset: 0,
31
+ total: 0
32
+ }, f = o?.validationSplit && o.validationSplit > 0 ? [new Uint16Array(c.shardSize)] : void 0, p = o?.masking && f ? [new Uint8Array(c.shardSize)] : null, m = {
33
+ offset: 0,
34
+ total: 0
35
+ }, h = 0, g = o?.cb, _ = o?.validationSeed === void 0 ? Math.random : n(o.validationSeed);
36
+ for (; h < i.length;) await i[h++].begin((e) => {
37
+ let t = o?.validationSplit && o.validationSplit > 0 && _() < o.validationSplit, n = t ? f : l, i = t ? m : d, h = t ? p : u, g = t ? c : s;
38
+ r(e, n, a, i, g.shardSize, h || void 0), n.length > 1 && (g.appendShard(n[0], h ? h[0] : void 0), n.shift(), h && h.shift());
39
+ }, g ? () => g(d.total) : void 0);
40
+ return l.length === 1 && (l[0] = l[0].subarray(0, d.offset), 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), c.appendShard(f[0], p ? p[0].subarray(0, m.offset) : void 0)), await s.finish(), c && await c.finish(), {
41
+ trainingTokens: s,
42
+ validationTokens: f ? c : void 0
43
+ };
44
+ }
45
+ //#endregion
46
+ export { i as tokensFromStreams };
@@ -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;