@genai-fi/nanogpt 0.21.0 → 0.22.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 (50) hide show
  1. package/dist/{DatasetBuilder-B9UGNQT5.js → DatasetBuilder-Ctb425Id.js} +111 -111
  2. package/dist/Generator.js +1 -1
  3. package/dist/TeachableLLM.d.ts +2 -1
  4. package/dist/TeachableLLM.js +1 -1
  5. package/dist/Trainer.d.ts +1 -1
  6. package/dist/Trainer.js +1 -1
  7. package/dist/data/stream.d.ts +24 -0
  8. package/dist/data/stream.js +2 -0
  9. package/dist/data/textLoader.d.ts +2 -2
  10. package/dist/data/textLoader.js +28 -67
  11. package/dist/loader/load.js +1 -1
  12. package/dist/loader/loadHF.js +1 -1
  13. package/dist/loader/loadTransformers.js +1 -1
  14. package/dist/loader/newZipLoad.js +1 -1
  15. package/dist/loader/oldZipLoad.js +1 -1
  16. package/dist/loader/save.js +1 -1
  17. package/dist/{main-DdsoTJAW.js → main-Bgc7_9kb.js} +18 -17
  18. package/dist/main.d.ts +3 -0
  19. package/dist/main.js +13 -11
  20. package/dist/models/NanoGPTV1.js +1 -1
  21. package/dist/models/NanoGPTV2.js +1 -1
  22. package/dist/models/factory.js +1 -1
  23. package/dist/models/model.js +1 -1
  24. package/dist/stream-DKl3GTDL.js +2287 -0
  25. package/dist/tokeniser/BaseTokeniser.d.ts +2 -1
  26. package/dist/tokeniser/CharTokeniser.d.ts +2 -2
  27. package/dist/tokeniser/CharTokeniser.js +7 -11
  28. package/dist/tokeniser/bpe.d.ts +2 -2
  29. package/dist/tokeniser/bpe.js +18 -27
  30. package/dist/tokeniser/type.d.ts +3 -2
  31. package/dist/training/DatasetBuilder.d.ts +1 -1
  32. package/dist/training/DatasetBuilder.js +1 -1
  33. package/dist/training/PreTrainer.js +1 -1
  34. package/dist/training/SFTTrainer.js +1 -1
  35. package/dist/training/tasks/ConversationTask.d.ts +9 -10
  36. package/dist/training/tasks/ConversationTask.js +15 -24
  37. package/dist/training/tasks/PretrainingTask.d.ts +4 -4
  38. package/dist/training/tasks/PretrainingTask.js +2 -2
  39. package/dist/training/tasks/StartSentenceTask.d.ts +4 -4
  40. package/dist/training/tasks/StartSentenceTask.js +3 -3
  41. package/dist/training/tasks/Task.d.ts +9 -11
  42. package/dist/training/tasks/Task.js +14 -27
  43. package/dist/training/tasks/splitter.d.ts +2 -2
  44. package/dist/training/tasks/splitter.js +11 -11
  45. package/dist/training/validation.d.ts +1 -1
  46. package/dist/training/validation.js +1 -1
  47. package/dist/utilities/tokens.d.ts +2 -0
  48. package/dist/utilities/tokens.js +40 -0
  49. package/dist/utilities/topP.js +6 -0
  50. package/package.json +2 -1
@@ -1,3 +1,4 @@
1
+ import { ConversationStream } from '../../data/stream';
1
2
  import { Conversation, ITokeniser } from './type';
2
3
  import { default as EE } from 'eventemitter3';
3
4
  export declare const SPECIALS: string[];
@@ -15,7 +16,7 @@ export default abstract class BaseTokeniser extends EE<'trainStatus'> implements
15
16
  protected addSpecialTokens(): void;
16
17
  protected addSpecialToken(token: string, index: number): void;
17
18
  generateID(): void;
