Refactor RMSNorm implementations to use torch.nn.functional.rms_norm#42461
Refactor RMSNorm implementations to use torch.nn.functional.rms_norm#42461mstojkovicTT wants to merge 2 commits into
Conversation
|
Hey @mstojkovicTT, thanks for the PR! We definitely want the functions to be a drop-in replacement, so they should return exactly the same dtype as the old functions did. Also, in your tests you're initializing |
This may be problematic, because of the following scenario:
return self.weight * hidden_states.to(input_dtype)
Here is the pytorch default implementation of
I did the same testing just with the additional with torch.no_grad():
random_weight = torch.randn(hidden_size, device=device) * 0.05 + 1.0
hf_module.weight.copy_(random_weight)
new_module.weight.copy_(random_weight)and everything still works. And also @Rocketknight1, thank you for taking a time to review this! |
|
Yeah, I understand! My guess is that the original code was made to follow the original model implementation, even if it seems weird. Downcasting |
|
Ah, that makes sense. What do you think about trying CI run against the changes for now, and if it breaks something I will take a closer look? @Rocketknight1 |
|
Sure, let's see how it goes |
|
run-slow: llama |
|
This comment contains models: ["models/llama"] |
CI ResultsModel CI Report❌ Failed tests
|
|
Hmn, it does seem like this might shift logits slightly |
dd4bfbd to
5f8619a
Compare
|
Thanks for running this @Rocketknight1! For With my change (new behavior)I see a small drift in the expected mean/slice:
And for the slice (
[[ 6.2500e-02, 3.1250e-02, -7.8188e-03, 3.1250e-02, 5.0068e-05,
0.0000e+00, 0.0000e+00, 0.0000e+00, -5.0068e-05, 3.1300e-02,
-5.0068e-05, -5.0068e-05, -1.5638e-02, -2.3438e-02, 0.0000e+00]]
[-12.5625, -7.1250, -0.6289, -7.8750, -6.9688, -7.8125, -6.5000,
-7.4375, -7.6562, -6.9688, -6.0312, -7.0312, -1.8203, 1.8750,
-8.5000]
[-12.5000, -7.0938, -0.6367, -7.8438, -6.9688, -7.8125, -6.5000,
-7.4375, -7.6562, -6.9375, -6.0312, -7.0312, -1.8359, 1.8516,
-8.5000]Baseline / original implementation (before my change)For comparison, with the original implementation I see different drift:
And for the slice (
[-6.2500e-02, 6.2500e-02, 7.8119e-02, -9.3750e-02, -1.2495e-01,
-6.2500e-02, 3.1250e-02, -1.2500e-01, -3.1300e-02, 5.0068e-05,
-6.2550e-02, -3.1300e-02, -1.5638e-02, 2.3438e-02, 0.0000e+00]
[-12.5625, -7.1250, -0.6289, -7.8750, -6.9688, -7.8125, -6.5000,
-7.4375, -7.6562, -6.9688, -6.0312, -7.0312, -1.8203, 1.8750,
-8.5000]
[-12.6250, -7.0625, -0.5508, -7.9688, -7.0938, -7.8750, -6.4688,
-7.5625, -7.6875, -6.9688, -6.0938, -7.0625, -1.8359, 1.8984,
-8.5000]So from my side it looks like the change does alter numerics, but it’s not obvious that it strictly makes things “worse”, it seems to move the error pattern relative to the golden expectations. I dont know if you have some kind of way to check the actual performance of the model? |
5f8619a to
995f7d8
Compare
|
[For maintainers] Suggested jobs to run (before merge) run-slow: aimv2, apertus, arcee, aria, bamba, bitnet, blt, chameleon, clvp, csm, cwm, deepseek_v2, deepseek_v3, dia, diffllama, doge |
|
Hi @mstojkovicTT, just realized we might actually need to pause this PR! The reason is that I don't think Torch 2.3 (our current minimum supported version) has |
|
That makes sense. Thanks for the responses, putting this on a pause till then :) |
|
Yeah, and thanks for investigating! My suspicion is the numerics are similar enough that we might be able to just switch everything to using |
What does this PR do?
Fixes #42398
This PR replaces custom
RMSNorm/T5-stylenorm implementations (e.g. in Llama) that manually compute variance and scaling with the built-intorch.nn.functional.rms_norm. For example, code like:is simplified to:
This keeps the behavior and epsilon handling the same while reducing the number of ops, this should improve performance for users without requiring any additional changes on their side.
To verify the performance and the numerical stability, i have wrote the following test
The results show the following:
note: I have encountered that when I try
dtypesthat are lower thenfloat32, old implementation will keep it atfloat32, but my new one will have thedtypeof the input tensor. Thats why i have to cast toy_hf.dtype(tryingfloat64for example will make both implementation outputfloat64). This can be changed, depending on what we want to accomplish.Who can review?
@Rocketknight1