Skip to content

release: v0.5.0 — version bump + changelog - #88

Merged
thad0ctor merged 5 commits into
mainfrom
release/v0.5.0
Jul 17, 2026
Merged

release: v0.5.0 — version bump + changelog#88
thad0ctor merged 5 commits into
mainfrom
release/v0.5.0

Conversation

@thad0ctor

@thad0ctor thad0ctor commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Release prep for v0.5.0. Version bump + changelog only — no source changes.

Two user-facing features landed since v0.4.1, and #83 adds a new public export, so semver says minor:

PR Change
#80 CPU-offloaded training for plain Gefen — CPU-resident stepping, DeepSpeed ZeRO-2/3 CPU-offload, FSDP2 CPUOffloadPolicy
#83 GefenDCPState — new public export making plain Gefen's FSDP2 optimizer state reshardable across world sizes (closes #81)

Both are additive. The CUDA same-device step path and the native state_dict/load_state_dict path are unchanged.

#87 (CI duplicate-run fix) also landed since v0.4.1 but is infrastructure-only with no user-facing effect, so it is intentionally not in the changelog.

Verified locally

  • Wheel builds as gefen_x-0.5.0-py3-none-any.whl.
  • The release workflow's Verify tag matches package version step reproduced verbatim against that wheel: tag=0.5.0 package=0.5.0pass.
  • twine checkpassed.
  • Prerelease gate logic: v0.5.0prerelease=false (reaches the PyPI gate); v0.5.0.dev1prerelease=true (stops at TestPyPI).

Release sequence after this merges

  1. Throwaway .dev1 commit off this one (version = "0.5.0.dev1"), tagged v0.5.0.dev1 and pushed to fork — not merged, matching the v0.4.1 pattern. Stops at TestPyPI.
  2. scripts/release_gpu_gate.sh v0.5.0.dev1 locally on two idle 3090s, zero skips.
  3. Approve testpypi — that approval is the attestation the GPU gate passed for that exact artifact.
  4. Tag v0.5.0 on the merged commit → full pipeline → GPU gate again → approve testpypi + pypi.
  5. Create the GitHub Release on tag 0.5.0, named v0.5.0, from this changelog entry.

Summary by CodeRabbit

  • New Features

    • Added CPU-offloaded training compatibility for plain Gefen, including improved device-mismatch preflight and checkpoint state co-location.
    • Introduced opt-in reshardable checkpoint support for FSDP2 optimizer state across topology changes.
    • Added bounded and asynchronous reshardable checkpoint saving.
  • Bug Fixes

    • Strengthened distributed checkpoint-load behavior with staged-restore validation and abort on rank/layout divergence.
    • Updated non-fused tensor learning-rate handling to resolve CUDA tensors to host scalars, with the associated device-to-host sync.
  • Chores

    • Bumped package version to 0.5.0 and updated the changelog entry.

Two user-facing features landed since v0.4.1, so this is a minor bump:

- #80 CPU-offloaded training for plain Gefen (CPU-resident stepping,
  DeepSpeed ZeRO-2/3 CPU-offload, FSDP2 CPUOffloadPolicy).
