Beispiel #1
0
def set_cufft_gpus(gpus):
    '''Set the GPUs to be used in multi-GPU FFT.

    Args:
        gpus (int or list of int): The number of GPUs or a list of GPUs
            to be used. For the former case, the first ``gpus`` GPUs
            will be used.

    .. warning::
        This API is currently experimental and may be changed in the future
        version.

    .. seealso:: `Multiple GPU cuFFT Transforms`_

    .. _Multiple GPU cuFFT Transforms:
        https://docs.nvidia.com/cuda/cufft/index.html#multiple-GPU-cufft-transforms
    '''
    util.experimental('cupy.fft.config.set_cufft_gpus')
    global _devices

    if isinstance(gpus, int):
        devs = [i for i in range(gpus)]
    elif isinstance(gpus, list):
        devs = gpus
    else:
        raise ValueError("gpus must be an int or a list of int.")
    if len(devs) <= 1:
        raise ValueError("Must use at least 2 GPUs.")

    _devices = devs
Beispiel #2
0
def fuse(*args, **kwargs):
    """Function fusing decorator.

    This decorator can be used to define an elementwise or reduction kernel
    more easily than `ElementwiseKernel` class or `ReductionKernel` class.

    This decorator makes `Fusion` class from the given function.

    Args:
        input_num (int): Number of input arguments of the given function.
        reduce (function): The reduce function which is applied after
            pre-mapping step. If not assigned, reduction step is skipped.
        post_map (function): Mapping function for reduced values.
            If not assigned, post_map step is skipped.
        kernel_name (str): Name of the fused kernel function.
            If omitted, the name of the decorated function is used.
    """
    util.experimental('cupy.core.fusion')

    def wrapper(
            f, input_num=None, reduce=None, post_map=lambda x: x,
            kernel_name=None):
        return Fusion(f, input_num, reduce, post_map, kernel_name)

    if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
        return functools.update_wrapper(wrapper(args[0]), args[0])
    else:
        return lambda f: functools.update_wrapper(
            wrapper(f, *args, **kwargs), f)
Beispiel #3
0
def repeat(func,
           args=(),
           kwargs={},
           n_repeat=10000,
           *,
           name=None,
           n_warmup=10,
           max_duration=math.inf,
           devices=None):

    util.experimental('cupyx.time.repeat')
    if name is None:
        name = func.__name__

    if devices is None:
        devices = (cupy.cuda.get_device_id(), )

    if not callable(func):
        raise ValueError('`func` should be a callable object.')
    if not isinstance(args, tuple):
        raise ValueError('`args` should be of tuple type.')
    if not isinstance(kwargs, dict):
        raise ValueError('`kwargs` should be of dict type.')
    if not isinstance(n_repeat, int):
        raise ValueError('`n_repeat` should be an integer.')
    if not isinstance(name, str):
        raise ValueError('`str` should be a string.')
    if not isinstance(n_warmup, int):
        raise ValueError('`n_warmup` should be an integer.')
    if not isinstance(devices, tuple):
        raise ValueError('`devices` should be of tuple type')

    return _repeat(func, args, kwargs, n_repeat, name, n_warmup, max_duration,
                   devices)
Beispiel #4
0
    def multivariate_normal(self,
                            mean,
                            cov,
                            size=None,
                            check_valid='ignore',
                            tol=1e-8,
                            dtype=float):
        """(experimental) Returns an array of samples drawn from the
        multivariate normal distribution.

        .. seealso::
            :func:`cupy.random.multivariate_normal` for full documentation,
            :meth:`numpy.random.RandomState.multivariate_normal
            <numpy.random.mtrand.RandomState.multivariate_normal>`
        """
        util.experimental('cupy.random.RandomState.multivariate_normal')
        mean = cupy.asarray(mean, dtype=dtype)
        cov = cupy.asarray(cov, dtype=dtype)
        if size is None:
            shape = ()
        elif isinstance(size, cupy.util.collections_abc.Sequence):
            shape = tuple(size)
        else:
            shape = size,

        if mean.ndim != 1:
            raise ValueError('mean must be 1 dimensional')
        if (cov.ndim != 2) or (cov.shape[0] != cov.shape[1]):
            raise ValueError('cov must be 2 dimensional and square')
        if len(mean) != len(cov):
            raise ValueError('mean and cov must have same length')
        shape += (len(mean), )

        x = self.standard_normal(size=shape, dtype=dtype)

        u, s, v = cupy.linalg.svd(cov)

        if check_valid != 'ignore':
            if check_valid != 'warn' and check_valid != 'raise':
                raise ValueError(
                    'check_valid must equal \'warn\', \'raise\', or '
                    '\'ignore\'')

            a = cupy.dot(v.T * s, v)
            b = cov
            psd = cupy.all(cupy.abs(a - b) <= tol * (1 + cupy.abs(b)))
            if not psd:
                if check_valid == 'warn':
                    warnings.warn(
                        'covariance is not symmetric positive-semidefinite.',
                        RuntimeWarning)
                else:
                    raise ValueError(
                        'covariance is not symmetric positive-semidefinite.')

        x = cupy.dot(x, cupy.sqrt(s)[:, None] * v)
        x += mean
        return x
