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

Fix numpy dtypes bug in cuda.to_gpu and cuda.copy #4380

Merged
merged 4 commits into from
Feb 22, 2018

Conversation

tkerola
Copy link
Contributor

@tkerola tkerola commented Feb 21, 2018

I found a bug in cuda.to_gpu and cuda.copy that would not change the device when the device identifier is a numpy dtype. Users might use numpy to generate the device ids, and would therefore be subject to this subtle bug.

MWE

Illustrating the problem for to_gpu, but the same thing happens for copy.

from chainer import cuda
import numpy as np

gpus = [0, 1, 2, 3]
batch_size = 2
eval_gpus = np.repeat(gpus, batch_size)

xs = []
for gpu in eval_gpus:
    y = np.ones(1)
    x = cuda.to_gpu(y, device=gpu)
    xs.append(x)

for x in xs:
    print(x.device)

Output

Without this PR:

<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 0>

With this PR (expected):

<CUDA Device 0>
<CUDA Device 0>
<CUDA Device 1>
<CUDA Device 1>
<CUDA Device 2>
<CUDA Device 2>
<CUDA Device 3>
<CUDA Device 3>

else:
_integer_types = six.integer_types
_integer_types = six.integer_types + (numpy.integer,)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about factoring out common part?:

_integer_types = six.integer_types + (numpy.integer,)
if six.PY2:
     _integer_types +=  (_newint,)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea, thanks.

@@ -219,7 +219,7 @@ def get_device(*args):

def _get_device(*args):
for arg in args:
if type(arg) in _integer_types:
if isinstance(arg, _integer_types):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this way bool is evaluated as True.
How about excluding bool explicitly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, done.

@niboshi niboshi added cat:bug Bug report or fix. cat:enhancement Implementation that does not break interfaces. and removed cat:bug Bug report or fix. labels Feb 21, 2018
@niboshi niboshi self-assigned this Feb 21, 2018
@niboshi niboshi added the to-be-backported Pull request that should be backported. label Feb 21, 2018
@@ -219,7 +218,8 @@ def get_device(*args):

def _get_device(*args):
for arg in args:
if type(arg) in _integer_types:
if isinstance(arg, _integer_types) and not numpy.issubdtype(
type(arg), numpy.bool_):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I meant bool, not numpy.bool_.
(isinstance(numpy.bool_, numpy.integer) and isinstance(numpy.bool_, six.integer_types)) are both False, but isinstance(bool, six.integer_types) is True).

So the correct condition would be:
if type(arg) is not bool and isinstance(arg, _integer_types):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't my condition also correct? It works for both numpy.bool, numpy.bool_ and bool.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. So the outcome would be the same, but it does duplicate check and slower (numpy.bool_ never satisfies the first condition). Also note that numpy.bool and bool are identical.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, bool and np.bool are identical. Then your solution is cleaner. Thanks! I will update it.

@niboshi niboshi added the st:test-and-merge State indicating that pull request is approved by a reviewer and can be merged after CI passes. label Feb 21, 2018
@niboshi
Copy link
Member

niboshi commented Feb 22, 2018

Thank you for the fix.
jenkins, test this please

@niboshi
Copy link
Member

niboshi commented Feb 22, 2018

LGTM!

@niboshi niboshi merged commit a4f321a into chainer:master Feb 22, 2018
niboshi added a commit to niboshi/chainer that referenced this pull request Feb 22, 2018
Fix numpy dtypes bug in cuda.to_gpu and cuda.copy
@niboshi niboshi added this to the v4.0.0rc1 milestone Feb 22, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cat:enhancement Implementation that does not break interfaces. st:test-and-merge State indicating that pull request is approved by a reviewer and can be merged after CI passes. to-be-backported Pull request that should be backported.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants