def test_as_strided(self): a = cp.array([1, 2, 3, 4]) a_view = as_strided(a, shape=(2, ), strides=(2 * a.itemsize, )) expected = cp.array([1, 3]) assert_array_equal(a_view, expected) a = cp.array([1, 2, 3, 4]) a_view = as_strided(a, shape=(3, 4), strides=(0, 1 * a.itemsize)) expected = cp.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]) assert_array_equal(a_view, expected)
def _dot_convolve(a1, a2, mode): offset = 0 if a1.size < a2.size: a1, a2 = a2, a1 offset = 1 - a2.size % 2 dtype = cupy.result_type(a1, a2) n1, n2 = a1.size, a2.size a1 = a1.astype(dtype, copy=False) a2 = a2.astype(dtype, copy=False) if mode == 'full': out_size = n1 + n2 - 1 a1 = cupy.pad(a1, n2 - 1) elif mode == 'same': out_size = n1 pad_size = (n2 - 1) // 2 + offset a1 = cupy.pad(a1, (n2 - 1 - pad_size, pad_size)) elif mode == 'valid': out_size = n1 - n2 + 1 stride = a1.strides[0] a1 = stride_tricks.as_strided(a1, (out_size, n2), (stride, stride)) output = _dot_kernel(a1, a2[::-1], axis=1) return output
def _dot_convolve(a1, a2, mode): if a1.size == 0 or a2.size == 0: raise ValueError('Array arguments cannot be empty') is_inverted = False if a1.size < a2.size: a1, a2 = a2, a1 is_inverted = True dtype = cupy.result_type(a1, a2) n1, n2 = a1.size, a2.size a1 = a1.astype(dtype, copy=False) a2 = a2.astype(dtype, copy=False) if mode == 'full': out_size = n1 + n2 - 1 a1 = cupy.pad(a1, n2 - 1) elif mode == 'same': out_size = n1 pad_size = (n2 - 1) // 2 a1 = cupy.pad(a1, (n2 - 1 - pad_size, pad_size)) elif mode == 'valid': out_size = n1 - n2 + 1 stride = a1.strides[0] a1 = stride_tricks.as_strided(a1, (out_size, n2), (stride, stride)) output = _dot_kernel(a1, a2[::-1], axis=1) return is_inverted, output
def toeplitz(c, r=None): """ Construct a Toeplitz matrix. The Toeplitz matrix has constant diagonals, with c as its first column and r as its first row. If r is not given, ``r == conjugate(c)`` is assumed. Parameters ---------- c : array_like First column of the matrix. Whatever the actual shape of `c`, it will be converted to a 1-D array. r : array_like, optional First row of the matrix. If None, ``r = conjugate(c)`` is assumed; in this case, if c[0] is real, the result is a Hermitian matrix. r[0] is ignored; the first row of the returned matrix is ``[c[0], r[1:]]``. Whatever the actual shape of `r`, it will be converted to a 1-D array. Returns ------- A : (len(c), len(r)) ndarray The Toeplitz matrix. Dtype is the same as ``(c[0] + r[0]).dtype``. See Also -------- circulant : circulant matrix hankel : Hankel matrix solve_toeplitz : Solve a Toeplitz system. Notes ----- The behavior when `c` or `r` is a scalar, or when `c` is complex and `r` is None, was changed in version 0.8.0. The behavior in previous versions was undocumented and is no longer supported. Examples -------- >>> from scipy.linalg import toeplitz >>> toeplitz([1,2,3], [1,4,5,6]) array([[1, 4, 5, 6], [2, 1, 4, 5], [3, 2, 1, 4]]) >>> toeplitz([1.0, 2+3j, 4-1j]) array([[ 1.+0.j, 2.-3.j, 4.+1.j], [ 2.+3.j, 1.+0.j, 2.-3.j], [ 4.-1.j, 2.+3.j, 1.+0.j]]) """ c = cp.asarray(c).ravel() if r is None: r = cp.conjugate() else: r = cp.asarray(r).ravel() # Form a 1D array containing a reversed c followed by r[1:] that could be # strided to give us toeplitz matrix. vals = cp.concatenate((c[::-1], r[1:])) out_shp = len(c), len(r) n = vals.strides[0] return as_strided(vals[len(c) - 1:], shape=out_shp, strides=(-n, n)).copy()
def allocate_gpu_unmanaged(default_origin, shape, layout_map, dtype, alignment_bytes): dtype = np.dtype(dtype) assert (alignment_bytes % dtype.itemsize ) == 0, "Alignment must be a multiple of byte-width of dtype." itemsize = dtype.itemsize items_per_alignment = int(alignment_bytes / itemsize) order_idx = idx_from_order([i for i in layout_map if i is not None]) padded_shape = compute_padded_shape(shape, items_per_alignment, order_idx) strides = strides_from_padded_shape(padded_shape, order_idx, itemsize) if len(order_idx) > 0: halo_offset = ( int(math.ceil(default_origin[order_idx[-1]] / items_per_alignment)) * items_per_alignment - default_origin[order_idx[-1]]) else: halo_offset = 0 padded_size = int(np.prod(padded_shape)) buffer_size = padded_size + items_per_alignment - 1 ptr = cp.cuda.alloc_pinned_memory(buffer_size * itemsize) raw_buffer = np.frombuffer(ptr, dtype, buffer_size) device_raw_buffer = cp.empty((buffer_size, ), dtype=dtype) allocation_mismatch = int( (raw_buffer.ctypes.data % alignment_bytes) / itemsize) alignment_offset = (halo_offset - allocation_mismatch) % items_per_alignment field = np.reshape( raw_buffer[alignment_offset:alignment_offset + padded_size], padded_shape) if field.ndim > 0: field.strides = strides field = field[tuple(slice(0, s, None) for s in shape)] allocation_mismatch = int( (device_raw_buffer.data.ptr % alignment_bytes) / itemsize) alignment_offset = (halo_offset - allocation_mismatch) % items_per_alignment device_field = as_strided( device_raw_buffer[alignment_offset:alignment_offset + padded_size], shape=padded_shape, strides=strides, ) if device_field.ndim > 0: device_field = device_field[tuple(slice(0, s, None) for s in shape)] return raw_buffer, field, device_raw_buffer, device_field
def hankel(c, r=None): """ Construct a Hankel matrix. The Hankel matrix has constant anti-diagonals, with `c` as its first column and `r` as its last row. If `r` is not given, then `r = zeros_like(c)` is assumed. Parameters ---------- c : array_like First column of the matrix. Whatever the actual shape of `c`, it will be converted to a 1-D array. r : array_like, optional Last row of the matrix. If None, ``r = zeros_like(c)`` is assumed. r[0] is ignored; the last row of the returned matrix is ``[c[-1], r[1:]]``. Whatever the actual shape of `r`, it will be converted to a 1-D array. Returns ------- A : (len(c), len(r)) ndarray The Hankel matrix. Dtype is the same as ``(c[0] + r[0]).dtype``. See Also -------- toeplitz : Toeplitz matrix circulant : circulant matrix Examples -------- >>> from scipy.linalg import hankel >>> hankel([1, 17, 99]) array([[ 1, 17, 99], [17, 99, 0], [99, 0, 0]]) >>> hankel([1,2,3,4], [4,7,7,8,9]) array([[1, 2, 3, 4, 7], [2, 3, 4, 7, 7], [3, 4, 7, 7, 8], [4, 7, 7, 8, 9]]) """ c = cp.asarray(c).ravel() if r is None: r = cp.zeros_like(c) else: r = cp.asarray(r).ravel() # Form a 1D array of values to be used in the matrix, containing `c` # followed by r[1:]. vals = cp.concatenate((c, r[1:])) # Stride on concatenated array to get hankel matrix out_shp = len(c), len(r) n = vals.strides[0] return as_strided(vals, shape=out_shp, strides=(n, n)).copy()
def rolling_window(a, window, axis=-1): """ Make an ndarray with a rolling window along axis. This function is taken from https://github.com/numpy/numpy/pull/31 but slightly modified to accept axis option. """ a = numpy.swapaxes(a, axis, -1) shape = a.shape[:-1] + (a.shape[-1] - window + 1, window) strides = a.strides + (a.strides[-1], ) if isinstance(a, numpy.ndarray): rolling = numpy.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) elif isinstance(a, cupy.ndarray): rolling = stride_tricks.as_strided(a, shape=shape, strides=strides) return rolling.swapaxes(-2, axis)
def split_by_strides(X, kh, kw, s): """ reference 1,一种卷积算法的高效实现 :https://zhuanlan.zhihu.com/p/64933417 (forward 借鉴了这个,backward是自己推的) :param X: 原矩阵 :param kh: 卷积核h :param kw: 卷积核w :param s: 步长 :return: """ N, C, H, W = X.shape oh = (H - kh) // s + 1 ow = (W - kw) // s + 1 strides = (*X.strides[:-2], X.strides[-2] * s, X.strides[-1] * s, *X.strides[-2:]) A = as_strided(X, shape=(N, C, oh, ow, kh, kw), strides=strides) return A
def sliding_window(x, w, s): shape = (x.shape[0], ((x.shape[1] - w) // s + 1), w) strides = (x.strides[0], x.strides[1]*s, x.strides[1]) return as_strided(x, shape, strides)
def view_as_blocks(arr_in, block_shape): """Block view of the input n-dimensional array (using re-striding). Blocks are non-overlapping views of the input array. Parameters ---------- arr_in : ndarray N-d input array. block_shape : tuple The shape of the block. Each dimension must divide evenly into the corresponding dimensions of `arr_in`. Returns ------- arr_out : ndarray Block view of the input array. If `arr_in` is non-contiguous, a copy is made. Examples -------- >>> import cupy as cp >>> from skimage.util.shape import view_as_blocks >>> A = cp.arange(4*4).reshape(4,4) >>> A array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) >>> B = view_as_blocks(A, block_shape=(2, 2)) >>> B[0, 0] array([[0, 1], [4, 5]]) >>> B[0, 1] array([[2, 3], [6, 7]]) >>> B[1, 0, 1, 1] 13 >>> A = cp.arange(4*4*6).reshape(4,4,6) >>> A # doctest: +NORMALIZE_WHITESPACE array([[[ 0, 1, 2, 3, 4, 5], [ 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17], [18, 19, 20, 21, 22, 23]], [[24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35], [36, 37, 38, 39, 40, 41], [42, 43, 44, 45, 46, 47]], [[48, 49, 50, 51, 52, 53], [54, 55, 56, 57, 58, 59], [60, 61, 62, 63, 64, 65], [66, 67, 68, 69, 70, 71]], [[72, 73, 74, 75, 76, 77], [78, 79, 80, 81, 82, 83], [84, 85, 86, 87, 88, 89], [90, 91, 92, 93, 94, 95]]]) >>> B = view_as_blocks(A, block_shape=(1, 2, 2)) >>> B.shape (4, 2, 3, 1, 2, 2) >>> B[2:, 0, 2] # doctest: +NORMALIZE_WHITESPACE array([[[[52, 53], [58, 59]]], [[[76, 77], [82, 83]]]]) """ if not isinstance(block_shape, tuple): raise TypeError("block needs to be a tuple") if any(s <= 0 for s in block_shape): raise ValueError("'block_shape' elements must be strictly positive") if len(block_shape) != arr_in.ndim: raise ValueError( "'block_shape' must have the same length as 'arr_in.shape'") if any(s % bs for s, bs in zip(arr_in.shape, block_shape)): raise ValueError("'block_shape' is not compatible with 'arr_in'") # TODO: This C-contiguous check and call to ascontiguousarray is not in # skimage. Remove it? if not arr_in.flags.c_contiguous: # c_contiguous: warn( RuntimeWarning("Cannot provide views on a non-contiguous " "input array without copying.")) arr_in = cp.ascontiguousarray(arr_in) # -- restride the array to build the block view new_shape = tuple([s // bs for s, bs in zip(arr_in.shape, block_shape) ]) + tuple(block_shape) new_strides = (tuple(s * bs for s, bs in zip(arr_in.strides, block_shape)) + arr_in.strides) arr_out = as_strided(arr_in, shape=new_shape, strides=new_strides) return arr_out
def view_as_windows(arr_in, window_shape, step=1): """Rolling window view of the input n-dimensional array. Windows are overlapping views of the input array, with adjacent windows shifted by a single row or column (or an index of a higher dimension). Parameters ---------- arr_in : ndarray N-d input array. window_shape : integer or tuple of length arr_in.ndim Defines the shape of the elementary n-dimensional orthotope (better know as hyperrectangle [1]_) of the rolling window view. If an integer is given, the shape will be a hypercube of sidelength given by its value. step : integer or tuple of length arr_in.ndim Indicates step size at which extraction shall be performed. If integer is given, then the step is uniform in all dimensions. Returns ------- arr_out : ndarray (rolling) window view of the input array. Notes ----- One should be very careful with rolling views when it comes to memory usage. Indeed, although a 'view' has the same memory footprint as its base array, the actual array that emerges when this 'view' is used in a computation is generally a (much) larger array than the original, especially for 2-dimensional arrays and above. For example, let us consider a 3 dimensional array of size (100, 100, 100) of ``float64``. This array takes about 8*100**3 Bytes for storage which is just 8 MB. If one decides to build a rolling view on this array with a window of (3, 3, 3) the hypothetical size of the rolling view (if one was to reshape the view for example) would be 8*(100-3+1)**3*3**3 which is about 203 MB! The scaling becomes even worse as the dimension of the input array becomes larger. References ---------- .. [1] https://en.wikipedia.org/wiki/Hyperrectangle Examples -------- >>> import cupy as cp >>> from skimage.util.shape import view_as_windows >>> A = cp.arange(4*4).reshape(4,4) >>> A array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) >>> window_shape = (2, 2) >>> B = view_as_windows(A, window_shape) >>> B[0, 0] array([[0, 1], [4, 5]]) >>> B[0, 1] array([[1, 2], [5, 6]]) >>> A = cp.arange(10) >>> A array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> window_shape = (3,) >>> B = view_as_windows(A, window_shape) >>> B.shape (8, 3) >>> B array([[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9]]) >>> A = cp.arange(5*4).reshape(5, 4) >>> A array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19]]) >>> window_shape = (4, 3) >>> B = view_as_windows(A, window_shape) >>> B.shape (2, 2, 4, 3) >>> B # doctest: +NORMALIZE_WHITESPACE array([[[[ 0, 1, 2], [ 4, 5, 6], [ 8, 9, 10], [12, 13, 14]], [[ 1, 2, 3], [ 5, 6, 7], [ 9, 10, 11], [13, 14, 15]]], [[[ 4, 5, 6], [ 8, 9, 10], [12, 13, 14], [16, 17, 18]], [[ 5, 6, 7], [ 9, 10, 11], [13, 14, 15], [17, 18, 19]]]]) """ # -- basic checks on arguments if not isinstance(arr_in, cp.ndarray): raise TypeError("`arr_in` must be a cupy ndarray") ndim = arr_in.ndim if isinstance(window_shape, numbers.Number): window_shape = (window_shape, ) * ndim if not (len(window_shape) == ndim): raise ValueError("`window_shape` is incompatible with `arr_in.shape`") if isinstance(step, numbers.Number): if step < 1: raise ValueError("`step` must be >= 1") step = (step, ) * ndim if len(step) != ndim: raise ValueError("`step` is incompatible with `arr_in.shape`") arr_shape = arr_in.shape window_shape = tuple([int(w) for w in window_shape]) if any(s < ws for s, ws in zip(arr_shape, window_shape)): raise ValueError("`window_shape` is too large") if any(ws < 0 for ws in window_shape): raise ValueError("`window_shape` is too small") # -- build rolling window view slices = tuple(slice(None, None, st) for st in step) win_indices_shape = tuple([ (s - ws) // st + 1 for s, ws, st in zip(arr_shape, window_shape, step) ]) new_shape = win_indices_shape + window_shape window_strides = arr_in.strides indexing_strides = arr_in[slices].strides strides = indexing_strides + window_strides arr_out = as_strided(arr_in, shape=new_shape, strides=strides) return arr_out