Beispiel #5
0
def repeat(func,
           args=(),
           kwargs={},
           n_repeat=10000,
           *,
           name=None,
           n_warmup=10,
           max_duration=math.inf):
    util.experimental('cupyx.time.repeat')
    if name is None:
        name = func.__name__

    if not callable(func):
        raise ValueError('`func` should be a callable object.')
    if not isinstance(args, tuple):
        raise ValueError('`args` should be of tuple type.')
    if not isinstance(kwargs, dict):
        raise ValueError('`kwargs` should be of dict type.')
    if not isinstance(n_repeat, int):
        raise ValueError('`n_repeat` should be an integer.')
    if not isinstance(name, str):
        raise ValueError('`str` should be a string.')
    if not isinstance(n_warmup, int):
        raise ValueError('`n_warmup` should be an integer.')

    ev1 = cupy.cuda.stream.Event()
    ev2 = cupy.cuda.stream.Event()

    for i in range(n_warmup):
        func(*args, **kwargs)

    ev1.record()
    ev1.synchronize()

    cpu_times = []
    gpu_times = []
    duration = 0
    for i in range(n_repeat):
        ev1.record()
        t1 = time.perf_counter()

        func(*args, **kwargs)

        t2 = time.perf_counter()
        ev2.record()
        ev2.synchronize()
        cpu_time = t2 - t1
        gpu_time = cupy.cuda.get_elapsed_time(ev1, ev2) * 1e-3
        cpu_times.append(cpu_time)
        gpu_times.append(gpu_time)

        duration += time.perf_counter() - t1
        if duration > max_duration:
            break

    ts = numpy.asarray([cpu_times, gpu_times], dtype=numpy.float64)
    return _PerfCaseResult(name, ts)
Beispiel #6
0
def fuse(input_num=None, reduce=None, post_map=lambda x: x):
    """Function fusing decorator.

    This decorator can be used to define an elementwise or reduction kernel
    more easily than `ElementwiseKernel` class or `ReductionKernel` class.

    This decorator makes `Fusion` class from the given function.

    Args:
        input_num (int): Number of input arguments of the given function.
        reduce (function): The reduce function which is applied after
            pre-mapping step. If not assigned, reduction step is skipped.
        post_map (function): Mapping function for reduced values.
            If not assigned, post_map step is skipped.
    """
    util.experimental('cupy.core.fusion')
    return lambda f: Fusion(f, input_num, reduce, post_map)
Beispiel #7
0
def allow_synchronize(allow):
    """Allows or disallows device synchronization temporarily in the current \
thread.

    If device synchronization is detected, :class:`cupyx.DeviceSynchronized`
    will be raised.

    Note that there can be false negatives and positives.
    Device synchronization outside CuPy will not be detected.
    """
    util.experimental('cupyx.allow_synchronize')
    old = _is_allowed()
    _thread_local.allowed = allow
    try:
        yield
    finally:
        _thread_local.allowed = old
Beispiel #8
0
def fuse(input_num=None, reduce=None, post_map=lambda x: x):
    """Function fusing decorator.

    This decorator can be used to define an elementwise or reduction kernel
    more easily than `ElementwiseKernel` class or `ReductionKernel` class.

    This decorator makes `Fusion` class from the given function.

    Args:
        input_num (int): Number of input arguments of the given function.
        reduce (function): The reduce function which is applied after
            pre-mapping step. If not assigned, reduction step is skipped.
        post_map (function): Mapping function for reduced values.
            If not assigned, post_map step is skipped.
    """
    util.experimental('cupy.core.fusion')
    return lambda f: Fusion(f, input_num, reduce, post_map)
