Пример #1
0
 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))
Пример #2
0
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)
Пример #4
0
    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
Пример #5
0
    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))
Пример #6
0
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()
Пример #7
0
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)))
Пример #8
0
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))
Пример #9
0
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