- #83 GefenDCPState, a new public export making plain Gefen's FSDP2
  optimizer state reshardable across world sizes (closes #81).

Both are additive; the CUDA same-device step path and the native
state_dict/load_state_dict path are unchanged.
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be4983a1-94c9-40ab-a3cb-0f154a503553

📥 Commits

Reviewing files that changed from the base of the PR and between a588184 and eba3bc0.

📒 Files selected for processing (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

The package version is bumped from 0.4.1 to 0.5.0. The changelog adds release notes for CPU-offloaded training, tensor learning rates, reshardable checkpoints, and async saving, while revising the 0.4.1 entry.

Changes

0.5.0 Release Metadata

Layer / File(s) Summary
Version and changelog updates
pyproject.toml, CHANGELOG.md
The project version changes to 0.5.0, and release notes document CPU-offloaded training, tensor learning-rate handling, checkpoint resharding, async saving, and hardening changes. The 0.4.1 section removes its standalone GefenDCPState bullet.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the release version bump and changelog update.
Linked Issues check ✅ Passed The changelog and release bump reflect the new DCP-shardable GefenDCPState path and topology-change resharding work in #81.
Out of Scope Changes check ✅ Passed No unrelated code changes are present; the remaining additions are release-note updates and version metadata.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v0.5.0

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9fba8de239

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md
Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated
Addresses the Codex review on #88. All three findings were verified against
the code and tests before fixing; all three were valid.

- Restore the [0.4.1] section to its as-released text. #83 wrote its
  GefenDCPState entry into the already-published 0.4.1 section, which shipped
  on 2026-07-15 from e986963 -- a commit that contains no src/gefen/dcp.py.
  gefen-x==0.4.1 on PyPI has no GefenDCPState, so the attribution was wrong
  and my 0.5.0 entry duplicated it. GefenDCPState is now credited to 0.5.0
  only, and the 0.4.1 section is byte-identical to e986963:CHANGELOG.md.

- Drop the "resume across a device move is bit-exact" claim. The cross-device
  test (test_cpu_resident_step.py) asserts state co-location and a finite
  continuation, not bit-exactness, and test_cpu_vs_cuda_nonfused_parity
  documents that CPU/CUDA bit-exactness is not achievable because the grad^2
  reductions use different accumulation orders. Now described as a correct,
  numerically close continuation.

- Qualify "the CUDA same-device step path is unchanged". Values stay
  bit-identical, but #80 scalarizes a tensor lr on the non-fused,
  non-capturable path, and _lr_scalar re-reads via .item() whenever the lr
  tensor's identity or _version changes. An in-place LR scheduler on a CUDA
  tensor lr therefore now costs one D2H sync per step on that path. Documented
  as an explicit behavior change with the float-lr workaround.
@thad0ctor

Copy link
Copy Markdown
Owner Author

Thanks — all three findings verified against the code and tests, all three valid. Fixed in 3e1656f.

P2: duplicated GefenDCPState attribution — valid, and worse than a duplicate

This is a real docs bug already on main, not just a duplication in my new section. #83 wrote its GefenDCPState entry into the already-published [0.4.1] section, and also rewrote that section's summary line from "no public API changes" to "the only public API addition is the opt-in GefenDCPState resharding wrapper".

v0.4.1 shipped on 2026-07-15 from e986963, and that commit contains no src/gefen/dcp.py:

$ git ls-tree e986963 src/gefen/ --name-only | grep -i dcp
(no output)
$ git log --oneline --diff-filter=A -- src/gefen/dcp.py
df3a615 Compat: DCP resharding for FSDP2 Gefen state (#83)

So gefen-x==0.4.1 on PyPI has no GefenDCPState at all — anyone reading that entry would go looking for an API that isn't in the release. Restored the [0.4.1] section to its as-released text; it is now byte-identical to e986963:CHANGELOG.md. GefenDCPState is credited to 0.5.0 only.

P2: bit-exact continuation across devices — valid

Dropped. The cross-device test asserts only co-location and a finite continuation:

assert opt_cpu._gefen_codebook.device.type == "cpu"
assert dev.type == "cpu", "restored state stranded off the CPU param"
assert torch.isfinite(p).all()

and test_cpu_vs_cuda_nonfused_parity documents the opposite of my claim outright: "Bit-exactness is NOT achievable: the grad^2 reductions feeding the second moment ... use different accumulation orders and backend math on CPU vs CUDA." The claim came from #80's PR body; the tests don't support it as I phrased it. Now: state loads intact and co-located and continues correctly, but a resume onto a different device type is a numerically close continuation, not a bit-exact one.

P2: unchanged CUDA-path claim — valid, qualified rather than dropped

Right on both counts. Values stay bit-identical (the scalar equals lr.item()), but the sync is real — _lr_scalar's own docstring concedes it:

A tensor lr is .item()'d (a D2H sync) only when its identity or _version changes -- an in-place scheduler update (e.g. lr.mul_) bumps _version ... one shared slot already costs just one .item() per step (O(steps), per version).

An in-place scheduler bumps _version every step, so it's a per-step D2H sync; before #80 the non-fused path passed the 0-dim tensor through and did the math on-device. The in-code comment calling _lr_scalar a "cached no-sync .item() hoist" is optimistic — it's no-sync only while the tensor is unchanged.

Split into two claims: the summary now says same-device CUDA updates stay numerically bit-identical, and there's a dedicated bullet documenting the sync as an explicit behavior change, scoped to tensor-lr + non-fused + non-capturable, with the plain-float workaround. Float lrs, the fused path, and capturable=True are unaffected.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc71da351c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a588184275

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md Outdated
With nonzero weight decay the non-fused tensor-LR path computes 1 - lr*wd on
the host in double precision rather than as tensor arithmetic in the LR dtype,
so the update is numerically equivalent, not bit-identical (a float16 LR rounds
1 - tiny to 1.0 on the old device path). The LR value itself is still exact.
@thad0ctor
thad0ctor merged commit bd3bf64 into main Jul 17, 2026
8 checks passed
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.

FSDP2 optimizer state is not DCP-shardable (no dcp.save/load, no optimizer-state resharding)

1 participant