blob: 11df34b91ef7acc3cbc1cbe68f9e64f23d18145e [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: skip-file
from __future__ import absolute_import
from __future__ import division
import itertools
import os
import pytest
import operator
import numpy as _np
import mxnet as mx
from mxnet import np, npx, autograd
from mxnet.gluon import HybridBlock
from mxnet.test_utils import same, assert_almost_equal, rand_shape_nd, rand_ndarray, use_np
from common import retry, TemporaryDirectory, xfail_when_nonstandard_decimal_separator
from mxnet.test_utils import verify_generator, gen_buckets_probs_with_ppf, assert_exception, is_op_runnable, collapse_sum_like
from mxnet.ndarray.ndarray import py_slice
from mxnet.base import integer_types
@use_np
def test_np_empty():
# (input dtype, expected output dtype)
dtype_pairs = [
(np.int8, np.int8),
(np.int32, np.int32),
(np.float16, np.float16),
(np.float32, np.float32),
(np.float64, np.float64),
(np.bool_, np.bool_),
(np.bool, np.bool_),
('int8', np.int8),
('int32', np.int32),
('float16', np.float16),
('float32', np.float32),
('float64', np.float64),
('bool', np.bool_),
(None, np.float32),
]
orders = ['C', 'F', 'A']
shapes = [
(),
0,
(0,),
(0, 0),
2,
(2,),
(3, 0),
(4, 5),
(1, 1, 1, 1),
]
devices = [npx.current_device(), None]
for dtype, expected_dtype in dtype_pairs:
for shape in shapes:
for order in orders:
for device in devices:
if order == 'C':
ret = np.empty(shape, dtype=dtype, order=order, device=device)
assert ret.dtype == expected_dtype
assert ret.shape == shape if isinstance(shape, tuple) else (shape,)
assert ret.device == npx.current_device()
else:
assert_exception(np.empty, NotImplementedError, shape, dtype=dtype, order=order, device=device)
@use_np
def test_np_array_creation():
dtypes = [_np.int8, _np.int32, _np.float16, _np.float32, _np.float64, _np.bool, _np.bool_,
'int8', 'int32', 'float16', 'float32', 'float64', 'bool', None]
objects = [
[],
(),
[[1, 2], [3, 4]],
_np.random.randint(-10, 10, size=rand_shape_nd(3)),
_np.random.uniform(size=rand_shape_nd(3)),
_np.random.uniform(size=(3, 0, 4))
]
for dtype in dtypes:
for src in objects:
mx_arr = np.array(src, dtype=dtype)
assert mx_arr.device == mx.current_device()
if dtype is None:
dtype = src.dtype if isinstance(src, _np.ndarray) else _np.float32
if isinstance(src, mx.nd.NDArray):
np_arr = _np.array(src.asnumpy(), dtype=dtype)
else:
np_arr = _np.array(src, dtype=dtype)
assert mx_arr.dtype == np_arr.dtype
assert same(mx_arr.asnumpy(), np_arr)
@use_np
@pytest.mark.serial
def test_np_zeros():
# test np.zeros in Gluon
class TestZeros(HybridBlock):
def __init__(self, shape, dtype=None):
super(TestZeros, self).__init__()
self._shape = shape
self._dtype = dtype
def forward(self, x, *args, **kwargs):
return x + np.zeros(shape, dtype=dtype)
class TestZerosOutputType(HybridBlock):
def forward(self, x, *args, **kwargs):
return x, np.zeros(shape=())
# test np.zeros in imperative
def check_zero_array_creation(shape, dtype):
np_out = _np.zeros(shape=shape, dtype=dtype)
mx_out = np.zeros(shape=shape, dtype=dtype)
assert same(mx_out.asnumpy(), np_out)
if dtype is None:
assert mx_out.dtype == _np.float32
assert np_out.dtype == _np.float64
else:
assert mx_out.dtype == np_out.dtype
shapes = [(0,), (2, 0, 2), (0, 0, 0, 0), ()]
shapes += [rand_shape_nd(ndim, allow_zero_size=True) for ndim in range(5)]
dtypes = [_np.int8, _np.int32, _np.float16, _np.float32, _np.float64, None]
for shape in shapes:
for dtype in dtypes:
check_zero_array_creation(shape, dtype)
x = np.array(_np.random.uniform(size=shape), dtype=dtype)
if dtype is None:
x = x.astype('float32')
for hybridize in [True, False]:
test_zeros = TestZeros(shape, dtype)
test_zeros_output_type = TestZerosOutputType()
if hybridize:
test_zeros.hybridize()
test_zeros_output_type.hybridize()
y = test_zeros(x)
assert type(y) == np.ndarray
assert same(x.asnumpy(), y.asnumpy())
y = test_zeros_output_type(x)
assert type(y[1]) == np.ndarray
for shape in shapes:
for dtype in [_np.bool, bool, _np.bool, 'bool']:
check_zero_array_creation(shape, dtype)
@use_np
def test_np_ones():
# test np.ones in Gluon
class TestOnes(HybridBlock):
def __init__(self, shape, dtype=None):
super(TestOnes, self).__init__()
self._shape = shape
self._dtype = dtype
def forward(self, x, *args, **kwargs):
return x * np.ones(shape, dtype=dtype)
class TestOnesOutputType(HybridBlock):
def forward(self, x, *args, **kwargs):
return x, np.ones(shape=())
# test np.ones in imperative
def check_ones_array_creation(shape, dtype):
np_out = _np.ones(shape=shape, dtype=dtype)
mx_out = np.ones(shape=shape, dtype=dtype)
assert same(mx_out.asnumpy(), np_out)
if dtype is None:
assert mx_out.dtype == _np.float32
assert np_out.dtype == _np.float64
else:
assert mx_out.dtype == np_out.dtype
shapes = [(0,), (2, 0, 2), (0, 0, 0, 0), ()]
shapes += [rand_shape_nd(ndim, allow_zero_size=True) for ndim in range(5)]
dtypes = [_np.int8, _np.int32, _np.float16, _np.float32, _np.float64, None]
for shape in shapes:
for dtype in dtypes:
check_ones_array_creation(shape, dtype)
x = mx.nd.array(_np.random.uniform(size=shape), dtype=dtype).as_np_ndarray()
if dtype is None:
x = x.astype('float32')
for hybridize in [True, False]:
test_ones = TestOnes(shape, dtype)
test_ones_output_type = TestOnesOutputType()
if hybridize:
test_ones.hybridize()
test_ones_output_type.hybridize()
y = test_ones(x)
assert type(y) == np.ndarray
assert same(x.asnumpy(), y.asnumpy())
y = test_ones_output_type(x)
assert type(y[1]) == np.ndarray
for shape in shapes:
for dtype in [_np.bool, bool, _np.bool, 'bool']:
check_ones_array_creation(shape, dtype)
@use_np
@pytest.mark.serial
def test_identity():
class TestIdentity(HybridBlock):
def __init__(self, shape, dtype=None):
super(TestIdentity, self).__init__()
self._n = n
self._dtype = dtype
def forward(self, x):
return x * np.identity(self._n, self._dtype)
class TestIdentityOutputType(HybridBlock):
def forward(self, x):
return x, np.identity(0)
def check_identity_array_creation(shape, dtype):
np_out = _np.identity(n=n, dtype=dtype)
mx_out = np.identity(n=n, dtype=dtype)
assert same(mx_out.asnumpy(), np_out)
if dtype is None:
assert mx_out.dtype == _np.float32
assert np_out.dtype == _np.float64
ns = [0, 1, 2, 3, 5, 15, 30, 200]
dtypes = [_np.int8, _np.int32, _np.float16, _np.float32, _np.float64, None]
for n in ns:
for dtype in dtypes:
check_identity_array_creation(n, dtype)
x = mx.nd.array(_np.random.uniform(size=(n, n)), dtype=dtype).as_np_ndarray()
if dtype is None:
x = x.astype('float32')
for hybridize in [True, False]:
test_identity = TestIdentity(n, dtype)
test_identity_output_type = TestIdentityOutputType()
if hybridize:
test_identity.hybridize()
test_identity_output_type.hybridize()
y = test_identity(x)
assert type(y) == np.ndarray
assert same(x.asnumpy() * _np.identity(n, dtype), y.asnumpy())
y = test_identity_output_type(x)
assert type(y[1]) == np.ndarray
@xfail_when_nonstandard_decimal_separator
@pytest.mark.serial
def test_np_ndarray_binary_element_wise_ops():
np_op_map = {
'+': _np.add,
'*': _np.multiply,
'-': _np.subtract,
'/': _np.divide,
'mod': _np.mod,
'pow': _np.power,
}
if is_op_runnable():
np_op_map.update({
'==': _np.equal,
'!=': _np.not_equal,
'>': _np.greater,
'>=': _np.greater_equal,
'<': _np.less,
'<=': _np.less_equal
})
def _get_grad_func(op, scalar=None, reverse=False):
if op == '+':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd, x1.shape),
collapse_sum_like(ograd, x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd
else:
return lambda ograd, x1, x2, out: ograd
elif op == '-':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd, x1.shape),
-collapse_sum_like(ograd, x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd
else:
return lambda ograd, x1, x2, out: -ograd
elif op == '*':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd * x2, x1.shape),
collapse_sum_like(ograd * x1, x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd * x2
else:
return lambda ograd, x1, x2, out: ograd * x1
elif op == '/':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd / x2, x1.shape),
collapse_sum_like(-x1 * ograd / (x2 * x2), x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd / x2
else:
return lambda ograd, x1, x2, out: -x1 * ograd / (x2 * x2)
elif op == 'mod':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd, x1.shape),
collapse_sum_like(-ograd * _np.floor(x1 / x2), x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd
else:
return lambda ograd, x1, x2, out: -ograd * _np.floor(x1 / x2)
elif op == 'pow':
if scalar is None:
return lambda ograd, x1, x2, out: (collapse_sum_like(ograd * x2 * _np.power(x1, x2 - 1), x1.shape),
collapse_sum_like(ograd * out * _np.log(x1), x2.shape))
elif not reverse:
return lambda ograd, x1, x2, out: ograd * x2 * _np.power(x1, x2 - 1)
else:
return lambda ograd, x1, x2, out: ograd * out * _np.log(x1)
elif op in ('==', '!=', '<', '<=', '>', '>='):
if scalar is None:
return lambda ograd, x1, x2, out: (_np.zeros_like(x1), _np.zeros_like(x2))
else:
return lambda ograd, x1, x2, out: _np.zeros_like(ograd)
return None
def get_np_ret(x1, x2, op):
return np_op_map[op](x1, x2)
@use_np
class TestBinaryElementWiseOp(HybridBlock):
def __init__(self, op, scalar=None, reverse=False):
super(TestBinaryElementWiseOp, self).__init__()
self._op = op
self._scalar = scalar
self._reverse = reverse # if false, scalar is the right operand.
def forward(self, x, *args):
if self._op == '+':
if self._scalar is not None:
return x + self._scalar if not self._reverse else self._scalar + x
else:
return x + args[0] if not self._reverse else args[0] + x
elif self._op == '*':
if self._scalar is not None:
return x * self._scalar if not self._reverse else self._scalar * x
else:
return x * args[0] if not self._reverse else args[0] * x
elif self._op == '-':
if self._scalar is not None:
return x - self._scalar if not self._reverse else self._scalar - x
else:
return x - args[0] if not self._reverse else args[0] - x
elif self._op == '/':
if self._scalar is not None:
return x / self._scalar if not self._reverse else self._scalar / x
else:
return x / args[0] if not self._reverse else args[0] / x
elif self._op == 'mod':
if self._scalar is not None:
return x % self._scalar if not self._reverse else self._scalar % x
else:
return x % args[0] if not self._reverse else args[0] % x
elif self._op == 'pow':
if self._scalar is not None:
return x ** self._scalar if not self._reverse else self._scalar ** x
else:
return x ** args[0] if not self._reverse else args[0] ** x
elif self._op == '>':
if self._scalar is not None:
return x > self._scalar if not self._reverse else self._scalar > x
else:
return x > args[0]
elif self._op == '>=':
if self._scalar is not None:
return x >= self._scalar if not self._reverse else self._scalar >= x
else:
return x >= args[0]
elif self._op == '<':
if self._scalar is not None:
return x < self._scalar if not self._reverse else self._scalar < x
else:
return x < args[0]
elif self._op == '<=':
if self._scalar is not None:
return x <= self._scalar if not self._reverse else self._scalar <= x
else:
return x <= args[0]
elif self._op == '==':
if self._scalar is not None:
return x == self._scalar if not self._reverse else self._scalar == x
else:
return x == args[0]
elif self._op == '!=':
if self._scalar is not None:
return x != self._scalar if not self._reverse else self._scalar != x
else:
return x != args[0]
else:
print(self._op)
assert False
logic_ops = ['==', '!=', '>', '<', '>=', '<=']
@use_np
def check_binary_op_result(shape1, shape2, op, dtype=None):
if shape1 is None:
mx_input1 = abs(_np.random.uniform()) + 1
np_input1 = mx_input1
else:
mx_input1 = (rand_ndarray(shape1, dtype=dtype).abs() + 1).as_np_ndarray()
mx_input1.attach_grad()
np_input1 = mx_input1.asnumpy()
if shape2 is None:
mx_input2 = abs(_np.random.uniform()) + 1
np_input2 = mx_input2
else:
mx_input2 = (rand_ndarray(shape2, dtype=dtype).abs() + 1).as_np_ndarray()
mx_input2.attach_grad()
np_input2 = mx_input2.asnumpy()
scalar = None
reverse = False
if isinstance(mx_input1, mx.nd.NDArray) and not isinstance(mx_input2, mx.nd.NDArray):
scalar = mx_input2
reverse = False
elif isinstance(mx_input2, mx.nd.NDArray) and not isinstance(mx_input1, mx.nd.NDArray):
scalar = mx_input1
reverse = True
grad_func = _get_grad_func(op, scalar, reverse)
np_out = get_np_ret(np_input1, np_input2, op)
ograd = _np.ones_like(np_out)
for hybridize in [True, False]:
if scalar is None:
get_mx_ret_np = TestBinaryElementWiseOp(op)
get_mx_ret_classic = TestBinaryElementWiseOp(op)
if hybridize:
get_mx_ret_np.hybridize()
get_mx_ret_classic.hybridize()
if grad_func is None:
mx_out = get_mx_ret_np(mx_input1, mx_input2)
else:
with mx.autograd.record():
mx_out = get_mx_ret_np(mx_input1, mx_input2)
mx_out.backward()
assert type(mx_out) == np.ndarray
if op in logic_ops:
assert np_out.dtype == mx_out.dtype
assert_almost_equal(mx_out.asnumpy(), np_out, atol=1e-6, rtol=1e-5, use_broadcast=False)
if grad_func is not None:
x1_grad_expected, x2_grad_expected = grad_func(ograd, np_input1, np_input2, np_out)
assert_almost_equal(mx_input1.grad.asnumpy(), x1_grad_expected, atol=1e-5, rtol=1e-3,
use_broadcast=False)
assert_almost_equal(mx_input2.grad.asnumpy(), x2_grad_expected, atol=1e-5, rtol=1e-3,
use_broadcast=False)
else:
get_mx_ret = TestBinaryElementWiseOp(op, scalar=scalar, reverse=reverse)
if hybridize:
get_mx_ret.hybridize()
if reverse:
mx_input = mx_input2
else:
mx_input = mx_input1
if grad_func is None:
mx_out = get_mx_ret(mx_input)
else:
with mx.autograd.record():
mx_out = get_mx_ret(mx_input)
mx_out.backward()
assert type(mx_out) == np.ndarray
if op in logic_ops:
assert np_out.dtype == mx_out.dtype
assert_almost_equal(mx_out.asnumpy(), np_out, atol=1e-6, rtol=1e-5, use_broadcast=False)
# check grad
if grad_func is not None:
x_grad_expected = grad_func(ograd, np_input1, np_input2, np_out)
assert_almost_equal(mx_input.grad.asnumpy(), x_grad_expected, atol=1e-5, rtol=1e-3,
use_broadcast=False)
dtypes = [_np.float32, _np.float64, None]
ops = np_op_map.keys()
for dtype in dtypes:
for op in ops:
check_binary_op_result((3, 4), (3, 4), op, dtype)
check_binary_op_result(None, (3, 4), op, dtype)
check_binary_op_result((3, 4), None, op, dtype)
check_binary_op_result((1, 4), (3, 1), op, dtype)
check_binary_op_result(None, (3, 1), op, dtype)
check_binary_op_result((1, 4), None, op, dtype)
check_binary_op_result((1, 4), (3, 5, 4), op, dtype)
check_binary_op_result((), (3, 5, 4), op, dtype)
check_binary_op_result((), None, op, dtype)
check_binary_op_result(None, (), op, dtype)
check_binary_op_result((0, 2), (1, 1), op, dtype)
check_binary_op_result((0, 2), None, op, dtype)
check_binary_op_result(None, (0, 2), op, dtype)
@pytest.mark.serial
def test_np_hybrid_block_multiple_outputs():
@use_np
class TestAllNumpyOutputs(HybridBlock):
def forward(self, x, *args, **kwargs):
return np.add(x, x), np.multiply(x, x)
data_np = np.ones((2, 3))
block, expected_out_type = TestAllNumpyOutputs, np.ndarray
net = block()
for hybridize in [True, False]:
if hybridize:
net.hybridize(active=hybridize)
out1, out2 = net(data_np)
assert type(out1) is expected_out_type
assert type(out2) is expected_out_type
@use_np
class TestMixedTypeOutputsFailure(HybridBlock):
def forward(self, x, *args, **kwargs):
return x.as_nd_ndarray() + x.as_nd_ndarray(), np.multiply(x, x)
net = TestMixedTypeOutputsFailure()
assert_exception(net, TypeError, data_np)
net.hybridize()
assert_exception(net, TypeError, data_np)
@use_np
def test_np_grad_ndarray_type():
data = np.array(2, dtype=_np.float32)
data.attach_grad()
assert type(data.grad) == np.ndarray
assert type(data.detach()) == np.ndarray
@use_np
@pytest.mark.serial
def test_np_ndarray_astype():
class TestAstype(HybridBlock):
def __init__(self, dtype, copy):
super(TestAstype, self).__init__()
self._dtype = dtype
self._copy = copy
def forward(self, x):
return x.astype(dtype=self._dtype, copy=self._copy)
def check_astype_equal(itype, otype, copy, expect_zero_copy=False, hybridize=False):
expect_zero_copy = copy is False and itype == otype
mx_data = np.array([2, 3, 4, 5], dtype=itype)
np_data = mx_data.asnumpy()
test_astype = TestAstype(otype, copy)
if hybridize:
test_astype.hybridize()
mx_ret = test_astype(mx_data)
assert type(mx_ret) is np.ndarray
np_ret = np_data.astype(dtype=otype, copy=copy)
assert mx_ret.dtype == np_ret.dtype
assert same(mx_ret.asnumpy(), np_ret)
if expect_zero_copy and not hybridize:
assert id(mx_ret) == id(mx_data)
assert id(np_ret) == id(np_data)
dtypes = [np.int8, np.uint8, np.int32, np.float16, np.float32, np.float64, np.bool, np.bool_,
'int8', 'uint8', 'int32', 'float16', 'float32', 'float64', 'bool']
for itype, otype in itertools.product(dtypes, dtypes):
for copy in [True, False]:
for hybridize in [True, False]:
check_astype_equal(itype, otype, copy, hybridize)
def test_np_ndarray_copy():
mx_data = np.array([2, 3, 4, 5], dtype=_np.int32)
assert_exception(mx_data.copy, NotImplementedError, order='F')
mx_ret = mx_data.copy()
np_ret = mx_data.asnumpy().copy()
assert same(mx_ret.asnumpy(), np_ret)
def test_formatting():
def test_0d():
a = np.array(np.pi)
_a = a.asnumpy()
assert '{:0.3g}'.format(a) == '{:0.3g}'.format(_a)
assert '{:0.3g}'.format(a[()]) == '{:0.3g}'.format(_a[()])
def test_nd_format():
a = np.array([np.pi])
assert_exception('{:30}'.format, TypeError, a)
def test_nd_no_format():
a = np.array([np.pi])
_a = a.asnumpy()
assert '{}'.format(a) == '{}'.format(_a)
b = np.arange(8).reshape(2,2,2)
assert '{}'.format(a) == '{}'.format(_a)
device = mx.device.current_device()
if str(device)[:3] != 'gpu':
test_0d()
test_nd_format()
test_nd_no_format()
# if the program is running in GPU, the formatted string would be appended with device notation
# for exmpale, if a = np.array([np.pi]), the return value of '{}'.format(a) is '[3.1415927] @gpu(0)'
@use_np
@pytest.mark.serial
def test_np_ndarray_indexing():
def np_int(index, int_type=_np.int32):
"""
Helper function for testing indexing that converts slices to slices of ints or None, and tuples to
tuples of ints or None.
"""
def convert(num):
if num is None:
return num
else:
return int_type(num)
if isinstance(index, slice):
return slice(convert(index.start), convert(index.stop), convert(index.step))
elif isinstance(index, tuple): # tuple of slices and integers
ret = []
for elem in index:
if isinstance(elem, slice):
ret.append(slice(convert(elem.start), convert(elem.stop), convert(elem.step)))
else:
ret.append(convert(elem))
return tuple(ret)
else:
assert False
# Copied from test_ndarray.py. Under construction.
def test_getitem(np_array, index):
np_index = index
if type(index) == mx.nd.NDArray: # use of NDArray is prohibited
assert False
if isinstance(index, np.ndarray):
np_index = index.asnumpy()
if isinstance(index, tuple):
np_index = tuple([
idx.asnumpy() if isinstance(idx, mx.nd.NDArray) else idx
for idx in index]
)
np_indexed_array = np_array[np_index]
mx_np_array = np.array(np_array, dtype=np_array.dtype)
for autograd in [True, False]:
try:
if autograd:
with mx.autograd.record():
mx_indexed_array = mx_np_array[index]
else:
mx_indexed_array = mx_np_array[index]
except Exception as e:
print('Failed with index = {}'.format(index))
raise e
mx_indexed_array = mx_indexed_array.asnumpy()
assert same(np_indexed_array, mx_indexed_array), 'Failed with index = {}'.format(index)
def test_getitem_slice_bound():
mx_array = np.arange(10)
np_array = mx_array.asnumpy()
assert_almost_equal(mx_array[100:], np_array[100:])
assert_almost_equal(mx_array[:100], np_array[:100])
assert_almost_equal(mx_array[-100:], np_array[-100:])
assert_almost_equal(mx_array[:-100], np_array[:-100])
mx_array = np.arange(81).reshape(3, 3, 3, 3)
np_array = mx_array.asnumpy()
assert_almost_equal(mx_array[100:], np_array[100:])
assert_almost_equal(mx_array[:100], np_array[:100])
assert_almost_equal(mx_array[-100:], np_array[-100:])
assert_almost_equal(mx_array[:-100], np_array[:-100])
def test_setitem(np_array, index):
def assert_same(np_array, np_index, mx_array, mx_index, mx_value, np_value=None):
if np_value is not None:
np_array[np_index] = np_value
elif isinstance(mx_value, np.ndarray):
np_array[np_index] = mx_value.asnumpy()
else:
np_array[np_index] = mx_value
try:
mx_array[mx_index] = mx_value
except Exception as e:
print('Failed with index = {}, value.shape = {}'.format(mx_index, mx_value.shape))
raise e
assert same(np_array, mx_array.asnumpy())
def _is_basic_index(index):
if isinstance(index, (integer_types, py_slice)):
return True
if isinstance(index, tuple) and all(isinstance(i, (integer_types, py_slice)) for i in index):
return True
return False
np_index = index # keep this native numpy type
if isinstance(index, np.ndarray):
np_index = index.asnumpy()
if isinstance(index, tuple):
np_index = []
for idx in index:
if isinstance(idx, np.ndarray):
np_index.append(idx.asnumpy())
else:
np_index.append(idx)
np_index = tuple(np_index)
mx_array = np.array(np_array, dtype=np_array.dtype) # mxnet.np.ndarray
np_array = mx_array.asnumpy() # native numpy array
indexed_array_shape = np_array[np_index].shape
np_indexed_array = _np.random.randint(low=-10000, high=0, size=indexed_array_shape)
# test value is a native numpy array without broadcast
assert_same(np_array, np_index, mx_array, index, np_indexed_array)
# test value is a list without broadcast
assert_same(np_array, np_index, mx_array, index, np_indexed_array.tolist())
# test value is a mxnet numpy array without broadcast
assert_same(np_array, np_index, mx_array, index, np.array(np_indexed_array))
# test value is an numeric_type
assert_same(np_array, np_index, mx_array, index, _np.random.randint(low=-10000, high=0))
np_value = _np.random.randint(low=-10000, high=0,
size=(indexed_array_shape[-1],) if len(indexed_array_shape) > 0 else ())
# test mxnet ndarray with broadcast
assert_same(np_array, np_index, mx_array, index, np.array(np_value))
# test native numpy array with broadcast
assert_same(np_array, np_index, mx_array, index, np_value)
# test python list with broadcast
assert_same(np_array, np_index, mx_array, index, np_value.tolist())
# test value shape are expanded to be longer than index array's shape
# this is currently only supported in basic indexing
if _is_basic_index(index):
expanded_value_shape = (1, 1) + np_value.shape
assert_same(np_array, np_index, mx_array, index, np.array(np_value.reshape(expanded_value_shape)))
assert_same(np_array, np_index, mx_array, index, np_value.reshape(expanded_value_shape))
if len(expanded_value_shape) <= np_array[index].ndim:
# NumPy does not allow value.ndim > np_array[index].ndim when value is a python list.
# It may be a bug of NumPy.
assert_same(np_array, np_index, mx_array, index, np_value.reshape(expanded_value_shape).tolist())
# test list with broadcast
assert_same(np_array, np_index, mx_array, index,
[_np.random.randint(low=-10000, high=0)] * indexed_array_shape[-1] if len(indexed_array_shape) > 0
else _np.random.randint(low=-10000, high=0))
def test_getitem_autograd(np_array, index):
"""
np_array: native numpy array.
"""
x = np.array(np_array, dtype=np_array.dtype)
x.attach_grad()
with mx.autograd.record():
y = x[index]
y.backward()
value = np.ones_like(y)
x_grad = np.zeros_like(x)
x_grad[index] = value
assert same(x_grad.asnumpy(), x.grad.asnumpy())
def test_setitem_autograd(np_array, index):
"""
np_array: native numpy array.
"""
x = np.array(np_array, dtype=np_array.dtype)
out_shape = x[index].shape
y = np.array(_np.random.uniform(size=out_shape))
y.attach_grad()
try:
with mx.autograd.record():
x[index] = y
x.backward()
y_grad = np.ones_like(y)
assert same(y_grad.asnumpy(), y.grad.asnumpy())
except mx.base.MXNetError as err:
assert str(err).find('Inplace operations (+=, -=, x[:]=, etc) are not supported when recording with') != -1
shape = (8, 16, 9, 9)
np_array = _np.arange(_np.prod(_np.array(shape)), dtype='int32').reshape(shape) # native np array
# Test sliced output being ndarray:
index_list = [
(),
# Basic indexing
# Single int as index
0,
_np.int32(0),
_np.int64(0),
np.array(0, dtype='int32'),
np.array(0, dtype='int64'),
5,
_np.int32(5),
_np.int64(5),
np.array(5, dtype='int32'),
np.array(5, dtype='int64'),
-1,
_np.int32(-1),
_np.int64(-1),
np.array(-1, dtype='int32'),
np.array(-1, dtype='int64'),
# Slicing as index
slice(5),
np_int(slice(5), _np.int32),
np_int(slice(5), _np.int64),
slice(1, 5),
np_int(slice(1, 5), _np.int32),
np_int(slice(1, 5), _np.int64),
slice(1, 5, 2),
slice(1, 2, 2),
np_int(slice(1, 5, 2), _np.int32),
np_int(slice(1, 5, 2), _np.int64),
slice(7, 0, -1),
np_int(slice(7, 0, -1)),
np_int(slice(7, 0, -1), _np.int64),
slice(None, 6),
np_int(slice(None, 6)),
np_int(slice(None, 6), _np.int64),
slice(None, 6, 3),
np_int(slice(None, 6, 3)),
np_int(slice(None, 6, 3), _np.int64),
slice(1, None),
np_int(slice(1, None)),
np_int(slice(1, None), _np.int64),
slice(1, None, 3),
np_int(slice(1, None, 3)),
np_int(slice(1, None, 3), _np.int64),
slice(None, None, 2),
np_int(slice(None, None, 2)),
np_int(slice(None, None, 2), _np.int64),
slice(None, None, -1),
np_int(slice(None, None, -1)),
np_int(slice(None, None, -1), _np.int64),
slice(None, None, -2),
np_int(slice(None, None, -2), _np.int32),
np_int(slice(None, None, -2), _np.int64),
# Multiple ints as indices
(1, 2, 3),
np_int((1, 2, 3)),
np_int((1, 2, 3), _np.int64),
(-1, -2, -3),
np_int((-1, -2, -3)),
np_int((-1, -2, -3), _np.int64),
(1, 2, 3, 4),
np_int((1, 2, 3, 4)),
np_int((1, 2, 3, 4), _np.int64),
(-4, -3, -2, -1),
(-4, mx.np.array(-3, dtype='int32'), -2, -1),
(-4, mx.np.array(-3, dtype='int64'), -2, -1),
np_int((-4, -3, -2, -1)),
np_int((-4, -3, -2, -1), _np.int64),
# slice(None) as indices
(slice(None), slice(None), 1, 8),
(slice(None), slice(None), np.array(1, dtype='int32'), 8),
(slice(None), slice(None), np.array(1, dtype='int64'), 8),
(slice(None), slice(None), -1, 8),
(slice(None), slice(None), 1, -8),
(slice(None), slice(None), -1, -8),
np_int((slice(None), slice(None), 1, 8)),
np_int((slice(None), slice(None), 1, 8), _np.int64),
(slice(None), slice(None), 1, 8),
np_int((slice(None), slice(None), -1, -8)),
np_int((slice(None), slice(None), -1, -8), _np.int64),
(slice(None), 2, slice(1, 5), 1),
np_int((slice(None), 2, slice(1, 5), 1)),
np_int((slice(None), 2, slice(1, 5), 1), _np.int64),
# Mixture of ints and slices as indices
(slice(None, None, -1), 2, slice(1, 5), 1),
np_int((slice(None, None, -1), 2, slice(1, 5), 1)),
np_int((slice(None, None, -1), 2, slice(1, 5), 1), _np.int64),
(slice(None, None, -1), 2, slice(1, 7, 2), 1),
np_int((slice(None, None, -1), 2, slice(1, 7, 2), 1)),
np_int((slice(None, None, -1), 2, slice(1, 7, 2), 1), _np.int64),
(slice(1, 8, 2), slice(14, 2, -2), slice(3, 8), slice(0, 7, 3)),
np_int((slice(1, 8, 2), slice(14, 2, -2), slice(3, 8), slice(0, 7, 3))),
np_int((slice(1, 8, 2), slice(14, 2, -2), slice(3, 8), slice(0, 7, 3)), _np.int64),
(slice(1, 8, 2), 1, slice(3, 8), 2),
np_int((slice(1, 8, 2), 1, slice(3, 8), 2)),
np_int((slice(1, 8, 2), 1, slice(3, 8), 2), _np.int64),
# Test Ellipsis ('...')
(1, Ellipsis, -1),
(slice(2), Ellipsis, None, 0),
# Test newaxis
None,
(1, None, -2, 3, -4),
(1, slice(2, 5), None),
(slice(None), slice(1, 4), None, slice(2, 3)),
(slice(1, 3), slice(1, 3), slice(1, 3), slice(1, 3), None),
(slice(1, 3), slice(1, 3), None, slice(1, 3), slice(1, 3)),
(None, slice(1, 2), 3, None),
(1, None, 2, 3, None, None, 4),
# Advanced indexing
([1, 2], slice(3, 5), None, None, [3, 4]),
(slice(None), slice(3, 5), None, None, [2, 3], [3, 4]),
(slice(None), slice(3, 5), None, [2, 3], None, [3, 4]),
(None, slice(None), slice(3, 5), [2, 3], None, [3, 4]),
[1],
[1, 2],
[2, 1, 3],
[7, 5, 0, 3, 6, 2, 1],
np.array([6, 3], dtype=np.int32),
np.array([[3, 4], [0, 6]], dtype=np.int32),
np.array([[7, 3], [2, 6], [0, 5], [4, 1]], dtype=np.int32),
np.array([[7, 3], [2, 6], [0, 5], [4, 1]], dtype=np.int64),
np.array([[2], [0], [1]], dtype=np.int32),
np.array([[2], [0], [1]], dtype=np.int64),
np.array([4, 7], dtype=np.int32),
np.array([4, 7], dtype=np.int64),
np.array([[3, 6], [2, 1]], dtype=np.int32),
np.array([[3, 6], [2, 1]], dtype=np.int64),
np.array([[7, 3], [2, 6], [0, 5], [4, 1]], dtype=np.int32),
np.array([[7, 3], [2, 6], [0, 5], [4, 1]], dtype=np.int64),
(1, [2, 3]),
(1, [2, 3], np.array([[3], [0]], dtype=np.int32)),
(1, [2, 3]),
(1, [2, 3], np.array([[3], [0]], dtype=np.int64)),
(1, [2], np.array([[5], [3]], dtype=np.int32), slice(None)),
(1, [2], np.array([[5], [3]], dtype=np.int64), slice(None)),
(1, [2, 3], np.array([[6], [0]], dtype=np.int32), slice(2, 5)),
(1, [2, 3], np.array([[6], [0]], dtype=np.int64), slice(2, 5)),
(1, [2, 3], np.array([[4], [7]], dtype=np.int32), slice(2, 5, 2)),
(1, [2, 3], np.array([[4], [7]], dtype=np.int64), slice(2, 5, 2)),
(1, [2], np.array([[3]], dtype=np.int32), slice(None, None, -1)),
(1, [2], np.array([[3]], dtype=np.int64), slice(None, None, -1)),
(1, [2], np.array([[3]], dtype=np.int32), np.array([[5, 7], [2, 4]], dtype=np.int64)),
(1, [2], np.array([[4]], dtype=np.int32), np.array([[1, 3], [5, 7]], dtype='int64')),
[0],
[0, 1],
[1, 2, 3],
[2, 0, 5, 6],
([1, 1], [2, 3]),
([1], [4], [5]),
([1], [4], [5], [6]),
([[1]], [[2]]),
([[1]], [[2]], [[3]], [[4]]),
(slice(0, 2), [[1], [6]], slice(0, 2), slice(0, 5, 2)),
([[[[1]]]], [[1]], slice(0, 3), [1, 5]),
([[[[1]]]], 3, slice(0, 3), [1, 3]),
([[[[1]]]], 3, slice(0, 3), 0),
([[[[1]]]], [[2], [12]], slice(0, 3), slice(None)),
([1, 2], slice(3, 5), [2, 3], [3, 4]),
([1, 2], slice(3, 5), (2, 3), [3, 4]),
range(4),
range(3, 0, -1),
(range(4,), [1]),
(1, 1, slice(None), 1),
(1, 1, slice(None, 3), 1),
(1, 1, slice(None, 8, 3), 1),
]
for index in index_list:
test_getitem(np_array, index)
test_setitem(np_array, index)
test_getitem_autograd(np_array, index)
test_setitem_autograd(np_array, index)
# Test indexing to zero-size tensors
index_list = [
(slice(0, 0), slice(0, 0), 1, 2),
(slice(0, 0), slice(0, 0), slice(0, 0), slice(0, 0)),
]
for index in index_list:
test_getitem(np_array, index)
test_setitem(np_array, index)
test_getitem_autograd(np_array, index)
test_setitem_autograd(np_array, index)
# test zero-size tensors get and setitem
shapes_indices = [
((0), [slice(None, None, None)]),
((3, 0), [2, (slice(None, None, None)), (slice(None, None, None), None)]),
]
for shape, indices in shapes_indices:
np_array = _np.zeros(shape)
for index in indices:
test_getitem(np_array, index)
test_setitem(np_array, index)
test_getitem_autograd(np_array, index)
test_setitem_autograd(np_array, index)
test_getitem_slice_bound()
@use_np
@pytest.mark.parametrize('load_fn', [_np.load, npx.load])
def test_np_save_load_large_ndarrays(load_fn, tmp_path):
weight = mx.np.arange(32768 * 512).reshape((32768, 512))
mx.npx.savez(str(tmp_path / 'params.npz'), weight=weight)
arr_loaded = load_fn(str(tmp_path / 'params.npz'))['weight']
assert _np.array_equal(arr_loaded.asnumpy() if load_fn is npx.load
else arr_loaded, weight)
@use_np
@pytest.mark.serial
@pytest.mark.parametrize('load_fn', [_np.load, npx.load])
def test_np_save_load_ndarrays(load_fn):
shapes = [(2, 0, 1), (0,), (), (), (0, 4), (), (3, 0, 0, 0), (2, 1), (0, 5, 0), (4, 5, 6), (0, 0, 0)]
array_list = [_np.random.randint(0, 10, size=shape) for shape in shapes]
array_list = [np.array(arr, dtype=arr.dtype) for arr in array_list]
# test save/load single ndarray to npy format
for i, arr in enumerate(array_list):
with TemporaryDirectory() as work_dir:
fname = os.path.join(work_dir, 'dataset.npy')
npx.save(fname, arr)
arr_loaded = load_fn(fname)
assert _np.array_equal(arr_loaded.asnumpy() if load_fn is npx.load
else arr_loaded, array_list[i].asnumpy())
# test save/load a list of ndarrays
with TemporaryDirectory() as work_dir:
fname = os.path.join(work_dir, 'dataset.npz')
npx.savez(fname, *array_list)
if load_fn is _np.load:
with load_fn(fname) as array_dict_loaded: # Ensure NPZFile is closed
array_list_loaded = [
array_dict_loaded['arr_{}'.format(str(i))]
for i in range(len(array_dict_loaded))
]
else:
array_dict_loaded = load_fn(fname)
array_list_loaded = [
array_dict_loaded['arr_{}'.format(str(i))]
for i in range(len(array_dict_loaded))
]
assert len(array_list) == len(array_list_loaded)
assert all(isinstance(arr, np.ndarray) for arr in arr_loaded)
for a1, a2 in zip(array_list, array_list_loaded):
assert _np.array_equal(a1.asnumpy(), a2.asnumpy() if load_fn is npx.load else a2)
# test save/load a dict of str->ndarray
arr_dict = {}
keys = [str(i) for i in range(len(array_list))]
for k, v in zip(keys, array_list):
arr_dict[k] = v
with TemporaryDirectory() as work_dir:
fname = os.path.join(work_dir, 'dataset.npz')
npx.savez(fname, **arr_dict)
if load_fn is _np.load:
with load_fn(fname) as arr_dict_loaded: # Ensure NPZFile is closed
assert isinstance(arr_dict_loaded, _np.lib.npyio.NpzFile)
assert len(arr_dict_loaded) == len(arr_dict)
for k, v in arr_dict_loaded.items():
assert k in arr_dict
assert _np.array_equal(v.asnumpy() if load_fn is npx.load else v, arr_dict[k].asnumpy())
else:
arr_dict_loaded = load_fn(fname)
assert isinstance(arr_dict_loaded, dict)
assert len(arr_dict_loaded) == len(arr_dict)
for k, v in arr_dict_loaded.items():
assert k in arr_dict
assert _np.array_equal(v.asnumpy() if load_fn is npx.load else v, arr_dict[k].asnumpy())
@retry(5)
@use_np
@pytest.mark.serial
def test_np_multinomial():
pvals_list = [[0.0, 0.1, 0.2, 0.3, 0.4], [0.4, 0.3, 0.2, 0.1, 0.0]]
sizes = [None, (), (3,), (2, 5, 7), (4, 9)]
experiements = 10000
for pvals_mx_np_array in [False, True]:
for have_size in [False, True]:
for pvals in pvals_list:
if pvals_mx_np_array:
pvals = mx.np.array(pvals)
if have_size:
for size in sizes:
freq = mx.np.random.multinomial(experiements, pvals, size=size).asnumpy() / _np.float32(experiements)
# for those cases that didn't need reshape
if size in [None, ()]:
if type(pvals) == np.ndarray:
mx.test_utils.assert_almost_equal(freq, pvals.asnumpy(), rtol=0.20, atol=1e-1)
else:
mx.test_utils.assert_almost_equal(freq, pvals, rtol=0.20, atol=1e-1)
else:
# check the shape
assert freq.shape == size + (len(pvals),), 'freq.shape={}, size + (len(pvals))={}'.format(freq.shape, size + (len(pvals)))
freq = freq.reshape((-1, len(pvals)))
# check the value for each row
for i in range(freq.shape[0]):
if type(pvals) == np.ndarray:
mx.test_utils.assert_almost_equal(freq[i, :], pvals.asnumpy(), rtol=0.20, atol=1e-1)
else:
mx.test_utils.assert_almost_equal(freq[i, :], pvals, rtol=0.20, atol=1e-1)
else:
freq = mx.np.random.multinomial(experiements, pvals).asnumpy() / _np.float32(experiements)
if type(pvals) == np.ndarray:
mx.test_utils.assert_almost_equal(freq, pvals.asnumpy(), rtol=0.20, atol=1e-1)
else:
mx.test_utils.assert_almost_equal(freq, pvals, rtol=0.20, atol=1e-1)
# check the zero dimension
sizes = [(0), (0, 2), (4, 0, 2), (3, 0, 1, 2, 0)]
for pvals_mx_np_array in [False, True]:
for pvals in pvals_list:
for size in sizes:
if pvals_mx_np_array:
pvals = mx.np.array(pvals)
freq = mx.np.random.multinomial(experiements, pvals, size=size).asnumpy()
assert freq.size == 0
# check [] as pvals
for pvals_mx_np_array in [False, True]:
for pvals in [[], ()]:
if pvals_mx_np_array:
pvals = mx.np.array(pvals)
freq = mx.np.random.multinomial(experiements, pvals).asnumpy()
assert freq.size == 0
for size in sizes:
freq = mx.np.random.multinomial(experiements, pvals, size=size).asnumpy()
assert freq.size == 0
# test small experiment for github issue
# https://github.com/apache/mxnet/issues/15383
small_exp, total_exp = 20, 10000
for pvals_mx_np_array in [False, True]:
for pvals in pvals_list:
if pvals_mx_np_array:
pvals = mx.np.array(pvals)
x = np.random.multinomial(small_exp, pvals)
for _ in range(total_exp // small_exp):
x = x + np.random.multinomial(20, pvals)
freq = (x.asnumpy() / _np.float32(total_exp)).reshape((-1, len(pvals)))
for i in range(freq.shape[0]):
if type(pvals) == np.ndarray:
mx.test_utils.assert_almost_equal(freq[i, :], pvals.asnumpy(), rtol=0.20, atol=1e-1)
else:
mx.test_utils.assert_almost_equal(freq[i, :], pvals, rtol=0.20, atol=1e-1)
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_single():
# adapted from numpy's test_indexing.py
# Single boolean index
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.int32)
assert same(a[np.array(True, dtype=np.bool_)].asnumpy(), a[None].asnumpy())
assert same(a[np.array(False, dtype=np.bool_)].asnumpy(), a[None][0:0].asnumpy())
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_catch_exception():
# adapted from numpy's test_indexing.py
arr = np.ones((5, 4, 3))
index = np.array([True], dtype=np.bool_)
assert_exception(arr.__getitem__, IndexError, index)
index = np.array([False] * 6, dtype=np.bool_)
assert_exception(arr.__getitem__, IndexError, index)
index = np.zeros((4, 4), dtype=bool)
assert_exception(arr.__getitem__, IndexError, index)
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_onedim():
# adapted from numpy's test_indexing.py
# Indexing a 2-dimensional array with
# boolean array of length one
a = np.array([[0., 0., 0.]])
b = np.array([True], dtype=bool)
assert same(a[b].asnumpy(), a.asnumpy())
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_twodim():
# adapted from numpy's test_indexing.py
# Indexing a 2-dimensional array with
# 2-dimensional boolean array
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.int32)
b = np.array([[ True, False, True],
[False, True, False],
[ True, False, True]], dtype=np.bool_)
assert same(a[b].asnumpy(), _np.array([1, 3, 5, 7, 9], dtype=a.dtype))
assert same(a[b[1]].asnumpy(), _np.array([[4, 5, 6]], dtype=a.dtype))
assert same(a[b[0]].asnumpy(), a[b[2]].asnumpy())
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_list():
# adapted from numpy's test_indexing.py
a = np.array([1, 2, 3], dtype=np.int32)
b = [True, False, True]
# Two variants of the test because the first takes a fast path
assert same(a[b].asnumpy(), _np.array([1, 3], dtype=a.dtype))
(a[None, b], [[1, 3]])
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_tuple():
# case arr[:, mask, :] and arr[1, mask, 0]
# when a boolean array is in a tuple
a = np.array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]], dtype=np.int32)
b = np.array([[False,True],
[True,False]],dtype=np.bool)
_np_a = a.asnumpy()
_np_b = b.asnumpy()
assert same(a[:, b].asnumpy(), _np_a[:, _np_b])
assert same(a[b, :].asnumpy(), _np_a[_np_b, :])
assert same(a[0, b].asnumpy(), _np_a[0, _np_b])
assert same(a[b, 1].asnumpy(), _np_a[_np_b, 1])
a = np.arange(12).reshape(4,3)
b = np.array([1.,2.,3.])
_np_a = a.asnumpy()
_np_b = b.asnumpy()
assert same(a[:, b > 2].shape, _np_a[:, _np_b > 2].shape)
assert same(a[:, b > 2].asnumpy(), _np_a[:, _np_b > 2])
a = np.array([[1,2,3],[3,4,5]])
_np_a = a.asnumpy()
assert same(a[:,a[1,:] > 0].shape, _np_a[:,_np_a[1,: ] > 0].shape)
assert same(a[:,a[1,:] > 0].asnumpy(), _np_a[:,_np_a[1,: ] > 0])
a = np.ones((3,2), dtype='bool')
b = np.array([1,2,3])
_np_a = a.asnumpy()
_np_b = b.asnumpy()
assert same(a[b > 1].asnumpy(), _np_a[_np_b > 1])
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
@pytest.mark.xfail(reason='Flaky boolean index assign. See #18334')
def test_boolean_index_assign():
# test boolean indexing assign
shape = (3, 2, 3)
mx_data = np.random.uniform(size=shape)
mx_mask = np.array([[False,True], [True,False], [True,False]],dtype=np.bool)
np_data = mx_data.asnumpy()
np_mask = mx_mask.asnumpy()
np_data[np_data>0.5] = 0
mx_data[mx_data>0.5] = 0
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[np_mask] = 1
mx_data[mx_mask] = 1
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[np_mask, 1] = 2
mx_data[mx_mask, 1] = 2
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[np_mask, :] = 3
mx_data[mx_mask, :] = 3
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
mx_mask = np.array([[False,True, True],[False, True,False]],dtype=np.bool)
np_mask = mx_mask.asnumpy()
np_data[0, np_mask] = 5
mx_data[0, mx_mask] = 5
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[:, np_mask] = 6
mx_data[:, mx_mask] = 6
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[0, True, True, np_mask] = 7
mx_data[0, True, True, mx_mask] = 7
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
np_data[False, 1] = 8
mx_data[False, 1] = 8
assert_almost_equal(mx_data.asnumpy(), np_data, rtol=1e-3, atol=1e-5, use_broadcast=False)
@pytest.mark.skipif(not is_op_runnable(), reason="Comparison ops can only run on either CPU instances, or GPU instances with"
" compute capability >= 53 if MXNet is built with USE_TVM_OP=ON")
@use_np
def test_boolean_index_autograd():
a = np.random.uniform(size=(3, 4, 5))
a.attach_grad()
with mx.autograd.record():
out_mx = a[a < 0.5]
out_mx.backward()
a_np = a.asnumpy()
out_np = a_np[a_np < 0.5]
assert_almost_equal(out_mx.asnumpy(), out_np, rtol=1e-4, atol=1e-5, use_broadcast=False)
a_grad_np = _np.zeros(a.shape, dtype=a.dtype)
a_grad_np[a_np < 0.5] = 1
assert_almost_equal(a.grad.asnumpy(), a_grad_np, rtol=1e-4, atol=1e-5, use_broadcast=False)
@use_np
def test_np_get_dtype():
dtypes = [_np.int8, _np.int32, _np.float16, _np.float32, _np.float64, _np.bool, _np.bool_,
'int8', 'int32', 'float16', 'float32', 'float64', 'bool', None]
objects = [
[],
(),
[[1, 2], [3, 4]],
_np.random.uniform(size=rand_shape_nd(3)),
_np.random.uniform(size=(3, 0, 4))
]
for dtype in dtypes:
for src in objects:
mx_arr = np.array(src, dtype=dtype)
assert mx_arr.device == mx.current_device()
if isinstance(src, mx.nd.NDArray):
np_arr = _np.array(src.asnumpy(), dtype=dtype if dtype is not None else _np.float32)
else:
np_arr = _np.array(src, dtype=dtype if dtype is not None else _np.float32)
assert type(mx_arr.dtype) == type(np_arr.dtype)
@use_np
def test_np_ndarray_pickle():
a = np.random.uniform(size=(4, 5))
a_copy = a.copy()
import pickle
with TemporaryDirectory() as work_dir:
fname = os.path.join(work_dir, 'np_ndarray_pickle_test_file')
with open(fname, 'wb') as f:
pickle.dump(a_copy, f)
with open(fname, 'rb') as f:
a_load = pickle.load(f)
same(a.asnumpy(), a_load.asnumpy())
@pytest.mark.parametrize('dtype', [np.float32, np.int32])
@pytest.mark.parametrize('size', [
(3, 4, 5, 6),
(2, 10),
(15,),
()
])
@use_np
def test_dlpack(dtype, size):
a = mx.np.random.uniform(size=size)
a_np = a.copy()
a += 1
pack = mx.npx.to_dlpack_for_read(a)
b = mx.npx.from_dlpack(pack)
a_copy = a.copy()
pack2 = mx.npx.to_dlpack_for_write(a_copy)
c = mx.npx.from_dlpack(pack2)
c += 1
del a, pack, pack2
same(a_np+1, b)
same(a_np+2, c)
same(a_np+2, a_copy)
@use_np
@pytest.mark.parametrize('np_array', [
# ordinary numpy array
_np.array([[1, 2], [3, 4], [5, 6]], dtype="float32"),
# 0-dim
_np.array((1, )).reshape(()),
# 0-size
_np.array(()).reshape((1, 0, 2)),
])
@pytest.mark.parametrize('zero_copy', [False, True])
def test_from_numpy(np_array, zero_copy):
# Test zero_copy
mx_array = mx.npx.from_numpy(np_array, zero_copy=zero_copy)
mx.test_utils.assert_almost_equal(np_array, mx_array.asnumpy())
def test_from_numpy_exception():
np_array = _np.array([[1, 2], [3, 4], [5, 6]], dtype="float32")
mx_array = mx.npx.from_numpy(np_array)
with pytest.raises(ValueError):
np_array[2, 1] = 0
mx_array[2, 1] = 100
mx.test_utils.assert_almost_equal(np_array, mx_array.asnumpy())
np_array = _np.array([[1, 2], [3, 4], [5, 6]]).transpose()
assert not np_array.flags["C_CONTIGUOUS"]
with pytest.raises(ValueError):
mx_array = mx.nd.from_numpy(np_array)
np_array = _np.array([[1, 2], [3, 4], [5, 6]], dtype="float32")
mx_array = mx.npx.from_numpy(np_array, zero_copy=False)
np_array[2, 1] = 0 # no error
def test_mixed_array_types():
np_array = _np.array([[1, 2], [3, 4], [5, 6]], dtype="float32")
mx_array = mx.np.ones((3, 1))
assert_almost_equal(mx_array + np_array, 1+np_array)
def test_mixed_array_types_share_memory():
np_array = _np.array([[1, 2], [3, 4], [5, 6]], dtype="float32")
mx_array = mx.npx.from_numpy(np_array)
assert _np.may_share_memory(np_array, mx_array)
assert _np.shares_memory(np_array, mx_array)
np_array_slice = np_array[:2]
mx_array_slice = mx_array[1:]
assert _np.may_share_memory(np_array_slice, mx_array)
assert _np.shares_memory(np_array_slice, mx_array)
mx_pinned_array = mx_array.to_device(mx.cpu_pinned(0))
assert not _np.may_share_memory(np_array, mx_pinned_array)
assert not _np.shares_memory(np_array, mx_pinned_array)
@use_np
def test_save_load_empty(tmp_path):
mx.npx.savez(str(tmp_path / 'params.npz'))
mx.npx.load(str(tmp_path / 'params.npz'))
@use_np
@pytest.mark.parametrize('shape', [
(),
(1,),
(1,2)
])
@pytest.mark.parametrize('dtype', ['float16', 'float32', 'float64', 'bool', 'int32'])
def test_index_operator(shape, dtype):
if len(shape) >= 1 or not _np.issubdtype(dtype, _np.integer):
x = np.ones(shape=shape, dtype=dtype)
pytest.raises(TypeError, operator.index, x)
else:
assert operator.index(np.ones(shape=shape, dtype=dtype)) == \
operator.index(_np.ones(shape=shape, dtype=dtype))
@pytest.mark.parametrize('api_version, raise_exception', [
(None, False),
('2021.10', False),
('2020.09', True),
('2021.24', True),
])
def test_array_namespace(api_version, raise_exception):
x = np.array([1, 2, 3], dtype="float64")
if raise_exception:
pytest.raises(ValueError, x.__array_namespace__, api_version)
else:
xp = x.__array_namespace__(api_version)
y = xp.array([1, 2, 3], dtype="float64")
assert same(x, y)