op_plugin/utils/KernelNpuOutputSize.cpp 中的 clamp_npu_output_size 函数在 self.numel() == 0 时直接返回 self.sizes(),跳过了与 min/max 的 broadcast 计算。
op_plugin/utils/KernelNpuOutputSize.cpp
clamp_npu_output_size
self.numel() == 0
self.sizes()
该函数通过 op_plugin_functions.yaml 中 size: clamp_npu_output_size(self, min, max) 配置被 gen_opapi 自动生成的 clamp.Tensor / clamp.Tensor_out 调用,bug 会真实触发。
op_plugin_functions.yaml
size: clamp_npu_output_size(self, min, max)
clamp.Tensor
clamp.Tensor_out
调用 torch.clamp(input, min, max)(Tensor 版本),当 input 为空张量且 min/max 的维度需要 broadcast 扩展时:
torch.clamp(input, min, max)
import torch # self.ndim=1, min.ndim=2 → broadcast 应扩展为 2D input = torch.tensor([], dtype=torch.float32).reshape(1, 0) # shape (1, 0) min_val = torch.tensor([[0.0]] * 3) # shape (3, 1) # 期望输出 shape: (3, 0) # 实际输出 shape: (1, 0) ← 错误 result = torch.clamp(input, min=min_val)
短路分支 if (self.numel() == 0) 只复制 self.dim() 个维度,不做 left-pad 和逐维 broadcast 比较。导致:
if (self.numel() == 0)
self.dim()
self=(0,)
min=(3,1)
(3, 0)
(0,)
min=(3,)
broadcast_ops_npu_output_size 内部使用 at::infer_size,已正确处理 0 维、left-pad 和合法性校验,短路分支完全多余。
broadcast_ops_npu_output_size
at::infer_size
删除空张量短路分支,统一走 broadcast_ops_npu_output_size,与 PyTorch 上游 torch.clamp.Tensor 的 broadcast 语义一致。
torch.clamp.Tensor
修复后行为:
(3, 1)
(1, 0)
(3,)
()
关联 PR: https://gitcode.com/Ascend/op-plugin/merge_requests/5687
/assign @wangqi_ai
一、问题描述
op_plugin/utils/KernelNpuOutputSize.cpp中的clamp_npu_output_size函数在self.numel() == 0时直接返回self.sizes(),跳过了与 min/max 的 broadcast 计算。该函数通过
op_plugin_functions.yaml中size: clamp_npu_output_size(self, min, max)配置被 gen_opapi 自动生成的clamp.Tensor/clamp.Tensor_out调用,bug 会真实触发。二、重现步骤
调用
torch.clamp(input, min, max)(Tensor 版本),当 input 为空张量且 min/max 的维度需要 broadcast 扩展时:import torch # self.ndim=1, min.ndim=2 → broadcast 应扩展为 2D input = torch.tensor([], dtype=torch.float32).reshape(1, 0) # shape (1, 0) min_val = torch.tensor([[0.0]] * 3) # shape (3, 1) # 期望输出 shape: (3, 0) # 实际输出 shape: (1, 0) ← 错误 result = torch.clamp(input, min=min_val)三、根因分析
短路分支
if (self.numel() == 0)只复制self.dim()个维度,不做 left-pad 和逐维 broadcast 比较。导致:self=(0,),min=(3,1)→ 正确(3, 0),短路返回(0,)self=(0,),min=(3,))被静默接受broadcast_ops_npu_output_size内部使用at::infer_size,已正确处理 0 维、left-pad 和合法性校验,短路分支完全多余。四、预期结果
删除空张量短路分支,统一走
broadcast_ops_npu_output_size,与 PyTorch 上游torch.clamp.Tensor的 broadcast 语义一致。修复后行为:
(0,)(3, 1)(0,)❌(3, 0)✅(1, 0)(3, 1)(1, 0)❌(3, 0)✅(0,)(3,)(0,)❌(吞错)(0,)()标量(0,)✅(0,)✅关联 PR: https://gitcode.com/Ascend/op-plugin/merge_requests/5687