Files
paddlepaddle--paddle/test/xpu/test_rms_norm_xpu.py
T
2026-07-13 12:40:42 +08:00

160 lines
4.7 KiB
Python

# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import numpy as np
import paddle
from paddle.nn.functional import rms_norm
class TestFusedRMSNorm(unittest.TestCase):
def setUp(self):
paddle.seed(2023)
np.random.seed(2023)
def rms_norm_reference(self, x, scale, bias=None, epsilon=1e-5):
variance = paddle.mean(paddle.square(x), axis=-1, keepdim=True)
rms = paddle.sqrt(variance + epsilon)
y = x / rms
y = y * scale.reshape([1, -1])
if bias is not None:
y = y + bias.reshape([1, -1])
return y
def test_2d_input(self):
rows, cols = 32, 64
x = paddle.randn([rows, cols])
scale = paddle.randn([cols])
y_fused = rms_norm(x, (cols,), scale)
y_ref = self.rms_norm_reference(x, scale)
np.testing.assert_allclose(y_fused, y_ref, rtol=1e-5, atol=1e-5)
def test_3d_input(self):
batch, rows, cols = 16, 32, 64
x = paddle.randn([batch, rows, cols])
scale = paddle.randn([cols])
y_fused = rms_norm(x, (cols,), scale)
y_ref = self.rms_norm_reference(x, scale)
np.testing.assert_allclose(
y_fused.astype("float32"),
y_ref.astype("float32"),
rtol=1e-5,
atol=1e-5,
)
def test_without_bias(self):
rows, cols = 32, 64
x = paddle.randn([rows, cols])
scale = paddle.randn([cols])
y_fused = rms_norm(x, (cols,), scale)
y_ref = self.rms_norm_reference(x, scale)
np.testing.assert_allclose(y_fused, y_ref, rtol=1e-5, atol=1e-5)
def test_3d_backward(self):
batch, rows, cols = 8, 16, 32
x = paddle.randn([batch, rows, cols], dtype='float32')
x.stop_gradient = False
scale = paddle.randn([cols], dtype='float32')
scale.stop_gradient = False
y_fused = rms_norm(x, (cols,), scale)
loss = paddle.mean(y_fused)
loss.backward()
x_grad_fused = x.grad.clone()
scale_grad_fused = scale.grad.clone()
x.clear_gradient()
scale.clear_gradient()
y_ref = self.rms_norm_reference(x, scale)
loss_ref = paddle.mean(y_ref)
loss_ref.backward()
x_grad_ref = x.grad
scale_grad_ref = scale.grad
np.testing.assert_allclose(
x_grad_fused, x_grad_ref, rtol=1e-4, atol=1e-4
)
np.testing.assert_allclose(
scale_grad_fused, scale_grad_ref, rtol=1e-4, atol=1e-4
)
def test_backward(self):
rows, cols = 16, 32
test_type = ['float16', 'bfloat16', 'float32']
for x_type in test_type:
# for scale_type in test_type:
# FIXME(yangjianbang): XPU fused_rms_norm does not support x_type != scale_type
scale_type = x_type
x = paddle.randn([rows, cols], dtype=x_type)
x.stop_gradient = False
scale = paddle.randn([cols], dtype=scale_type)
scale.stop_gradient = False
y_fused = rms_norm(x, (cols,), scale)
loss = paddle.mean(y_fused)
loss.backward()
x_grad_fused = x.grad.clone()
scale_grad_fused = scale.grad.clone()
x.clear_gradient()
scale.clear_gradient()
if x_type == 'bfloat16':
# FIXME(yangjianbang): XPU sqrt_grad does not support bfloat16
x_fp32 = x.cast("float32")
scale_fp32 = scale.cast("float32")
y_ref = self.rms_norm_reference(x_fp32, scale_fp32)
else:
y_ref = self.rms_norm_reference(x, scale)
loss_ref = paddle.mean(y_ref)
loss_ref.backward()
x_grad_ref = x.grad
scale_grad_ref = scale.grad
np.testing.assert_allclose(
x_grad_fused.astype("float32"),
x_grad_ref.astype("float32"),
rtol=1e-4,
atol=1e-4,
)
np.testing.assert_allclose(
scale_grad_fused.astype("float32"),
scale_grad_ref.astype("float32"),
rtol=1e-4,
atol=1e-4,
)
if __name__ == '__main__':
unittest.main()