From 667fa17ca24608d9c8759b8f8eb1638ccb2e6c58 Mon Sep 17 00:00:00 2001 From: hvy Date: Tue, 27 Aug 2019 09:37:30 +0000 Subject: [PATCH 1/2] Fix backend.copyto for mismatched dtypes to CuPy ndarray --- chainer/backend.py | 3 ++- tests/chainer_tests/test_backend.py | 20 ++++++++++++++++---- tests/chainer_tests/test_variable.py | 19 +++++++++++++++---- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/chainer/backend.py b/chainer/backend.py index 0de927d4f4b0..c3ffb37ddae5 100644 --- a/chainer/backend.py +++ b/chainer/backend.py @@ -65,7 +65,8 @@ def copyto(dst, src): elif isinstance(dst, cuda.ndarray): if isinstance(src, chainer.get_cpu_array_types()): src = numpy.asarray(src) - if dst.flags.c_contiguous or dst.flags.f_contiguous: + if (src.dtype == dst.dtype + and (dst.flags.c_contiguous or dst.flags.f_contiguous)): dst.set(src) else: cuda.cupy.copyto(dst, cuda.to_gpu(src, device=dst.device)) diff --git a/tests/chainer_tests/test_backend.py b/tests/chainer_tests/test_backend.py index 1d6c19620206..330eaf636f3b 100644 --- a/tests/chainer_tests/test_backend.py +++ b/tests/chainer_tests/test_backend.py @@ -65,15 +65,21 @@ def test_from_chx_cuda(self): numpy.testing.assert_array_equal(self._to_cpu(dst), self.src_data) +@testing.parameterize(*testing.product({ + 'dtype': [numpy.float16, numpy.float32], +})) class TestCopyToCPU(_TestCopyToBase, unittest.TestCase): def _get_dst(self): - return self.dst_data + return self.dst_data.astype(self.dtype, copy=False) +@testing.parameterize(*testing.product({ + 'dtype': [numpy.float16, numpy.float32], +})) @attr.gpu class TestCopyToGPU(_TestCopyToBase, unittest.TestCase): def _get_dst(self): - return cuda.cupy.array(self.dst_data) + return cuda.cupy.array(self.dst_data, self.dtype) @attr.multi_gpu(2) def test_gpu_to_another_gpu(self): @@ -92,17 +98,23 @@ def _get_dst(self): return dst +@testing.parameterize(*testing.product({ + 'dtype': [numpy.float16, numpy.float32], +})) @attr.chainerx class TestCopyToChxNative(_TestCopyToBase, unittest.TestCase): def _get_dst(self): - return chainerx.array(self.dst_data, device='native') + return chainerx.array(self.dst_data, dtype=self.dtype, device='native') +@testing.parameterize(*testing.product({ + 'dtype': [numpy.float16, numpy.float32], +})) @attr.chainerx @attr.gpu class TestCopyToChxCuda(_TestCopyToBase, unittest.TestCase): def _get_dst(self): - return chainerx.array(self.dst_data, device='cuda:0') + return chainerx.array(self.dst_data, dtype=self.dtype, device='cuda:0') class TestCopyToError(unittest.TestCase): diff --git a/tests/chainer_tests/test_variable.py b/tests/chainer_tests/test_variable.py index 9f4aa66262b1..db39b9263da1 100644 --- a/tests/chainer_tests/test_variable.py +++ b/tests/chainer_tests/test_variable.py @@ -1837,11 +1837,13 @@ def setUp(self): self.a = np.random.rand(3, 2).astype(np.float32) self.b = np.random.rand(*self.a.shape).astype(self.a.dtype) - def check_constant_initialization(self, x, a, xp, expected_device): + def check_constant_initialization( + self, x, a, xp, expected_dtype, expected_device): x.initialize(a.shape) assert isinstance(x.data, xp.ndarray) assert x._has_chainerx_array is (xp is chainerx) - xp.testing.assert_array_equal(x.data, xp.asarray(a)) + xp.testing.assert_array_equal( + x.data.astype(expected_dtype, copy=False), xp.asarray(a)) xp.testing.assert_array_equal(x.grad, np.float32('nan')) assert backend.get_device_from_array(x.data) == expected_device assert backend.get_device_from_array(x.grad) == expected_device @@ -1850,14 +1852,23 @@ def test_initialize_to_device(self, backend_config): x = chainer.Parameter(initializer=initializers.Constant(self.a)) x.to_device(backend_config.device) self.check_constant_initialization( - x, self.a, backend_config.xp, backend_config.device) + x, self.a, backend_config.xp, self.a.dtype, backend_config.device) + + def test_initialize_to_device_with_dtype(self, backend_config): + x = chainer.Parameter(initializer=initializers.Constant( + self.a, dtype=np.float64)) + x.to_device(backend_config.device) + with chainer.using_config('dtype', np.float16): + self.check_constant_initialization( + x, self.a, backend_config.xp, np.float64, + backend_config.device) def test_initialize_with_device(self, backend_config): a = backend_config.get_array(self.a) x = chainer.Parameter(initializer=initializers.Constant(a)) # Parameters arrays are always initialized in numpy side self.check_constant_initialization( - x, self.a, np, _numpy_device) + x, self.a, np, self.a.dtype, _numpy_device) def check_zerograd(self, x, xp): assert isinstance(x.grad, xp.ndarray) From 0aa2ad707fc4ebcea56d74fc94c95180a6ec0879 Mon Sep 17 00:00:00 2001 From: hvy Date: Wed, 28 Aug 2019 01:55:27 +0000 Subject: [PATCH 2/2] Revert test_variable.py --- tests/chainer_tests/test_variable.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/tests/chainer_tests/test_variable.py b/tests/chainer_tests/test_variable.py index db39b9263da1..9f4aa66262b1 100644 --- a/tests/chainer_tests/test_variable.py +++ b/tests/chainer_tests/test_variable.py @@ -1837,13 +1837,11 @@ def setUp(self): self.a = np.random.rand(3, 2).astype(np.float32) self.b = np.random.rand(*self.a.shape).astype(self.a.dtype) - def check_constant_initialization( - self, x, a, xp, expected_dtype, expected_device): + def check_constant_initialization(self, x, a, xp, expected_device): x.initialize(a.shape) assert isinstance(x.data, xp.ndarray) assert x._has_chainerx_array is (xp is chainerx) - xp.testing.assert_array_equal( - x.data.astype(expected_dtype, copy=False), xp.asarray(a)) + xp.testing.assert_array_equal(x.data, xp.asarray(a)) xp.testing.assert_array_equal(x.grad, np.float32('nan')) assert backend.get_device_from_array(x.data) == expected_device assert backend.get_device_from_array(x.grad) == expected_device @@ -1852,23 +1850,14 @@ def test_initialize_to_device(self, backend_config): x = chainer.Parameter(initializer=initializers.Constant(self.a)) x.to_device(backend_config.device) self.check_constant_initialization( - x, self.a, backend_config.xp, self.a.dtype, backend_config.device) - - def test_initialize_to_device_with_dtype(self, backend_config): - x = chainer.Parameter(initializer=initializers.Constant( - self.a, dtype=np.float64)) - x.to_device(backend_config.device) - with chainer.using_config('dtype', np.float16): - self.check_constant_initialization( - x, self.a, backend_config.xp, np.float64, - backend_config.device) + x, self.a, backend_config.xp, backend_config.device) def test_initialize_with_device(self, backend_config): a = backend_config.get_array(self.a) x = chainer.Parameter(initializer=initializers.Constant(a)) # Parameters arrays are always initialized in numpy side self.check_constant_initialization( - x, self.a, np, self.a.dtype, _numpy_device) + x, self.a, np, _numpy_device) def check_zerograd(self, x, xp): assert isinstance(x.grad, xp.ndarray)