| # 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. |
| |
| import os |
| import mxnet as mx |
| import numpy as np |
| import pickle as pkl |
| |
| |
| def _np_reduce(dat, axis, keepdims, numpy_reduce_func): |
| if isinstance(axis, int): |
| axis = [axis] |
| else: |
| axis = list(axis) if axis is not None else range(len(dat.shape)) |
| ret = dat |
| for i in reversed(sorted(axis)): |
| ret = numpy_reduce_func(ret, axis=i) |
| if keepdims: |
| keepdims_shape = list(dat.shape) |
| for i in axis: |
| keepdims_shape[i] = 1 |
| ret = ret.reshape(tuple(keepdims_shape)) |
| return ret |
| |
| |
| def reldiff(a, b): |
| diff = np.abs(a - b) |
| norm = np.abs(a) |
| reldiff = np.max(diff / (norm + 1e-7)) |
| return reldiff |
| |
| |
| def same(a, b): |
| return np.sum(a != b) == 0 |
| |
| |
| def check_with_uniform(uf, arg_shapes, dim=None, npuf=None, rmin=-10, type_list=[np.float32]): |
| """check function consistency with uniform random numbers""" |
| if isinstance(arg_shapes, int): |
| assert dim |
| shape = tuple(np.random.randint(1, int(1000**(1.0/dim)), size=dim)) |
| arg_shapes = [shape] * arg_shapes |
| for dtype in type_list: |
| ndarray_arg = [] |
| numpy_arg = [] |
| for s in arg_shapes: |
| npy = np.random.uniform(rmin, 10, s).astype(dtype) |
| narr = mx.nd.array(npy, dtype=dtype) |
| ndarray_arg.append(narr) |
| numpy_arg.append(npy) |
| out1 = uf(*ndarray_arg) |
| if npuf is None: |
| out2 = uf(*numpy_arg).astype(dtype) |
| else: |
| out2 = npuf(*numpy_arg).astype(dtype) |
| |
| assert out1.shape == out2.shape |
| if isinstance(out1, mx.nd.NDArray): |
| out1 = out1.asnumpy() |
| if dtype == np.float16: |
| assert reldiff(out1, out2) < 2e-3 |
| else: |
| assert reldiff(out1, out2) < 1e-6 |
| |
| |
| def random_ndarray(dim): |
| shape = tuple(np.random.randint(1, int(1000**(1.0/dim)), size=dim)) |
| data = mx.nd.array(np.random.uniform(-10, 10, shape)) |
| return data |
| |
| |
| def test_ndarray_elementwise(): |
| np.random.seed(0) |
| nrepeat = 10 |
| maxdim = 4 |
| all_type = [np.float32, np.float64, np.float16, np.uint8, np.int32] |
| real_type = [np.float32, np.float64, np.float16] |
| for repeat in range(nrepeat): |
| for dim in range(1, maxdim): |
| check_with_uniform(lambda x, y: x + y, 2, dim, type_list=all_type) |
| check_with_uniform(lambda x, y: x - y, 2, dim, type_list=all_type) |
| check_with_uniform(lambda x, y: x * y, 2, dim, type_list=all_type) |
| check_with_uniform(lambda x, y: x / y, 2, dim, type_list=real_type) |
| check_with_uniform(lambda x, y: x / y, 2, dim, rmin=1, type_list=all_type) |
| check_with_uniform(mx.nd.sqrt, 1, dim, np.sqrt, rmin=0) |
| check_with_uniform(mx.nd.square, 1, dim, np.square, rmin=0) |
| check_with_uniform(lambda x: mx.nd.norm(x).asscalar(), 1, dim, np.linalg.norm) |
| |
| |
| def test_ndarray_negate(): |
| npy = np.random.uniform(-10, 10, (2,3,4)) |
| arr = mx.nd.array(npy) |
| assert reldiff(npy, arr.asnumpy()) < 1e-6 |
| assert reldiff(-npy, (-arr).asnumpy()) < 1e-6 |
| |
| # a final check to make sure the negation (-) is not implemented |
| # as inplace operation, so the contents of arr does not change after |
| # we compute (-arr) |
| assert reldiff(npy, arr.asnumpy()) < 1e-6 |
| |
| |
| def test_ndarray_choose(): |
| shape = (100, 20) |
| npy = np.arange(np.prod(shape)).reshape(shape) |
| arr = mx.nd.array(npy) |
| nrepeat = 3 |
| for repeat in range(nrepeat): |
| indices = np.random.randint(shape[1], size=shape[0]) |
| assert same(npy[np.arange(shape[0]), indices], |
| mx.nd.choose_element_0index(arr, mx.nd.array(indices)).asnumpy()) |
| |
| |
| def test_ndarray_fill(): |
| shape = (100, 20) |
| npy = np.arange(np.prod(shape)).reshape(shape) |
| arr = mx.nd.array(npy) |
| new_npy = npy.copy() |
| nrepeat = 3 |
| for repeat in range(nrepeat): |
| indices = np.random.randint(shape[1], size=shape[0]) |
| val = np.random.randint(shape[1], size=shape[0]) |
| new_npy[:] = npy |
| new_npy[np.arange(shape[0]), indices] = val |
| assert same(new_npy, |
| mx.nd.fill_element_0index(arr, mx.nd.array(val), mx.nd.array(indices)).asnumpy()) |
| |
| |
| def test_ndarray_onehot(): |
| shape = (100, 20) |
| npy = np.arange(np.prod(shape)).reshape(shape) |
| arr = mx.nd.array(npy) |
| nrepeat = 3 |
| for repeat in range(nrepeat): |
| indices = np.random.randint(shape[1], size=shape[0]) |
| npy[:] = 0.0 |
| npy[np.arange(shape[0]), indices] = 1.0 |
| mx.nd.onehot_encode(mx.nd.array(indices), out=arr) |
| assert same(npy, arr.asnumpy()) |
| |
| |
| def test_ndarray_copy(): |
| c = mx.nd.array(np.random.uniform(-10, 10, (10, 10))) |
| d = c.copyto(mx.Context('cpu', 0)) |
| assert np.sum(np.abs(c.asnumpy() != d.asnumpy())) == 0.0 |
| |
| |
| def test_ndarray_scalar(): |
| c = mx.nd.empty((10,10)) |
| d = mx.nd.empty((10,10)) |
| c[:] = 0.5 |
| d[:] = 1.0 |
| d -= c * 2 / 3 * 6.0 |
| c += 0.5 |
| assert(np.sum(c.asnumpy()) - 100 < 1e-5) |
| assert(np.sum(d.asnumpy()) + 100 < 1e-5) |
| c[:] = 2 |
| assert(np.sum(c.asnumpy()) - 200 < 1e-5) |
| d = -c + 2 |
| assert(np.sum(d.asnumpy()) < 1e-5) |
| |
| |
| def test_ndarray_pickle(): |
| np.random.seed(0) |
| maxdim = 5 |
| nrepeat = 10 |
| for repeat in range(nrepeat): |
| for dim in range(1, maxdim): |
| a = random_ndarray(dim) |
| b = mx.nd.empty(a.shape) |
| a[:] = np.random.uniform(-10, 10, a.shape) |
| b[:] = np.random.uniform(-10, 10, a.shape) |
| a = a + b |
| data = pkl.dumps(a) |
| a2 = pkl.loads(data) |
| assert np.sum(a.asnumpy() != a2.asnumpy()) == 0 |
| |
| |
| def test_ndarray_saveload(): |
| np.random.seed(0) |
| maxdim = 5 |
| nrepeat = 10 |
| fname = 'tmp_list.bin' |
| for repeat in range(nrepeat): |
| data = [] |
| for i in range(10): |
| data.append(random_ndarray(np.random.randint(1, 5))) |
| mx.nd.save(fname, data) |
| data2 = mx.nd.load(fname) |
| assert len(data) == len(data2) |
| for x, y in zip(data, data2): |
| assert np.sum(x.asnumpy() != y.asnumpy()) == 0 |
| dmap = {f'ndarray xx {i}': x for i, x in enumerate(data)} |
| mx.nd.save(fname, dmap) |
| dmap2 = mx.nd.load(fname) |
| assert len(dmap2) == len(dmap) |
| for k, x in dmap.items(): |
| y = dmap2[k] |
| assert np.sum(x.asnumpy() != y.asnumpy()) == 0 |
| os.remove(fname) |
| |
| |
| def test_ndarray_slice(): |
| shape = (10,) |
| A = mx.nd.array(np.random.uniform(-10, 10, shape)) |
| A2 = A.asnumpy() |
| assert same(A[3:8].asnumpy(), A2[3:8]) |
| A2[3:8] *= 10; |
| A[3:8] = A2[3:8] |
| assert same(A[3:8].asnumpy(), A2[3:8]) |
| |
| |
| def test_ndarray_slice_along_axis(): |
| arr = mx.nd.array(np.random.uniform(-10, 10, (3, 4, 2, 3))) |
| sub_arr = arr.slice(begin=(None, 1), end=(None, 3)) |
| |
| # test we sliced correctly |
| assert same(arr.asnumpy()[:, 1:3, :, :], sub_arr.asnumpy()) |
| |
| # test that slice is copy, instead of shared memory |
| sub_arr[:] = 0 |
| assert not same(arr.asnumpy()[:, 1:3, :, :], sub_arr.asnumpy()) |
| |
| |
| def test_clip(): |
| shape = (10,) |
| A = mx.random.uniform(-10, 10, shape) |
| B = mx.nd.clip(A, -2, 2) |
| B1 = B.asnumpy() |
| for i in range(shape[0]): |
| assert B1[i] >= -2 |
| assert B1[i] <= 2 |
| |
| |
| def test_dot(): |
| a = np.random.uniform(-3, 3, (3, 4)) |
| b = np.random.uniform(-3, 3, (4, 5)) |
| c = np.dot(a, b) |
| A = mx.nd.array(a) |
| B = mx.nd.array(b) |
| C = mx.nd.dot(A, B) |
| assert reldiff(c, C.asnumpy()) < 1e-5 |
| |
| |
| def test_reduce(): |
| sample_num = 200 |
| |
| def test_reduce_inner(numpy_reduce_func, nd_reduce_func): |
| for i in range(sample_num): |
| ndim = np.random.randint(1, 6) |
| shape = np.random.randint(1, 11, size=ndim) |
| axis_flags = np.random.randint(0, 2, size=ndim) |
| axes = [] |
| for (axis, flag) in enumerate(axis_flags): |
| if flag: |
| axes.append(axis) |
| keepdims = np.random.randint(0, 2) |
| dat = np.random.rand(*shape) - 0.5 |
| if 0 == len(axes): |
| axes = tuple(range(ndim)) |
| else: |
| axes = tuple(axes) |
| numpy_ret = numpy_reduce_func(dat, axis=axes, keepdims=keepdims) |
| |
| ndarray_ret = nd_reduce_func(mx.nd.array(dat), axis=axes, keepdims=keepdims) |
| if type(ndarray_ret) is mx.ndarray.NDArray: |
| ndarray_ret = ndarray_ret.asnumpy() |
| assert (ndarray_ret.shape == numpy_ret.shape) or \ |
| (ndarray_ret.shape == (1,) and numpy_ret.shape == ()), \ |
| f"nd:{ndarray_ret.shape}, numpy:{numpy_ret.shape}" |
| err = np.square(ndarray_ret - numpy_ret).mean() |
| assert err < 1E-4 |
| test_reduce_inner(lambda data, axis, keepdims:_np_reduce(data, axis, keepdims, np.sum), |
| mx.nd.sum) |
| test_reduce_inner(lambda data, axis, keepdims:_np_reduce(data, axis, keepdims, np.max), |
| mx.nd.max) |
| test_reduce_inner(lambda data, axis, keepdims:_np_reduce(data, axis, keepdims, np.min), |
| mx.nd.min) |
| |
| |
| def test_broadcast(): |
| sample_num = 1000 |
| |
| def test_broadcast_to(): |
| for i in range(sample_num): |
| ndim = np.random.randint(1, 6) |
| target_shape = np.random.randint(1, 11, size=ndim) |
| shape = target_shape.copy() |
| axis_flags = np.random.randint(0, 2, size=ndim) |
| axes = [] |
| for (axis, flag) in enumerate(axis_flags): |
| if flag: |
| shape[axis] = 1 |
| dat = np.random.rand(*shape) - 0.5 |
| numpy_ret = dat |
| ndarray_ret = mx.nd.array(dat).broadcast_to(shape=target_shape) |
| if type(ndarray_ret) is mx.ndarray.NDArray: |
| ndarray_ret = ndarray_ret.asnumpy() |
| assert (ndarray_ret.shape == target_shape).all() |
| err = np.square(ndarray_ret - numpy_ret).mean() |
| assert err < 1E-8 |
| test_broadcast_to() |
| |
| |
| if __name__ == '__main__': |
| mx.profiler.set_config(profile_all=True, filename='profile_ndarray.json') |
| mx.profiler.set_state('run') |
| test_ndarray_slice_along_axis() |
| test_broadcast() |
| test_ndarray_elementwise() |
| test_ndarray_slice() |
| test_ndarray_pickle() |
| test_ndarray_saveload() |
| test_ndarray_copy() |
| test_ndarray_negate() |
| test_ndarray_scalar() |
| test_clip() |
| test_dot() |
| test_ndarray_choose() |
| test_ndarray_onehot() |
| test_ndarray_fill() |
| test_reduce() |
| mx.profiler.set_state('stop') |