-
Notifications
You must be signed in to change notification settings - Fork 5.9k
[0-size Tensor No.318] Add 0-size Tensor support for paddle.Tensor.matmul API. #72780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
一个更鲁棒、支持广播规则、保留空维度(如 batch_size=0)的 MatmulKernel 实现版本 ,适用于多维张量的矩阵乘法(batched matmul)
matmul的0 size tensor输入的单测
|
你的PR提交成功,感谢你对开源项目的贡献! |
|
@wanghuancoder,想请问方便的时候能否帮忙审核下这个 PR?非常感谢你的review! |
|
@DanielSun11 请看下 |
|
@crashbussy 你可以看下CI日志,目前编译都没有过 |
|
@luotao1 总是跟不上develop分支的版本,develop不断的更新导致编译不通过。晚上人少的时候我同步完再试试。 |
|
@luotao1 求助,不知道为什么编译没有通过,编译报错是一些我没有动过的文件,不清楚报错与我的修改有何关联。 |
| } | ||
|
|
||
| template <typename T, typename Context> | ||
| void MatmulWithFlattenKernelImpl(const Context& dev_ctx, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MatmulWithFlattenKernelImpl 函数删了?在2216行有用到
|
在Tensor规范化第二期的活动中有关于0-size Tensor的测试,我正好看了关于matmul的问题,#70238 这个PR中修复的有一些问题 |
|
再次修改了一次,还是发现编译通不过。感谢@fangfangssj的细致讲解,这个修改难度确实大一些,目前还没有信心能找到对应解决办法,这个pr我就关闭了。我去完成一些添加单测的任务。 |




PR Category
Execute Infrastructure
PR Types
New features
Description
paddle.Tensor.matmul支持0-Size。
修改历程介绍如下:
在PaddleAPITest report/0size_tensor中检索paddle.Tensor.matmul的错误日志,发现[accuracy error]报错。分析可能是前向过程出错。!!!注意到(shapes (0, 100, 1, 40), (0, 100, 40) mismatch),也是就shape不匹配的问题
`2025-03-05 15:27:11.945992 test begin: paddle.Tensor.matmul(Tensor([0, 100, 1],"float64"), Tensor([0, 1, 40],"float64"), )
[accuracy error] paddle.Tensor.matmul(Tensor([0, 100, 1],"float64"), Tensor([0, 1, 40],"float64"), )
Not equal to tolerance rtol=0.01, atol=0.01
(shapes (0, 100, 1, 40), (0, 100, 40) mismatch)
x: array([], shape=(0, 100, 1, 40), dtype=float64)
y: array([], shape=(0, 100, 40), dtype=float64)
前向修复: a. 在Paddle代码中检索def matmul,发现matmul的核心实现调用的是_C_ops的matmul b. 以_C_ops的matmul在paddle/phi/ops/yaml中检索,发现matmul的InferMeta函数使用到一个: MatmulInferMeta- op: matmulargs : (Tensor x, Tensor y)
output : Tensor(out)
infer_meta :
func : MatmulInferMeta
param: [x, y, false, false]`
c. 在代码中检索MatmulInferMeta,并检查其dims(shape)的推导是否正确(在matmul中推导是正确因此不用修改)
d. 在paddle/phi/kernels中检索matmul,找全所有matmul的实现Kernel。发现共有五个涉及matmul的文件,分别为:
其中cc和cu文件均将前两个.h文件设为头文件,因此只用修改.h文件即可。而matmul_kernel.h和matmul_kernel_impl.h中不需要(不能)重复定义,故只修改了matmul_kernel_impl.h
注意,下面的文件仅以 paddle/phi/kernels/matmul_kernel.h为头文件,并不含有matmulkernel字段,所以不予以考虑
在paddle/phi/kernels/impl/matmul_kernel_impl.h中删除了原来的代码(因为有错误),加入以下代码,完成修复
` if (x.numel() == 0 || y.numel() == 0) {
auto x_dims = x.dims();
auto y_dims = y.dims();
}`
添加单测:
在test/legacy_test/test_matmul_op.py中添加0 size tensor输入的单测:
`import paddle
import numpy as np
所有测试用例
test_cases = [
# 格式: (x_shape, y_shape, expected_out_shape, dtype)
((0, 100, 1), (0, 1, 40), (0, 100, 40), "float64"),
((0, 100, 1), (0, 1, 4), (0, 100, 4), "float64"),
((0, 100, 1), (1, 1, 40), (0, 100, 40), "float64"),
((0, 100, 1), (1, 1, 4), (0, 100, 4), "float64"),
((0, 12, 197, 197), (0, 12, 197, 64), (0, 12, 197, 64), "float16"),
((0, 12, 197, 197), (0, 12, 197, 64), (0, 12, 197, 64), "float32"),
((1, 0, 1), (1, 1, 40), (1, 0, 40), "float64"),
((1, 0, 1), (1, 1, 4), (1, 0, 4), "float64"),
((1, 100, 1), (0, 1, 40), (0, 100, 40), "float64"),
((1, 100, 1), (0, 1, 4), (0, 100, 4), "float64"),
((1, 100, 1), (1, 1, 0), (1, 100, 0), "float64"),
((112, 0, 197, 197), (112, 0, 197, 64), (112, 0, 197, 64), "float16"),
((112, 0, 197, 197), (112, 0, 197, 64), (112, 0, 197, 64), "float32"),
((112, 12, 0, 197), (112, 12, 197, 64), (112, 12, 0, 64), "float16"),
((112, 12, 0, 197), (112, 12, 197, 64), (112, 12, 0, 64), "float32"),
((112, 12, 197, 197), (112, 12, 197, 0), (112, 12, 197, 0), "float16"),
((112, 12, 197, 197), (112, 12, 197, 0), (112, 12, 197, 0), "float32"),
]
def run_all_matmul_tests():
for idx, (x_shape, y_shape, expected_shape, dtype) in enumerate(test_cases):
print(f"\nTest {idx+1} begin: paddle.Tensor.matmul(Tensor({x_shape}), Tensor({y_shape}), dtype={dtype})")
try:
x = paddle.zeros(x_shape, dtype=dtype)
y = paddle.zeros(y_shape, dtype=dtype)
result = x.matmul(y)
if name == "main":
run_all_matmul_tests()`
备注:原来的代码存在错误,
std::vector<std::int64_t> out_dims(x_dims.size() - 1 + y_dims.size() - 1);对于二维 matmul 是对的,但对于多维(batched)matmul 来说,这会导致错误。
正确做法应是:batch 维度取广播后的结果;最后两维做矩阵乘法;所以输出 rank 应与广播后的 batch rank 相同 + 2(最后两个维度)
重写后支持任意 rank 的输入张量(>=2)
下面提供一个最简单的示例测试
`import paddle
测试数据
x = paddle.randn([0, 100, 1]) # shape: [0, 100, 1]
y = paddle.randn([1, 1, 4]) # shape: [1, 1, 4]
result = x.matmul(y)
print(result.shape) # 输出: [0, 100, 4], 而不是原来的[0, 100, 1, 4]`