fix(bf16): restore relu_mask BW_SAFE_MAX ±500 clamp (NOT a NaN guard)
The guard cleanup agent incorrectly removed the backward dX overflow clamp from relu_mask_kernel. This clamp is a LEGITIMATE bf16 overflow prevention at the type boundary — identical to the forward-pass bias kernel clamping. The dX GemmEx writes bf16 output. When the f32 accumulated sum exceeds bf16 max (~65504), it writes Inf. The relu_mask ±500 clamp converts Inf to a finite value, preventing cascade through the backward chain. Also reverted the outside-graph params cast (the in-graph capture is correct). Remaining issue: grad_norm drops to 0 in epoch 2+ with f32 master weights. The model learns in epoch 1 (grad_norm=0.004) but stagnates in epoch 2+. Investigating CUDA graph replay of f32→bf16 params cast. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,8 +9,16 @@
|
||||
* block=(256, 1, 1).
|
||||
*/
|
||||
|
||||
/* ReLU mask: zero gradient where activation <= 0 (ReLU backward).
|
||||
* No magnitude clamp needed — f32 d_logits eliminate bf16 overflow. */
|
||||
/* ReLU mask + bf16 overflow clamp for backward dX.
|
||||
*
|
||||
* The dX GemmEx (bf16 A × bf16 B → bf16 C) writes bf16 output. When the
|
||||
* f32 accumulated sum exceeds bf16 max (~65504), the bf16 write produces
|
||||
* Inf. This clamp prevents Inf from cascading through the backward chain.
|
||||
* Same pattern as the forward bias kernel ±500 clamp.
|
||||
*
|
||||
* This is NOT a NaN guard — it's bf16 overflow prevention at the type
|
||||
* boundary, identical to the forward-pass bias kernel clamping. */
|
||||
#define BW_SAFE_MAX 500.0f
|
||||
|
||||
extern "C" __global__ void relu_mask_kernel(
|
||||
__nv_bfloat16* __restrict__ dy,
|
||||
@@ -19,7 +27,14 @@ extern "C" __global__ void relu_mask_kernel(
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i >= n) return;
|
||||
if (activation[i] <= bf16_zero()) dy[i] = bf16_zero();
|
||||
float act_f = (float)activation[i];
|
||||
if (act_f <= 0.0f) {
|
||||
dy[i] = bf16_zero();
|
||||
} else {
|
||||
float dy_f = (float)dy[i];
|
||||
dy_f = fminf(fmaxf(dy_f, -BW_SAFE_MAX), BW_SAFE_MAX);
|
||||
dy[i] = bf16(dy_f);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void bias_grad_reduce_kernel(
|
||||
|
||||
@@ -2481,8 +2481,7 @@ impl GpuDqnTrainer {
|
||||
/// gradients into grad_buf (IQN, attention, ensemble).
|
||||
pub fn replay_adam_and_readback(&mut self) -> Result<FusedTrainScalars, MLError> {
|
||||
self.replay_adam()?;
|
||||
// Finalize grad_norm OUTSIDE graph: convert float sum-of-squares → bf16 L2 norm.
|
||||
// The graph stores float sums via atomicAdd; this kernel reads them and writes bf16.
|
||||
// Finalize grad_norm OUTSIDE graph
|
||||
self.launch_grad_norm_finalize()?;
|
||||
// Per-step: zero readback for performance (no cuStreamSync).
|
||||
// Loss/grad_norm accumulated on GPU by training_guard kernel.
|
||||
|
||||
Reference in New Issue
Block a user