Beispiel #9
0
def repeat(func, args=(), kwargs={}, n=10000, *, name=None, n_warmup=10):
    util.experimental('cupyx.time.repeat')
    if name is None:
        name = func.__name__

    if not callable(func):
        raise ValueError('`func` should be a callable object.')
    if not isinstance(args, tuple):
        raise ValueError('`args` should be of tuple type.')
    if not isinstance(kwargs, dict):
        raise ValueError('`kwargs` should be of dict type.')
    if not isinstance(n, int):
        raise ValueError('`n` should be an integer.')
    if not isinstance(name, str):
        raise ValueError('`str` should be a string.')
    if not isinstance(n_warmup, int):
        raise ValueError('`n_warmup` should be an integer.')

    ts = numpy.empty((
        2,
        n,
    ), dtype=numpy.float64)
    ev1 = cupy.cuda.stream.Event()
    ev2 = cupy.cuda.stream.Event()

    for i in range(n_warmup):
        func(*args, **kwargs)

    ev1.record()
    ev1.synchronize()

    for i in range(n):
        ev1.record()
        t1 = time.perf_counter()

        func(*args, **kwargs)

        t2 = time.perf_counter()
        ev2.record()
        ev2.synchronize()
        cpu_time = t2 - t1
        gpu_time = cupy.cuda.get_elapsed_time(ev1, ev2) * 1e-3
        ts[0, i] = cpu_time
        ts[1, i] = gpu_time

    return _PerfCaseResult(name, ts)
Beispiel #10
0
def multivariate_normal(mean,
                        cov,
                        size=None,
                        check_valid='ignore',
                        tol=1e-8,
                        dtype=float):
    """(experimental) Multivariate normal distribution.

    Returns an array of samples drawn from the multivariate normal
    distribution. Its probability density function is defined as

    .. math::
       f(x) = \\frac{1}{(2\\pi|\\Sigma|)^(n/2)} \
           \\exp\\left(-\\frac{1}{2} \
           (x-\\mu)^{\\top}\\Sigma^{-1}(x-\\mu)\\right).

    Args:
        mean (1-D array_like, of length N): Mean of the multivariate normal
            distribution :math:`\\mu`.
        cov (2-D array_like, of shape (N, N)): Covariance matrix
            :math:`\\Sigma` of the multivariate normal distribution. It must be
            symmetric and positive-semidefinite for proper sampling.
        size (int or tuple of ints): The shape of the array. If ``None``, a
            zero-dimensional array is generated.
        check_valid ('warn', 'raise', 'ignore'): Behavior when the covariance
            matrix is not positive semidefinite.
        tol (float): Tolerance when checking the singular values in
            covariance matrix.
        dtype: Data type specifier. Only :class:`numpy.float32` and
            :class:`numpy.float64` types are allowed.

    Returns:
        cupy.ndarray: Samples drawn from the multivariate normal distribution.

    .. seealso:: :meth:`numpy.random.multivariate_normal
                 <numpy.random.mtrand.RandomState.multivariate_normal>`

    """
    util.experimental('cupy.random.multivariate_normal')
    rs = generator.get_random_state()
    x = rs.multivariate_normal(mean, cov, size, check_valid, tol, dtype)
    return x
Beispiel #11
0
    def multivariate_normal(self,
                            mean,
                            cov,
                            size=None,
                            check_valid='ignore',
                            tol=1e-08,
                            method='cholesky',
                            dtype=float):
        """Returns an array of samples drawn from the multivariate normal
        distribution.

        .. warning::
            This function calls one or more cuSOLVER routine(s) which may yield
            invalid results if input conditions are not met.
            To detect these invalid results, you can set the `linalg`
            configuration to a value that is not `ignore` in
            :func:`cupyx.errstate` or :func:`cupyx.seterr`.

        .. seealso::
            :func:`cupy.random.multivariate_normal` for full documentation,
            :meth:`numpy.random.RandomState.multivariate_normal
            <numpy.random.mtrand.RandomState.multivariate_normal>`
        """
        util.experimental('cupy.random.RandomState.multivariate_normal')
        mean = cupy.asarray(mean, dtype=dtype)
        cov = cupy.asarray(cov, dtype=dtype)
        if size is None:
            shape = []
        elif isinstance(size, (int, cupy.integer)):
            shape = [size]
        else:
            shape = size

        if len(mean.shape) != 1:
            raise ValueError('mean must be 1 dimensional')
        if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]):
            raise ValueError('cov must be 2 dimensional and square')
        if mean.shape[0] != cov.shape[0]:
            raise ValueError('mean and cov must have same length')

        final_shape = list(shape[:])
        final_shape.append(mean.shape[0])

        if method not in {'eigh', 'svd', 'cholesky'}:
            raise ValueError(
                "method must be one of {'eigh', 'svd', 'cholesky'}")

        if check_valid != 'ignore':
            if check_valid != 'warn' and check_valid != 'raise':
                raise ValueError(
                    "check_valid must equal 'warn', 'raise', or 'ignore'")

        if check_valid == 'warn':
            with cupyx.errstate(linalg='raise'):
                try:
                    decomp = cupy.linalg.cholesky(cov)
                except LinAlgError:
                    with cupyx.errstate(linalg='ignore'):
                        if method != 'cholesky':
                            if method == 'eigh':
                                (s, u) = cupy.linalg.eigh(cov)
                                psd = not cupy.any(s < -tol)
                            if method == 'svd':
                                (u, s, vh) = cupy.linalg.svd(cov)
                                psd = cupy.allclose(cupy.dot(vh.T * s, vh),
                                                    cov,
                                                    rtol=tol,
                                                    atol=tol)
                            decomp = u * cupy.sqrt(cupy.abs(s))
                            if not psd:
                                warnings.warn(
                                    "covariance is not positive-" +
                                    "semidefinite, output may be " +
                                    "invalid.", RuntimeWarning)

                        else:
                            warnings.warn(
                                "covariance is not positive-" +
                                "semidefinite, output *is* " + "invalid.",
                                RuntimeWarning)
                            decomp = cupy.linalg.cholesky(cov)

        else:
            with cupyx.errstate(linalg=check_valid):
                try:
                    if method == 'cholesky':
                        decomp = cupy.linalg.cholesky(cov)
                    elif method == 'eigh':
                        (s, u) = cupy.linalg.eigh(cov)
                        decomp = u * cupy.sqrt(cupy.abs(s))
                    elif method == 'svd':
                        (u, s, vh) = cupy.linalg.svd(cov)
                        decomp = u * cupy.sqrt(cupy.abs(s))

                except LinAlgError:
                    raise LinAlgError("Matrix is not positive definite; if " +
                                      "matrix is positive-semidefinite, set" +
                                      "'check_valid' to 'warn'")

        x = self.standard_normal(final_shape,
                                 dtype=dtype).reshape(-1, mean.shape[0])
        x = cupy.dot(decomp, x.T)
        x = x.T
        x += mean
        x.shape = tuple(final_shape)
        return x
