为什么 np.astype('uint8') 在 Windows 和 Mac 上给出不同的结果?

nic*_*ine 2 python numpy

我有一个(1000,1000,3)整形的 numpy 数组 ( dtype='float32'),当我将其转换为时,dtype='uint8'我在 Windows 和 Mac 上得到不同的结果。

数组可在此处获取:https://www.dropbox.com/s/jrs4n2ayh86s0fn/image.npy ?dl=0

在苹果电脑上

>>> import numpy as np
>>> X = np.load('image.npy')
>>> X = X.astype('uint8')
>>> X.sum()
167942490
Run Code Online (Sandbox Code Playgroud)

在 Windows 上

>>> import numpy as np
>>> X = np.load('image.npy')
>>> X = X.astype('uint8')
>>> X.sum()
323510676
Run Code Online (Sandbox Code Playgroud)

也用这个数组重现:

import numpy as np
X = np.array([
[[46410., 42585., 32640.],
 [45645., 41820., 31875.],
 [45390., 41310., 32130.]],

[[44880., 41055., 31110.],
 [44115., 40290., 30345.],
 [46410., 42330., 33150.]],

[[45390., 41310., 32130.],
 [46155., 42075., 32895.],
 [42840., 38760., 30090.]]], dtype=np.float32)

print(X.sum(), X.astype('uint8').sum())
Run Code Online (Sandbox Code Playgroud)

1065135.0 2735在 Windows 和1065135.0 1860Mac 上打印。

以下是不同操作系统、Python 和 Numpy 的结果:

Python 3.8.8  (Win) Numpy 1.22.4 => 1065135.0 2735 
Python 3.10.6 (Mac) Numpy 1.24.2 => 1065135.0 2735 
Python 3.7.12 (Mac) Numpy 1.21.6 => 1065135.0 1860 
Run Code Online (Sandbox Code Playgroud)

Jér*_*ard 5

此问题是由于错误的转换导致整数溢出。事实上,Numpy 使用 C 类型转换来转换值,但是将 0-255 范围之外的浮点数转换为 8 位无符号整数会导致C 中出现未定义的行为。在这种情况下,我们尝试在不影响性能的情况下报告错误,但是这并非在所有情况下都可行。最新版本的 Numpy 应该可以解决这个问题,但问题仍然部分未解决。请参阅1.24.0 发行说明此问题此问题,以及此 PR(据我所知,对此问题的第一个引用可以在此处找到)。

无论如何,虽然您的目标计算机上可能无法检测到错误,但将浮点数转换为 0-255 范围之外的数字是不安全的,您不应期望得到正确的结果。您需要调整您的代码,以便首先不会出现溢出。我还建议您至少使用 Numpy 1.24.0 版本,以便更好地跟踪此类错误。

相关文章:为什么 numpy 处理溢出不一致?