Skip to content

Fp8 opt bugfix#68

Merged
ngc92 merged 7 commits into
devfrom
fp8-opt-bugfix
Jul 18, 2026
Merged

Fp8 opt bugfix#68
ngc92 merged 7 commits into
devfrom
fp8-opt-bugfix

Conversation

@ngc92

@ngc92 ngc92 commented Mar 6, 2026

Copy link
Copy Markdown
Collaborator

seems to work again for 1.5b

Copilot AI review requested due to automatic review settings March 6, 2026 21:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug in FP8 optimizer state allocation that caused failures when model weight tensors had a first dimension not divisible by 128 × world_size. The fix introduces a flat_view / flattened_view utility to correctly shape FP8 momentum scaling tensors by flattening each weight tensor before sharding, rather than directly dividing the first dimension of multi-dimensional tensors.

Changes:

  • New flat_view(Tensor) and flattened_view(GenericTensorContainer) utility functions to produce 1D views of tensors and containers
  • Rewrote FP8 scale tensor shaping in AdamWStateManager::allocate_state to flatten first, shard by mWorld, then shard by 128
  • Added early-exit and null-pointer guards to fill_imp to safely handle zero-element tensors

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/utilities/tensor.h Declares new flat_view(const Tensor&) function
src/utilities/tensor.cpp Implements flat_view and flattened_view(GenericTensorContainer)
src/utilities/tensor_container.h Declares flattened_view(GenericTensorContainer)
src/training/adamw_optimizer.cpp Replaces direct shard_empty_container(_, 128*mWorld) with a correct flatten-then-shard approach for FP8 scale tensors
src/kernels/fill.cu Adds count == 0 early return and null pointer guard to fill_imp

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/training/adamw_optimizer.cpp Outdated
Comment thread src/training/adamw_optimizer.cpp Outdated
Comment thread src/utilities/tensor_container.h Outdated
@ngc92
ngc92 force-pushed the fp8-opt-bugfix branch from 8b14573 to 6251283 Compare June 3, 2026 14:32
Copilot AI review requested due to automatic review settings June 3, 2026 14:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment thread src/utilities/tensor.cpp
@ngc92
ngc92 force-pushed the fp8-opt-bugfix branch from 1583035 to f58a068 Compare June 3, 2026 14:41
ngc92 and others added 3 commits July 18, 2026 18:36
…rs, grad-norm shard type

LazyAllocator::commit assigned every registered tensor a non-null Data
pointer, including zero-size ones (disabled QKV bias, tied LM head).
All 'disabled tensor' checks key off Data == nullptr, so those tensors
were suddenly considered live: backward_bias corrupted the attention-out
gradient on no-bias models, zero-element kernel launches and NCCL calls
crashed sharded/FP8-momentum configs, tied models lost the skip-zeroing
fast path, and optimizer-state checkpoints gained a bogus lm_head entry.
Commit now leaves zero-size tensors with a null Data pointer.

Also:
- rank-0 tensors now report nelem() == 0 instead of the empty product 1:
  the codebase uses default-constructed rank-0 tensors as 'no tensor'
  (never as scalars), and the phantom element made shard_view's
  consistency check throw on the disabled QKV bias in shard_block,
  aborting any multi-GPU run of a no-bias model during weight allocation
- ShardedBlocksGradientManager::notify_non_block skips the redundant
  reduce_scatter on single-GPU runs, matching the unsharded manager
- _calculate_gradient_norm takes gradient shards as const Tensor& to
  avoid synthesizing TensorShard temporaries with wrong metadata

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With --opt-m-dtype=e4m3, the momentum of every tensor was stored in FP8,
including tiny 1D tensors (norm weights, qkv bias). Their scale tensors
required the per-rank shard size to be divisible by 128, which fails for
e.g. hidden size 896 on 2 or 4 GPUs ("Cannot divide 448 by 128").

Quantizing these tensors saves almost no memory, so store their momentum
in BF16 instead and give them empty scale entries. Empty tensors are now
skipped uniformly in OptStateWrapper::iterate_tensors, which also covers
the tied lm_head and disabled qkv bias cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 18, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment thread src/utilities/tensor.h
Comment thread src/training/gradients.cpp
nvmlDeviceSetCpuAffinity fails with NVML_ERROR_UNKNOWN in sandboxed
environments (e.g. gVisor on Modal). The NVML_CHECK threw inside the
monitoring jthread, where the uncaught exception called std::terminate
and took down the whole training process — on Modal CI this killed the
worker mid-input, surfacing as "Server has lost track of input".

Affinity for the monitoring thread is an optimization; warn and
continue, matching how set_cpu_affinity failures are handled in comm.cpp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 18, 2026 21:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/training/gradients.cpp:173

  • When comm.world_size() == 1, this function skips reduce_scatter and never records mNonBlockEvent. However, end_micro_step() unconditionally calls cudaStreamWaitEvent(stream, mNonBlockEvent, 0) on the last micro-step, which can block indefinitely on an event that was never recorded.
void ShardedBlocksGradientManager::notify_non_block(std::size_t index, cudaStream_t stream, NCCLCommunicator& comm) {
    if(!is_last_micro_step()) return;
    if (comm.world_size() != 1) {
        NvtxRange r{"notify"};
        comm.reduce_scatter(mFullNonBlock.get_tensor(index), stream, mNonBlockEvent);
    }

Comment on lines +64 to +66
//! Flattens all tensors in the container.
GenericTensorContainer flattened_view(const GenericTensorContainer& c);

@ngc92
ngc92 merged commit 40519a8 into dev Jul 18, 2026
31 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.

2 participants