18
- abstract train(text: Conversation[][], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
19
+ abstract train(text: ConversationStream[], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
19
20
  abstract getVocab(): string[];
20
21
  abstract getMerges(): [string, string][];
21
22
  abstract destroy(): void;
@@ -1,5 +1,5 @@
1
1
  import { default as BaseTokeniser } from './BaseTokeniser';
2
- import { Conversation } from './type';
2
+ import { ConversationStream } from '../../data/stream';
3
3
  export default class CharTokeniser extends BaseTokeniser {
4
4
  vocabSize: number;
5
5
  eosToken: number;
@@ -12,7 +12,7 @@ export default class CharTokeniser extends BaseTokeniser {
12
12
  addToken(token: string, index?: number): number;
13
13
  get trained(): boolean;
14
14
  destroy(): void;
15
- train(text: Conversation[][], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
15
+ train(text: ConversationStream[], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
16
16
  tokenise(text: string[], numeric: true): number[][];
17
17
  tokenise(text: string[]): string[][];
18
18
  detokenise(tokens: (number[] | Uint16Array)[]): string[];
@@ -38,19 +38,15 @@ var r = ["<eos>", "<unk>"], i = class extends n {
38
38
  async train(t, n, i) {
39
39
  this.datasetID = i;
40
40
  let a = /* @__PURE__ */ new Set(), o = performance.now();
41
- for (let r of t) r.forEach((e) => {
42
- for (let t of e.content) a.add(t);
43
- }), o = await e(o, n, 0);
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
+ }
44
47
  let s = Array.from(a), c = this.vocab.indexOf("", this.unkToken + 1), l = this.vocabSize - r.length;
45
48
  if (c === -1) return this.generateID(), this.vocabSize;
46
- if (this._trained = !0, s.length > l) {
47
- let e = /* @__PURE__ */ new Map();
48
- t.forEach((t) => {
49
- t.forEach((t) => {
50
- for (let n of t.content) e.set(n, (e.get(n) || 0) + 1);
51
- });
52
- }), s.sort((t, n) => (e.get(t) || 0) - (e.get(n) || 0)), s.splice(0, s.length - l);
53
- }
49
+ if (this._trained = !0, s.length > l) throw Error("too_small_vocab");
54
50
  let u = c;
55
51
  if (u !== -1) {
56
52
  let e = new Set(this.vocab);
@@ -1,5 +1,5 @@
1
1
  import { default as BaseTokeniser } from './BaseTokeniser';
2
- import { Conversation } from './type';
2
+ import { ConversationStream } from '../../data/stream';
3
3
  export default class BPETokeniser extends BaseTokeniser {
4
4
  private targetSize;
5
5
  private vocab;
@@ -15,7 +15,7 @@ export default class BPETokeniser extends BaseTokeniser {
15
15
  get eosToken(): number;
16
16
  get bosToken(): number;
17
17
  get unkToken(): number;
18
- train(text?: Conversation[][], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
18
+ train(text?: ConversationStream[], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
19
19
  getVocab(): string[];
20
20
  getMerges(): [string, string][];
21
21
  private tokeniseWord;
@@ -100,40 +100,31 @@ var u = class extends n {
100
100
  }
101
101
  async train(t = [], n, i) {
102
102
  this.datasetID = i;
103
- let o = performance.now(), c = Array(t.length);
104
- for (let i = 0; i < t.length; i++) {
105
- let a = t[i], s = Array(a.length);
106
- for (let e = 0; e < a.length; e++) s[e] = r(a[e].content);
107
- o = await e(o, n, this.vocab.size), c[i] = s;
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
+ }
108
113
  }
109
- let u = c.flat(2), d = new Set(u);
110
114
  this.vocab = /* @__PURE__ */ new Set(), this.pretokenMap.clear(), this.merges = [], this.addSpecialTokens();
111
- let f = Array.from(d), p = f.map((e) => Array.from(e).map((e) => (this.vocab.add(e), e))), m = a(p);
112
- if (o = await e(o, n, this.vocab.size), this.vocab.size >= this.targetSize) {
113
- console.warn("Initial vocab size is greater than or equal to target size. No merges will be performed.");
114
- let e = /* @__PURE__ */ new Map();
115
- u.forEach((t) => {
116
- Array.from(t).forEach((t) => {
117
- e.set(t, (e.get(t) || 0) + 1);
118
- });
119
- });
120
- let t = Array.from(e.entries()).sort((e, t) => t[1] - e[1]);
121
- this.vocab = /* @__PURE__ */ new Set(), this.addSpecialTokens(), t.slice(0, this.targetSize - this.vocab.size).map(([e]) => e).forEach((e) => this.vocab.add(e)), this.vocabIndex.clear();
122
- let n = 0;
123
- for (let e of this.vocab.keys()) this.vocabIndex.set(e, n++);
124
- return this.generateID(), this.emit("trainStatus", "trained"), this.vocab.size;
125
- }
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");
126
117
  for (; this.vocab.size < this.targetSize && this.merges.length < this.targetSize;) {
127
- let t = s(m);
118
+ let t = s(f);
128
119
  if (!t) break;
129
- this.merges.push([t.a, t.b]), this.vocab.add(t.a + t.b), l(m, t), o = await e(o, n, this.vocab.size);
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);
130
121
  }
131
- f.forEach((e, t) => {
132
- let n = p[t];
122
+ u.forEach((e, t) => {
123
+ let n = d[t];
133
124
  this.pretokenMap.set(e, n);
134
125
  }), this.vocabIndex.clear();
135
- let h = 0;
136
- for (let e of this.vocab.keys()) this.vocabIndex.set(e, h++);
126
+ let p = 0;
127
+ for (let e of this.vocab.keys()) this.vocabIndex.set(e, p++);
137
128
  return this.generateID(), this.emit("trainStatus", "trained"), this.vocab.size;
138
129
  }
139
130
  getVocab() {
@@ -1,13 +1,14 @@
1
1
  import { default as EE } from 'eventemitter3';
2
+ import { ConversationStream } from '../data/stream';
2
3
  export type Roles = 'user' | 'assistant' | 'system' | 'text';
3
4
  export interface Conversation {
4
5
  role: Roles;
5
6
  content: string;
6
7
  }
7
- export interface ITokeniser extends EE<'trainStatus'> {
8
+ export interface ITokeniser extends EE<'trainStatus' | 'error'> {
8
9
  id: string;
9
10
  datasetID?: string;
10
- train(text: Conversation[][], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
11
+ train(text: ConversationStream[], cb?: (vocab: number) => void, datasetID?: string): Promise<number>;
11
12
  getVocab(): string[];
12
13
  getMerges(): [string, string][];
13
14
  destroy(): void;
@@ -15,7 +15,7 @@ export declare class DatasetBuilder {
15
15
  tokenizer: ITokeniser;
16
16
  blockSize: number;
17
17
  constructor(tokenizer: ITokeniser, blockSize?: number);
18
- createTextDataset(flatTokens: Uint16Array, batchSize?: number, indexes?: Uint32Array, mask?: Uint8Array, ignoreIndex?: number): Promise<{
18
+ createTextDataset(flatTokens: Uint16Array[], batchSize?: number, indexes?: Uint32Array, mask?: Uint8Array[], ignoreIndex?: number): Promise<{
19
19
  dataset: Dataset<{
20
20
  xs: Tensor;
21
21
  ys: Tensor;
@@ -1,2 +1,2 @@
1
- import { i as e, n as t, r as n, t as r } from "../DatasetBuilder-B9UGNQT5.js";
1
+ import { i as e, n as t, r as n, t as r } from "../DatasetBuilder-Ctb425Id.js";
2
2
  export { r as DatasetBuilder, t as flattenTokens, n as flattenTokensWithMask, e as shuffle };
@@ -1,4 +1,4 @@
1
- import { t as e } from "../DatasetBuilder-B9UGNQT5.js";
1
+ import { t as e } from "../DatasetBuilder-Ctb425Id.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-B9UGNQT5.js";
1
+ import { t as e } from "../DatasetBuilder-Ctb425Id.js";
2
2
  import t from "./BasicTrainer.js";
3
3
  //#region lib/training/SFTTrainer.ts
4
4
  var n = {
@@ -1,18 +1,17 @@
1
- import { Conversation, ITokeniser } from '../../../main';
1
+ import { Conversation, ConversationStream, ITokeniser } from '../../../main';
2
2
  import { Task } from './Task';
3
3
  export default class ConversationTask extends Task {
4
- private rawConvo;
5
- private shuffledIndices;
6
- private index;
4
+ private streams;
5
+ private streamIndex;
6
+ private currentCursor;
7
7
  get length(): number;
8
- constructor(conversations: Conversation[][]);
8
+ constructor(conversations: ConversationStream[]);
9
9
  hasMoreConversations(): boolean;
10
- nextConversation(): Conversation[] | null;
11
- nextTokens(tokeniser: ITokeniser): number[] | null;
12
- nextTokens(tokeniser: ITokeniser, masking: boolean): {
10
+ nextConversation(): Promise<Conversation[] | null>;
11
+ nextTokens(tokeniser: ITokeniser): Promise<number[] | null>;
12
+ nextTokens(tokeniser: ITokeniser, masking: boolean): Promise<{
13
13
  tokens: number[];
14
14
  mask: boolean[];
15
- } | null;
16
- shuffle(): void;
15
+ } | null>;
17
16
  estimateTokens(tokeniser: ITokeniser): Promise<number>;
18
17
  }
@@ -1,38 +1,29 @@
1
- import { i as e } from "../../DatasetBuilder-B9UGNQT5.js";
2
- import { Task as t } from "./Task.js";
1
+ import { Task as e } from "./Task.js";
3
2
  //#region lib/training/tasks/ConversationTask.ts
4
- var n = class extends t {
5
- rawConvo;
6
- shuffledIndices = null;
7
- index = 0;
3
+ var t = class extends e {
4
+ streams;
5
+ streamIndex = 0;
6
+ currentCursor = null;
8
7
  get length() {
9
- return this.rawConvo.length;
8
+ return this.streams.length;
10
9
  }
11
10
  constructor(e) {
12
- super(), this.rawConvo = e;
11
+ super(), this.streams = e;
13
12
  }
14
13
  hasMoreConversations() {
15
- return this.index < this.rawConvo.length;
14
+ return this.streamIndex < this.streams.length;
16
15
  }
17
- nextConversation() {
18
- if (this.index >= this.rawConvo.length) return null;
19
- let e = this.rawConvo[this.shuffledIndices ? this.shuffledIndices[this.index] : this.index];
20
- return this.index++, e;
16
+ async nextConversation() {
17
+ return this.streamIndex < this.streams.length ? (this.currentCursor ||= this.streams[this.streamIndex].cursor(), await this.currentCursor.next() || (this.streamIndex++, this.currentCursor = null, this.nextConversation())) : null;
21
18
  }
22
- nextTokens(e, t) {
23
- let n = this.nextConversation();
19
+ async nextTokens(e, t) {
20
+ let n = await this.nextConversation();
24
21
  return n ? e.encodeConversation(n, !1, t) : null;
25
22
  }
26
- shuffle() {
27
- if (!this.shuffledIndices) {
28
- this.shuffledIndices = new Uint32Array(this.rawConvo.length);
29
- for (let e = 0; e < this.rawConvo.length; e++) this.shuffledIndices[e] = e;
30
- }
31
- e(this.shuffledIndices), this.index = 0;
32
- }
33
23
  async estimateTokens(e) {
34
- return e.encodeConversation(this.rawConvo[0]).length * this.length;
24
+ let t = await this.streams[0].cursor().next();
25
+ return t ? e.encodeConversation(t).length * this.length : 0;
35
26
  }
36
27
  };
37
28
  //#endregion
38
- export { n as default };
29
+ export { t as default };
@@ -6,12 +6,12 @@ export default class PretrainingTask extends Task {
6
6
  get length(): number;
7
7
  constructor(texts: string[]);
8
8
  hasMoreConversations(): boolean;
9
- nextConversation(): Conversation[] | null;
10
- nextTokens(tokeniser: ITokeniser): number[] | null;
11
- nextTokens(tokeniser: ITokeniser, masking: boolean): {
9
+ nextConversation(): Promise<Conversation[] | null>;
10
+ nextTokens(tokeniser: ITokeniser): Promise<number[] | null>;
11
+ nextTokens(tokeniser: ITokeniser, masking: boolean): Promise<{
12
12
  tokens: number[];
13
13
  mask: boolean[];
14
- } | null;
14
+ } | null>;
15
15
  shuffle(): void;
16
16
  estimateTokens(tokeniser: ITokeniser): Promise<number>;
17
17
  }
@@ -12,7 +12,7 @@ var t = class extends e {
12
12
  hasMoreConversations() {
13
13
  return this.index < this.rawText.length;
14
14
  }
15
- nextConversation() {
15
+ async nextConversation() {
16
16
  if (this.index >= this.rawText.length) return null;
17
17
  let e = {
18
18
  role: "assistant",
@@ -20,7 +20,7 @@ var t = class extends e {
20
20
  };
21
21
  return this.index++, [e];
22
22
  }
23
- nextTokens(e, t) {
23
+ async nextTokens(e, t) {
24
24
  if (this.index >= this.rawText.length) return null;
25
25
  let n = e.encodeSequence(this.rawText[this.index]);
26
26
  return this.index++, t ? {
@@ -6,12 +6,12 @@ export default class StartSentenceTask extends Task {
6
6
  get length(): number;
7
7
  constructor(texts: string[]);
8
8
  hasMoreConversations(): boolean;
9
- nextConversation(): Conversation[] | null;
10
- nextTokens(tokeniser: ITokeniser): number[] | null;
11
- nextTokens(tokeniser: ITokeniser, masking: boolean): {
9
+ nextConversation(): Promise<Conversation[] | null>;
10
+ nextTokens(tokeniser: ITokeniser): Promise<number[] | null>;
11
+ nextTokens(tokeniser: ITokeniser, masking: boolean): Promise<{
12
12
  tokens: number[];
13
13
  mask: boolean[];
14
- } | null;
14
+ } | null>;
15
15
  shuffle(): void;
16
16
  private conversationFromString;
17
17
  estimateTokens(tokeniser: ITokeniser): Promise<number>;
@@ -12,13 +12,13 @@ var t = class extends e {
12
12
  hasMoreConversations() {
13
13
  return this.index < this.rawText.length;
14
14
  }
15
- nextConversation() {
15
+ async nextConversation() {
16
16
  if (this.index >= this.rawText.length) return null;
17
17
  let e = this.rawText[this.index];
18
18
  return this.index++, this.conversationFromString(e);
19
19
  }
20
- nextTokens(e, t) {
21
- let n = this.nextConversation();
20
+ async nextTokens(e, t) {
21
+ let n = await this.nextConversation();
22
22
  return n ? e.encodeConversation(n, !1, t) : null;
23
23
  }
24
24
  shuffle() {
@@ -2,21 +2,19 @@ import { Conversation, ITokeniser } from '../../../main';
2
2
  export declare abstract class Task {
3
3
  abstract get length(): number;
4
4
  abstract hasMoreConversations(): boolean;
5
- abstract nextConversation(): Conversation[] | null;
6
- abstract nextTokens(tokeniser: ITokeniser): number[] | null;
7
- abstract nextTokens(tokeniser: ITokeniser, masking: boolean): {
5
+ abstract nextConversation(): Promise<Conversation[] | null>;
6
+ abstract nextTokens(tokeniser: ITokeniser): Promise<number[] | null>;
7
+ abstract nextTokens(tokeniser: ITokeniser, masking: boolean): Promise<{
8
8
  tokens: number[];
9
9
  mask: boolean[];
10
- } | null;
11
- abstract nextTokens(tokeniser: ITokeniser, masking?: boolean): number[] | {
10
+ } | null>;
11
+ abstract nextTokens(tokeniser: ITokeniser, masking?: boolean): Promise<number[] | {
12
12
  tokens: number[];
13
13
  mask: boolean[];
14
- } | null;
15
- abstract estimateTokens(tokeniser: ITokeniser): Promise<number>;
16
- abstract shuffle(): void;
14
+ } | null>;
17
15
  }
18
- export declare function tokensFromTasks(tasks: Task[], tokenizer: ITokeniser, cb?: (tokens: number) => void): Promise<Uint16Array>;
16
+ export declare function tokensFromTasks(tasks: Task[], tokenizer: ITokeniser, cb?: (tokens: number) => void): Promise<Uint16Array[]>;
19
17
  export declare function tokensFromTasks(tasks: Task[], tokenizer: ITokeniser, cb?: (tokens: number) => void, masking?: boolean): Promise<{
20
- tokens: Uint16Array;
21
- mask: Uint8Array;
18
+ tokens: Uint16Array[];
19
+ mask: Uint8Array[];
22
20
  }>;
@@ -1,9 +1,9 @@
1
1
  import { yieldIfNeeded as e } from "../../utilities/yielder.js";
2
2
  //#region lib/training/tasks/Task.ts
3
3
  var t = class {};
4
- function n(e, t, n, r, i, a) {
4
+ async function n(e, t, n, r, i, a) {
5
5
  for (let o of e) {
6
- let e = o.nextTokens(n, a ? !0 : void 0);
6
+ let e = await o.nextTokens(n, a ? !0 : void 0);
7
7
  if (e) {
8
8
  let n = Array.isArray(e) ? e : e.tokens;
9
9
  r.total += n.length;
@@ -11,7 +11,9 @@ function n(e, t, n, r, i, a) {
11
11
  if (r.offset + n.length > o.length) {
12
12
  let c = o.length - r.offset;
13
13
  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));
14
+ let l = n.length - c;
15
+ if (l > i) throw Error(`Estimated tokens (${i}) is too small for the next batch of tokens (${l}).`);
16
+ let u = new Uint16Array(i);
15
17
  if (u.set(n.slice(c), 0), t.push(u), a && s && !Array.isArray(e)) {
16
18
  s.set(e.mask.slice(0, c).map((e) => +!!e), r.offset);
17
19
  let t = new Uint8Array(u.length);
@@ -23,33 +25,18 @@ function n(e, t, n, r, i, a) {
23
25
  }
24
26
  }
25
27
  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
+ let o = 1e4 * 1024, s = [new Uint16Array(o)], c = a ? [new Uint8Array(o)] : null, l = {
27
29
  offset: 0,
28
30
  total: 0
29
31
  }, 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
- };
51
- }
52
- return f;
32
+ for (; await n(t, s, r, l, o, c || void 0), !t.every((e) => !e.hasMoreConversations());) u = await e(u, i, l.total);
33
+ return s.length === 1 ? c ? {
34
+ tokens: [s[0].subarray(0, l.offset)],
35
+ mask: [c[0].subarray(0, l.offset)]
36
+ } : [s[0].subarray(0, l.offset)] : (s[s.length - 1] = s[s.length - 1].subarray(0, l.offset), c ? (c[c.length - 1] = c[c.length - 1].subarray(0, l.offset), {
37
+ tokens: s,
38
+ mask: c
39
+ }) : s);
53
40
  }
54
41
  //#endregion
55
42
  export { t as Task, r as tokensFromTasks };
@@ -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-DKl3GTDL.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 };
@@ -2,7 +2,7 @@ import { ITokeniser, Task } from '../../main';
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
+ export declare function createTrainValidationSplit(tasks: Task[] | Uint16Array[], tokeniser: ITokeniser, datasetBuilder: DatasetBuilder, batchSize: number, validationSplit?: number, masking?: boolean): Promise<{
6
6
  trainDataset: Dataset<{
7
7
  xs: Tensor;
8
8
  ys: Tensor;
@@ -1,2 +1,2 @@
1
- import { o as e } from "../main-DdsoTJAW.js";
1
+ import { o as e } from "../main-Bgc7_9kb.js";
2
2
  export { e as createTrainValidationSplit };
@@ -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.22.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",