Paddle icon indicating copy to clipboard operation
Paddle copied to clipboard

`masked_fill_`對int64處理異常,塞入paddle.iinfo(paddle.int64).max會被當作min

Open anderson101866 opened this issue 9 months ago • 11 comments

bug描述 Describe the Bug

如下單純的script,帶入int64最大值時,會變成最小值

import paddle; print(paddle.__version__) #2.6.0

t = paddle.zeros((2,2), dtype=paddle.int64)
print(paddle.iinfo(paddle.int64).max == 2**63-1) #True
t.masked_fill_(paddle.to_tensor([[0,0],[0,1]]), 2**63-1) #<--------------
print(t) 
#Tensor(shape=[2, 2], dtype=int64, place=Place(gpu:1), stop_gradient=True,
#       [[ 0                  ,  0                  ],
#        [ 0                  , -9223372036854775808]])

其他补充信息 Additional Supplementary Information

No response

anderson101866 avatar May 16 '24 07:05 anderson101866

@AndSonder 这个问题能否辛苦看下呢?

OP来源:https://github.com/PaddlePaddle/Paddle/pull/57355

zyfncg avatar May 16 '24 09:05 zyfncg

@zyfncg 看起来是 full op 里面的 bug,如下代码会产生溢出

>>> paddle.full([], 2**63-1, paddle.int64)
Tensor(shape=[], dtype=int64, place=Place(gpu:0), stop_gradient=True,
       -9223372036854775808)

AndSonder avatar May 16 '24 13:05 AndSonder

@anderson101866 您可以通过如下代码实现想要的功能

import paddle; print(paddle.__version__) #2.6.0

t = paddle.zeros((2,2), dtype=paddle.int64)
print(paddle.iinfo(paddle.int64).max == 2**63-1) #True
val = paddle.to_tensor(2**63-1, paddle.int64)
t.masked_fill_(paddle.to_tensor([[0,0],[0,1]]), val) #<--------------
print(t) 
#Tensor(shape=[2, 2], dtype=int64, place=Place(gpu:0), stop_gradient=True,
#       [[0                  , 0                  ],
#        [0                  , 9223372036854775807]])

AndSonder avatar May 16 '24 13:05 AndSonder

@zyfncg 看起来是 full op 里面的 bug,如下代码会产生溢出

>>> paddle.full([], 2**63-1, paddle.int64)
Tensor(shape=[], dtype=int64, place=Place(gpu:0), stop_gradient=True,
       -9223372036854775808)

👍

这样的话paddle.full是否可以替换为to_tensor呢?

zyfncg avatar May 16 '24 13:05 zyfncg

@zyfncg 看起来是 full op 里面的 bug,如下代码会产生溢出

>>> paddle.full([], 2**63-1, paddle.int64)
Tensor(shape=[], dtype=int64, place=Place(gpu:0), stop_gradient=True,
       -9223372036854775808)

👍

这样的话paddle.full是否可以替换为to_tensor呢?

可以替换,但是是不是还是修复 full 的这个 bug 会好一些,要不还有可能有其他 api 有类似的没发现的越界问题

AndSonder avatar May 16 '24 13:05 AndSonder

類似的問題我也有碰到 也很像overflow的問題

import paddle; print(paddle.__version__) #2.6.0
x = paddle.to_tensor([[0, 0], 
                      [-2**63, 0]], dtype=paddle.int64)
print(x) 
x == 2**63-1 # __eq__
#Tensor(shape=[2, 2], dtype=bool, place=Place(gpu:0), stop_gradient=True,
#       [[False, False],
#        [True , False]])

一樣是max會被當成min

anderson101866 avatar May 16 '24 13:05 anderson101866

類似的問題我也有碰到 也很像overflow的問題

import paddle; print(paddle.__version__) #2.6.0
x = paddle.to_tensor([[0, 0], 
                      [-2**63, 0]], dtype=paddle.int64)
print(x) 
x == 2**63-1 # __eq__
#Tensor(shape=[2, 2], dtype=bool, place=Place(gpu:0), stop_gradient=True,
#       [[False, False],
#        [True , False]])

一樣是max會被當成min

这个应该是数值溢出导致的,也有可能是类似的原因导致的

AndSonder avatar May 16 '24 13:05 AndSonder

image

进一步分析了下,通过pybind将Python数据类型转到C++时2**63-1会被识别为float类型,而2**63-12**63的浮点表示是相同的,所以在C++层转回int64类型时解析为2**63就会出现精度溢出的问题。

这个问题看起来不是很好解决,对于临界值的处理经常会有风险,如果有绕过方式建议先避开这里的逻辑。

zyfncg avatar May 17 '24 03:05 zyfncg

image 进一步分析了下,通过pybind将Python数据类型转到C++时`2**63-1`会被识别为float类型,而`2**63-1`和`2**63`的浮点表示是相同的,所以在C++层转回int64类型时解析为`2**63`就会出现精度溢出的问题。

这个问题看起来不是很好解决,对于临界值的处理经常会有风险,如果有绕过方式建议先避开这里的逻辑。

这个 float 会不会是这里导致的?

image

AndSonder avatar May 17 '24 04:05 AndSonder

验证了下,确实是这里导致的

zyfncg avatar May 17 '24 04:05 zyfncg

还有一个问题就是在静态图模式下这里的value也只能用float类型表示,动态图的类型即使转为int64,在动转静后还是会遇到这里精度溢出的问题

zyfncg avatar May 17 '24 04:05 zyfncg

这个问题,早期的版本修复过,会使用str_value来传递值,以下是2.2分支中的实现: https://github.com/PaddlePaddle/Paddle/blob/0ee230a7d3177f791d2a5388ab4dffdccc03f4aa/paddle/fluid/operators/fill_constant_op.h#L39-L70

https://github.com/PaddlePaddle/Paddle/blob/0ee230a7d3177f791d2a5388ab4dffdccc03f4aa/python/paddle/fluid/layers/tensor.py#L716-L722

Xreki avatar May 30 '24 04:05 Xreki

與百度溝通後,Kai Wang表示現在這個工作沒有排期,NV目前沒有blocking。 先close

附帶,對int64的操作,可能也有其他API有這種精度溢出問題,

比如相等__eq__,同樣導致過大/過小的數字會被當成相同的數字

import paddle; print(paddle.__version__) #2.6.0
x = paddle.to_tensor([[0, 0], 
                      [-2**63, 0]], dtype=paddle.int64)
print(x) 
x == 2**63-1 # __eq__
#Tensor(shape=[2, 2], dtype=bool, place=Place(gpu:0), stop_gradient=True,
#       [[False, False],
#        [True , False]])

anderson101866 avatar Jul 04 '24 02:07 anderson101866