def fallback_device(self): # TODO(niboshi): Write unit test backend_name = self.device.backend.name if backend_name == 'native': return _cpu.CpuDevice() if backend_name == 'cuda': return cuda.GpuDevice.from_device_id(self.device.index) raise RuntimeError( 'Only \'native\' or \'cuda\' devices have corresponding fallback ' 'devices. Actual: {}'.format(backend_name))
def _guess_device_from_array_module(xp): """Returns a plausible device from array module .. warning:: There can be multiple devices for a module """ if xp is cuda.cupy: return cuda.GpuDevice(cuda.Device()) elif xp is chainerx: return _chainerx.ChainerxDevice(chainerx.get_default_device()) else: # Cannot detect intel64, because xp of intel64 is numpy. return _cpu.CpuDevice()
def check_converter_received_device_arg( self, received_device_arg, device_arg): new_style = self.converter_style == 'new' # None if device_arg is None: self.assertIs(received_device_arg, None) return # Normalize input device types is_cpu = False cuda_device_id = None if isinstance(device_arg, int): if device_arg < 0: is_cpu = True else: cuda_device_id = device_arg elif isinstance(device_arg, _cpu.CpuDevice): is_cpu = True elif isinstance(device_arg, cuda.GpuDevice): cuda_device_id = device_arg.device.id else: assert False # Check received device if is_cpu: if new_style: self.assertEqual(received_device_arg, _cpu.CpuDevice()) else: self.assertEqual(received_device_arg, -1) elif cuda_device_id is not None: if new_style: self.assertEqual( received_device_arg, cuda.GpuDevice.from_device_id(cuda_device_id)) else: self.assertIsInstance(received_device_arg, int) self.assertEqual(received_device_arg, cuda_device_id) else: self.assertTrue(new_style) self.assertIs(received_device_arg, device_arg)
def check_converter_received_device_arg(self, received_device_arg, device_arg): new_style = self.converter_style == 'new' # None if device_arg is None: assert received_device_arg is None return # Normalize input device types is_cpu = False cuda_device_id = None if isinstance(device_arg, int): if device_arg < 0: is_cpu = True else: cuda_device_id = device_arg elif isinstance(device_arg, _cpu.CpuDevice): is_cpu = True elif isinstance(device_arg, cuda.GpuDevice): cuda_device_id = device_arg.device.id else: assert False # Check received device if is_cpu: if new_style: assert received_device_arg == _cpu.CpuDevice() else: assert received_device_arg == -1 elif cuda_device_id is not None: if new_style: assert (received_device_arg == cuda.GpuDevice.from_device_id( cuda_device_id)) else: assert isinstance(received_device_arg, int) assert received_device_arg == cuda_device_id else: assert new_style assert received_device_arg is device_arg
def fallback_device(self): """Fallback device. A fallback device is either a :class:`~chainer.backend.CpuDevice` or a :class:`~chainer.backend.GpuDevice` which shares the same physical device with the original ChainerX device. For example, the fallback device of ``native:0`` ChainerX device is :class:`~chainer.backend.CpuDevice`. The fallback device of ``cuda:1`` ChainerX device is :class:`~chainer.backend.GpuDevice` with device ID 1. """ backend_name = self.device.backend.name if backend_name == 'native': return _cpu.CpuDevice() if backend_name == 'cuda': return cuda.GpuDevice.from_device_id(self.device.index) raise RuntimeError( 'Only \'native\' or \'cuda\' devices have corresponding fallback ' 'devices. Actual: {}'.format(backend_name))
def _get_device_cupy_or_numpy(device_spec): # legacy spec of (gpu) device if device_spec >= 0: return cuda.GpuDevice.from_device_id(device_spec) else: return _cpu.CpuDevice()
def get_device(device_spec: types.DeviceSpec) -> Device: """Returns a device object. Args: device_spec (object): Device specifier. If a :class:`chainer.backend.Device` instance is given, it is returned intact. Otherwise the following values are supported: * ChainerX devices * A string representing a device. (ex. ``'native:0'``, ``'native'``) * A :class:`chainerx.Device` object. * CuPy * A string starts with ``'@cupy:'``. (ex. ``'@cupy:0'``) * A :class:`cupy.cuda.Device` object. * NumPy * The string ``'@numpy'``. * NumPy with Intel Architecture * The string ``'@intel64'``. """ if isinstance(device_spec, Device): return device_spec if isinstance(device_spec, cuda._integer_types): return _get_device_cupy_or_numpy(device_spec) if chainerx.is_available() and isinstance(device_spec, chainerx.Device): return _chainerx.ChainerxDevice(device_spec) if cuda.available and isinstance(device_spec, cuda.Device): return cuda.GpuDevice(device_spec) if isinstance(device_spec, six.string_types): # '-1', '0', '1', ... try: int_device_spec = int(device_spec) except ValueError: pass else: return _get_device_cupy_or_numpy(int_device_spec) if device_spec.startswith('@'): # '@module:...' mod_name, colon, precise_spec = device_spec[1:].partition(':') if mod_name == 'numpy': if not colon: return _cpu.CpuDevice() elif mod_name == 'cupy': if colon: return cuda.GpuDevice.from_device_id(int(precise_spec)) elif mod_name == 'intel64': if not colon: return intel64.Intel64Device() raise ValueError( 'Device specifiers starting with \'@\' must be followed by' ' a module name and depending on the module, module specific' ' precise device specifiers. Actual: {}'.format(device_spec)) else: # String device specifier without '@' prefix is assumed to be a # ChainerX device. if not chainerx.is_available(): raise RuntimeError( 'Tried to parse ChainerX device specifier \'{}\', ' 'but ChainerX is not available. ' 'Note that device specifiers without \'@\' prefix are ' 'assumed to be ChainerX device ' 'specifiers.'.format(device_spec)) return _chainerx.ChainerxDevice(chainerx.get_device(device_spec)) raise TypeError( 'Device specifier must be a backend.Device, cuda.Device,' ' chainerx.Device, integer or a string. Actual: {}'.format( type(device_spec)))
def get_device(device_spec): # type: (types.DeviceSpec) -> Device """Returns a device object. Args: device_spec (object): Device specifier. If a :class:`chainer.backend.Device` instance is given, it is returned intact. Otherwise the following values are supported: * ChainerX devices * A string representing a device. (ex. ``'native:0'``, ``'native'``) * A :class:`chainerx.Device` object. * CuPy * A string starts with ``'@cupy:'``. (ex. ``'@cupy:0'``) * A :class:`cupy.cuda.Device` object. * NumPy * The string ``'@numpy'``. * NumPy with Intel Architecture * The string ``'@intel64'``. """ if isinstance(device_spec, Device): return device_spec if isinstance(device_spec, cuda._integer_types): return _get_device_cupy_or_numpy(device_spec) if chainerx.is_available() and isinstance(device_spec, chainerx.Device): return _chainerx.ChainerxDevice(device_spec) if cuda.available and isinstance(device_spec, cuda.Device): return cuda.GpuDevice(device_spec) if isinstance(device_spec, six.string_types): # '-1', '0', '1', ... try: int_device_spec = int(device_spec) except ValueError: pass else: return _get_device_cupy_or_numpy(int_device_spec) if device_spec.startswith('@'): # '@module:...' mod_name, colon, precise_spec = device_spec[1:].partition(':') if mod_name == 'numpy': if not colon: return _cpu.CpuDevice() elif mod_name == 'cupy': if colon: return cuda.GpuDevice.from_device_id(int(precise_spec)) elif mod_name == 'intel64': if not colon: return intel64.Intel64Device() elif chainerx.is_available(): return _chainerx.ChainerxDevice(chainerx.get_device(device_spec)) raise ValueError('Invalid device specifier: {}'.format(device_spec))
class DeviceResident(utils.enable_final(meta_base=abc.ABCMeta)): """A base class of objects with multi-device hierarchy.""" _device = _cpu.CpuDevice() def __init__(self): # Store overridden to_device family method names. self._overridden_to_methods = tuple([ m for m in ('to_cpu', 'to_gpu', 'to_intel64') if _is_to_device_method_overridden(self, m) ]) def device_resident_accept(self, visitor): """Applies the visitor to all the device objects in this instance. Args: visitor(~chainer.device_resident.DeviceResidentsVisitor): Visitor. This method should be overridden if the concrete class has custom sub-hierarchy of device resident objects. """ visitor.visit_device_resident(self) @property def device(self): """:class:`~chainer.backend.Device` instance.""" return self._device @property def xp(self): # type: () -> types.Xp """Array module corresponding to the device. Depending on the device in which this object resides, this property returns :mod:`numpy`, :mod:`cupy` or :mod:`chainerx`. """ device = self.device if device is None: return None return device.xp def to_cpu(self): # type: () -> 'DeviceResident' """Copies parameter variables and persistent values to CPU. This method does not handle non-registered attributes. If some of such attributes must be copied to CPU, the link implementation should override :meth:`~DeviceResident.device_resident_accept` to do so. Returns: self """ visitor = _ToDeviceVisitor(backend.CpuDevice(), entry_method_info=('to_cpu', {}), starting_device_resident=self) self.__to_device(visitor) return self def to_gpu( self, device=None, # type: tp.Optional[types.CudaDeviceSpec] ): # type: (...) -> 'DeviceResident' """Copies parameter variables and persistent values to GPU. This method does not handle non-registered attributes. If some of such attributes must be copied to GPU, the link implementation must override :meth:`~DeviceResident.device_resident_accept` to do so. .. warning:: This method does not transfer the parameters if they are already on GPU. Use ``to_device`` to perform inter-GPU transfer. Args: device: Target device specifier. If omitted, the current device is used. Returns: self """ cuda.check_cuda_available() cuda_device = cuda._get_device_or_current(device) device = chainer.backends.cuda.GpuDevice(cuda_device) visitor = _ToDeviceVisitor(device, entry_method_info=('to_gpu', { 'device': device.device }), skip_between_cupy_devices=True, starting_device_resident=self) self.__to_device(visitor) return self def to_intel64(self): # type: () -> 'DeviceResident' """Copies parameter variables and persistent values to CPU.""" intel64.check_ideep_available() visitor = _ToDeviceVisitor(chainer.get_device(intel64.Intel64Device()), entry_method_info=('to_intel64', {}), starting_device_resident=self) self.__to_device(visitor) return self @utils.final def to_chx(self): """Converts parameter variables and persistent values to ChainerX \ without any copy. This method does not handle non-registered attributes. If some of such attributes must be copied to ChainerX, the link implementation must override this method to do so. Returns: self """ if not chainerx.is_available(): raise RuntimeError('ChainerX is not available.') if self.xp is chainerx: return self self.device_resident_accept(_ToChxVisitor()) return self @utils.final def from_chx(self): """Converts parameter variables and persistent values from ChainerX \ to NumPy/CuPy devices without any copy.""" if self._device.xp is chainerx: self._device = self._device.fallback_device self.device_resident_accept(_FromChxVisitor()) return self def __to_device(self, to_device_visitor): self.device_resident_accept(to_device_visitor) @utils.final def to_device( self, device # type: types.DeviceSpec ): # type: (...) -> 'DeviceResident' """Copies parameter variables and persistent values to the specified \ device. This method does not handle non-registered attributes. If some of such attributes must be copied to the device, the link implementation must override this method to do so. Args: device: Target device specifier. See :func:`~chainer.get_device` for available values. Returns: self """ device = chainer.get_device(device) self.__to_device(_ToDeviceVisitor(device)) return self