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

192 lines
6.6 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 import base
def reference_matmul(X, Y, transpose_X=False, transpose_Y=False):
"""Reference forward implementation using np.matmul."""
# np.matmul does not support the transpose flags, so we manually
# transpose X and Y appropriately.
if transpose_X:
if X.ndim == 1:
X = X.reshape((X.size,))
elif X.ndim == 2:
X = X.T
else:
dim = list(range(len(X.shape)))
dim[-1], dim[len(X.shape) - 2] = dim[len(X.shape) - 2], dim[-1]
X = np.transpose(X, tuple(dim))
if transpose_Y:
if Y.ndim == 1:
Y = Y.reshape((Y.size,))
else:
dim = list(range(len(Y.shape)))
dim[-1], dim[len(Y.shape) - 2] = dim[len(Y.shape) - 2], dim[-1]
Y = np.transpose(Y, tuple(dim))
Out = np.matmul(X, Y)
return Out
class TestMatmulOutAndParamDecorator(unittest.TestCase):
def setUp(self):
paddle.disable_static()
self.x_shape = [3, 4]
self.y_shape = [4, 3]
self.x_np = np.random.rand(*self.x_shape).astype(np.float32)
self.y_np = np.random.rand(*self.y_shape).astype(np.float32)
self.apis = [paddle.matmul, paddle.linalg.matmul]
self.test_types = [
# "decorator1",
# "decorator2",
"out",
# "out_decorator",
]
def do_test(self, api, test_type):
x = paddle.to_tensor(self.x_np, stop_gradient=False)
y = paddle.to_tensor(self.y_np, stop_gradient=False)
out = paddle.empty((3, 3), dtype='float32')
out.stop_gradient = False
if test_type == 'raw':
result = api(x, y)
result.mean().backward()
return result, x.grad, y.grad
elif test_type == 'decorator1':
result = api(x, y)
result.mean().backward()
return result, x.grad, y.grad
elif test_type == 'decorator2':
result = api(input=x, other=y)
result.mean().backward()
return result, x.grad, y.grad
elif test_type == 'out':
api(x, y, out=out)
out.mean().backward()
return out, x.grad, y.grad
elif test_type == 'out_decorator':
api(input=x, other=y, out=out)
out.mean().backward()
return out, x.grad, y.grad
else:
raise ValueError(f"Unknown test type: {test_type}")
def test_matmul_out(self):
out_std, grad_std, y_grad_std = self.do_test(paddle.matmul, 'raw')
for test_type in self.test_types:
out, grad, y_grad = self.do_test(paddle.matmul, test_type)
np.testing.assert_allclose(out.numpy(), out_std.numpy(), rtol=1e-20)
np.testing.assert_allclose(
grad.numpy(), grad_std.numpy(), rtol=1e-20
)
np.testing.assert_allclose(
y_grad.numpy(), y_grad_std.numpy(), rtol=1e-20
)
class TestMatMulAPI_Compatibility(unittest.TestCase):
def setUp(self):
np.random.seed(123)
paddle.enable_static()
self.x_shape = [5, 6]
self.y_shape = [6, 4]
self.dtype = 'float32'
self.init_data()
def init_data(self):
self.np_x_input = np.random.randint(0, 8, self.x_shape).astype(
self.dtype
)
self.np_y_input = np.random.randint(3, 9, self.y_shape).astype(
self.dtype
)
def test_dygraph_Compatibility(self):
paddle.disable_static()
x = paddle.to_tensor(self.np_x_input)
y = paddle.to_tensor(self.np_y_input)
paddle_dygraph_out = []
# Position args (args)
out1 = paddle.matmul(x, y)
paddle_dygraph_out.append(out1)
# Keywords args (kwargs) for paddle
out2 = paddle.matmul(x=x, y=y)
paddle_dygraph_out.append(out2)
# Keywords args for torch
out3 = paddle.matmul(input=x, other=y)
paddle_dygraph_out.append(out3)
# Combined args and kwargs
out4 = paddle.matmul(x, other=y)
paddle_dygraph_out.append(out4)
# Tensor method args
out5 = x.matmul(y)
paddle_dygraph_out.append(out5)
# Tensor method kwargs
out6 = x.matmul(other=y)
paddle_dygraph_out.append(out6)
# Test out
out7 = paddle.empty([])
paddle.matmul(x, other=y, out=out7)
paddle_dygraph_out.append(out7)
# Numpy reference out
ref_out = reference_matmul(self.np_x_input, self.np_y_input)
# Check
for out in paddle_dygraph_out:
np.testing.assert_allclose(ref_out, out.numpy())
paddle.enable_static()
def test_static_Compatibility(self):
main = paddle.static.Program()
startup = paddle.static.Program()
with base.program_guard(main, startup):
x = paddle.static.data(
name="x", shape=self.x_shape, dtype=self.dtype
)
y = paddle.static.data(
name="y", shape=self.y_shape, dtype=self.dtype
)
# Position args (args)
out1 = paddle.matmul(x, y)
# Keywords args (kwargs) for paddle
out2 = paddle.matmul(x=x, y=y)
# Keywords args for torch
out3 = paddle.matmul(input=x, other=y)
# Combined args and kwargs
out4 = paddle.matmul(x, other=y)
# Tensor method args
out5 = x.matmul(y)
# Tensor method kwargs
out6 = x.matmul(other=y)
exe = base.Executor(paddle.CPUPlace())
fetches = exe.run(
main,
feed={"x": self.np_x_input, "y": self.np_y_input},
fetch_list=[out1, out2, out3, out4, out5, out6],
)
ref_out = reference_matmul(self.np_x_input, self.np_y_input)
for out in fetches:
np.testing.assert_allclose(out, ref_out)
if __name__ == "__main__":
unittest.main()