Skip to content
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

strange astype casting behavior on MacOS x86_64 #249

Open
1 task done
grlee77 opened this issue Dec 6, 2021 · 7 comments
Open
1 task done

strange astype casting behavior on MacOS x86_64 #249

grlee77 opened this issue Dec 6, 2021 · 7 comments

Comments

@grlee77
Copy link
Member

grlee77 commented Dec 6, 2021

We saw some strange test failures on x86_64 MacOS builds in conda-forge/scikit-image-feedstock#85. There is apparently a NumPy issue completely unrelated to scikit-image that is causing these failures.

Consider the following example with an out-of-range float32 value being cast to uint8. On my linux system an array of float32 with value 485. becomes an array of 229's when converted to uint8 (485 % 256 = 229).

However, with the conda-forge NumPy on MacOS I see different behavior depending on the data length (making me suspect this is a SIMD-related issue):

np.full((5,), 485., dtype=np.float32).astype(np.uint8)

gives the expected: array([229, 229, 229, 229, 229], dtype=uint8)

but for a longer array:

np.full((8,), 485., dtype=np.float32).astype(np.uint8)

gives unexpected: array([255, 255, 255, 255, 255, 255, 255, 255], dtype=uint8)

and an odd-sized array

np.full((9,), 485., dtype=np.float32).astype(np.uint8)

gives unexpected: array([255, 255, 255, 255, 255, 255, 255, 229], dtype=uint8)
Note here that the first 8 values are unexpected, but the last value is what would be expected (probably computed in a separate final loop without SIMD).

These size differences are what make me suspect this is a SIMD-related bug. However, using a pip installed NumPy does not show the same issue.

This was observed for numpy 1.21.4 py39h7eed0ac_0 conda-forge


Environment (conda list):
$ conda list

Name Version Build Channel

ca-certificates 2021.10.8 h033912b_0 conda-forge
libblas 3.9.0 12_osx64_openblas conda-forge
libcblas 3.9.0 12_osx64_openblas conda-forge
libffi 3.4.2 h0d85af4_5 conda-forge
libgfortran 5.0.0 9_3_0_h6c81a4c_23 conda-forge
libgfortran5 9.3.0 h6c81a4c_23 conda-forge
liblapack 3.9.0 12_osx64_openblas conda-forge
libopenblas 0.3.18 openmp_h3351f45_0 conda-forge
libzlib 1.2.11 h9173be1_1013 conda-forge
llvm-openmp 12.0.1 hda6cdc1_1 conda-forge
ncurses 6.2 h2e338ed_4 conda-forge
numpy 1.21.4 py39h7eed0ac_0 conda-forge
openssl 3.0.0 h0d85af4_2 conda-forge
pip 21.3.1 pyhd8ed1ab_0 conda-forge
python 3.9.7 h38b4d05_3_cpython conda-forge
python_abi 3.9 2_cp39 conda-forge
readline 8.1 h05e3726_0 conda-forge
setuptools 59.4.0 py39h6e9494a_0 conda-forge
sqlite 3.37.0 h23a322b_0 conda-forge
tk 8.6.11 h5dbffcc_1 conda-forge
tzdata 2021e he74cb21_0 conda-forge
wheel 0.37.0 pyhd8ed1ab_1 conda-forge
xz 5.2.5 haf1e3a3_1 conda-forge
zlib 1.2.11 h9173be1_1013 conda-forge


Details about conda and system ( conda info ):
$ conda info

     active environment : py39pip
    active env location : /Users/glee/mambaforge/envs/py39pip
            shell level : 2
       user config file : /Users/glee/.condarc
 populated config files : /Users/glee/mambaforge/.condarc
          conda version : 4.10.3
    conda-build version : 3.21.7
         python version : 3.9.7.final.0
       virtual packages : __osx=12.0.1=0
                          __unix=0=0
                          __archspec=1=x86_64
       base environment : /Users/glee/mambaforge  (writable)
      conda av data dir : /Users/glee/mambaforge/etc/conda
  conda av metadata url : None
           channel URLs : https://conda.anaconda.org/conda-forge/osx-64
                          https://conda.anaconda.org/conda-forge/noarch
          package cache : /Users/glee/mambaforge/pkgs
                          /Users/glee/.conda/pkgs
       envs directories : /Users/glee/mambaforge/envs
                          /Users/glee/.conda/envs
               platform : osx-64
             user-agent : conda/4.10.3 requests/2.26.0 CPython/3.9.7 Darwin/21.1.0 OSX/12.0.1
                UID:GID : 502:20
             netrc file : None
           offline mode : False

@grlee77 grlee77 changed the title strange astype casting behavior on MacOS arm64 strange astype casting behavior on MacOS x86_64 Dec 6, 2021
@isuruf
Copy link
Member

isuruf commented Dec 6, 2021

Can you open this issue in numpy upstream? This error sounds familiar, but I can't find it. Maybe another numpy developer will recall.

@grlee77
Copy link
Member Author

grlee77 commented Dec 6, 2021

Searched around a bit and perhaps it is this one?: numpy/numpy#19881 (comment) (or older issues linked in the first comment there). From that issue it sounds like it may be expected that this is undefined behavior and can't be relied on to be consistent across architectures. In that case, we should fix the few test cases in scikit-image that currently assuming a particular behavior.

@isuruf
Copy link
Member

isuruf commented Dec 6, 2021

Nope. Some issue where the array size changed the behaviour.

@grlee77
Copy link
Member Author

grlee77 commented Dec 6, 2021

Okay. Heading to bed now, but will look into it tomorrow.

@grlee77
Copy link
Member Author

grlee77 commented Dec 6, 2021

Here is another comment mentioning that undefined casting can give different results even on the same architecture due to different code paths (e.g. SIMD vs. non-SIMD): numpy/numpy#14412 (comment)

ping @seberg: should I open an issue for the example above on the NumPy repo or is there already an existing issue that covers this? I am not so surprised by the odd behavior given that this out of range float->uint8 conversion is undefined in C, but am not sure why PyPI wheels do not also show the issue (possible difference in compilers/flags?)

(we can already avoid reliance on undefined casting behavior in the scikit-image test suite, so there is no urgency on our end to address this)

@seberg
Copy link

seberg commented Dec 6, 2021

I guess linking over to there is about as much you can do (it adds to the visibility at least a bit). Unless you are interested in fixing it (either by looking into defining the cast or by floating errors), in which case I am happy to tell you where to look :).

@isuruf
Copy link
Member

isuruf commented Dec 7, 2021

but am not sure why PyPI wheels do not also show the issue (possible difference in compilers/flags?)

Since it is undefined behaviour, the compiler is free to do whatever and we use different compilers for conda vs pip wheels.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants