Skip to content

feat(optim): mutable learning rate and warmup+cosine LR schedule#866

Merged
michalharakal merged 1 commit into
developfrom
feature/865-lr-schedules
Jul 24, 2026
Merged

feat(optim): mutable learning rate and warmup+cosine LR schedule#866
michalharakal merged 1 commit into
developfrom
feature/865-lr-schedules

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Closes #865.

What

  • AdamOptimizer.lr and SgdOptimizer.lr are now public var (previously private val), so training loops can adjust the learning rate between steps without recreating the optimizer and discarding Adam's moment estimates.
  • New LrSchedule fun interface + linearWarmupCosineDecay(totalSteps, warmupSteps, peakLr, initialLr, minLr) factory in sk.ainet.lang.nn.optim: linear ramp from initialLr to peakLr over the warmup steps, then cosine decay to minLr — the standard GPT-style pretraining recipe.

Schedules stay stateless and decoupled from optimizers; usage is one assignment per step:

val schedule = linearWarmupCosineDecay(totalSteps, warmupSteps, peakLr = 5e-4)
optimizer.lr = schedule.lrAt(globalStep)
trainStep(model, loss, optimizer, ctx, x, y)

No changes to the Optimizer interface.

Tests

  • LrScheduleTest (lang-core commonTest): warmup starts at initialLr and ramps with constant increments, peak reached exactly at warmup end, decay is monotonic and approaches minLr, invalid arguments rejected, lr assignable on both optimizers.
  • SgdOptimizerTest.lr_can_be_rescheduled_between_steps (backend-cpu): a rescheduled lr changes the applied update (0.1 → 9.8, then 0.5 → 8.8 on a hand-computed example).
  • API dumps updated (jvm via apiDump; android mirrored by hand — no Android SDK on this machine, additions are the property accessors and the two new types).

Motivation

Found while porting an educational GPT pretraining pipeline (appendix D of Raschka's book: warmup + cosine decay + gradient clipping) to SKaiNET — previously impossible without a project-local optimizer re-implementation whose only difference was var lr.

@github-actions

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully for this PR.

Generated Files:

  • Operator documentation: docs/modules/operators/_generated_/
  • JSON schema output: operators.json

Artifacts:

  • Download the documentation-preview-866 artifact to view the complete documentation locally.

This comment will be updated automatically when the PR is updated.

AdamOptimizer and SgdOptimizer expose lr as a public var so training
loops can adjust it between steps without recreating the optimizer and
losing the moment estimates. A stateless LrSchedule fun interface plus
a linearWarmupCosineDecay factory cover the GPT-style pretraining
recipe: linear ramp from initialLr to peakLr over the warmup steps,
then cosine decay to minLr.

Closes #865
@michalharakal
michalharakal force-pushed the feature/865-lr-schedules branch from cbbcbb5 to 6559806 Compare July 23, 2026 21:04
@github-actions

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully for this PR.

Generated Files:

  • Operator documentation: docs/modules/operators/_generated_/
  • JSON schema output: operators.json

Artifacts:

  • Download the documentation-preview-866 artifact to view the complete documentation locally.

This comment will be updated automatically when the PR is updated.

@michalharakal
michalharakal requested a review from aharakal July 24, 2026 09:40
@michalharakal
michalharakal merged commit 11f77c5 into develop Jul 24, 2026
18 checks passed
@michalharakal
michalharakal deleted the feature/865-lr-schedules branch July 24, 2026 09:43
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.

Learning-rate schedules: optimizer lr is immutable, no warmup/decay support

2 participants