Repository navigation
fix(personaplex): store RMSNorm weights in the model dtype - #1800
Closed
chaofengw-nv wants to merge 1 commit into
Closed
chaofengw-nv wants to merge 1 commit into
chaofengw-nv wants to merge 1 commit into
Conversation
The reference loads PersonaPlex in FP16, so each BF16 RMSNorm weight is stored as Half before the FP32 norm computes with it. The family graph kept the checkpoint weight in FP32. Small BF16 weights that fall into the Half subnormal range then differ: transformer.layers.0.norm1.alpha[65] is -1.0207295e-06 in the checkpoint but -1.0132790e-06 in the reference. Round gamma to the input dtype inside the FP32 norm when the norm runs on a lower-precision input. FP32 builds keep the FP32 weight. Signed-off-by: chaofengw <chaofengw@nvidia.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Comment |
This was referenced Oct 18, 2026
chaofengw-nv
added a commit
to chaofengw-nv/TensorRT-Model-Connect-fork
that referenced
this pull request
Oct 20, 2026
Round RMSNorm scale weights to the model dtype before the FP32 normalization computation. Closes NVIDIA#1799 Refs NVIDIA#1800 Signed-off-by: chaofengw <chaofengw@nvidia.com>
3 of 11 tasks
Collaborator
Author
chaofengw-nv
added a commit
to chaofengw-nv/TensorRT-Model-Connect-fork
that referenced
this pull request
Oct 21, 2026
Round RMSNorm scale weights to the model dtype before the FP32 normalization computation. Closes NVIDIA#1799 Refs NVIDIA#1800 Signed-off-by: chaofengw <chaofengw@nvidia.com>
chaofengw-nv
added a commit
that referenced
this pull request
Oct 21, 2026
* fix(personaplex): decode with the FP32 Mimi codec Build the Mimi decoder in FP32, matching the encoder and native codec for every language-model precision. Closes #1750 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): keep RMSNorm epsilon in FP32 Create RMSNorm epsilon in FP32 so the 1e-8 value survives Half network construction. Closes #1779 Refs #1780 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): preserve Half embedding additions Sum audio embeddings before text and round each addition to Half for Half temporal engines. Closes #1778 Refs #1781 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): round the FP16 depth input like the reference Round depth projection weights, inputs, projection output and token embedding additions at the reference Half boundaries. Closes #1788 Refs #1789 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): preserve reference RoPE precision Construct RoPE angles and rotation in FP32, then restore the input dtype across the family decoder variants. Closes #1790 Refs #1791 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): round the SwiGLU gate product once Evaluate SiLU and its gate product in FP32, casting the combined result to the projection dtype once. Closes #1793 Refs #1794 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): build the FP16 profile with a Half core Remove component-promotion selectors from the primary FP16 manifest. Preserve the declared BF16 E2E reference and all existing thresholds. Refs #1786 Refs #1795 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): preserve residual input rounding Preserve rounded branch outputs before residual addition across the family decoder variants. Closes #1796 Refs #1797 Signed-off-by: chaofengw <chaofengw@nvidia.com> * fix(personaplex): store RMSNorm weights in the model dtype Round RMSNorm scale weights to the model dtype before the FP32 normalization computation. Closes #1799 Refs #1800 Signed-off-by: chaofengw <chaofengw@nvidia.com> --------- Signed-off-by: chaofengw <chaofengw@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
Fixes #1799. The pinned Moshi reference loads PersonaPlex with
dtype=torch.float16. EachRMSNorm.alpha, stored as BF16 in the checkpoint, is therefore held in Half._rms_normthen computes in FP32 with that Half value.The family
add_rms_norminstead embedded the checkpoint weight as an FP32 constant and never rounded it. Most BF16 weights are exact in Half, but small ones that land in the Half subnormal range are not. 5 of the 278,528 PersonaPlex RMSNorm weights differ this way, all in temporal layers 0, 1 and 3norm1.Exit Criteria
Implementation
graph_ops.add_rms_norm: whenneed_castis set, the FP32gammaconstant is cast to the input dtype and back to FP32 before the multiply. The rounding is expressed in the graph, so it follows the network's actual dtype (Half or BF16). The FP32 norm computation is unchanged.families/personaplex/tests/test_rmsnorm_weight_dtype.py(markersgpuandtrt; it skips without CUDA):x = [3, 1, 1, 1]andgamma = [-1.0207295417785645e-06, 1, 1, 1], the real BF16 checkpoint value oftransformer.layers.0.norm1.alpha[65];mean(x * x)is exactly 3 at every width, so neither the reduction order nor the operation grouping affects the result;_rms_normon CUDA:-1.7285346984863281e-06and0.5771484375(the old graph gives-1.7881393432617188e-06);Change categories
Validation
Commands and Results
main9a8b545 and of this head, each with the identical new test (sha256cda09fa8...). Command:python -m pytest -q -rA families/personaplex/tests/test_rmsnorm_weight_dtype.py.5.96e-08(one Half subnormal step).graph_ops.pyin the fixed tree equals this head (7fd7ea81...).python -m pytest -q -m "not gpu and not trt and not e2e" families/personaplex/tests: 13 passed, 4 skipped.norm1/norm2inputs captured at layers 0 and 31, steps 0, 27 and 28:_rms_normreproduces every captured output exactly.norm1(step 0) is removed only by rounding the weight to Half.ruff checkon both files andruff format --checkon the new test: clean.git diff --check: clean.Hardware, Environment, and Revisions
GB300 (SBSA), CUDA 13.0, TensorRT 11.2.0.113, PyTorch from the product container. Tested head
3f15493d00d61a21889e9c72bf275f57c20e5ddb. Reference data: checkpointnvidia/personaplex-7b-v1revisionfdaf4090a61cb315c138a1faee287ffd6c716309, run with the pinned PersonaPlex reference environment in FP16.Not Run / Remaining Gaps
add_rms_norm, but no separate BF16 or TP evidence was collected.personaplex-7baudio-parity profile, original 20 clips, true-FP16 temporal/depth core, against the unchanged Native FP16 outputs and gate. The tree ismainplus the current heads of fix(personaplex): align FP16 inference with Native #1751, fix(personaplex): keep RMSNorm epsilon in FP32 #1780, fix(personaplex): preserve Half embedding additions #1781, fix(personaplex): avoid timing discarded audio decode #1783, fix(personaplex): round the FP16 depth input like the reference #1789, fix(personaplex): preserve reference RoPE precision #1791, fix(personaplex): round the SwiGLU gate product once #1794, fix(personaplex): build the FP16 profile with a Half core #1795, fix(personaplex): preserve residual input rounding #1797, fix(personaplex): match Native HQ audio resampling #1798 and this PR, on one GB300 with one bundle build.Contributor Self-Review
I checked every caller of
add_rms_normin the family:graph_blocks.apply_normfrom the default and TP decoders, andutils.norm_multifrom the dual-profile decoder. They all pass the decoder's work dtype, so FP32 networks keepneed_castfalse and are unchanged. I also confirmed that the cast pair rounds subnormals as the reference does: the captured row and the frozen test both match exactly.Notes For Future Readers
x * (alpha * rsqrt(var))in FP32, while this graph computes(x * (1 / sqrt(var))) * alpha, also in FP32. This same-precision reordering accounts for most of the remaining 1-ULP norm differences on GB300. It is a numerical-alignment candidate, not a confirmed defect:POW(var, -0.5)with the reference grouping still differs from CUDArsqrtin 11 of 66,560 synthetic cases (2 of them new), and no full-model improvement has been shown. It is deliberately left out of this PR.add_rms_normand a new test.Risk level
Risk rationale: one weight-rounding step in FP16/BF16 RMSNorm. With this checkpoint, only 5 weights change, and only in the Half subnormal range. FP32 builds are unchanged. It rebuilds PersonaPlex bundles.