Beispiel #12
0
def multivariate_normal(mean,
                        cov,
                        size=None,
                        check_valid='ignore',
                        tol=1e-08,
                        method='cholesky',
                        dtype=float):
    """Multivariate normal distribution.

    Returns an array of samples drawn from the multivariate normal
    distribution. Its probability density function is defined as

    .. math::
       f(x) = \\frac{1}{(2\\pi|\\Sigma|)^(n/2)} \
           \\exp\\left(-\\frac{1}{2} \
           (x-\\mu)^{\\top}\\Sigma^{-1}(x-\\mu)\\right).

    Args:
        mean (1-D array_like, of length N): Mean of the multivariate normal
            distribution :math:`\\mu`.
        cov (2-D array_like, of shape (N, N)): Covariance matrix
            :math:`\\Sigma` of the multivariate normal distribution. It must be
            symmetric and positive-semidefinite for proper sampling.
        size (int or tuple of ints): The shape of the array. If ``None``, a
            zero-dimensional array is generated.
        check_valid ('warn', 'raise', 'ignore'): Behavior when the covariance
            matrix is not positive semidefinite.
        tol (float): Tolerance when checking the singular values in
            covariance matrix.
        method : { 'cholesky', 'eigh', 'svd'}, optional
            The cov input is used to compute a factor matrix A such that
            ``A @ A.T = cov``. This argument is used to select the method
            used to compute the factor matrix A. The default method 'cholesky'
            is the fastest, while 'svd' is the slowest but more robust than
            the fastest method. The method `eigh` uses eigen decomposition to
            compute A and is faster than svd but slower than cholesky.
        dtype: Data type specifier. Only :class:`numpy.float32` and
            :class:`numpy.float64` types are allowed.

    Returns:
        cupy.ndarray: Samples drawn from the multivariate normal distribution.

    .. note:: Default `method` is set to fastest, 'cholesky', unlike numpy
        which defaults to 'svd'. Cholesky decomposition in CuPy will fail
        silently if the input covariance matrix is not positive definite and
        give invalid results, unlike in numpy, where an invalid covariance
        matrix will raise an exception. Setting `check_valid` to 'raise' will
        replicate numpy behavior by checking the input, but will also force
        device synchronization. If validity of input is unknown, setting
        `method` to 'einh' or 'svd' and `check_valid` to 'warn' will use
        cholesky decomposition for positive definite matrices, and fallback to
        the specified `method` for other matrices (i.e., not positive
        semi-definite), and will warn if decomposition is suspect.

    .. seealso:: :meth:`numpy.random.multivariate_normal
                 <numpy.random.mtrand.RandomState.multivariate_normal>`

    """
    util.experimental('cupy.random.multivariate_normal')
    rs = _generator.get_random_state()
    x = rs.multivariate_normal(mean, cov, size, check_valid, tol, method,
                               dtype)
    return x
Beispiel #13
0
from cupy import util as _util

# Attributes and Methods for fallback_mode
# Auto-execute numpy method when corresponding cupy method is not found

# "NOQA" to suppress flake8 warning
from cupyx.fallback_mode.fallback import numpy  # NOQA


_util.experimental('cupyx.fallback_mode.numpy')