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
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)
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 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
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)
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)
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 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)
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
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
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
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')