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)
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.") # make it hashable _devices = tuple(devs)
def min(self, axis=None, out=None, *, explicit=False): """Returns the minimum of the matrix or maximum along an axis. Args: axis (int): {-2, -1, 0, 1, ``None``} (optional) Axis along which the sum is computed. The default is to compute the minimum over all the matrix elements, returning a scalar (i.e. ``axis`` = ``None``). out (None): (optional) This argument is in the signature *solely* for NumPy compatibility reasons. Do not pass in anything except for the default value, as this argument is not used. explicit (bool): Return the minimum value explicitly specified and ignore all implicit zero entries. If the dimension has no explicit values, a zero is then returned to indicate that it is the only implicit value. This parameter is experimental and may change in the future. Returns: (cupy.ndarray or float): Minimum of ``a``. If ``axis`` is None, the result is a scalar value. If ``axis`` is given, the result is an array of dimension ``a.ndim - 1``. This differs from numpy for computational efficiency. .. seealso:: max : The maximum value of a sparse matrix along a given axis. .. seealso:: numpy.matrix.min : NumPy's implementation of 'min' for matrices """ if explicit: api_name = 'explicit of cupyx.scipy.sparse.{}.min'.format( self.__class__.__name__) _util.experimental(api_name) return self._min_or_max(axis, out, cupy.min, explicit)
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:: :func:`numpy.random.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
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
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` """ _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
from cupy import _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')
def repeat(func, args=(), kwargs={}, n_repeat=10000, *, name=None, n_warmup=10, max_duration=_math.inf, devices=None): """ Timing utility for measuring time spent by both CPU and GPU. This function is a very convenient helper for setting up a timing test. The GPU time is properly recorded by synchronizing internal streams. As a result, to time a multi-GPU function all participating devices must be passed as the ``devices`` argument so that this helper knows which devices to record. A simple example is given as follows: .. code-block:: py import cupy as cp from cupyx.time import repeat def f(a, b): return 3 * cp.sin(-a) * b a = 0.5 - cp.random.random((100,)) b = cp.random.random((100,)) print(repeat(f, (a, b), n_repeat=1000)) Args: func (callable): a callable object to be timed. args (tuple): positional argumens to be passed to the callable. kwargs (dict): keyword arguments to be passed to the callable. n_repeat (int): number of times the callable is called. Increasing this value would improve the collected statistics at the cost of longer test time. name (str): the function name to be reported. If not given, the callable's ``__name__`` attribute is used. n_warmup (int): number of times the callable is called. The warm-up runs are not timed. max_duration (float): the maximum time (in seconds) that the entire test can use. If the taken time is longer than this limit, the test is stopped and the statistics collected up to the breakpoint is reported. devices (tuple): a tuple of device IDs (int) that will be timed during the timing test. If not given, the current device is used. Returns: :class:`_PerfCaseResult`: an object collecting all test results. .. warning:: This API is currently experimental and subject to change in future releases. """ _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('`name` should be a string.') if not isinstance(n_warmup, int): raise ValueError('`n_warmup` should be an integer.') if not _numpy.isreal(max_duration): raise ValueError('`max_duration` should be given in seconds') 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)