Skip to content

Draft: GPT2 training on MCQ med data#1111

Open
mina5rovic wants to merge 60 commits into
developfrom
gpt2-training
Open

Draft: GPT2 training on MCQ med data#1111
mina5rovic wants to merge 60 commits into
developfrom
gpt2-training

Conversation

@mina5rovic

Copy link
Copy Markdown
Collaborator

No description provided.

@mina5rovic
mina5rovic requested a review from JulienVig April 16, 2026 11:51
@mina5rovic mina5rovic changed the title GPT2 training on MCQ med data Draft: GPT2 training on MCQ med data Apr 16, 2026
@mina5rovic
mina5rovic requested a review from JulienVig July 6, 2026 22:55

@JulienVig JulienVig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1st part of my review, I'll finish at a different time, feel free to start addressing these comments

Comment thread datasets/.gitignore
/simple_face-example.png
/titanic*
/mnist*
/medicalMCQtxtNoExplanation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To remove from main PR

Comment thread cli/src/args.ts
Comment on lines +20 to +25
roundIterations?: number;
batchSize: number;
validationSplit: number;
validationFrequency?: number;
datasetPath?: string;
validationDatasetPath?: string;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you document how all the validation parameters interact with each others? For example what happens if you specify both validationSplit and validationDatasetPath?

)
throw new Error("validationFrequency must be a non-negative integer");

// if (!Number.isInteger(this.#epochs / this.#roundDuration))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// if (!Number.isInteger(this.#epochs / this.#roundDuration))

Comment on lines +159 to +164
debugProcessMemory(
`[${shortenId(this.ownId)}] round ${round} before encode`,
);
const payload = await serialization.weights.encode(payloadToServer);
debugProcessMemory(
`[${shortenId(this.ownId)}] round ${round} after encode`,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it useful to log the before after?

id: NodeID;
waitForMoreParticipants: boolean;
payload: serialization.Encoded;
payload?: serialization.Encoded | null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why allow null?

Comment on lines +148 to +149
? this.#runRounds(dataset, validationDataset)
: this.#runIterationRounds(dataset, validationDataset);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these method names are not explicit enough, what about #runRoundsByEpoch and #runRoundsByIteration? Can you add documentation for each method to clearly differentiate their intended use and behaviors?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment for runRound and runIterationRound

Comment on lines +208 to +211
let pendingBatch: Batched<DataFormat.ModelEncoded[D]> | undefined =
next.done === true ? undefined : next.value;

while (pendingBatch !== undefined) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let pendingBatch: Batched<DataFormat.ModelEncoded[D]> | undefined =
next.done === true ? undefined : next.value;
while (pendingBatch !== undefined) {
while (next.done !== true) {

I think you can simplify the implementation and drop pendingBatch if you directly use next.done and next.value instead

Comment on lines +306 to +321
const [gen, result] = async_iterator.split(
model.trainNextBatches(
datasetIterator as AsyncIterator<
Batched<DataFormat.ModelEncoded["text"]>
>,
maxBatchCount,
validationDataset as
| Dataset<Batched<DataFormat.ModelEncoded["text"]>>
| undefined,
setDone,
),
);

yield gen;
const epochLogs = await result;
epochsLogs = epochsLogs.push(epochLogs);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const [gen, result] = async_iterator.split(
model.trainNextBatches(
datasetIterator as AsyncIterator<
Batched<DataFormat.ModelEncoded["text"]>
>,
maxBatchCount,
validationDataset as
| Dataset<Batched<DataFormat.ModelEncoded["text"]>>
| undefined,
setDone,
),
);
yield gen;
const epochLogs = await result;
epochsLogs = epochsLogs.push(epochLogs);
const [gen, epochLogs] = async_iterator.split(
model.trainNextBatches(
datasetIterator as AsyncIterator<
Batched<DataFormat.ModelEncoded["text"]>
>,
maxBatchCount,
validationDataset as
| Dataset<Batched<DataFormat.ModelEncoded["text"]>>
| undefined,
setDone,
),
);
yield gen;
epochsLogs = epochsLogs.push(await epochLogs);

Comment on lines +289 to 307
#hashTokenContext(tokens: number[]): number {
let hash = 0x811c9dc5;

for (const token of tokens) {
hash ^= token & 0xff;
hash = Math.imul(hash, 0x01000193);
hash ^= (token >>> 8) & 0xff;
hash = Math.imul(hash, 0x01000193);
hash ^= (token >>> 16) & 0xff;
hash = Math.imul(hash, 0x01000193);
hash ^= (token >>> 24) & 0xff;
hash = Math.imul(hash, 0x01000193);
hash ^= 0xff;
hash = Math.imul(hash, 0x01000193);
}

return hash >>> 0;
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add documentation to this method?

Comment on lines +302 to +305
const model = this.model as unknown as IterationTrainableTextModel;
if (typeof model.trainNextBatches !== "function")
throw new Error("model does not support iteration-based training");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this part really inconvenient because it's not generic, it only addresses on particular case. Here's an idea to work around this, let me know what you think

  1. Implement a new dataset method that splits the dataset after a specified number of steps and returns 1) one dataset with only the next specified number of batches and 2) the remainder of the dataset after these batches. e.g., const [nextBatches, datasetRemainder] = dataset.subset(maxBatchCount)
  2. From runIterationRounds, I think this allows you to do reuse the existing #runRound, e.g. this.#runRound(nextBatches, roundValidationDataset)
  3. With this method I don't think you need to deal with all the iterators

Let me know what you think and whether this is feasible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants