You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by GitBox <gi...@apache.org> on 2018/02/18 11:12:05 UTC

[GitHub] marcoabreu closed pull request #9791: CI test randomness 3

marcoabreu closed pull request #9791: CI test randomness 3
URL: https://github.com/apache/incubator-mxnet/pull/9791
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/python/mxnet/test_utils.py b/python/mxnet/test_utils.py
index c159f47e9c..1f3853b3cd 100644
--- a/python/mxnet/test_utils.py
+++ b/python/mxnet/test_utils.py
@@ -49,8 +49,6 @@
 from .ndarray import array
 from .symbol import Symbol
 
-_rng = np.random.RandomState(1234)
-
 
 def default_context():
     """Get default context for regression test."""
@@ -844,7 +842,7 @@ def random_projection(shape):
         """
         # random_projection should not have elements too small,
         # otherwise too much precision is lost in numerical gradient
-        plain = _rng.rand(*shape) + 0.1
+        plain = np.random.rand(*shape) + 0.1
         return plain
 
     location = _parse_location(sym=sym, location=location, ctx=ctx, dtype=dtype)
@@ -876,8 +874,9 @@ def random_projection(shape):
     location = dict(list(location.items()) +
                     [("__random_proj", mx.nd.array(random_projection(out_shape[0]),
                                                    ctx=ctx, dtype=dtype))])
-    args_grad_npy = dict([(k, _rng.normal(0, 0.01, size=location[k].shape)) for k in grad_nodes]
-                         + [("__random_proj", _rng.normal(0, 0.01, size=out_shape[0]))])
+    args_grad_npy = dict([(k, np.random.normal(0, 0.01, size=location[k].shape))
+                          for k in grad_nodes]
+                         + [("__random_proj", np.random.normal(0, 0.01, size=out_shape[0]))])
 
     args_grad = {k: mx.nd.array(v, ctx=ctx, dtype=dtype) for k, v in args_grad_npy.items()}
     if grad_stype_dict is not None:
@@ -1068,7 +1067,7 @@ def check_symbolic_backward(sym, location, out_grads, expected, rtol=1e-5, atol=
     if isinstance(expected, (list, tuple)):
         expected = {k:v for k, v in zip(sym.list_arguments(), expected)}
 
-    args_grad_npy = {k:_rng.normal(size=v.shape) for k, v in expected.items()}
+    args_grad_npy = {k:np.random.normal(size=v.shape) for k, v in expected.items()}
     args_grad_data = {}
     for k, v in args_grad_npy.items():
         nd = mx.nd.array(v, ctx=ctx, dtype=dtype)
@@ -1162,7 +1161,7 @@ def check_speed(sym, location=None, ctx=None, N=20, grad_req=None, typ="whole",
         grad_req = 'write'
     if location is None:
         exe = sym.simple_bind(grad_req=grad_req, ctx=ctx, **kwargs)
-        location = {k: _rng.normal(size=arr.shape, scale=1.0) for k, arr in
+        location = {k: np.random.normal(size=arr.shape, scale=1.0) for k, arr in
                     exe.arg_dict.items()}
     else:
         assert isinstance(location, dict), "Expect dict, get \"location\"=%s" %str(location)
diff --git a/tests/python/gpu/test_forward.py b/tests/python/gpu/test_forward.py
index aae62065a6..453161fcfe 100644
--- a/tests/python/gpu/test_forward.py
+++ b/tests/python/gpu/test_forward.py
@@ -15,10 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import sys
 import os
 import numpy as np
 import mxnet as mx
 from mxnet.test_utils import *
+curr_path = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
+sys.path.insert(0, os.path.join(curr_path, '../unittest'))
+from common import setup_module, with_seed
 from mxnet.gluon import utils
 
 def _get_model():
@@ -51,6 +55,7 @@ def _get_data(shape):
                    path='data/inception-v3-dump.npz',
                    sha1_hash=hash_inception_v3)
 
+@with_seed()
 def test_consistency(dump=False):
     shape = (299, 299)
     _get_model()
diff --git a/tests/python/gpu/test_gluon_model_zoo_gpu.py b/tests/python/gpu/test_gluon_model_zoo_gpu.py
index aebbed63bd..6456436a9b 100644
--- a/tests/python/gpu/test_gluon_model_zoo_gpu.py
+++ b/tests/python/gpu/test_gluon_model_zoo_gpu.py
@@ -23,7 +23,11 @@
 from mxnet.gluon.model_zoo.vision import get_model
 from mxnet.test_utils import assert_almost_equal
 import sys
+import os
 import unittest
+curr_path = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
+sys.path.insert(0, os.path.join(curr_path, '../unittest'))
+from common import setup_module, with_seed
 
 def eprint(*args, **kwargs):
     print(*args, file=sys.stderr, **kwargs)
@@ -34,6 +38,7 @@ def download_data():
         'http://data.mxnet.io/data/val-5k-256.rec', VAL_DATA)
 
 @unittest.skip("test fails intermittently. temporarily disabled.")
+@with_seed()
 def test_inference():
     all_models = ['resnet50_v1', 'vgg19_bn', 'alexnet', #'inceptionv3',
                   'densenet201', 'squeezenet1.0', 'mobilenet0.25']
@@ -91,6 +96,10 @@ def get_nn_model(name):
     else:
         return get_model(name)
 
+# Seed 1521019752 produced a failure on the Py2 MKLDNN-GPU CI runner
+# on 2/16/2018 that was not reproducible.  Problem could be timing related or
+# based on non-deterministic algo selection.
+@with_seed()
 def test_training():
     # We use network models without dropout for testing.
     # TODO(zhengda) mobilenet can't pass this test even without MKLDNN.
diff --git a/tests/python/gpu/test_kvstore_gpu.py b/tests/python/gpu/test_kvstore_gpu.py
index 3249c98b2d..5fd3097f29 100644
--- a/tests/python/gpu/test_kvstore_gpu.py
+++ b/tests/python/gpu/test_kvstore_gpu.py
@@ -16,10 +16,15 @@
 # under the License.
 
 # pylint: skip-file
+import sys
+import os
 import mxnet as mx
 import numpy as np
 import unittest
 from mxnet.test_utils import assert_almost_equal, default_context
+curr_path = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
+sys.path.insert(0, os.path.join(curr_path, '../unittest'))
+from common import setup_module, with_seed
 
 shape = (4, 4)
 keys = [5, 7, 11]
@@ -35,7 +40,9 @@ def init_kv_with_str(stype='default', kv_type='local'):
     kv.init(str_keys, [mx.nd.zeros(shape=shape, stype=stype)] * len(keys))
     return kv
 
-
+# Test seed 89411477 (module seed 1829754103) resulted in a py3-gpu CI runner core dump.
+# Not reproducible, so this test is back on random seeds.
+@with_seed()
 def test_rsp_push_pull():
     def check_rsp_push_pull(kv_type, is_push_cpu=True):
         kv = init_kv_with_str('row_sparse', kv_type)
diff --git a/tests/python/gpu/test_operator_gpu.py b/tests/python/gpu/test_operator_gpu.py
index 2fdd96db95..2cef29c03f 100644
--- a/tests/python/gpu/test_operator_gpu.py
+++ b/tests/python/gpu/test_operator_gpu.py
@@ -29,6 +29,7 @@
 
 curr_path = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
 sys.path.insert(0, os.path.join(curr_path, '../unittest'))
+from common import setup_module, with_seed
 from test_operator import *
 from test_optimizer import *
 from test_random import *
@@ -87,8 +88,8 @@ def check_countsketch(in_dim,out_dim,n):
                 a[j,i] = out_grad.asnumpy()[j, h[0,i]] * s[0,i]
     assert_almost_equal(a,arr_grad[0].asnumpy(),rtol=1e-3, atol=1e-12)
 
+@with_seed(0)
 def test_countsketch():
-    np.random.seed(0)
     nrepeat = 2
     minindim = 40
     maxindim = 100
@@ -101,6 +102,7 @@ def test_countsketch():
         n = np.random.randint(1,maxn)
         check_countsketch(in_dim, out_dim, n)
 
+
 def check_ifft(shape):
     shape_old = shape
     if len(shape) == 2:
@@ -172,9 +174,8 @@ def check_ifft(shape):
         a = np.fft.fft(out_grad.asnumpy(), n=None, axis=-1, norm=None)
         assert_almost_equal(a.real, temp, rtol=1e-3, atol=1e-12)
 
-
+@with_seed(0)
 def test_ifft():
-    np.random.seed(0)
     nrepeat = 2
     maxdim = 10
     for repeat in range(nrepeat):
@@ -182,6 +183,7 @@ def test_ifft():
             shape = tuple(np.random.randint(1, maxdim, size=order))
             check_ifft(shape)
 
+
 def check_fft(shape):
     sym = mx.sym.contrib.fft(name='fft', compute_size = 128)
     if len(shape) == 2:
@@ -260,8 +262,8 @@ def check_fft(shape):
         a = np.fft.ifft(out_grad_complex, n=None, axis=-1, norm=None)
         assert_almost_equal(a.real, exe.grad_arrays[0].asnumpy()/shape[3],rtol=1e-3, atol=1e-6)
 
+@with_seed(0)
 def test_fft():
-    np.random.seed(0)
     nrepeat = 2
     maxdim = 10
     for repeat in range(nrepeat):
@@ -269,6 +271,8 @@ def test_fft():
             shape = tuple(np.random.randint(1, maxdim, size=order))
             check_fft(shape)
 
+
+@with_seed()
 def test_batchnorm_with_type():
   ctx_list_v1_2D = [
     {'ctx': mx.cpu(0), 'norm_data': (10, 2, 10, 10), 'type_dict': {'norm_data': np.float32}},
@@ -336,6 +340,7 @@ def test_batchnorm_with_type():
   check_consistency(sym, ctx_list_v2_3D)
 
 
+@with_seed()
 def test_batchnorm_versions():
   def test_batchnorm_versions_helper(batchnorm_op_list, data, fix_gamma, use_global_stats):
     ctx_list = []
@@ -415,8 +420,8 @@ def test_3d_batchnorm(fix_gamma, use_global_stats):
   test_3d_batchnorm(True,  True)
 
 
+@with_seed(1234)
 def test_convolution_with_type():
-    np.random.seed(1234)
     sym1 = mx.sym.Convolution(num_filter=3, kernel=(3,3), name='conv')
 
     data = mx.sym.Variable('conv_data')
@@ -449,12 +454,14 @@ def test_convolution_with_type():
     # test ability to turn off training on bias
     check_consistency(sym, ctx_list, grad_req={'conv_data': 'write', 'conv_weight': 'write', 'conv_bias': 'null'}, tol=tol)
 
+
 # Apply N symbols against each of M contexts, checking that all NxM combinations match.
 def check_consistency_NxM(sym_list, ctx_list):
     # e.g. if sym_list=[sym1, sym2] and ctx_list=[ctx1, ctx2, ctx3], then resulting lists are:
     # sym_list=[sym1, sym1, sym1, sym2, sym2, sym2] and ctx_list=[ctx1, ctx2, ctx3, ctx1, ctx2, ctx3]
     check_consistency(np.repeat(sym_list, len(ctx_list)), ctx_list * len(sym_list))
 
+@with_seed()
 def test_convolution_options():
     # 1D convolution
     ctx_list = [{'ctx': mx.gpu(0), 'conv_data': (2, 2, 7), 'type_dict': {'conv_data': np.float64}},
@@ -520,6 +527,8 @@ def test_convolution_options():
     sym_no_cudnn = mx.sym.Convolution(num_filter=3, kernel=(1,1,1), pad=(0,0,0), cudnn_off=True, name='conv')
     check_consistency_NxM([sym, sym_no_cudnn], ctx_list)
 
+
+@with_seed()
 def test_convolution_versions():
     # 2D convolution NCHW
     ctx_list = [{'ctx': mx.cpu(0), 'conv_data': (2, 2, 7, 7), 'type_dict': {'conv_data': np.float32}},
@@ -545,6 +554,8 @@ def test_convolution_versions():
     syms = [conv_cudnn, conv_cpu, conv_gpu]
     check_consistency(syms, ctx_list)
 
+
+@with_seed()
 def test_pooling_with_type():
     ctx_list = [{'ctx': mx.gpu(0), 'pool_data': (2, 2, 10, 10), 'type_dict': {'pool_data': np.float64}},
                 {'ctx': mx.gpu(0), 'pool_data': (2, 2, 10, 10), 'type_dict': {'pool_data': np.float32}},
@@ -560,6 +571,8 @@ def test_pooling_with_type():
     sym = mx.sym.Pooling(kernel=(300,300), pool_type='max', global_pool=True, name='pool')
     check_consistency(sym, ctx_list)
 
+
+@with_seed()
 def test_deconvolution_with_type():
     # Test basic deconvolution without exercising stride, pad or dilation.
     # 1D deconvolution
@@ -594,6 +607,8 @@ def test_deconvolution_with_type():
     check_consistency(sym, ctx_list, tol=tol)
     check_consistency(sym, ctx_list, tol=tol, grad_req="add")
 
+
+@with_seed()
 def test_deconvolution_options():
 
     # 1D deconvolution
@@ -648,8 +663,9 @@ def test_deconvolution_options():
 #    sym_no_cudnn = mx.sym.Convolution(num_filter=3, kernel=(2,3,3), stride=(2,2,2), cudnn_off=True, name='conv')
 #    check_consistency_NxM([sym, sym_no_cudnn], ctx_list)
 
+
+@with_seed(1234)
 def test_bilinear_sampler_with_type():
-    np.random.seed(1234)
     data = mx.sym.Variable('data')
     grid = mx.sym.Variable('grid')
     sym = mx.sym.BilinearSampler(data=data, grid=grid)
@@ -666,6 +682,8 @@ def test_bilinear_sampler_with_type():
     check_consistency(sym, ctx_list)
     check_consistency(sym, ctx_list, grad_req="add")
 
+
+@with_seed()
 def test_grid_generator_with_type():
     data = mx.sym.Variable('data')
     sym = mx.sym.GridGenerator(data=data, transform_type='affine', target_shape=(20, 20))
@@ -679,9 +697,10 @@ def test_grid_generator_with_type():
     check_consistency(sym, ctx_list)
     check_consistency(sym, ctx_list, grad_req="add")
 
+
 @unittest.skip("test fails intermittently. temporarily disabled till it gets fixed. tracked at https://github.com/apache/incubator-mxnet/issues/7645")
+@with_seed(1234)
 def test_spatial_transformer_with_type():
-    np.random.seed(1234)
     data = mx.sym.Variable('data')
     loc = mx.sym.Flatten(data)
     loc = mx.sym.FullyConnected(data=loc, num_hidden=10)
@@ -694,11 +713,12 @@ def test_spatial_transformer_with_type():
     check_consistency(sym, ctx_list)
     check_consistency(sym, ctx_list, grad_req="add")
 
+
 # Checking max pooling consistency over the data sets of different float types is problematic
 # as one max value in a float32 data set may not be the max value in a float16 data set.
 # This function will not be called.
+@with_seed(1234)
 def test_pooling_with_type():
-    np.random.seed(1234)
     ctx_list = [{'ctx': mx.gpu(0), 'pool_data': (10, 2, 10, 10), 'type_dict': {'pool_data': np.float64}},
                 {'ctx': mx.gpu(0), 'pool_data': (10, 2, 10, 10), 'type_dict': {'pool_data': np.float32}},
                 {'ctx': mx.gpu(0), 'pool_data': (10, 2, 10, 10), 'type_dict': {'pool_data': np.float16}},
@@ -719,6 +739,7 @@ def test_pooling_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_pooling_versions():
     def test_pooling_versions_helper(pool_op_list, data, kernel, pool_type, pad, stride,
                                      pooling_convention='valid', global_pool=False):
@@ -876,6 +897,7 @@ def test_3d_pooling(pool_type):
     test_3d_pooling('sum')
 
 
+@with_seed()
 def test_global_pooling():
     def test_1d_pooling(pool_type):
         data = (2, 3, 20)
@@ -968,6 +990,7 @@ def test_2d_pooling(pool_type):
     test_2d_pooling('sum')
 
 
+@with_seed()
 def test_upsampling_with_type():
     sym = mx.sym.UpSampling(scale=2, num_filter=2, name='up', sample_type='nearest', num_args=1)
     ctx_list = [{'ctx': mx.gpu(0), 'up_arg0': (2, 2, 2, 10), 'type_dict': {'up_arg0': np.float64}},
@@ -978,6 +1001,7 @@ def test_upsampling_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_upsampling_bilinear_with_type():
     sym = mx.sym.UpSampling(scale=2, num_filter=2, name='up', sample_type='bilinear', num_args=1)
     ctx_list = [{'ctx': mx.gpu(0), 'up_data': (2, 2, 2, 10), 'type_dict': {'up_data': np.float64}},
@@ -988,6 +1012,7 @@ def test_upsampling_bilinear_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_concat_with_type():
     sym = mx.sym.Concat(name='concat', num_args=2)
     ctx_list = [{'ctx': mx.gpu(0), 'concat_arg1': (2, 10), 'concat_arg0': (2, 10),
@@ -1003,6 +1028,7 @@ def test_concat_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_elementwisesum_with_type():
     dev_types = [[mx.gpu(0), [np.float64, np.float32, np.float16]],
                  [mx.cpu(0), [np.float64, np.float32]] ]
@@ -1024,6 +1050,7 @@ def test_elementwisesum_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_reshape_with_type():
     sym = mx.sym.Reshape(name='reshape', shape=(-1,1,1,0))
     ctx_list = [{'ctx': mx.gpu(0), 'reshape_data': (2, 2, 2, 10), 'type_dict': {'reshape_data': np.float64}},
@@ -1034,6 +1061,7 @@ def test_reshape_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_blockgrad_with_type():
     sym = mx.sym.BlockGrad(name='bg')
     ctx_list = [{'ctx': mx.gpu(0), 'bg_data': (2, 2, 2, 10), 'type_dict': {'bg_data': np.float64}},
@@ -1044,6 +1072,7 @@ def test_blockgrad_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_swapaxis_with_type():
     sym = mx.sym.SwapAxis(name='swap', dim1=1)
     ctx_list = [{'ctx': mx.gpu(0), 'swap_data': (2, 2, 2, 10), 'type_dict': {'swap_data': np.float64}},
@@ -1054,6 +1083,7 @@ def test_swapaxis_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_fullyconnected_with_type():
     sym = mx.sym.FullyConnected(num_hidden=3, name='inner')
     ctx_list = [{'ctx': mx.gpu(0), 'inner_data': (2, 10), 'type_dict': {'inner_data': np.float64}},
@@ -1069,6 +1099,7 @@ def test_fullyconnected_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_activation_with_type():
     sym = mx.sym.Activation(name='act', act_type='sigmoid')
     ctx_list = [{'ctx': mx.gpu(0), 'act_data': (2, 2, 10, 10), 'type_dict': {'act_data': np.float64}},
@@ -1080,6 +1111,7 @@ def test_activation_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_lrn():
     sym = mx.sym.LRN(alpha=0.0001, beta=0.75, knorm=2, nsize=5, name='lrn')
     ctx_list = [{'ctx': mx.gpu(0), 'lrn_data': (2, 6, 10, 10), 'type_dict': {'lrn_data': np.float32}},
@@ -1087,6 +1119,7 @@ def test_lrn():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_embedding_with_type():
     def test_embedding_helper(data_types, weight_types, low_pad, high_pad):
         NVD = [[20, 10, 20], [200, 10, 300]]
@@ -1110,7 +1143,9 @@ def test_embedding_helper(data_types, weight_types, low_pad, high_pad):
     weight_types = [np.float16, np.float32, np.float64]
     test_embedding_helper(data_types, weight_types, 0, 5)
 
+
 @unittest.skip("test fails intermittently. temporarily disabled till it gets fixed. tracked at https://github.com/apache/incubator-mxnet/issues/8288")
+@with_seed()
 def test_svmoutput_with_type():
     sym = mx.sym.SVMOutput(name='svmoutput', use_linear=True)
     ctx_list = [{'ctx': mx.gpu(0), 'svmoutput_data': (20, 10), 'type_dict': {'svmoutput_data': np.float64}},
@@ -1122,6 +1157,7 @@ def test_svmoutput_with_type():
     check_consistency(sym, ctx_list)
 
 
+@with_seed()
 def test_take_with_type():
     sym = mx.sym.take(name='take')
     for data_ndim in range(2, 5):
@@ -1190,7 +1226,7 @@ def check_rnn_consistency(cell1, cell2):
 
     assert_allclose(mod1.get_outputs()[0].asnumpy(), mod2.get_outputs()[0].asnumpy(), rtol=1e-2, atol=1e-4)
 
-
+@with_seed()
 def test_rnn():
     fused = mx.rnn.FusedRNNCell(100, num_layers=2, mode='rnn_relu', prefix='')
 
@@ -1202,6 +1238,7 @@ def test_rnn():
     check_rnn_consistency(stack, fused)
 
 
+@with_seed()
 def test_lstm():
     fused = mx.rnn.FusedRNNCell(100, num_layers=2, mode='lstm', prefix='')
 
@@ -1213,6 +1250,7 @@ def test_lstm():
     check_rnn_consistency(stack, fused)
 
 
+@with_seed()
 def test_lstm_forget_bias():
     forget_bias = 2.0
     fused = mx.rnn.FusedRNNCell(10, forget_bias=forget_bias, num_layers=2, mode='lstm', prefix='')
@@ -1234,6 +1272,7 @@ def test_lstm_forget_bias():
     assert_allclose(args[bias_name].asnumpy(), expected_bias)
 
 
+@with_seed()
 def test_gru():
     fused = mx.rnn.FusedRNNCell(100, num_layers=2, mode='gru', prefix='')
 
@@ -1245,6 +1284,7 @@ def test_gru():
     check_rnn_consistency(stack, fused)
 
 
+@with_seed()
 def test_bidirectional():
     fused = mx.rnn.FusedRNNCell(100, num_layers=2, mode='gru', prefix='',
             bidirectional=True)
@@ -1262,6 +1302,8 @@ def test_bidirectional():
     check_rnn_consistency(fused, stack)
     check_rnn_consistency(stack, fused)
 
+
+@with_seed()
 def test_unfuse():
     for mode in ['rnn_tanh', 'rnn_relu', 'lstm', 'gru']:
         fused = mx.rnn.FusedRNNCell(
@@ -1275,8 +1317,9 @@ def test_unfuse():
         check_rnn_consistency(fused, stack)
         check_rnn_consistency(stack, fused)
 
+
+@with_seed(1234)
 def test_psroipooling_with_type():
-    np.random.seed(1234)
     arg_params = {
         'psroipool_rois': np.array([[0, 10, 22, 161, 173], [0, 20, 15, 154, 160]])}
 
@@ -1299,8 +1342,9 @@ def test_psroipooling_with_type():
     check_consistency(sym, ctx_list, grad_req={'psroipool_data': 'write',
                                                'psroipool_rois': 'null'}, arg_params=arg_params)
 
+
+@with_seed(1234)
 def test_deformable_psroipooling_with_type():
-    np.random.seed(1234)
     arg_params = {
         'deformable_psroipool_rois': np.array([[0, 10, 22, 161, 173], [0, 20, 15, 154, 160]])}
 
@@ -1332,8 +1376,9 @@ def test_deformable_psroipooling_with_type():
                                                'deformable_psroipool_rois': 'null',
                                                'deformable_psroipool_trans': 'write'}, arg_params=arg_params)
 
+
+@with_seed(1234)
 def test_deformable_convolution_with_type():
-    np.random.seed(1234)
     sym = mx.sym.contrib.DeformableConvolution(num_filter=3, kernel=(3,3), name='deformable_conv')
     # since atomicAdd does not support fp16 (which deformable conv uses in backward), we do not test fp16 here
     ctx_list = [{'ctx': mx.gpu(0),
@@ -1361,6 +1406,9 @@ def test_deformable_convolution_with_type():
                                                'deformable_conv_offset': 'write',
                                                'deformable_conv_weight': 'write',
                                                'deformable_conv_bias': 'null'}, tol=tol)
+
+
+@with_seed()
 def test_deformable_convolution_options():
     # 2D convolution
 
@@ -1436,6 +1484,8 @@ def test_deformable_convolution_options():
     sym = mx.sym.contrib.DeformableConvolution(num_filter=4, kernel=(3,3), num_deformable_group=2,
                                                name='deformable_conv')
 
+
+@with_seed()
 def test_residual_fused():
     cell = mx.rnn.ResidualCell(
             mx.rnn.FusedRNNCell(50, num_layers=3, mode='lstm',
@@ -1455,6 +1505,7 @@ def test_residual_fused():
     expected_outputs = np.ones((10, 2, 50))+5
     assert np.array_equal(outputs[0].asnumpy(), expected_outputs)
 
+
 def check_rnn_layer(layer):
     layer.collect_params().initialize(ctx=[mx.cpu(0), mx.gpu(0)])
     with mx.gpu(0):
@@ -1467,11 +1518,12 @@ def check_rnn_layer(layer):
         states = layer.begin_state(16)
         co, cs = layer(x, states)
 
-    assert_almost_equal(go.asnumpy(), co.asnumpy(), rtol=1e-2, atol=1e-8)
+    # atol of 1e-6 required, as exposed by seed 2124685726
+    assert_almost_equal(go.asnumpy(), co.asnumpy(), rtol=1e-2, atol=1e-6)
     for g, c in zip(gs, cs):
-        assert_almost_equal(g.asnumpy(), c.asnumpy(), rtol=1e-2, atol=1e-8)
-
+        assert_almost_equal(g.asnumpy(), c.asnumpy(), rtol=1e-2, atol=1e-6)
 
+@with_seed()
 def test_rnn_layer():
     check_rnn_layer(gluon.rnn.RNN(100, num_layers=3))
     check_rnn_layer(gluon.rnn.RNN(100, activation='tanh', num_layers=3))
@@ -1481,10 +1533,13 @@ def test_rnn_layer():
     check_rnn_layer(gluon.rnn.LSTM(100, num_layers=3, bidirectional=True))
 
 
+@with_seed()
 def test_sequence_reverse():
     check_sequence_reverse(mx.gpu(0))
 
+
 @unittest.skip("Test fails intermittently. Temporarily disabled until fixed. Tracked at https://github.com/apache/incubator-mxnet/issues/8211")
+@with_seed()
 def test_autograd_save_memory():
     x = mx.nd.zeros((128, 512, 512), ctx=mx.gpu(0))
     x.attach_grad()
@@ -1495,6 +1550,8 @@ def test_autograd_save_memory():
             x.wait_to_read()
     x.backward()
 
+
+@with_seed()
 def test_gluon_ctc_consistency():
     loss = mx.gluon.loss.CTCLoss()
     data = mx.nd.arange(0, 4, repeat=40, ctx=mx.gpu(0)).reshape((2,20,4)).flip(axis=0)
@@ -1516,6 +1573,7 @@ def test_gluon_ctc_consistency():
     assert_almost_equal(cpu_data.grad.asnumpy(), gpu_data.grad.asnumpy(), atol=1e-3, rtol=1e-3)
 
 
+@with_seed()
 def test_cuda_rtc():
     source = r'''
     extern "C" __global__ void axpy(const float *x, float *y, float alpha) {
@@ -1545,6 +1603,7 @@ def test_cuda_rtc():
     assert (y.asnumpy() == 12).all()
 
 
+@with_seed()
 def test_global_norm_clip_multi_device():
     x1 = mx.nd.ones((3,3), ctx=mx.gpu(0))
     x2 = mx.nd.ones((4,4), ctx=mx.cpu(0))
@@ -1554,6 +1613,7 @@ def test_global_norm_clip_multi_device():
     assert_almost_equal(x2.asnumpy(), np.ones((4,4))/5)
 
 
+@with_seed()
 def test_cross_device_autograd():
     x = mx.nd.random.uniform(shape=(10,))
     x.attach_grad()
diff --git a/tests/python/unittest/common.py b/tests/python/unittest/common.py
index 782534bf80..35c7e3ffc8 100644
--- a/tests/python/unittest/common.py
+++ b/tests/python/unittest/common.py
@@ -15,12 +15,17 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import sys, os
+import sys, os, logging
+import mxnet as mx
+import numpy as np
+import random
 curr_path = os.path.dirname(os.path.abspath(os.path.expanduser(__file__)))
 sys.path.append(os.path.join(curr_path, '../common/'))
 sys.path.insert(0, os.path.join(curr_path, '../../../python'))
 
 import models
+from contextlib import contextmanager
+from nose.tools import make_decorator
 
 def assertRaises(expected_exception, func, *args, **kwargs):
     try:
@@ -30,3 +35,193 @@ def assertRaises(expected_exception, func, *args, **kwargs):
     else:
         # Did not raise exception
         assert False, "%s did not raise %s" % (func.__name__, expected_exception.__name__)
+
+def default_logger():
+    """A logger used to output seed information to nosetests logs."""
+    logger = logging.getLogger(__name__)
+    # getLogger() lookups will return the same logger, but only add the handler once.
+    if not len(logger.handlers):
+        handler = logging.StreamHandler(sys.stderr)
+        handler.setFormatter(logging.Formatter('[%(levelname)s] %(message)s'))
+        logger.addHandler(handler)
+        if (logger.getEffectiveLevel() == logging.NOTSET):
+            logger.setLevel(logging.INFO)
+    return logger
+
+@contextmanager
+def random_seed(seed=None):
+    """
+    Runs a code block with a new seed for np, mx and python's random.
+
+    Parameters
+    ----------
+
+    seed : the seed to pass to np.random, mx.random and python's random.
+
+    To impose rng determinism, invoke e.g. as in:
+
+    with random_seed(1234):
+        ...
+
+    To impose rng non-determinism, invoke as in:
+
+    with random_seed():
+        ...
+
+    Upon conclusion of the block, the rng's are returned to
+    a state that is a function of their pre-block state, so
+    any prior non-determinism is preserved.
+
+    """
+
+    try:
+        next_seed = np.random.randint(0, np.iinfo(np.int32).max)
+        if seed is None:
+            np.random.seed()
+            seed = np.random.randint(0, np.iinfo(np.int32).max)
+        logger = default_logger()
+        logger.debug('Setting np, mx and python random seeds = %s', seed)
+        np.random.seed(seed)
+        mx.random.seed(seed)
+        random.seed(seed)
+        yield
+    finally:
+        # Reinstate prior state of np.random and other generators
+        np.random.seed(next_seed)
+        mx.random.seed(next_seed)
+        random.seed(next_seed)
+
+
+def with_seed(seed=None):
+    """
+    A decorator for nosetests test functions that manages rng seeds.
+
+    Parameters
+    ----------
+
+    seed : the seed to pass to np.random and mx.random
+
+
+    This tests decorator sets the np, mx and python random seeds identically
+    prior to each test, then outputs those seeds if the test fails or
+    if the test requires a fixed seed (as a reminder to make the test
+    more robust against random data).
+
+    @with_seed()
+    def test_ok_with_random_data():
+        ...
+
+    @with_seed(1234)
+    def test_not_ok_with_random_data():
+        ...
+
+    Use of the @with_seed() decorator for all tests creates
+    tests isolation and reproducability of failures.  When a
+    test fails, the decorator outputs the seed used.  The user
+    can then set the environment variable MXNET_TEST_SEED to
+    the value reported, then rerun the test with:
+
+        nosetests --verbose -s <test_module_name.py>:<failing_test>
+
+    To run a test repeatedly, set MXNET_TEST_COUNT=<NNN> in the environment.
+    To see the seeds of even the passing tests, add '--logging-level=DEBUG' to nosetests.
+    """
+    def test_helper(orig_test):
+        @make_decorator(orig_test)
+        def test_new(*args, **kwargs):
+            test_count = int(os.getenv('MXNET_TEST_COUNT', '1'))
+            env_seed_str = os.getenv('MXNET_TEST_SEED')
+            for i in range(test_count):
+                if seed is not None:
+                    this_test_seed = seed
+                    log_level = logging.INFO
+                elif env_seed_str is not None:
+                    this_test_seed = int(env_seed_str)
+                    log_level = logging.INFO
+                else:
+                    this_test_seed = np.random.randint(0, np.iinfo(np.int32).max)
+                    log_level = logging.DEBUG
+                post_test_state = np.random.get_state()
+                np.random.seed(this_test_seed)
+                mx.random.seed(this_test_seed)
+                random.seed(this_test_seed)
+                logger = default_logger()
+                # 'nosetests --logging-level=DEBUG' shows this msg even with an ensuing core dump.
+                test_count_msg = '{} of {}: '.format(i+1,test_count) if test_count > 1 else ''
+                test_msg = ('{}Setting test np/mx/python random seeds, use MXNET_TEST_SEED={}'
+                            ' to reproduce.').format(test_count_msg, this_test_seed)
+                logger.log(log_level, test_msg)
+                try:
+                    orig_test(*args, **kwargs)
+                except:
+                    # With exceptions, repeat test_msg at INFO level to be sure it's seen.
+                    if log_level < logging.INFO:
+                        logger.info(test_msg)
+                    raise
+                finally:
+                    np.random.set_state(post_test_state)
+        return test_new
+    return test_helper
+
+def setup_module():
+    """
+    A function with a 'magic name' executed automatically before each nosetests module
+    (file of tests) that helps reproduce a test segfault by setting and outputting the rng seeds.
+
+    The segfault-debug procedure on a module called test_module.py is:
+
+    1. run "nosetests --verbose test_module.py".  A seg-faulting output might be:
+
+       [INFO] np, mx and python random seeds = 4018804151
+       test_module.test1 ... ok
+       test_module.test2 ... Illegal instruction (core dumped)
+
+    2. Copy the module-starting seed into the next command, then run:
+
+       MXNET_MODULE_SEED=4018804151 nosetests --logging-level=DEBUG --verbose test_module.py
+
+       Output might be:
+
+       [WARNING] **** module-level seed is set: all tests running deterministically ****
+       [INFO] np, mx and python random seeds = 4018804151
+       test_module.test1 ... [DEBUG] np and mx random seeds = 3935862516
+       ok
+       test_module.test2 ... [DEBUG] np and mx random seeds = 1435005594
+       Illegal instruction (core dumped)
+
+    3. Copy the segfaulting-test seed into the command:
+       MXNET_TEST_SEED=1435005594 nosetests --logging-level=DEBUG --verbose test_module.py:test2
+       Output might be:
+
+       [INFO] np, mx and python random seeds = 2481884723
+       test_module.test2 ... [DEBUG] np and mx random seeds = 1435005594
+       Illegal instruction (core dumped)
+
+    3. Finally reproduce the segfault directly under gdb (might need additional os packages)
+       by editing the bottom of test_module.py to be
+
+       if __name__ == '__main__':
+           logging.getLogger().setLevel(logging.DEBUG)
+           test2()
+
+       MXNET_TEST_SEED=1435005594 gdb -ex r --args python test_module.py
+
+    4. When finished debugging the segfault, remember to unset any exported MXNET_ seed
+       variables in the environment to return to non-deterministic testing (a good thing).
+    """
+
+    module_seed_str = os.getenv('MXNET_MODULE_SEED')
+    logger = default_logger()
+    if module_seed_str is None:
+        seed = np.random.randint(0, np.iinfo(np.int32).max)
+    else:
+        seed = int(module_seed_str)
+        logger.warn('*** module-level seed is set: all tests running deterministically ***')
+    logger.info('Setting module np/mx/python random seeds, use MXNET_MODULE_SEED=%s to reproduce.', seed)
+    np.random.seed(seed)
+    mx.random.seed(seed)
+    random.seed(seed)
+    # The MXNET_TEST_SEED environment variable will override MXNET_MODULE_SEED for tests with
+    #  the 'with_seed()' decoration.  Inform the user of this once here at the module level.
+    if os.getenv('MXNET_TEST_SEED') is not None:
+        logger.warn('*** test-level seed set: all "@with_seed()" tests run deterministically ***')
diff --git a/tests/python/unittest/test_autograd.py b/tests/python/unittest/test_autograd.py
index c95ccdf299..c2d0d26c9d 100644
--- a/tests/python/unittest/test_autograd.py
+++ b/tests/python/unittest/test_autograd.py
@@ -20,6 +20,7 @@
 from mxnet.ndarray import zeros_like
 from mxnet.autograd import *
 from mxnet.test_utils import *
+from common import setup_module, with_seed
 
 
 def grad_and_loss(func, argnum=None):
@@ -105,6 +106,7 @@ def autograd_assert(*args, **kwargs):
     for a, b in zip(grad_vals, grad_res):
         assert same(a.asnumpy(), b.asnumpy())
 
+@with_seed()
 def test_unary_func():
     def check_unary_func(x):
         f_exp         = lambda x: nd.exp(x)
@@ -121,6 +123,7 @@ def check_unary_func(x):
     for stype in stypes:
         check_unary_func(uniform.tostype(stype))
 
+@with_seed()
 def test_binary_func():
     def check_binary_func(x, y):
         f_add      = lambda x, y: x+y
@@ -142,6 +145,7 @@ def check_binary_func(x, y):
             check_binary_func(x, y)
 
 
+@with_seed()
 def test_operator_with_state():
     def f_fc(a, b, weight, bias):
         x = a*b
@@ -158,6 +162,7 @@ def f_fc(a, b, weight, bias):
     grad_vals, outputs = grad_func(a, b, weight, bias)
     # (TODO) assert
 
+@with_seed()
 def test_argnum():
     def f_with_mode(a, b, mode):
         if mode:
@@ -175,6 +180,7 @@ def f_with_mode(a, b, mode):
         argnum=[0, 1], func=f_with_mode, grad_func=f_mul_grad)
 
 
+@with_seed()
 def test_training():
     x = nd.ones((10, 10))
     with record():
@@ -185,6 +191,7 @@ def test_training():
             assert (y.asnumpy() == x.asnumpy()).all()
 
 
+@with_seed()
 def test_out_grads():
     x = nd.ones((3, 5))
     dx = nd.zeros_like(x)
@@ -203,6 +210,7 @@ def test_out_grads():
          [5,4,3,2,1]])).all()
 
 
+@with_seed()
 def test_detach_updated_grad():
     x = nd.ones((2, 2))
     dx = nd.zeros_like(x)
@@ -235,6 +243,7 @@ def test_detach_updated_grad():
     assert x._fresh_grad == False
 
 
+@with_seed()
 def test_retain_grad():
     x = mx.nd.ones((2, 2))
     dx = mx.nd.zeros((2, 2))
@@ -266,6 +275,7 @@ def test_retain_grad():
         "differentiating the same graph twice without retain_graph should fail")
 
 
+@with_seed()
 def test_attach_grad():
     def check_attach_grad(x):
         assert x.grad is None
@@ -282,6 +292,7 @@ def check_attach_grad(x):
         check_attach_grad(x)
 
 
+@with_seed()
 def test_is_train():
     x = mx.nd.ones((10, 10))
     x.attach_grad()
@@ -328,7 +339,7 @@ def test_is_train():
         y = mx.nd.Dropout(x, p=0.5)
         assert y.asnumpy().max() == 2 and y.asnumpy().min() == 0
 
-
+@with_seed()
 def test_function():
     class func(Function):
         def forward(self, x, y):
@@ -358,10 +369,13 @@ def backward(self, dm, dn):
     with record():
         backward([x/y, x*y])
 
-    assert_almost_equal(x.grad.asnumpy(), dx1)
-    assert_almost_equal(y.grad.asnumpy(), dy1)
+    # Non-zero atol required, as exposed by seed 630179191
+    atol = 1e-6
+    assert_almost_equal(x.grad.asnumpy(), dx1, atol=atol)
+    assert_almost_equal(y.grad.asnumpy(), dy1, atol=atol)
 
 
+@with_seed()
 def test_get_symbol():
     x = mx.nd.ones((1,))
     x.attach_grad()
@@ -375,6 +389,7 @@ def test_get_symbol():
         y = x*x + 2*z - 1
     assert len(get_symbol(y).list_arguments()) == 2
 
+@with_seed()
 def test_grad_with_stype():
     def check_grad_with_stype(array_stype, grad_stype, expected_stype):
         x = mx.nd.zeros((1, 1), stype=array_stype)
@@ -393,6 +408,7 @@ def check_grad_with_stype(array_stype, grad_stype, expected_stype):
             # check the stype of the gradient when provided
             check_grad_with_stype(stype, grad_stype, grad_stype)
 
+@with_seed()
 def test_sparse_dot_grad():
     def check_sparse_dot_grad(rhs):
         lhs = rand_ndarray((2, 8), 'csr')
@@ -415,6 +431,7 @@ def check_sparse_dot_grad(rhs):
     dns.attach_grad(stype='row_sparse')
     check_sparse_dot_grad(dns)
 
+@with_seed()
 def test_gradient():
     x = mx.nd.ones((1,))
     x.attach_grad()
diff --git a/tests/python/unittest/test_contrib_autograd.py b/tests/python/unittest/test_contrib_autograd.py
index a144c34332..9e80bba306 100644
--- a/tests/python/unittest/test_contrib_autograd.py
+++ b/tests/python/unittest/test_contrib_autograd.py
@@ -18,6 +18,7 @@
 import mxnet.ndarray as nd
 from mxnet.contrib.autograd import *
 from mxnet.test_utils import *
+from common import setup_module, with_seed
 
 def autograd_assert(*args, **kwargs):
     func   = kwargs["func"]
@@ -33,6 +34,7 @@ def autograd_assert(*args, **kwargs):
     for a, b in zip(grad_vals, grad_res):
         assert same(a.asnumpy(), b.asnumpy())
 
+@with_seed()
 def test_unary_func():
     x = nd.uniform(shape=(4, 5))
     f_exp         = lambda x: nd.exp(x)
@@ -45,6 +47,7 @@ def test_unary_func():
     f_square_grad = lambda x: [2*x]
     autograd_assert(x, func=f_square, grad_func=f_square_grad)
 
+@with_seed()
 def test_binary_func():
     x = nd.uniform(shape=(4, 5))
     y = nd.uniform(shape=(4, 5))
@@ -58,6 +61,7 @@ def test_binary_func():
     f_compose_grad = lambda x, y: [nd.ones(x.shape) + y, x]
     autograd_assert(x, y, func=f_compose, grad_func=f_compose_grad)
 
+@with_seed()
 def test_operator_with_state():
     def f_fc(a, b, weight, bias):
         x = a*b
@@ -74,6 +78,7 @@ def f_fc(a, b, weight, bias):
     grad_vals, outputs = grad_func(a, b, weight, bias)
     # (TODO) assert
 
+@with_seed()
 def test_argnum():
     def f_with_mode(a, b, mode):
         if mode:
@@ -91,6 +96,7 @@ def f_with_mode(a, b, mode):
         argnum=[0, 1], func=f_with_mode, grad_func=f_mul_grad)
 
 
+@with_seed()
 def test_training():
     x = nd.ones((10, 10))
     with train_section():
@@ -101,6 +107,7 @@ def test_training():
             assert (y.asnumpy() == x.asnumpy()).all()
 
 
+@with_seed()
 def test_out_grads():
     x = nd.ones((3, 5))
     dx = nd.zeros_like(x)
@@ -119,6 +126,7 @@ def test_out_grads():
          [5,4,3,2,1]])).all()
 
 
+@with_seed()
 def test_detach_updated_grad():
     x = nd.ones((2, 2))
     dx = nd.zeros_like(x)
@@ -151,6 +159,7 @@ def test_detach_updated_grad():
     assert x._fresh_grad == False
 
 
+@with_seed()
 def test_retain_grad():
     x = mx.nd.ones((2, 2))
     dx = mx.nd.zeros((2, 2))
diff --git a/tests/python/unittest/test_exc_handling.py b/tests/python/unittest/test_exc_handling.py
index 0c2c43db65..bbfed94785 100644
--- a/tests/python/unittest/test_exc_handling.py
+++ b/tests/python/unittest/test_exc_handling.py
@@ -18,11 +18,13 @@
 import mxnet as mx
 import numpy as np
 from mxnet import gluon
+from common import setup_module, with_seed
 from mxnet.gluon import nn
 from mxnet.base import MXNetError
 from mxnet.test_utils import assert_exception, default_context, set_default_context
 from nose.tools import assert_raises
 
+@with_seed()
 def test_exc_imperative():
     def imperative(exec_numpy=True):
         a = mx.nd.random.normal(0, 1, (2, 2))
@@ -34,6 +36,7 @@ def imperative(exec_numpy=True):
     imperative(exec_numpy=False)
     assert_raises(MXNetError, imperative, True)
 
+@with_seed()
 def test_exc_symbolic():
     def symbolic(exec_backward=True):
         x = mx.sym.Variable('x')
@@ -62,6 +65,7 @@ def symbolic(exec_backward=True):
     assert_raises(MXNetError, symbolic, False)
     assert_raises(MXNetError, symbolic, True)
 
+@with_seed()
 def test_exc_gluon():
     def gluon(exec_wait=True):
         model = nn.Sequential()
@@ -79,6 +83,7 @@ def gluon(exec_wait=True):
     gluon(exec_wait=False)
     assert_raises(MXNetError, gluon, True)
 
+@with_seed()
 def test_exc_multiple_waits():
     caught = False
     try:
@@ -94,6 +99,7 @@ def test_exc_multiple_waits():
         caught = True
     assert caught, "No exception thrown"
 
+@with_seed()
 def test_exc_post_fail():
     caught = False
     try:
@@ -104,6 +110,7 @@ def test_exc_post_fail():
     assert caught, "No exception thrown"
     b.asnumpy()
 
+@with_seed()
 def test_exc_mutable_var_fail():
     def mutable_var_check():
         a, b = mx.nd.random_normal(0, -1, (2, 2)).copyto(default_context())
diff --git a/tests/python/unittest/test_executor.py b/tests/python/unittest/test_executor.py
index 40a922cf5c..45b9a09922 100644
--- a/tests/python/unittest/test_executor.py
+++ b/tests/python/unittest/test_executor.py
@@ -17,6 +17,7 @@
 
 import numpy as np
 import mxnet as mx
+from common import setup_module, with_seed
 
 
 def reldiff(a, b):
@@ -77,13 +78,13 @@ def check_bind_with_uniform(uf, gf, dim, sf=None, lshape=None, rshape=None):
     assert reldiff(rhs_grad.asnumpy(), rhs_grad2) < 1e-6
 
 
+@with_seed(0)
 def test_bind():
     def check_bind(disable_bulk_exec):
         if disable_bulk_exec:
             prev_bulk_inf_val = mx.test_utils.set_env_var("MXNET_EXEC_BULK_EXEC_INFERENCE", "0", "1")
             prev_bulk_train_val = mx.test_utils.set_env_var("MXNET_EXEC_BULK_EXEC_TRAIN", "0", "1")
 
-        np.random.seed(0)
         nrepeat = 10
         maxdim = 4
         for repeat in range(nrepeat):
@@ -116,8 +117,9 @@ def check_bind(disable_bulk_exec):
     check_bind(True)
     check_bind(False)
 
+
+@with_seed(0)
 def test_dot():
-    np.random.seed(0)
     nrepeat = 10
     maxdim = 4
     for repeat in range(nrepeat):
@@ -138,6 +140,7 @@ def test_dot():
                                 sf = mx.symbol.dot)
 
 
+@with_seed()
 def test_reshape():
     x = mx.sym.Variable('x')
     y = mx.sym.FullyConnected(x, num_hidden=4)
@@ -157,6 +160,7 @@ def test_reshape():
     exe.forward(is_train=False)
     assert np.all(exe.outputs[0].asnumpy() == 4)
 
+
 if __name__ == "__main__":
     import nose
     nose.runmodule()
diff --git a/tests/python/unittest/test_gluon.py b/tests/python/unittest/test_gluon.py
index 9a09e13328..50b60a2db3 100644
--- a/tests/python/unittest/test_gluon.py
+++ b/tests/python/unittest/test_gluon.py
@@ -19,6 +19,7 @@
 from mxnet import gluon
 from mxnet.gluon import nn
 from mxnet.test_utils import assert_almost_equal
+from common import setup_module, with_seed
 import numpy as np
 from nose.tools import raises
 from copy import deepcopy
@@ -26,6 +27,7 @@
 import json
 
 
+@with_seed()
 def test_parameter():
     p = gluon.Parameter('weight', shape=(10, 10))
     p.initialize(init='xavier', ctx=[mx.cpu(0), mx.cpu(1)])
@@ -39,6 +41,7 @@ def test_parameter():
     assert p.list_ctx() == [mx.cpu(1), mx.cpu(2)]
 
 
+@with_seed()
 def test_paramdict():
     params = gluon.ParameterDict('net_')
     params.get('weight', shape=(10, 10))
@@ -48,6 +51,7 @@ def test_paramdict():
     params.load('test.params', mx.cpu())
 
 
+@with_seed()
 def test_parameter_sharing():
     class Net(gluon.Block):
         def __init__(self, **kwargs):
@@ -70,6 +74,7 @@ def forward(self, x):
     net3.load_params('net1.params', mx.cpu())
 
 
+@with_seed()
 def test_parameter_str():
     class Net(gluon.Block):
         def __init__(self, **kwargs):
@@ -86,6 +91,8 @@ def __init__(self, **kwargs):
     assert 'numpy.float32' in lines[1]
     assert lines[2] == ')'
 
+
+@with_seed()
 def test_collect_paramters():
     net = nn.HybridSequential(prefix="test_")
     with net.name_scope():
@@ -98,6 +105,7 @@ def test_collect_paramters():
     assert set(net.collect_params('test_conv0_bias|test_dense0_bias').keys()) == \
         set(['test_conv0_bias', 'test_dense0_bias'])
 
+@with_seed()
 def test_basic():
     model = nn.Sequential()
     model.add(nn.Dense(128, activation='tanh', in_units=10, flatten=False))
@@ -123,6 +131,7 @@ def test_basic():
     assert list(model.collect_params().values())[0]._grad is not None
 
 
+@with_seed()
 def test_dense():
     model = nn.Dense(128, activation='tanh', in_units=10, flatten=False, prefix='test_')
     inputs = mx.sym.Variable('data')
@@ -141,6 +150,7 @@ def test_dense():
     assert outs == [(17, 128)]
 
 
+@with_seed()
 def test_symbol_block():
     model = nn.HybridSequential()
     model.add(nn.Dense(128, activation='tanh'))
@@ -204,6 +214,7 @@ def check_layer_forward(layer, dshape):
     mx.test_utils.assert_almost_equal(np_out, out.asnumpy(), rtol=1e-5, atol=1e-6)
     mx.test_utils.assert_almost_equal(np_dx, x.grad.asnumpy(), rtol=1e-5, atol=1e-6)
 
+@with_seed()
 def test_conv():
     layers1d = [
         nn.Conv1D(16, 3, in_channels=4),
@@ -244,6 +255,7 @@ def test_conv():
     # check_layer_forward(layer, (1, 10, 10, 10, 4))
 
 
+@with_seed()
 def test_deconv():
     # layers1d = [
     #     nn.Conv1DTranspose(16, 3, in_channels=4),
@@ -285,6 +297,7 @@ def test_deconv():
     # # check_layer_forward(layer, (1, 10, 10, 10, 4))
 
 
+@with_seed()
 def test_pool():
     layers1d = [
         nn.MaxPool1D(),
@@ -329,21 +342,25 @@ def test_pool():
     assert (layer(x).shape==(2, 2, 4, 4))
 
 
+@with_seed()
 def test_batchnorm():
     layer = nn.BatchNorm(in_channels=10)
     check_layer_forward(layer, (2, 10, 10, 10))
 
 
+@with_seed()
 def test_instancenorm():
     layer = nn.InstanceNorm(in_channels=10)
     check_layer_forward(layer, (2, 10, 10, 10))
 
 
+@with_seed()
 def test_reflectionpad():
     layer = nn.ReflectionPad2D(3)
     check_layer_forward(layer, (2, 3, 24, 24))
 
 
+@with_seed()
 def test_reshape():
     x = mx.nd.ones((2, 4, 10, 10))
     layer = nn.Conv2D(10, 2, in_channels=4)
@@ -355,6 +372,7 @@ def test_reshape():
     x.backward()
 
 
+@with_seed()
 def test_slice():
     x = mx.nd.ones((5, 4, 10, 10))
     layer = nn.Conv2D(10, 2, in_channels=4)
@@ -366,6 +384,7 @@ def test_slice():
     x.backward()
 
 
+@with_seed()
 def test_at():
     x = mx.nd.ones((5, 4, 10, 10))
     layer = nn.Conv2D(10, 2, in_channels=4)
@@ -377,6 +396,7 @@ def test_at():
     x.backward()
 
 
+@with_seed()
 def test_deferred_init():
     x = mx.nd.ones((5, 4, 10, 10))
     layer = nn.Conv2D(10, 2)
@@ -391,6 +411,7 @@ def check_split_data(x, num_slice, batch_axis, **kwargs):
                                       x.asnumpy())
 
 
+@with_seed()
 def test_split_data():
     x = mx.nd.random.uniform(shape=(128, 33, 64))
 
@@ -405,6 +426,7 @@ def test_split_data():
     assert False, "Should have failed"
 
 
+@with_seed()
 def test_flatten():
     flatten = nn.Flatten()
     x = mx.nd.zeros((3,4,5,6))
@@ -415,6 +437,7 @@ def test_flatten():
     assert flatten(x).shape == (3, 1)
 
 
+@with_seed()
 def test_trainer():
     def dict_equ(a, b):
         assert set(a) == set(b)
@@ -454,6 +477,7 @@ def dict_equ(a, b):
         assert trainer._optimizer == trainer._updaters[0].optimizer
 
 
+@with_seed()
 def test_block_attr_hidden():
     b = gluon.Block()
 
@@ -461,7 +485,9 @@ def test_block_attr_hidden():
     b.a = None
     b.a = 1
 
+
 @raises(TypeError)
+@with_seed()
 def test_block_attr_block():
     b = gluon.Block()
 
@@ -469,7 +495,9 @@ def test_block_attr_block():
     b.b = gluon.Block()
     b.b = (2,)
 
+
 @raises(TypeError)
+@with_seed()
 def test_block_attr_param():
     b = gluon.Block()
 
@@ -477,6 +505,8 @@ def test_block_attr_param():
     b.b = gluon.Parameter()
     b.b = (2,)
 
+
+@with_seed()
 def test_block_attr_regular():
     b = gluon.Block()
 
@@ -486,6 +516,8 @@ def test_block_attr_regular():
     b.c = c2
     assert b.c is c2 and b._children[0] is c2
 
+
+@with_seed()
 def test_block_attr_list_of_block():
     class Model1(gluon.Block):
         def __init__(self, **kwargs):
@@ -530,13 +562,19 @@ def __init__(self, **kwargs):
         model.collect_params()
         assert len(w) == 0
 
+
+@with_seed()
 def test_sequential_warning():
     with warnings.catch_warnings(record=True) as w:
+        # The following line permits the test to pass if run multiple times
+        warnings.simplefilter('always')
         b = gluon.nn.Sequential()
         b.add(gluon.nn.Dense(20))
         b.hybridize()
         assert len(w) == 1
 
+
+@with_seed()
 def test_global_norm_clip():
     x1 = mx.nd.ones((3,3))
     x2 = mx.nd.ones((4,4))
@@ -552,6 +590,7 @@ def test_global_norm_clip():
         assert len(w) == 1
 
 
+@with_seed()
 def test_embedding():
     layer = gluon.nn.Embedding(10, 100)
     layer.initialize()
@@ -563,6 +602,7 @@ def test_embedding():
     assert (layer.weight.grad()[5:] == 0).asnumpy().all()
 
 
+@with_seed()
 def test_export():
     ctx = mx.context.current_context()
     model = gluon.model_zoo.vision.resnet18_v1(
@@ -587,6 +627,7 @@ def test_export():
     assert_almost_equal(out.asnumpy(), out2.asnumpy())
 
 
+@with_seed()
 def test_hybrid_stale_cache():
     net = mx.gluon.nn.HybridSequential()
     with net.name_scope():
@@ -615,6 +656,7 @@ def test_hybrid_stale_cache():
     assert net(mx.nd.ones((2,3,5))).shape == (2, 10)
 
 
+@with_seed()
 def test_lambda():
     net1 = mx.gluon.nn.HybridSequential()
     net1.add(nn.Activation('tanh'),
@@ -636,6 +678,7 @@ def test_lambda():
     assert_almost_equal(out1.asnumpy(), out3.asnumpy())
 
 
+@with_seed()
 def test_fill_shape_deferred():
     net = nn.HybridSequential()
     with net.name_scope():
@@ -650,6 +693,7 @@ def test_fill_shape_deferred():
     assert net[2].weight.shape[1] == 3072, net[2].weight.shape[1]
 
 
+@with_seed()
 def test_dtype():
     net = mx.gluon.model_zoo.vision.resnet18_v1()
     net.initialize()
@@ -669,6 +713,7 @@ def test_dtype():
     mx.nd.waitall()
 
 
+@with_seed()
 def test_fill_shape_load():
     ctx = mx.context.current_context()
     net1 = nn.HybridSequential()
@@ -694,6 +739,7 @@ def test_fill_shape_load():
     assert net2[2].weight.shape[1] == 3072, net2[2].weight.shape[1]
 
 
+@with_seed()
 def test_inline():
     net = mx.gluon.nn.HybridSequential()
     with net.name_scope():
diff --git a/tests/python/unittest/test_gluon_contrib.py b/tests/python/unittest/test_gluon_contrib.py
index 2f8558f338..68eec5573a 100644
--- a/tests/python/unittest/test_gluon_contrib.py
+++ b/tests/python/unittest/test_gluon_contrib.py
@@ -21,6 +21,7 @@
 from mxnet.gluon import nn
 from mxnet.gluon.contrib.nn import Concurrent, HybridConcurrent, Identity
 from mxnet.test_utils import almost_equal
+from common import setup_module, with_seed
 import numpy as np
 from numpy.testing import assert_allclose
 
@@ -48,6 +49,7 @@ def check_rnn_forward(layer, inputs):
     mx.nd.waitall()
 
 
+@with_seed()
 def test_rnn_cells():
     check_rnn_forward(contrib.rnn.Conv1DLSTMCell((5, 7), 10, (3,), (3,)),
                       mx.nd.ones((8, 3, 5, 7)))
@@ -63,6 +65,7 @@ def test_rnn_cells():
     check_rnn_forward(net, mx.nd.ones((8, 3, 5, 7)))
 
 
+@with_seed()
 def test_convrnn():
     cell = contrib.rnn.Conv1DRNNCell((10, 50), 100, 3, 3, prefix='rnn_')
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 50), out_shape=(1, 100, 48))
@@ -74,6 +77,7 @@ def test_convrnn():
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 20, 30, 50), out_shape=(1, 100, 18, 28, 48))
 
 
+@with_seed()
 def test_convlstm():
     cell = contrib.rnn.Conv1DLSTMCell((10, 50), 100, 3, 3, prefix='rnn_')
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 50), out_shape=(1, 100, 48))
@@ -85,6 +89,7 @@ def test_convlstm():
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 20, 30, 50), out_shape=(1, 100, 18, 28, 48))
 
 
+@with_seed()
 def test_convgru():
     cell = contrib.rnn.Conv1DGRUCell((10, 50), 100, 3, 3, prefix='rnn_')
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 50), out_shape=(1, 100, 48))
@@ -96,6 +101,7 @@ def test_convgru():
     check_rnn_cell(cell, prefix='rnn_', in_shape=(1, 10, 20, 30, 50), out_shape=(1, 100, 18, 28, 48))
 
 
+@with_seed()
 def test_conv_fill_shape():
     cell = contrib.rnn.Conv1DLSTMCell((0, 7), 10, (3,), (3,))
     cell.hybridize()
@@ -103,6 +109,7 @@ def test_conv_fill_shape():
     assert cell.i2h_weight.shape[1] == 5, cell.i2h_weight.shape[1]
 
 
+@with_seed()
 def test_vardrop():
     def check_vardrop(drop_inputs, drop_states, drop_outputs):
         cell = contrib.rnn.VariationalDropoutCell(mx.gluon.rnn.RNNCell(100, prefix='rnn_'),
diff --git a/tests/python/unittest/test_gluon_data.py b/tests/python/unittest/test_gluon_data.py
index 63c5d28b7c..49b1b8e935 100644
--- a/tests/python/unittest/test_gluon_data.py
+++ b/tests/python/unittest/test_gluon_data.py
@@ -21,7 +21,9 @@
 import mxnet as mx
 import numpy as np
 from mxnet import gluon
+from common import setup_module, with_seed
 
+@with_seed()
 def test_array_dataset():
     X = np.random.uniform(size=(10, 20))
     Y = np.random.uniform(size=(10,))
@@ -54,6 +56,7 @@ def prepare_record():
     return 'data/test.rec'
 
 
+@with_seed()
 def test_recordimage_dataset():
     recfile = prepare_record()
     dataset = gluon.data.vision.ImageRecordDataset(recfile)
@@ -63,6 +66,7 @@ def test_recordimage_dataset():
         assert x.shape[0] == 1 and x.shape[3] == 3
         assert y.asscalar() == i
 
+@with_seed()
 def test_sampler():
     seq_sampler = gluon.data.SequentialSampler(10)
     assert list(seq_sampler) == list(range(10))
@@ -75,6 +79,7 @@ def test_sampler():
     rand_batch_keep = gluon.data.BatchSampler(rand_sampler, 3, 'keep')
     assert sorted(sum(list(rand_batch_keep), [])) == list(range(10))
 
+@with_seed()
 def test_datasets():
     assert len(gluon.data.vision.MNIST(root='data/mnist')) == 60000
     assert len(gluon.data.vision.MNIST(root='data/mnist', train=False)) == 10000
@@ -86,6 +91,7 @@ def test_datasets():
     assert len(gluon.data.vision.CIFAR100(root='data/cifar100', fine_label=True)) == 50000
     assert len(gluon.data.vision.CIFAR100(root='data/cifar100', train=False)) == 10000
 
+@with_seed()
 def test_image_folder_dataset():
     prepare_record()
     dataset = gluon.data.vision.ImageFolderDataset('data/test_images')
diff --git a/tests/python/unittest/test_gluon_data_vision.py b/tests/python/unittest/test_gluon_data_vision.py
index 52e9d4a825..fe360ac970 100644
--- a/tests/python/unittest/test_gluon_data_vision.py
+++ b/tests/python/unittest/test_gluon_data_vision.py
@@ -22,13 +22,18 @@
 from mxnet.gluon.data.vision import transforms
 from mxnet.test_utils import assert_almost_equal
 from mxnet.test_utils import almost_equal
+from common import setup_module, with_seed
 
+
+@with_seed()
 def test_to_tensor():
     data_in = np.random.uniform(0, 255, (300, 300, 3)).astype(dtype=np.uint8)
     out_nd = transforms.ToTensor()(nd.array(data_in, dtype='uint8'))
     assert_almost_equal(out_nd.asnumpy(), np.transpose(
         data_in.astype(dtype=np.float32) / 255.0, (2, 0, 1)))
 
+
+@with_seed()
 def test_normalize():
     data_in = np.random.uniform(0, 255, (300, 300, 3)).astype(dtype=np.uint8)
     data_in = transforms.ToTensor()(nd.array(data_in, dtype='uint8'))
@@ -39,12 +44,16 @@ def test_normalize():
     data_expected[:][:][2] = data_expected[:][:][2] - 2.0
     assert_almost_equal(data_expected, out_nd.asnumpy())
 
+
+@with_seed()
 def test_flip_left_right():
     data_in = np.random.uniform(0, 255, (300, 300, 3)).astype(dtype=np.uint8)
     flip_in = data_in[:, ::-1, :]
     data_trans = nd.image.flip_left_right(nd.array(data_in, dtype='uint8'))
     assert_almost_equal(flip_in, data_trans.asnumpy())
 
+
+@with_seed()
 def test_flip_top_bottom():
     data_in = np.random.uniform(0, 255, (300, 300, 3)).astype(dtype=np.uint8)
     flip_in = data_in[::-1, :, :]
@@ -52,6 +61,7 @@ def test_flip_top_bottom():
     assert_almost_equal(flip_in, data_trans.asnumpy())
 
 
+@with_seed()
 def test_transformer():
     from mxnet.gluon.data.vision import transforms
 
diff --git a/tests/python/unittest/test_gluon_model_zoo.py b/tests/python/unittest/test_gluon_model_zoo.py
index 5b338cc885..935340ea23 100644
--- a/tests/python/unittest/test_gluon_model_zoo.py
+++ b/tests/python/unittest/test_gluon_model_zoo.py
@@ -19,10 +19,12 @@
 import mxnet as mx
 from mxnet.gluon.model_zoo.vision import get_model
 import sys
+from common import setup_module, with_seed
 
 def eprint(*args, **kwargs):
     print(*args, file=sys.stderr, **kwargs)
 
+@with_seed()
 def test_models():
     all_models = ['resnet18_v1', 'resnet34_v1', 'resnet50_v1', 'resnet101_v1', 'resnet152_v1',
                   'resnet18_v2', 'resnet34_v2', 'resnet50_v2', 'resnet101_v2', 'resnet152_v2',
diff --git a/tests/python/unittest/test_kvstore.py b/tests/python/unittest/test_kvstore.py
index 174d577556..6bab06c5b7 100644
--- a/tests/python/unittest/test_kvstore.py
+++ b/tests/python/unittest/test_kvstore.py
@@ -20,6 +20,7 @@
 import numpy as np
 import unittest
 from mxnet.test_utils import rand_ndarray, assert_almost_equal, assert_exception
+from common import setup_module, with_seed
 from mxnet.base import py_str, MXNetError
 
 shape = (4, 4)
@@ -50,6 +51,7 @@ def check_diff_to_scalar(A, x):
     assert(np.sum(np.abs((A - x).asnumpy())) == 0)
 
 
+@with_seed()
 def test_single_kv_pair():
     """single key-value pair push & pull"""
     def check_single_kv_pair(kv, key):
@@ -61,6 +63,7 @@ def check_single_kv_pair(kv, key):
     check_single_kv_pair(init_kv(), 3)
     check_single_kv_pair(init_kv_with_str(), 'a')
 
+@with_seed()
 def test_row_sparse_pull():
     kv = init_kv_with_str('row_sparse')
     kv.init('e', mx.nd.ones(shape).tostype('row_sparse'))
@@ -89,6 +92,7 @@ def check_row_sparse_pull(kv, count):
     check_row_sparse_pull(kv, 1)
     check_row_sparse_pull(kv, 4)
 
+@with_seed()
 def test_init():
     """test init"""
     def check_init(kv, key):
@@ -100,6 +104,7 @@ def check_init(kv, key):
     check_init(mx.kv.create(), 3)
     check_init(mx.kv.create(), 'a')
 
+@with_seed()
 def test_list_kv_pair():
     """list key-value pair push & pull"""
     def check_list_kv_pair(kv, key):
@@ -113,6 +118,7 @@ def check_list_kv_pair(kv, key):
     check_list_kv_pair(init_kv_with_str(), str_keys)
 
 
+@with_seed()
 def test_aggregator():
     """aggregate value on muliple devices"""
 
@@ -143,6 +149,7 @@ def check_aggregator(kv, key, key_list):
     check_aggregator(init_kv_with_str(), 'a', str_keys)
 
 
+@with_seed()
 def test_sparse_aggregator():
     """aggregate sparse ndarray on muliple devices"""
 
@@ -194,6 +201,7 @@ def str_updater(key, recv, local):
     assert(isinstance(key, str))
     local += recv
 
+@with_seed()
 def test_updater(dev = 'cpu'):
     """updater"""
 
@@ -232,11 +240,13 @@ def check_updater(kv, key, key_list):
     str_kv._set_updater(str_updater)
     check_updater(str_kv, 'a', str_keys)
 
+@with_seed()
 def test_get_type():
     kvtype = 'local_allreduce_cpu'
     kv = mx.kv.create(kvtype)
     assert kv.type == kvtype
 
+@with_seed()
 def test_invalid_pull():
     def check_ignored_pull_single(kv, key):
         dns_val = (mx.nd.ones(shape) * 2)
diff --git a/tests/python/unittest/test_loss.py b/tests/python/unittest/test_loss.py
index 9fb303352b..5a3237d2d6 100644
--- a/tests/python/unittest/test_loss.py
+++ b/tests/python/unittest/test_loss.py
@@ -19,9 +19,11 @@
 import numpy as np
 from mxnet import gluon
 from mxnet.test_utils import assert_almost_equal, default_context
+from common import setup_module, with_seed
 import unittest
 
 
+@with_seed()
 def test_loss_ndarray():
     output = mx.nd.array([1, 2, 3, 4])
     label = mx.nd.array([1, 3, 5, 7])
@@ -62,9 +64,8 @@ def get_net(num_hidden, flatten=True):
     fc3 = mx.symbol.FullyConnected(act2, name='fc3', num_hidden=num_hidden, flatten=flatten)
     return fc3
 
-
+@with_seed(1234)
 def test_ce_loss():
-    np.random.seed(1234)
     nclass = 10
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, nclass))
@@ -81,8 +82,8 @@ def test_ce_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_bce_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 20))
     label = mx.nd.array(np.random.randint(2, size=(N,)), dtype='float32')
@@ -106,6 +107,7 @@ def test_bce_loss():
     npy_bce_loss = - label_npy * np.log(prob_npy) - (1 - label_npy) * np.log(1 - prob_npy)
     assert_almost_equal(mx_bce_loss, npy_bce_loss)
 
+@with_seed()
 def test_bce_equal_ce2():
     N = 100
     loss1 = gluon.loss.SigmoidBCELoss(from_sigmoid=True)
@@ -125,8 +127,8 @@ def test_logistic_loss_equal_bce():
     assert_almost_equal(loss_binary(data, label).asnumpy(), loss_bce(data, label).asnumpy())
     assert_almost_equal(loss_signed(data, 2 * label - 1).asnumpy(), loss_bce(data, label).asnumpy())
 
+@with_seed(1234)
 def test_kl_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.nd.softmax(mx.random.uniform(0, 1, shape=(N, 2)))
@@ -142,8 +144,8 @@ def test_kl_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_l2_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.random.uniform(-1, 1, shape=(N, 1))
@@ -160,8 +162,8 @@ def test_l2_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_l1_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.random.uniform(-1, 1, shape=(N, 1))
@@ -179,6 +181,7 @@ def test_l1_loss():
 
 
 @unittest.skip("flaky test. https://github.com/apache/incubator-mxnet/issues/8892")
+@with_seed()
 def test_ctc_loss():
     loss = gluon.loss.CTCLoss()
     l = loss(mx.nd.ones((2,20,4)), mx.nd.array([[1,0,-1,-1],[2,1,1,-1]]))
@@ -205,8 +208,8 @@ def test_ctc_loss():
     mx.test_utils.assert_almost_equal(l.asnumpy(), np.array([18.82820702, 16.50581741]))
 
 @unittest.skip("flaky test. https://github.com/apache/incubator-mxnet/issues/8892")
+@with_seed(1234)
 def test_ctc_loss_train():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 20, 10))
     label = mx.nd.arange(4, repeat=N).reshape((N, 4))
@@ -223,8 +226,8 @@ def test_ctc_loss_train():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 10
 
 
+@with_seed(1234)
 def test_sample_weight_loss():
-    np.random.seed(1234)
     nclass = 10
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, nclass))
@@ -248,9 +251,8 @@ def test_sample_weight_loss():
     assert score < 0.05
 
 
+@with_seed(1234)
 def test_saveload():
-    mx.random.seed(1234)
-    np.random.seed(1234)
     nclass = 10
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, nclass))
@@ -271,8 +273,8 @@ def test_saveload():
             eval_metric=mx.metric.Loss())
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
+@with_seed(1234)
 def test_huber_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.random.uniform(-1, 1, shape=(N, 1))
@@ -289,8 +291,8 @@ def test_huber_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_hinge_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.nd.sign(mx.random.uniform(-1, 1, shape=(N, 1)))
@@ -307,8 +309,8 @@ def test_hinge_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_squared_hinge_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.nd.sign(mx.random.uniform(-1, 1, shape=(N, 1)))
@@ -325,8 +327,8 @@ def test_squared_hinge_loss():
     assert mod.score(data_iter, eval_metric=mx.metric.Loss())[0][1] < 0.05
 
 
+@with_seed(1234)
 def test_triplet_loss():
-    np.random.seed(1234)
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     pos = mx.random.uniform(-1, 1, shape=(N, 10))
diff --git a/tests/python/unittest/test_module.py b/tests/python/unittest/test_module.py
index db5508deef..d6e15c2c0e 100644
--- a/tests/python/unittest/test_module.py
+++ b/tests/python/unittest/test_module.py
@@ -21,12 +21,11 @@
 import numpy as np
 from functools import reduce
 from mxnet.module.executor_group import DataParallelExecutorGroup
-from common import assertRaises
+from common import setup_module, with_seed, assertRaises
 from collections import namedtuple
 
-import numpy.random as rnd
-
 
+@with_seed()
 def test_module_dtype():
     dtype = np.float16
     dshape = (3, 8, 7)
@@ -45,6 +44,7 @@ def test_module_dtype():
       assert x.dtype == dtype
 
 
+@with_seed()
 def test_module_input_grads():
     a = mx.sym.Variable('a', __layout__='NC')
     b = mx.sym.Variable('b', __layout__='NC')
@@ -70,6 +70,7 @@ def test_module_input_grads():
     assert np.all(c_grad == 3), c_grad
 
 
+@with_seed()
 def test_module_ctx_group():
     def check_module_ctx_group(ctxs, group2ctxs, grad_ctxs=None):
         with mx.AttrScope(ctx_group='dev1'):
@@ -109,6 +110,7 @@ def check_module_ctx_group(ctxs, group2ctxs, grad_ctxs=None):
     check_module_ctx_group([mx.cpu(0), mx.cpu(1)],
         {'dev1':[mx.cpu(2), mx.cpu(2)], 'dev2':[mx.cpu(3), mx.cpu(3)]})
 
+@with_seed()
 def test_bucket_module_ctx_group():
     num_hidden = 10
     batch_size = 5
@@ -139,6 +141,7 @@ def sym_gen(seq_len):
              for_training=True, inputs_need_grad=True)
     assert(mod.binded)
 
+@with_seed()
 def test_module_layout():
     sym = mx.sym.Variable('data')
     sym = mx.sym.Activation(data=sym, act_type='relu', __layout__='TNC')
@@ -157,6 +160,7 @@ def test_module_layout():
         assert x.shape == hdshape
 
 
+@with_seed()
 def test_save_load():
     def dict_equ(a, b):
         assert set(a) == set(b)
@@ -197,6 +201,7 @@ def dict_equ(a, b):
     dict_equ(mod._kvstore._updater.states, mod2._updater.states)
 
 
+@with_seed()
 def test_module_reshape():
     data = mx.sym.Variable('data')
     sym = mx.sym.FullyConnected(data, num_hidden=20, name='fc')
@@ -224,6 +229,7 @@ def test_module_reshape():
     assert (mod.get_params()[0]['fc_bias'].asnumpy() == -3).all()
 
 
+@with_seed()
 def test_module_states():
     stack = mx.rnn.SequentialRNNCell()
     for i in range(2):
@@ -251,6 +257,7 @@ def test_module_states():
         assert not mx.test_utils.almost_equal(x1.asnumpy(), x2.asnumpy(), rtol=1e-3)
 
 
+@with_seed()
 def test_module_switch_bucket():
     vocab_dim = 5000
     num_hidden = 100
@@ -307,9 +314,9 @@ def create_bucketing_module(key):
 
 
 
+@with_seed(11)
 def test_module_set_params():
     # data iter
-    mx.random.seed(11)
     data = mx.nd.array([[0.05, .10]]);
     label = mx.nd.array([[.01, 0.99]]);
     train_data = mx.io.NDArrayIter(data, label, batch_size=1)
@@ -370,9 +377,9 @@ def test_module_set_params():
                  aux_params={}, allow_missing=True, allow_extra=False)
 
 
+@with_seed(11)
 def test_monitor():
     # data iter
-    mx.random.seed(11)
     data = mx.nd.array([[0.05, .10]]);
     label = mx.nd.array([[.01, 0.99]]);
     train_data = mx.io.NDArrayIter(data, label, batch_size=1)
@@ -417,6 +424,7 @@ def mean_abs(x):
                 break
     assert(mon_result_counts == [2, 2, 1, 6, 6, 4])
 
+@with_seed()
 def test_executor_group():
     def get_rnn_sym(num_layers, num_words, num_hidden, num_embed, seq_len, sparse_embedding):
         stack = mx.rnn.SequentialRNNCell()
@@ -545,13 +553,11 @@ def check_shared_exec_group(sparse_embedding):
     for opt in sparse_embedding_opt:
         check_shared_exec_group(opt)
 
-
+@with_seed(11)
 def test_factorization_machine_module(verbose=False):
     """ Test factorization machine model with sparse operators """
     def check_factorization_machine_module(optimizer=None, num_epochs=None):
         print("check_factorization_machine_module( {} )".format(optimizer))
-        mx.random.seed(11)
-        rnd.seed(11)
 
         def fm(factor_size, feature_dim, init):
             x = mx.symbol.Variable("data", stype='csr')
@@ -662,6 +668,7 @@ def fm(factor_size, feature_dim, init):
         print("Duration: {}".format(time.clock() - start))
 
 
+@with_seed()
 def test_module_initializer():
     def regression_model(m):
          x = mx.symbol.var("data", stype='csr')
@@ -688,6 +695,7 @@ def regression_model(m):
     assert(v.stype == 'row_sparse')
     assert(np.sum(v.asnumpy()) != 0)
 
+@with_seed()
 def test_forward_reshape():
     num_class=10
     data1 = mx.sym.Variable('data1')
diff --git a/tests/python/unittest/test_ndarray.py b/tests/python/unittest/test_ndarray.py
index 22ff6e8cf5..75389eb187 100644
--- a/tests/python/unittest/test_ndarray.py
+++ b/tests/python/unittest/test_ndarray.py
@@ -21,6 +21,7 @@
 import pickle as pkl
 import unittest
 from nose.tools import raises
+from common import setup_module, with_seed
 from mxnet.test_utils import almost_equal
 from mxnet.test_utils import assert_almost_equal
 from mxnet.test_utils import default_context
@@ -57,13 +58,13 @@ def check_with_uniform(uf, arg_shapes, dim=None, npuf=None, rmin=-10, type_list=
         else:
             assert_almost_equal(out1, out2)
 
-
 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
 
 
+@with_seed()
 def test_ndarray_setitem():
     shape = (3, 4, 2)
 
@@ -107,8 +108,8 @@ def test_ndarray_setitem():
     assert same(x.asnumpy(), x_np)
 
 
+@with_seed(0)
 def test_ndarray_elementwise():
-    np.random.seed(0)
     nrepeat = 10
     maxdim = 4
     all_type = [np.float32, np.float64, np.float16, np.uint8, np.int32]
@@ -124,11 +125,13 @@ def test_ndarray_elementwise():
             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)
 
+@with_seed()
 def test_ndarray_elementwisesum():
     ones = mx.nd.ones((10,), dtype=np.int32)
     res = mx.nd.ElementWiseSum(ones, ones*2, ones*4, ones*8)
     assert same(res.asnumpy(), ones.asnumpy()*15)
 
+@with_seed()
 def test_ndarray_negate():
     npy = np.random.uniform(-10, 10, (2,3,4))
     arr = mx.nd.array(npy)
@@ -140,6 +143,7 @@ def test_ndarray_negate():
     # we compute (-arr)
     assert_almost_equal(npy, arr.asnumpy())
 
+@with_seed()
 def test_ndarray_reshape():
     tensor  = mx.nd.array([[[1, 2], [3, 4]],
                            [[5, 6], [7, 8]]])
@@ -156,6 +160,7 @@ def test_ndarray_reshape():
     assert same(tensor.reshape((-1, 2)).asnumpy(), true_res.asnumpy())
 
 
+@with_seed()
 def test_ndarray_choose():
     shape = (100, 20)
     npy = np.arange(np.prod(shape)).reshape(shape)
@@ -167,6 +172,7 @@ def test_ndarray_choose():
                     mx.nd.choose_element_0index(arr, mx.nd.array(indices)).asnumpy())
 
 
+@with_seed()
 def test_ndarray_fill():
     shape = (100, 20)
     npy = np.arange(np.prod(shape)).reshape(shape)
@@ -182,6 +188,7 @@ def test_ndarray_fill():
                     mx.nd.fill_element_0index(arr, mx.nd.array(val), mx.nd.array(indices)).asnumpy())
 
 
+@with_seed()
 def test_ndarray_onehot():
     shape = (100, 20)
     npy = np.arange(np.prod(shape)).reshape(shape)
@@ -195,12 +202,14 @@ def test_ndarray_onehot():
         assert same(npy, arr.asnumpy())
 
 
+@with_seed()
 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
 
 
+@with_seed()
 def test_ndarray_scalar():
     c = mx.nd.empty((10,10))
     d = mx.nd.empty((10,10))
@@ -215,8 +224,9 @@ def test_ndarray_scalar():
     d = -c + 2
     assert(np.sum(d.asnumpy()) < 1e-5)
 
+
+@with_seed(0)
 def test_ndarray_pickle():
-    np.random.seed(0)
     maxdim = 5
     nrepeat = 10
     for repeat in range(nrepeat):
@@ -231,8 +241,8 @@ def test_ndarray_pickle():
             assert np.sum(a.asnumpy() != a2.asnumpy()) == 0
 
 
+@with_seed()
 def test_ndarray_saveload():
-    np.random.seed(0)
     nrepeat = 10
     fname = 'tmp_list.bin'
     for repeat in range(nrepeat):
@@ -263,6 +273,8 @@ def test_ndarray_saveload():
         assert np.sum(single_ndarray.asnumpy() != single_ndarray_loaded.asnumpy()) == 0
     os.remove(fname)
 
+
+@with_seed()
 def test_ndarray_legacy_load():
     data = []
     for i in range(6):
@@ -273,6 +285,8 @@ def test_ndarray_legacy_load():
     for i in range(len(data)):
         assert same(data[i].asnumpy(), legacy_data[i].asnumpy())
 
+
+@with_seed()
 def test_ndarray_slice():
     shape = (10,)
     A = mx.nd.array(np.random.uniform(-10, 10, shape))
@@ -295,6 +309,7 @@ def test_ndarray_slice():
     assert (a[mx.nd.array([1, 1, 0]), mx.nd.array([0, 1, 0])].asnumpy() == [2, 3, 0]).all()
 
 
+@with_seed()
 def test_ndarray_crop():
     # get crop
     x = mx.nd.ones((2, 3, 4))
@@ -319,6 +334,7 @@ def test_ndarray_crop():
     assert same(x.asnumpy(), np_x)
 
 
+@with_seed()
 def test_ndarray_concatenate():
     axis = 1
     shapes = [(2, 3, 4, 2), (2, 2, 4, 2), (2, 1, 4, 2)]
@@ -331,6 +347,7 @@ def test_ndarray_concatenate():
     assert same(array_np, array_nd.asnumpy())
 
 
+@with_seed()
 def test_clip():
     shape = (10,)
     A = mx.random.uniform(-10, 10, shape)
@@ -340,7 +357,11 @@ def test_clip():
         assert B1[i] >= -2
         assert B1[i] <= 2
 
+
+@with_seed()
 def test_dot():
+    # Non-zero atol required, as exposed by seed 828791701
+    atol = 1e-5
     # Test normal dot
     a = np.random.uniform(-3, 3, (3, 4))
     b = np.random.uniform(-3, 3, (4, 5))
@@ -348,7 +369,7 @@ def test_dot():
     A = mx.nd.array(a)
     B = mx.nd.array(b)
     C = mx.nd.dot(A, B)
-    assert_almost_equal(c, C.asnumpy())
+    assert_almost_equal(c, C.asnumpy(), atol=atol)
     # Test dot with transpose kargs
     a = np.random.uniform(-3, 3, (3, 4))
     b = np.random.uniform(-3, 3, (3, 5))
@@ -356,7 +377,7 @@ def test_dot():
     A = mx.nd.array(a)
     B = mx.nd.array(b)
     C = mx.nd.dot(A, B, transpose_a=True)
-    assert_almost_equal(c, C.asnumpy())
+    assert_almost_equal(c, C.asnumpy(), atol=atol)
     # Test dot with transpose kargs
     a = np.random.uniform(-3, 3, (3, 4))
     b = np.random.uniform(-3, 3, (5, 4))
@@ -364,7 +385,7 @@ def test_dot():
     A = mx.nd.array(a)
     B = mx.nd.array(b)
     C = mx.nd.dot(A, B, transpose_b=True)
-    assert_almost_equal(c, C.asnumpy())
+    assert_almost_equal(c, C.asnumpy(), atol=atol)
     # Test dot with transpose kargs
     a = np.random.uniform(-3, 3, (4, 3))
     b = np.random.uniform(-3, 3, (5, 4))
@@ -372,10 +393,10 @@ def test_dot():
     A = mx.nd.array(a)
     B = mx.nd.array(b)
     C = mx.nd.dot(A, B, transpose_a=True, transpose_b=True)
-    assert_almost_equal(c, C.asnumpy())
-
+    assert_almost_equal(c, C.asnumpy(), atol=atol)
 
 
+@with_seed()
 def test_reduce():
     sample_num = 200
     def test_reduce_inner(numpy_reduce_func, nd_reduce_func, multi_axes):
@@ -412,11 +433,16 @@ def test_reduce_inner(numpy_reduce_func, nd_reduce_func, multi_axes):
                       mx.nd.max, True)
     test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, keepdims, np.min),
                       mx.nd.min, True)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, keepdims, np.argmax),
+    # argmax and argmin are sensitive to the precision of the calculation (repro seed 1985162693).
+    # Force numpy to match mxnet's float32.
+    test_reduce_inner(lambda data, axis,
+                             keepdims:np_reduce(np.float32(data), axis, keepdims, np.argmax),
                       mx.nd.argmax, False)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, keepdims, np.argmin),
+    test_reduce_inner(lambda data, axis,
+                             keepdims:np_reduce(np.float32(data), axis, keepdims, np.argmin),
                       mx.nd.argmin, False)
 
+@with_seed()
 def test_broadcast():
     sample_num = 1000
     def test_broadcast_to():
@@ -439,6 +465,8 @@ def test_broadcast_to():
             assert err < 1E-8
     test_broadcast_to()
 
+
+@with_seed()
 def test_broadcast_binary():
     N = 100
     def check_broadcast_binary(fn):
@@ -464,12 +492,16 @@ def check_broadcast_binary(fn):
     check_broadcast_binary(lambda x, y: x - y)
     check_broadcast_binary(lambda x, y: x * y)
     check_broadcast_binary(lambda x, y: x / y)
-    check_broadcast_binary(lambda x, y: x > y)
-    check_broadcast_binary(lambda x, y: x < y)
-    check_broadcast_binary(lambda x, y: x >= y)
-    check_broadcast_binary(lambda x, y: x <= y)
-    check_broadcast_binary(lambda x, y: x == y)
+    # The following ops are sensitive to the precision of the calculation.
+    # Force numpy to match mxnet's float32.
+    check_broadcast_binary(lambda x, y: x.astype(np.float32) > y.astype(np.float32))
+    check_broadcast_binary(lambda x, y: x.astype(np.float32) < y.astype(np.float32))
+    check_broadcast_binary(lambda x, y: x.astype(np.float32) >= y.astype(np.float32))
+    check_broadcast_binary(lambda x, y: x.astype(np.float32) <= y.astype(np.float32))
+    check_broadcast_binary(lambda x, y: x.astype(np.float32) == y.astype(np.float32))
+
 
+@with_seed()
 def test_moveaxis():
     X = mx.nd.array([[[1, 2, 3], [4, 5, 6]],
                      [[7, 8, 9], [10, 11, 12]]])
@@ -483,6 +515,8 @@ def test_moveaxis():
     assert same(res, true_res.asnumpy())
     assert mx.nd.moveaxis(X, 2, 0).shape == (3, 2, 2)
 
+
+@with_seed()
 def test_arange():
     for i in range(5):
         start = np.random.rand() * 10
@@ -498,7 +532,10 @@ def test_arange():
                         dtype="int32").asnumpy()
     assert_almost_equal(pred, gt)
 
-def test_order(ctx=default_context()):
+@with_seed()
+def test_order():
+    ctx = default_context()
+    dat_size = 5
     def gt_topk(dat, axis, ret_typ, k, is_ascend):
         if ret_typ == "indices":
             if is_ascend:
@@ -513,7 +550,7 @@ def gt_topk(dat, axis, ret_typ, k, is_ascend):
                 indices = np.arange(-1, -k-1, -1)
             ret = np.take(np.sort(dat, axis=axis), axis=axis, indices=indices, mode='wrap')
         else:
-            assert dat.shape == (5, 5, 5, 5)
+            assert dat.shape == (dat_size, dat_size, dat_size, dat_size)
             assert axis is None or axis ==1
             ret = np.zeros(dat.shape)
             if is_ascend:
@@ -524,12 +561,27 @@ def gt_topk(dat, axis, ret_typ, k, is_ascend):
             if axis is None:
                 ret.ravel()[gt_argsort] = 1
             else:
-                for i in range(5):
-                    for j in range(5):
-                        for k in range(5):
+                for i in range(dat_size):
+                    for j in range(dat_size):
+                        for k in range(dat_size):
                             ret[i, gt_argsort[i, :, j, k], j, k] = 1
         return ret
-    a_npy = np.random.normal(size=(5, 5, 5, 5))
+
+    # Produce input data for the tests, including ensuring unique values if desired.
+    # Numpy's argsort does not consistently return lowest-index-first for matching
+    # values, making it hard to generate a numpy 'golden copy' to compare against
+    # the mxnet operator.  The 'mask' function is particularly hard to test given that
+    # equal values might span the 'k' boundary.  Issue exposed with seed 1405838964.
+    def get_values(ensure_unique):
+        while True:
+            data = np.float32(np.random.normal(size=(dat_size, dat_size, dat_size, dat_size)))
+            if not ensure_unique:
+                return data
+            num_unique_values = len(set(data.flatten()))
+            if data.size == num_unique_values:
+                return data
+
+    a_npy = get_values(ensure_unique=True)
     a_nd = mx.nd.array(a_npy, ctx=ctx)
 
     # test for ret_typ=indices
@@ -576,24 +628,53 @@ def gt_topk(dat, axis, ret_typ, k, is_ascend):
 
     # test for sort
     nd_ret_sort = mx.nd.sort(a_nd, axis=1, is_ascend=True).asnumpy()
-    gt = gt_topk(a_npy, axis=1, ret_typ="value", k=5, is_ascend=True)
+    gt = gt_topk(a_npy, axis=1, ret_typ="value", k=dat_size, is_ascend=True)
     assert_almost_equal(nd_ret_sort, gt)
     nd_ret_sort = mx.nd.sort(a_nd, axis=None, is_ascend=False).asnumpy()
-    gt = gt_topk(a_npy, axis=None, ret_typ="value", k=5*5*5*5, is_ascend=False)
+    gt = gt_topk(a_npy, axis=None, ret_typ="value",
+                 k=dat_size*dat_size*dat_size*dat_size, is_ascend=False)
     assert_almost_equal(nd_ret_sort, gt)
 
     # test for argsort
     nd_ret_argsort = mx.nd.argsort(a_nd, axis=3, is_ascend=True).asnumpy()
-    gt = gt_topk(a_npy, axis=3, ret_typ="indices", k=5, is_ascend=True)
+    gt = gt_topk(a_npy, axis=3, ret_typ="indices", k=dat_size, is_ascend=True)
     assert_almost_equal(nd_ret_argsort, gt)
     nd_ret_argsort = mx.nd.argsort(a_nd, axis=None, is_ascend=False).asnumpy()
-    gt = gt_topk(a_npy, axis=None, ret_typ="indices", k=5*5*5*5, is_ascend=False)
+    gt = gt_topk(a_npy, axis=None, ret_typ="indices",
+                 k=dat_size*dat_size*dat_size*dat_size, is_ascend=False)
     assert_almost_equal(nd_ret_argsort, gt)
 
     # test topk with a big shape
     a = mx.nd.arange(0, 54686454, step=1, repeat=1)
     assert_almost_equal(a.topk(k=54686454).asnumpy(), a.asnumpy()[::-1])
 
+    # Repeat those tests that don't involve indices.  These should pass even with
+    # duplicated input data values (over many repeated runs with different random seeds,
+    # this will be tested).
+    a_npy = get_values(ensure_unique=False)
+    a_nd = mx.nd.array(a_npy, ctx=ctx)
+
+    # test for ret_typ=value
+    nd_ret_topk = mx.nd.topk(a_nd, axis=1, ret_typ="value", k=3, is_ascend=True).asnumpy()
+    gt = gt_topk(a_npy, axis=1, ret_typ="value", k=3, is_ascend=True)
+    assert_almost_equal(nd_ret_topk, gt)
+    nd_ret_topk = mx.nd.topk(a_nd, axis=3, ret_typ="value", k=2, is_ascend=False).asnumpy()
+    gt = gt_topk(a_npy, axis=3, ret_typ="value", k=2, is_ascend=False)
+    assert_almost_equal(nd_ret_topk, gt)
+    nd_ret_topk = mx.nd.topk(a_nd, axis=None, ret_typ="value", k=21, is_ascend=False).asnumpy()
+    gt = gt_topk(a_npy, axis=None, ret_typ="value", k=21, is_ascend=False)
+    assert_almost_equal(nd_ret_topk, gt)
+
+    # test for sort
+    nd_ret_sort = mx.nd.sort(a_nd, axis=1, is_ascend=True).asnumpy()
+    gt = gt_topk(a_npy, axis=1, ret_typ="value", k=dat_size, is_ascend=True)
+    assert_almost_equal(nd_ret_sort, gt)
+    nd_ret_sort = mx.nd.sort(a_nd, axis=None, is_ascend=False).asnumpy()
+    gt = gt_topk(a_npy, axis=None, ret_typ="value",
+                 k=dat_size*dat_size*dat_size*dat_size, is_ascend=False)
+    assert_almost_equal(nd_ret_sort, gt)
+
+@with_seed()
 def test_ndarray_equal():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -602,6 +683,8 @@ def test_ndarray_equal():
     z = 0 == x
     assert (z.asnumpy() == np.ones((2, 3))).all()
 
+
+@with_seed()
 def test_ndarray_not_equal():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -610,6 +693,8 @@ def test_ndarray_not_equal():
     z = 0 != x
     assert (z.asnumpy() == np.zeros((2, 3))).all()
 
+
+@with_seed()
 def test_ndarray_greater():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -620,6 +705,8 @@ def test_ndarray_greater():
     z = 0 > y
     assert (z.asnumpy() == np.zeros((2, 3))).all()
 
+
+@with_seed()
 def test_ndarray_greater_equal():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -632,6 +719,8 @@ def test_ndarray_greater_equal():
     z = y >= 1
     assert (z.asnumpy() == np.ones((2, 3))).all()
 
+
+@with_seed()
 def test_ndarray_lesser():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -642,6 +731,8 @@ def test_ndarray_lesser():
     z = y < 0
     assert (z.asnumpy() == np.zeros((2, 3))).all()
 
+
+@with_seed()
 def test_ndarray_lesser_equal():
     x = mx.nd.zeros((2, 3))
     y = mx.nd.ones((2, 3))
@@ -654,6 +745,8 @@ def test_ndarray_lesser_equal():
     z = 1 <= y
     assert (z.asnumpy() == np.ones((2, 3))).all()
 
+
+@with_seed()
 def test_take():
     for data_ndim in range(2, 5):
         for idx_ndim in range(1, 4):
@@ -671,6 +764,7 @@ def test_take():
             assert_almost_equal(result.asnumpy(), data_real[idx_real])
 
 
+@with_seed()
 def test_iter():
     x = mx.nd.array([1, 2, 3])
     y = []
@@ -723,6 +817,7 @@ def test_cached():
         o.backward()
 
 
+@with_seed()
 def test_output():
     shape = (2,2)
     ones = mx.nd.ones(shape)
@@ -737,6 +832,8 @@ def test_output():
     arange_out = mx.nd.arange(0, 20, dtype='int64')
     assert_almost_equal(arange_out.asnumpy(), np.arange(0, 20))
 
+
+@with_seed()
 def test_ndarray_fluent():
     has_grad = set(['flatten', 'expand_dims', 'flip', 'tile', 'transpose', 'sum', 'nansum', 'prod',
                     'nanprod', 'mean', 'max', 'min', 'reshape', 'broadcast_to', 'split',
@@ -792,16 +889,19 @@ def check_fluent_regular(func, kwargs, shape=(5, 17, 1), equal_nan=False):
     check_fluent_regular('broadcast_to', {'shape': (5, 17, 47)})
     check_fluent_regular('squeeze', {'axis': (1, 3)}, shape=(2, 1, 3, 1, 4))
 
+
 @raises(ValueError)
 def test_bool_ambiguous():
     bool(mx.nd.ones((2,3,4)))
 
+
 def test_bool():
     assert not bool(mx.nd.array([]))
     assert not bool(mx.nd.zeros((1,)))
     assert bool(mx.nd.ones((1,)))
 
 
+@with_seed()
 def test_ndarray_indexing():
     def test_getitem(np_array, index, is_scalar=False):
         """`is_scalar` indicates whether we should expect a scalar for the result.
diff --git a/tests/python/unittest/test_operator.py b/tests/python/unittest/test_operator.py
index af38b687ad..63b7c66855 100644
--- a/tests/python/unittest/test_operator.py
+++ b/tests/python/unittest/test_operator.py
@@ -24,6 +24,7 @@
 import itertools
 from numpy.testing import assert_allclose, assert_array_equal
 from mxnet.test_utils import *
+from common import setup_module, with_seed
 import unittest
 
 
@@ -62,8 +63,8 @@ def check_elementwise_sum_with_shape(shape, n):
         assert_almost_equal(a.asnumpy(), out_grad.asnumpy())
 
 
+@with_seed(0)
 def test_elementwise_sum():
-    np.random.seed(0)
     nrepeat = 2
     maxdim = 4
     for repeat in range(nrepeat):
@@ -117,6 +118,7 @@ def check_concat_with_shape(shapes, dimension, skip_second):
             assert_almost_equal(grad.asnumpy(), np_grad + 1)
 
 
+@with_seed()
 def test_concat():
     for dimension in range(4):
         n = 2
@@ -173,6 +175,7 @@ def test_concat():
             check_concat_with_shape(shapes, dimension - 4, True)
             check_concat_with_shape(shapes, dimension - 4, False)
 
+@with_seed()
 def test_slice_channel():
     def check_slice_channel(data_ndim, axis, num_outputs, squeeze_axis):
         ins = []
@@ -230,13 +233,16 @@ def check_regression(symbol, forward, backward):
     exec1.forward(is_train=True)
     out1 = exec1.outputs[0].asnumpy()
     npout = forward(arr_data.asnumpy())
-    assert_almost_equal(npout, out1)
+    # Non-zero atol required by test_operator_gpu.py:test_regression with seed 651640549
+    atol = 1e-5
+    assert_almost_equal(npout, out1, atol=atol)
 
     exec1.backward()
     npout = backward(npout,  arr_label.asnumpy().reshape(npout.shape))
-    assert_almost_equal(npout, arr_grad.asnumpy())
+    assert_almost_equal(npout, arr_grad.asnumpy(), atol=atol)
 
 
+@with_seed()
 def test_regression():
     check_regression(mx.symbol.LogisticRegressionOutput,
                      lambda x: 1.0 / (1.0 + np.exp(-x)),
@@ -340,9 +346,12 @@ def check_softmax_with_shape(shape, xpu, preserve_shape=False):
     exec1 = Y.bind(xpu, args = [x, l], args_grad = {'X': grad})
     exec1.forward(is_train=True)
     out = exec1.outputs[0].asnumpy()
-    assert_almost_equal(out, np_softmax(x.asnumpy()), rtol=1e-4)
+    # Non-zero atol required by test_softmax with seed 781663739
+    rtol = 1e-4
+    atol = 1e-6
+    assert_almost_equal(out, np_softmax(x.asnumpy()), rtol=rtol, atol=atol)
     exec1.backward()
-    assert_almost_equal(grad.asnumpy(), np_softmax(x.asnumpy()) - l.asnumpy(), rtol=1e-4)
+    assert_almost_equal(grad.asnumpy(), np_softmax(x.asnumpy()) - l.asnumpy(), rtol=rtol, atol=atol)
 
 
 def test_python_op():
@@ -379,6 +388,7 @@ def test_swapaxes():
     assert_almost_equal(out, swap_)
 
 
+@with_seed()
 def test_scalarop():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -400,6 +410,7 @@ def test_scalarop():
     check_symbolic_backward(test, [data_tmp], [np.ones(shape)*2], [npout_grad])
 
 
+@with_seed()
 def test_scalar_pow():
     data = mx.symbol.Variable('data')
     shape = (1, 1)
@@ -410,6 +421,7 @@ def test_scalar_pow():
     check_symbolic_backward(test, [data_tmp], [np.ones(shape)], [2 * data_tmp])
 
 
+@with_seed()
 def test_symbol_pow():
     shape = (1, 1)
 
@@ -429,6 +441,7 @@ def test_symbol_pow():
     check_symbolic_backward(test, [data_tmp, exp_tmp], [np.ones(shape)], [data_dir, exp_dir])
 
 
+@with_seed()
 def test_pow_fn():
     shape = (3, 4)
     exp = mx.symbol.Variable("exp")
@@ -439,6 +452,7 @@ def test_pow_fn():
     check_symbolic_backward(y, [x], [np.ones(shape)], [np.log(2) * 2**x])
 
 
+@with_seed()
 def test_relu():
     def frelu(x):
         return np.maximum(x, 0.0)
@@ -448,13 +462,18 @@ def frelu_grad(x):
     x = mx.symbol.Variable("x")
     y = mx.sym.relu(x)
     xa = np.random.uniform(low=-1.0,high=1.0,size=shape)
+    eps = 1e-4
+    # Avoid finite difference method inaccuracies due to discontinuous gradient at the origin.
+    # Here we replace small problematic inputs with 1.0.  Repro issue with seed 97264195.
+    xa[abs(xa) < eps] = 1.0
     ya = frelu(xa)
     ga = frelu_grad(xa)
-    check_numeric_gradient(y, [xa], numeric_eps=1E-3)
+    check_numeric_gradient(y, [xa], numeric_eps=eps)
     check_symbolic_forward(y, [xa], [ya])
     check_symbolic_backward(y, [xa], [np.ones(shape)], [ga])
 
 
+@with_seed()
 def test_sigmoid():
     def fsigmoid(a):
         return np.divide(1.0, (1.0 + np.exp(-a)))
@@ -468,6 +487,7 @@ def fsigmoid(a):
     check_symbolic_backward(y, [xa], [np.ones(shape)], [ya * (1 - ya)])
 
 
+@with_seed()
 def test_binary_logic():
     def _inner_test(forward_gt, logic_sym, x_shape, y_shape, test_scalar=True):
         x = mx.symbol.Variable("x")
@@ -524,6 +544,7 @@ def _inner_test(forward_gt, logic_sym, x_shape, y_shape, test_scalar=True):
                 x_shape=(1, 10), y_shape=(10, 1), test_scalar=False)
 
 
+@with_seed()
 def test_embedding():
     in_dim = 10
     out_dim = 4
@@ -542,16 +563,20 @@ def test_embedding():
     arg_map["data"][:] = np_data
     arg_map["embed_weight"][:] = np_weight
     exe_test.forward(is_train=True)
-    assert_almost_equal(exe_test.outputs[0].asnumpy(), np.dot(np_onehot, np_weight))
+    # Non-zero atol required, as exposed by seed 781663739
+    rtol = 1e-5
+    atol = 1e-5
+    assert_almost_equal(exe_test.outputs[0].asnumpy(), np.dot(np_onehot, np_weight), rtol=rtol, atol=atol)
     # backward
     np_grad = np.random.uniform(-1, 1, exe_test.outputs[0].shape)
     grad = mx.nd.zeros(np_grad.shape)
     grad[:] = np_grad
     exe_test.backward([grad])
-    assert_almost_equal(grad_map["embed_weight"].asnumpy(), np.dot(np_onehot.T, np_grad))
+    assert_almost_equal(grad_map["embed_weight"].asnumpy(), np.dot(np_onehot.T, np_grad), rtol=rtol, atol=atol)
 
 
 # check ops handle duplicate input correctly.
+@with_seed()
 def test_binary_op_duplicate_input():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -570,6 +595,7 @@ def test_binary_op_duplicate_input():
     assert_almost_equal(arr_grad.asnumpy(), 2.0 * data_tmp)
 
 
+@with_seed()
 def test_sign():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -594,6 +620,7 @@ def test_sign():
     assert_almost_equal(arr_grad.asnumpy(), npout_grad)
 
 
+@with_seed()
 def test_round_ceil_floor():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -611,6 +638,7 @@ def test_round_ceil_floor():
     assert_almost_equal(out, npout)
 
 
+@with_seed()
 def test_trunc():
     data_tmp = np.random.rand(3, 4) * 10 - 5
     arr_data = mx.nd.array(data_tmp)
@@ -620,11 +648,14 @@ def test_trunc():
     exe_test = test.bind(default_context(), args=[arr_data])
     exe_test.forward(is_train=True)
     out = exe_test.outputs[0].asnumpy()
-    npout = np.trunc(data_tmp)
+    # 'trunc' is sensitive to the precision of the calculation.  Force numpy to match mxnet's float32.
+    # Repro issue with seed 1660190454
+    npout = np.trunc(np.float32(data_tmp))
 
     assert_almost_equal(out, npout)
 
 
+@with_seed()
 def test_rsqrt_cos_sin():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -649,6 +680,7 @@ def test_rsqrt_cos_sin():
     assert_almost_equal(arr_grad.asnumpy(), npout_grad)
 
 
+@with_seed()
 def test_maximum_minimum():
     data1 = mx.symbol.Variable('data')
     data2 = mx.symbol.Variable('data')
@@ -686,6 +718,7 @@ def test_maximum_minimum():
     assert_almost_equal(arr_grad2.asnumpy(), npout_grad2)
 
 
+@with_seed()
 def test_maximum_minimum_scalar():
     data1 = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -717,6 +750,7 @@ def test_maximum_minimum_scalar():
     assert_almost_equal(arr_grad1.asnumpy(), npout_grad1)
 
 
+@with_seed()
 def test_abs():
     data = mx.symbol.Variable('data')
     shape = (3, 4)
@@ -858,6 +892,7 @@ def check_deconvolution_target_shape(input_shape, kernel, stride, pad, adj, targ
     assert out_shapes[0] == (input_shape[0], 5) + target_shape
 
 
+@with_seed()
 def test_deconvolution():
     # 2D
     check_deconvolution_target_shape(
@@ -981,6 +1016,7 @@ def check_bilinear_upsampling_with_shape(shapes, scale, root_scale):
         assert_allclose(arr[name].asnumpy()*root_scale**2*scale**(2*k), arr_grad[name].asnumpy(), rtol=1e-4)
 
 
+@with_seed()
 def test_nearest_upsampling():
     for root_scale in [1,2,3]:
         for scale in [1,2,3]:
@@ -991,6 +1027,7 @@ def test_nearest_upsampling():
 
 
 @unittest.skip("test fails intermittently. temporarily disabled till it gets fixed. tracked at https://github.com/apache/incubator-mxnet/issues/8044")
+@with_seed()
 def test_batchnorm_training():
     def check_batchnorm_training(stype):
         for shape in [(2, 3), (2, 3, 2, 2)]:
@@ -1076,6 +1113,7 @@ def check_batchnorm_training(stype):
         check_batchnorm_training(stype)
 
 
+@with_seed()
 def test_convolution_grouping():
     for dim in [1, 2, 3]:
         num_filter = 4
@@ -1109,6 +1147,7 @@ def test_convolution_grouping():
 
 
 @unittest.skip("test fails intermittently. temporarily disabled till it gets fixed. tracked at https://github.com/apache/incubator-mxnet/issues/8712")
+@with_seed()
 def test_depthwise_convolution():
     for dim in [1,2]:
         for num_base in [1, 4, 16, 32, 64]:
@@ -1151,7 +1190,6 @@ def test_depthwise_convolution():
                             for arr1, arr2 in zip(exe1.outputs + exe1.grad_arrays, exe2.outputs + exe2.grad_arrays):
                                 np.testing.assert_allclose(arr1.asnumpy(), arr2.asnumpy(), rtol=1e-3, atol=1e-3)
 
-
 def gen_broadcast_data(idx):
     # Manually set test cases
     binary_op_data_shape = np.array(
@@ -1281,6 +1319,7 @@ def reduce_op(shape, x):
         assert_allclose(y_2.asnumpy(), x_2, rtol=rtol, atol=atol)
 
 
+@with_seed()
 def test_binary_op():
     a = mx.sym.Variable('a')
     b = mx.sym.Variable('b')
@@ -1307,8 +1346,11 @@ def test_bdiv(a, b):
 
     def test_bmod(a, b):
         c = a % b
-        check_binary_op_forward(c, lambda a, b: a % b, gen_binary_data)
-        check_binary_op_backward(c, lambda g_out, a, b: (g_out, - g_out * (a // b)), gen_binary_data)
+        # '%' is sensitive to the precision of the calculation.  Force numpy to match mxnet's float32.
+        # Issue exposed with seed 1768433044
+        check_binary_op_forward(c, lambda a, b: np.float32(a) % np.float32(b), gen_binary_data)
+        check_binary_op_backward(c,
+            lambda g_out, a, b: (g_out, - g_out * (np.float32(a) // np.float32(b))), gen_binary_data)
 
     def test_bmod_int(a, b):
         c = mx.sym.cast(a, dtype='int32') % mx.sym.cast(b, dtype='int32')
@@ -1323,7 +1365,9 @@ def test_bpow(a, b):
 
     def test_bneq(a, b):
         c = a != b
-        check_binary_op_forward(c, lambda a, b: (a != b).astype(a.dtype), gen_binary_data)
+        # '!=' is sensitive to the precision of the comparison.  Force numpy to match mxnet's float32.
+        # Issue exposed with seed 1644387363
+        check_binary_op_forward(c, lambda a, b: (np.float32(a) != np.float32(b)).astype(a.dtype), gen_binary_data)
         check_binary_op_backward(c, lambda g_out, a, b: (np.zeros_like(a), np.zeros_like(b)), gen_binary_data)
 
     test_bplus(a, b)
@@ -1336,6 +1380,7 @@ def test_bneq(a, b):
     test_bneq(a, b)
 
 
+@with_seed()
 def test_broadcast_binary_op():
     def check_bmaxmin_gradient(test_sym, x, y, delta, rtol, atol):
         """This function ensures that checking the numerical gradient of
@@ -1420,6 +1465,7 @@ def test_bmin(a, b):
     test_bmin(a, b)
 
 
+@with_seed()
 def test_run_convolution_dilated_impulse_response(dil=(1,1), kernel_shape=(3,3), verbose=False):
     dim = len(dil)
     assert(len(kernel_shape) == dim)
@@ -1489,6 +1535,7 @@ def test_run_convolution_dilated_impulse_response(dil=(1,1), kernel_shape=(3,3),
     assert(out[center] - np.sum(kernel_gradient) - out_orig[center] < 0.001)
 
 
+@with_seed()
 def test_convolution_dilated_impulse_response():
     # 1D
     for dil in [ (1,), (2,), (3,) ]:
@@ -1500,6 +1547,7 @@ def test_convolution_dilated_impulse_response():
             test_run_convolution_dilated_impulse_response(dil=dil, kernel_shape=ks)
 
 
+@with_seed()
 def test_reshape():
 
     def test_reshape_new(src_shape, shape_args, reverse, dst_shape):
@@ -1573,6 +1621,7 @@ def test_reshape_new(src_shape, shape_args, reverse, dst_shape):
     assert_allclose(exe.grad_arrays[0].asnumpy(), out_grad_npy.reshape((5, 4, 3, 7)))
 
 
+@with_seed()
 def test_reduce():
     sample_num = 500
     def test_reduce_inner(numpy_reduce_func, numpy_reduce_grad_func, mx_reduce_sym, nan_prob = 0):
@@ -1659,6 +1708,7 @@ def test_reduce_inner(numpy_reduce_func, numpy_reduce_grad_func, mx_reduce_sym,
                       mx.symbol.min)
 
 
+@with_seed()
 def test_broadcast():
     sample_num = 200
     for i in range(sample_num):
@@ -1691,6 +1741,7 @@ def test_broadcasting_ele(sym_bcast):
         test_broadcasting_ele(sym_bcast_to)
 
 
+@with_seed()
 def test_transpose():
     for ndim in range(1, 7):
         for t in range(5):
@@ -1706,6 +1757,7 @@ def test_transpose():
             assert_allclose(np.transpose(x.asnumpy()), y.asnumpy())
 
 
+@with_seed()
 def test_expand_dims():
     for ndim in range(1, 6):
         for axis in range(-ndim + 1, ndim):
@@ -1717,6 +1769,7 @@ def test_expand_dims():
             assert_allclose(x1.shape, y1.shape)
 
 
+@with_seed()
 def test_crop():
     for ndim in range(1, 6):
         for t in range(5):
@@ -1749,6 +1802,7 @@ def test_crop():
             check_numeric_gradient(vy, [x.asnumpy()])
 
 
+@with_seed()
 def test_slice_axis():
     for ndim in range(1, 6):
         shape = np.random.randint(1, 11, size=(ndim,))
@@ -1792,6 +1846,7 @@ def test_slice_axis():
             assert_allclose(xx + x_grad_npy, xgrad.asnumpy(), atol=1E-5)
 
 
+@with_seed()
 def test_flip():
     for ndim in range(1, 6):
         for t in range(5):
@@ -1803,6 +1858,7 @@ def test_flip():
             assert_allclose(x.asnumpy()[idx], y.asnumpy())
 
 
+@with_seed()
 def test_stn():
     np.set_printoptions(threshold=np.nan)
     num_filter = 2  # conv of loc net
@@ -1844,8 +1900,10 @@ def test_stn():
                     assert_almost_equal(out_grad.asnumpy(), grad_grad[0].asnumpy()[:, :, h//4:h-h//4, w//4:w-w//4], rtol=1e-2, atol=1e-4)
 
 
-def test_dot(ctx=default_context()):
-    np.random.seed(1234)
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1234)
+def test_dot():
+    ctx=default_context()
     dtypes = ['float32', 'float64']
 
     # Test normal dot.
@@ -1908,6 +1966,7 @@ def dot_sym_xT_yT(data_type):
             check_numeric_gradient(dot_sym_xT_yT(data_type), [m1_npy.T, m2_npy.T], numeric_eps=1e-1, rtol=2e-2, atol=1e-3)
 
 
+@with_seed()
 def test_batch_dot():
     dtypes = ['float32', 'float64']
 
@@ -1935,9 +1994,9 @@ def test_batch_dot():
                             c_npy[i, :, :] = np.dot(a_npy[i, :, :], b_npy[i, :, :])
                             bgrad_npy[i, :, :] = np.dot(a_npy[i, :, :].T, ograd_npy[i, :, :])
                             agrad_npy[i, :, :] = np.dot(ograd_npy[i, :, :], b_npy[i, :, :].T)
-                            a = mx.sym.Variable('a', dtype=data_type)
-                            b = mx.sym.Variable('b', dtype=data_type)
-                            c = mx.sym.batch_dot(a, b, transpose_a=transpose_a, transpose_b=transpose_b)
+                        a = mx.sym.Variable('a', dtype=data_type)
+                        b = mx.sym.Variable('b', dtype=data_type)
+                        c = mx.sym.batch_dot(a, b, transpose_a=transpose_a, transpose_b=transpose_b)
                         if transpose_a:
                             a_npy = np.transpose(a_npy, axes=(0, 2, 1))
                             agrad_npy = np.transpose(agrad_npy, axes=(0, 2, 1))
@@ -1946,23 +2005,23 @@ def test_batch_dot():
                             b_npy = np.transpose(b_npy, axes=(0, 2, 1))
                             bgrad_npy = np.transpose(bgrad_npy, axes=(0, 2, 1))
                             b_init_grad_npy = np.transpose(b_init_grad_npy, axes=(0, 2, 1))
-                            exe = c.simple_bind(ctx=default_context(),
-                                a=a_npy.shape, b=b_npy.shape, grad_req='write')
-                            exe_add = c.simple_bind(ctx=default_context(),
-                                a=a_npy.shape, b=b_npy.shape, grad_req='add')
-                            exe_add.grad_dict['a'][:] = a_init_grad_npy
-                            exe_add.grad_dict['b'][:] = b_init_grad_npy
-                            outputs = exe.forward(is_train=True, a=a_npy, b=b_npy)
-                            assert_almost_equal(outputs[0].asnumpy(), c_npy, rtol=1e-3, atol=1e-4)
-                            exe.backward(out_grads=[mx.nd.array(ograd_npy, ctx=exe._ctx)])
-                            assert_almost_equal(exe.grad_dict['a'].asnumpy(), agrad_npy, rtol=1e-3, atol=1e-4)
-                            assert_almost_equal(exe.grad_dict['b'].asnumpy(), bgrad_npy, rtol=1e-3, atol=1e-4)
-                            exe_add.forward(is_train=True, a=a_npy, b=b_npy)
-                            exe_add.backward(out_grads=[mx.nd.array(ograd_npy, ctx=exe._ctx)])
-                            assert_almost_equal(exe_add.grad_dict['a'].asnumpy(),
-                                agrad_npy + a_init_grad_npy, rtol=1e-3, atol=1e-4)
-                            assert_almost_equal(exe_add.grad_dict['b'].asnumpy(),
-                                bgrad_npy + b_init_grad_npy, rtol=1e-3, atol=1e-4)
+                        exe = c.simple_bind(ctx=default_context(),
+                            a=a_npy.shape, b=b_npy.shape, grad_req='write')
+                        exe_add = c.simple_bind(ctx=default_context(),
+                            a=a_npy.shape, b=b_npy.shape, grad_req='add')
+                        exe_add.grad_dict['a'][:] = a_init_grad_npy
+                        exe_add.grad_dict['b'][:] = b_init_grad_npy
+                        outputs = exe.forward(is_train=True, a=a_npy, b=b_npy)
+                        assert_almost_equal(outputs[0].asnumpy(), c_npy, rtol=1e-3, atol=1e-4)
+                        exe.backward(out_grads=[mx.nd.array(ograd_npy, ctx=exe._ctx)])
+                        assert_almost_equal(exe.grad_dict['a'].asnumpy(), agrad_npy, rtol=1e-3, atol=1e-4)
+                        assert_almost_equal(exe.grad_dict['b'].asnumpy(), bgrad_npy, rtol=1e-3, atol=1e-4)
+                        exe_add.forward(is_train=True, a=a_npy, b=b_npy)
+                        exe_add.backward(out_grads=[mx.nd.array(ograd_npy, ctx=exe._ctx)])
+                        assert_almost_equal(exe_add.grad_dict['a'].asnumpy(),
+                            agrad_npy + a_init_grad_npy, rtol=1e-3, atol=1e-4)
+                        assert_almost_equal(exe_add.grad_dict['b'].asnumpy(),
+                            bgrad_npy + b_init_grad_npy, rtol=1e-3, atol=1e-4)
 
 
 def get_correlation(data1,data2,kernel_size,max_displacement,stride1,stride2,pad_size,is_multiply):
@@ -2106,6 +2165,7 @@ def unittest_correlation(data_shape,kernel_size,max_displacement,stride1,stride2
     assert_almost_equal(exe1.grad_dict['img2'].asnumpy(), grad2, rtol=1e-3, atol=1e-4)
 
 
+@with_seed()
 def test_correlation():
     unittest_correlation((1,3,10,10), kernel_size = 1,max_displacement = 4,stride1 = 1,stride2 = 1,pad_size = 4,is_multiply = False)
     unittest_correlation((5,1,15,15), kernel_size = 1,max_displacement = 5,stride1 = 1,stride2 = 1,pad_size = 5,is_multiply = False)
@@ -2118,6 +2178,7 @@ def test_correlation():
     unittest_correlation((5,1,11,11), kernel_size = 5,max_displacement = 1,stride1 = 1,stride2 = 1,pad_size = 2,is_multiply = False)
 
 
+@with_seed()
 def test_support_vector_machine_l1_svm():
     xpu = default_context()
     shape = (20, 10)
@@ -2147,6 +2208,7 @@ def test_support_vector_machine_l1_svm():
     assert_almost_equal(grad_np, grad.asnumpy())
 
 
+@with_seed()
 def test_support_vector_machine_l2_svm():
     xpu = default_context()
     shape = (20, 10)
@@ -2177,8 +2239,9 @@ def test_support_vector_machine_l2_svm():
     assert_almost_equal(grad_np, grad.asnumpy())
 
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1234)
 def test_roipooling():
-    np.random.seed(1234)
 
     data = mx.symbol.Variable(name='data')
     rois = mx.symbol.Variable(name='rois')
@@ -2214,6 +2277,7 @@ def check_pad_with_shape(shape, xpu, pad_width, mode):
     check_numeric_gradient(Y, [x.asnumpy()], numeric_eps=1e-2, rtol=1e-2)
 
 
+@with_seed()
 def test_pad():
     shape1 = (2, 3, 3, 5)
     pad1 = (0, 0, 0, 0, 1, 2, 3, 4)
@@ -2265,6 +2329,7 @@ def check_instance_norm_with_shape(shape, xpu):
                            numeric_eps=1e-2, rtol=1e-2, atol=1e-2)
 
 
+@with_seed()
 def test_instance_normalization():
     check_instance_norm_with_shape((1, 1, 1), default_context())
     check_instance_norm_with_shape((2, 1, 2), default_context())
@@ -2272,11 +2337,10 @@ def test_instance_normalization():
     check_instance_norm_with_shape((3,3,2,3,2,1,1), default_context())
 
 
-def check_l2_normalization(in_shape, mode, ctx=default_context(), norm_eps=1e-10):
+def check_l2_normalization(in_shape, mode, norm_eps=1e-10):
+    ctx = default_context()
     data = mx.symbol.Variable('data')
     out = mx.symbol.L2Normalization(data=data, mode=mode, eps=norm_eps)
-    # TODO(szha): Seeding this masks failures. We need to do a deep dive for failures without this seed.
-    np.random.seed(1234)
     in_data = np.random.uniform(-1, 1, in_shape)
     # calculate numpy results
     if mode == 'channel':
@@ -2306,6 +2370,8 @@ def check_l2_normalization(in_shape, mode, ctx=default_context(), norm_eps=1e-10
     check_numeric_gradient(out, [in_data], numeric_eps=1e-3, rtol=1e-2, atol=1e-3)
 
 
+# TODO(szha): Seeding this masks failures. We need to do a deep dive for failures without this seed.
+@with_seed(1234)
 def test_l2_normalization():
     for mode in ['channel', 'spatial', 'instance']:
         for nbatch in [1, 4]:
@@ -2393,11 +2459,13 @@ def check_sequence_func(ftype, mask_value=0, axis=0):
                 numeric_eps=1e-3, rtol=1e-2, atol=1E-4)
 
 
+@with_seed()
 def test_sequence_last():
     check_sequence_func("last", axis=0)
     check_sequence_func("last", axis=1)
 
 
+@with_seed()
 def test_sequence_mask():
     check_sequence_func("mask", axis = 0, mask_value=-2.3)
     check_sequence_func("mask", axis = 1, mask_value=0.3)
@@ -2468,6 +2536,7 @@ def test_wrapper(arr, xpu, sequence_length=None, use_sequence_length=False):
     assert_array_equal(test_wrapper(arr_4, xpu, sequence_length=seq_len_1, use_sequence_length=True), arr_5)
 
 
+@with_seed()
 def test_sequence_reverse():
     check_sequence_func("reverse", axis=0)
     check_sequence_reverse(mx.cpu())
@@ -2547,6 +2616,7 @@ def mathematical_core(name, forward_mxnet_call, forward_numpy_call, backward_num
     assert_almost_equal(arr_grad, npout_grad)
 
 
+@with_seed()
 def test_special_functions_using_scipy():
     try:
         from scipy import special as scipy_special
@@ -2578,6 +2648,7 @@ def rounding(name, forward_mxnet_call, forward_numpy_call, data_init=5., grad_in
     assert_almost_equal(out, npout)
 
 
+@with_seed()
 def test_mathematical():
     # rsqrt
     mathematical_core("rsqrt",
@@ -2665,6 +2736,7 @@ def test_mathematical():
     rounding("fix", lambda x: mx.sym.fix(x), lambda x: np.fix(x))
 
 
+@with_seed()
 def test_special_functions_using_scipy():
     try:
         from scipy import special as scipy_special
@@ -2681,6 +2753,7 @@ def test_special_functions_using_scipy():
                      lambda x: scipy_special.psi(x), 0.5, 0.5)
 
 
+@with_seed()
 def test_clip():
     data = mx.symbol.Variable('data')
     shape = (30, 30)
@@ -2691,6 +2764,7 @@ def test_clip():
                             [np.where(data_tmp < 0.6, [1], [0]) * np.where(data_tmp > -0.6, [1], [0])])
 
 
+@with_seed()
 def test_init():
     def test_basic_val_init(sym_func, np_func, shape, dtype):
         x = sym_func(shape=shape, dtype=dtype)
@@ -2721,6 +2795,7 @@ def test_arange():
     test_arange()
 
 
+@with_seed()
 def test_order():
     ctx = default_context()
 
@@ -2821,6 +2896,7 @@ def gt_topk(dat, axis, ret_typ, k, is_ascend):
                                              is_ascend=True)])
 
 
+@with_seed()
 def test_blockgrad():
     a = mx.sym.Variable('a')
     b = mx.sym.BlockGrad(a)
@@ -2831,6 +2907,7 @@ def test_blockgrad():
     exe.backward()  # No error if BlockGrad works
 
 
+@with_seed()
 def test_take():
     def check_output_n_grad(data_shape, idx_shape):
         exe = result.simple_bind(default_context(), a=data_shape,
@@ -2867,6 +2944,7 @@ def check_output_n_grad(data_shape, idx_shape):
             check_output_n_grad(data_shape, idx_shape)
 
 
+@with_seed()
 def test_grid_generator():
     # transform_type =  affine
     test_case = [(20,21),(4,3),(6,12),(15,17)]
@@ -2935,8 +3013,9 @@ def test_grid_generator():
         assert_almost_equal(exe_add.grad_dict['flow'].asnumpy(), grad_est + flow_grad_npy, rtol=1e-3, atol=1e-5)
 
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1234)
 def test_bilinear_sampler():
-    np.random.seed(1234)
     from math import floor
 
     def between(x, lowerbound, upperbound):
@@ -3095,6 +3174,7 @@ def bilinear_backward_numpy(out_grad, data, grid):
             assert_almost_equal(exe_addto.grad_dict['grid'].asnumpy(), grid_grad + grid_initial_grid, rtol=1e-3,atol=1e-5)
 
 
+@with_seed()
 def test_index2d():
     for _ in range(30):
         n = np.random.randint(1, 100)
@@ -3105,6 +3185,7 @@ def test_index2d():
         assert_almost_equal(r.asnumpy(), data.asnumpy()[np.arange(n), x.asnumpy()])
 
 
+@with_seed()
 def test_cast():
     for srctype in [np.int32, np.float32, np.float16]:
         for dsttype in [np.float32, np.int32, np.float16]:
@@ -3121,6 +3202,7 @@ def test_cast():
             assert_almost_equal(exe.grad_arrays[0].asnumpy(), X.astype(dsttype).astype(srctype), rtol=1e-3)
 
 
+@with_seed()
 def test_repeat():
     def test_repeat_forward():
         ndim_max = 6 # max number of dims of the ndarray
@@ -3195,6 +3277,7 @@ def test_repeat_numeric_gradient():
     test_repeat_numeric_gradient()
 
 
+@with_seed()
 def test_reverse():
     data = mx.symbol.Variable('data')
     shape = (5, 5, 5)
@@ -3206,6 +3289,7 @@ def test_reverse():
     check_symbolic_backward(test, [data_tmp], [grad], [grad[:, ::-1, ::-1]])
 
 
+@with_seed()
 def test_tile():
     def test_normal_case():
         ndim_max = 3 # max number of dims of the ndarray
@@ -3301,6 +3385,7 @@ def test_tile_numeric_gradient():
     test_tile_numeric_gradient()
 
 
+@with_seed()
 def test_one_hot():
     def test_normal_case(index_type=np.int32):
         ndim_max = 6
@@ -3357,6 +3442,7 @@ def test_zero_depth():
     test_zero_depth()
 
 
+@with_seed()
 def test_where():
     def get_forward_expected_output(condition, x, y):
         original_shape = x.shape
@@ -3493,6 +3579,7 @@ def test_where_numeric_gradient(shape, same_shape):
     test_where_numeric_gradient((5, 7, 9), False)
 
 
+@with_seed()
 def test_new_softmax():
     for ndim in range(1, 5):
         for _ in range(5):
@@ -3504,6 +3591,7 @@ def test_new_softmax():
             check_numeric_gradient(sym, [data], rtol=0.05, atol=1e-3)
 
 
+@with_seed()
 def test_log_softmax():
     for ndim in range(1, 5):
         for _ in range(5):
@@ -3515,6 +3603,7 @@ def test_log_softmax():
             check_numeric_gradient(sym, [data], rtol=0.05, atol=1e-3)
 
 
+@with_seed()
 def test_pick():
     def test_pick_helper(index_type=np.int32):
         for _ in range(100):
@@ -3571,7 +3660,7 @@ def check_ctc_loss(acts, labels, loss_truth):
     # test grad
     check_numeric_gradient(ctc, [acts, labels], grad_nodes=['input'], rtol=0.05, atol=1e-3)
 
-
+@with_seed()
 def test_ctc_loss():
     # Test 1: check that batches are same + check against Torch WarpCTC
     acts = np.array([
@@ -3592,6 +3681,7 @@ def test_ctc_loss():
     check_ctc_loss(acts2, labels2, true_loss)
 
 
+@with_seed()
 def test_ctc_loss_grad():
     def check_ctc_loss_grad(blank_label): # from tf
         vocab_size = 5
@@ -3675,6 +3765,7 @@ def check_ctc_loss_grad(blank_label): # from tf
     check_ctc_loss_grad('last')
 
 
+@with_seed()
 def test_quantization_op():
     min0 = mx.nd.array([0.0])
     max0 = mx.nd.array([1.0])
@@ -3689,34 +3780,55 @@ def test_quantization_op():
     assert same(a_.asnumpy(),  a_real.asnumpy())
 
 
+@with_seed()
 def test_reciprocal_op():
+    eps = 2**(-11)
     data_tmp = np.random.rand(3, 4) * 10 - 5
-    # Avoid possible division by 0 errors
-    data_tmp[data_tmp == 0] = 1.0
+    # Avoid possible division by 0 errors and finite difference method inaccuracies.
+    # Factor of 6 below set empirically, depends on eps.
+    # Issue exposed by seed 879579887.
+    # Replace problematic inputs with 1.0.
+    data_tmp[abs(data_tmp) < 6*eps] = 1.0
     data = mx.symbol.Variable('data')
     test = mx.sym.reciprocal(data)
 
-    check_numeric_gradient(test, [data_tmp])
+    check_numeric_gradient(test, [data_tmp], numeric_eps = eps)
     check_symbolic_forward(test, [data_tmp], [np.reciprocal(data_tmp)])
 
+
+@with_seed()
 def test_cbrt_op():
+    eps = 2**(-11)
     data_tmp = np.random.rand(3, 4) * 10 - 5
+    # Avoid finite difference method inaccuracies due to infinite gradient at the origin.
+    # Factor of 4 below set empirically, depends on eps.
+    # Issue exposed by seed 553872106.
+    # Replace problematic inputs with 1.0.
+    data_tmp[abs(data_tmp) < 4*eps] = 1.0
     data = mx.symbol.Variable('data')
     test = mx.sym.cbrt(data)
 
-    check_numeric_gradient(test, [data_tmp])
+    check_numeric_gradient(test, [data_tmp], numeric_eps=eps)
     check_symbolic_forward(test, [data_tmp], [np.cbrt(data_tmp)])
 
+
+@with_seed()
 def test_rcbrt_op():
+    eps = 2**(-11)
     data_tmp = np.random.rand(3, 4) * 10 - 5
-    # Avoid possible division by 0 errors
-    data_tmp[data_tmp == 0] = 1.0
+    # Avoid possible division by 0 errors and finite difference method inaccuracies.
+    # Factor of 4 below set empirically, depends on eps.
+    # Issue exposed by seed 788174893.
+    # Replace problematic inputs with 1.0.
+    data_tmp[abs(data_tmp) < 4*eps] = 1.0
     data = mx.symbol.Variable('data')
     test = mx.sym.rcbrt(data)
 
-    check_numeric_gradient(test, [data_tmp])
+    check_numeric_gradient(test, [data_tmp], numeric_eps = eps)
     check_symbolic_forward(test, [data_tmp], [1/np.cbrt(data_tmp)])
 
+
+@with_seed()
 def test_custom_op():
     class Sqr(mx.operator.CustomOp):
         def forward(self, is_train, req, in_data, out_data, aux):
@@ -3769,6 +3881,7 @@ def create_operator(self, ctx, shapes, dtypes):
         y.backward()
 
 
+@with_seed()
 def test_psroipooling():
     for num_rois in [1, 2]:
         for num_classes, num_group in itertools.product([2, 3], [2, 3]):
@@ -3794,6 +3907,7 @@ def test_psroipooling():
                                                grad_nodes=grad_nodes, ctx=mx.gpu(0))
 
 
+@with_seed()
 def test_deformable_convolution():
     for num_batch in [1, 2]:
         for num_channel_data, num_deformable_group in itertools.product([4, 8], [1, 2]):
@@ -3831,6 +3945,9 @@ def test_deformable_convolution():
                                                    grad_nodes=grad_nodes, ctx=mx.gpu(0))
 
 
+# Seed set because the test is not robust enough to operate on random data.  Repro issue with:
+# MXNET_TEST_SEED=1234 nosetests --verbose tests/python/gpu/test_operator_gpu.py:test_deformable_psroipooling
+@with_seed(0)
 def test_deformable_psroipooling():
     for num_rois in [1, 2]:
         for num_classes, num_group in itertools.product([2, 3], [2, 3]):
@@ -3889,6 +4006,8 @@ def _make_lower_triangle_symm(a, ndims, m, dtype=np.float32):
     lt_mask = mx.sym.reshape(lt_mask, shape=shp)
     return mx.sym.broadcast_mul(a, lt_mask)
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(42)
 def test_laop():
     dtype = np.float64
     rtol_fw = 1e-7
@@ -3917,8 +4036,6 @@ def test_laop():
     shape2 = (3, 2)
     shape3 = (3, 3)
     shape4 = (2, 2)
-    #Ensure that ithis tests don't get changed by other calls to random.
-    np.random.seed(42)
     data_in1 = np.random.uniform(1, 10, shape1)
     data_in2 = np.random.uniform(1, 10, shape2)
     data_in3 = np.random.uniform(1, 10, shape3)
@@ -4167,8 +4284,9 @@ def _syevd_combined_symbol(a):
                                    transpose_b=False, name='Ut_L_U')
     return mx.sym.Group([u_ut, ut_lam_u])
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1896893923)
 def test_laop_2():
-    np.random.seed(1896893923)
     dtype = np.float64
     rtol_fw = 1e-7
     atol_fw = 1e-9
@@ -4290,13 +4408,14 @@ def _syevd_backward(grad_u, grad_l, u, l):
     temp3 = np.dot(u.T, temp2)
     return np.dot(temp3, u)
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1896893923)
 def test_laop_3():
     # Currently disabled on GPU as syevd needs cuda8
     # and MxNet builds use cuda 7.5
     if not (default_context() == mx.cpu()):
         return
 
-    np.random.seed(1896893923)
     dtype = np.float64
     rtol_fw = 1e-6
     atol_fw = 1e-6
@@ -4358,13 +4477,14 @@ def test_laop_3():
             check_grad(test_syevd_l_4, [a_batch])
 
 
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(1896893923)
 def test_laop_4():
     # Currently disabled on GPU as syevd needs cuda8
     # and MxNet builds use cuda 7.5
     if not (default_context() == mx.cpu()):
         return
 
-    np.random.seed(1896893923)
     rtol_fw = 1e-6
     atol_fw = 1e-6
 
@@ -4386,6 +4506,7 @@ def test_laop_4():
     check_fw(test_syevd, [a_np], [u_np, l_np], np.float32)
 
 
+@with_seed()
 def test_stack():
     for _ in range(100):
         ndim = random.randint(1, 5)
@@ -4402,6 +4523,8 @@ def test_stack():
         check_numeric_gradient(out, inputs)
 
 
+# test fails with seed 990952066: 0 output seen with dropout ratio=0. See issue #9816
+@with_seed(1234)
 def test_dropout():
     def zero_count(array, ratio):
         zeros = 0
@@ -4498,6 +4621,8 @@ def check_dropout_ratio(ratio, shape):
     check_dropout_ratio(0.75, shape)
     check_dropout_ratio(0.25, shape)
 
+
+@with_seed()
 def test_scatter_gather_nd():
     def check(data, idx):
         data.attach_grad()
@@ -4590,8 +4715,9 @@ def np_smooth_l1_grad(x, sigma):
 # - Forward: Comparison to NumPy (several dtype)
 # - Backward: Comparison to NumPy (several dtype)
 # - Finite difference tests (only dtype = float64)
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(192837465)
 def test_unary_math_operators():
-    np.random.seed(192837465)
     have_scipy = True
     try:
         from scipy import special as scipy_special
@@ -4793,8 +4919,9 @@ def finite_diff_binary_op(
 # - Forward: Comparison to NumPy (several dtype)
 # - Backward: Comparison to NumPy (several dtype)
 # - Finite difference tests (only dtype = float64)
+# Seed set because the test is not robust enough to operate on random data
+@with_seed(192837465)
 def test_binary_math_operators():
-    np.random.seed(192837465)
     shape=(9, 10)
     dtype_l = [np.float64, np.float32, np.float16]
     rtol_l = [1e-7, 1e-6, 1e-2]
@@ -4828,6 +4955,7 @@ def test_binary_math_operators():
             num_eps)
 
 
+@with_seed()
 def test_softmax():
     check_softmax_with_shape((3, 4), default_context(), preserve_shape=False)
     check_softmax_with_shape((3, 4), default_context(), preserve_shape=True)
@@ -4836,6 +4964,7 @@ def test_softmax():
     check_smoothed_softmax_grad(default_context())
 
 
+@with_seed()
 def test_slice():
     def test_slice_forward_backward(a, index):
         a_np = a.asnumpy()
@@ -4873,6 +5002,7 @@ def test_slice_forward_backward(a, index):
     check_numeric_gradient(slice_sym, [in_data])
 
 
+@with_seed()
 def test_float16_min_max():
     """Test for issue: https://github.com/apache/incubator-mxnet/issues/9007"""
     a = mx.nd.array([np.finfo('float16').min, np.finfo('float16').max], dtype='float16')
@@ -4881,6 +5011,7 @@ def test_float16_min_max():
     assert np.finfo('float16').max == mx.nd.max(a).asscalar()
 
 
+@with_seed()
 def test_squeeze_op():
     def check_squeeze_op(shape, axis=None):
         data = mx.nd.random.uniform(low=-10.0, high=10.0, shape=shape)
diff --git a/tests/python/unittest/test_optimizer.py b/tests/python/unittest/test_optimizer.py
index f7ee6d0653..159c9bac89 100644
--- a/tests/python/unittest/test_optimizer.py
+++ b/tests/python/unittest/test_optimizer.py
@@ -23,7 +23,9 @@
 from nose.tools import raises
 import math
 from mxnet.test_utils import *
+from common import setup_module, with_seed
 
+@with_seed()
 def test_learning_rate():
     o1 = mx.optimizer.Optimizer(learning_rate=0.01)
     o1.set_learning_rate(0.2)
@@ -37,12 +39,14 @@ def test_learning_rate():
 
 
 @raises(UserWarning)
+@with_seed()
 def test_learning_rate_expect_user_warning():
     lr_s = lr_scheduler.FactorScheduler(step=1)
     o = mx.optimizer.Optimizer(lr_scheduler=lr_s, learning_rate=0.3)
     o.set_learning_rate(0.5)
 
 
+@with_seed()
 def test_lr_wd_mult():
     data = mx.sym.Variable('data')
     bias = mx.sym.Variable('fc1_bias', lr_mult=1.0)
@@ -76,7 +80,8 @@ def compare_ndarray_tuple(t1, t2, rtol=None, atol=None):
             assert_almost_equal(t1.asnumpy(), t2.asnumpy(), rtol=rtol, atol=atol)
 
 
-def compare_optimizer(opt1, opt2, shape, dtype, w_stype='default', g_stype='default'):
+def compare_optimizer(opt1, opt2, shape, dtype, w_stype='default', g_stype='default',
+                      rtol=1e-4, atol=1e-5):
     if w_stype == 'default':
         w2 = mx.random.uniform(shape=shape, ctx=default_context(), dtype=dtype)
         w1 = w2.copyto(default_context())
@@ -100,8 +105,8 @@ def compare_optimizer(opt1, opt2, shape, dtype, w_stype='default', g_stype='defa
 
     opt1.update_multi_precision(0, w1, g1, state1)
     opt2.update_multi_precision(0, w2, g2, state2)
-    compare_ndarray_tuple(state1, state2, rtol=1e-4, atol=1e-5)
-    assert_almost_equal(w1.asnumpy(), w2.asnumpy(), rtol=1e-4, atol=1e-5)
+    compare_ndarray_tuple(state1, state2, rtol=rtol, atol=atol)
+    assert_almost_equal(w1.asnumpy(), w2.asnumpy(), rtol=rtol, atol=atol)
 
 # SGD
 
@@ -200,8 +205,8 @@ def update_multi_precision(self, index, weight, grad, state):
         self.update(index, weight, grad, state)
 
 @unittest.skip("Test fails intermittently. Temporarily disabled until fixed. Tracked at https://github.com/apache/incubator-mxnet/issues/9000")
+@with_seed()
 def test_sgd():
-    mx.random.seed(0)
     opt1 = PySGD
     opt2 = mx.optimizer.SGD
     shape = (3, 4, 5)
@@ -308,8 +313,8 @@ def update(self, index, weight, grad, state):
                   mom[row] = self.momentum*mom[row] - lr*wd*weight[row] - lr*self.rescale_grad*grad[row]
                   weight[row] += mom[row]
 
+@with_seed()
 def test_sparse_sgd():
-    mx.random.seed(0)
     opt1 = PySparseSGD
     opt2 = mx.optimizer.SGD
     shape = (3, 4, 5)
@@ -334,8 +339,8 @@ def test_sparse_sgd():
                                               w_stype='row_sparse', g_stype='row_sparse')
 
 
+@with_seed(0)
 def test_std_sparse_sgd():
-    mx.random.seed(0)
     opt1 = PySGD
     opt2 = mx.optimizer.SGD
     shape = (3, 4, 5)
@@ -438,9 +443,8 @@ def update(self, index, weight, grad, state):
             tmp = weight32.astype(weight.dtype)
             tmp.copyto(weight)
 
-
+@with_seed(0)
 def test_nag():
-    mx.random.seed(0)
     opt1 = PyNAG
     opt2 = mx.optimizer.NAG
     shape = (3, 4, 5)
@@ -509,9 +513,8 @@ def update(self, index, weight, grad, state):
         prev_v[:] = v_t
         prev_z[:] = z_t
 
-
+@with_seed(0)
 def test_ftml():
-    mx.random.seed(0)
     opt1 = PyFTML
     opt2 = mx.optimizer.FTML
     shape = (3, 4, 5)
@@ -608,8 +611,8 @@ def update(self, index, weight, grad, state):
             weight[row] -= lr*mean[row]/(mx.nd.sqrt(variance[row]) + self.epsilon)
 
 
+@with_seed()
 def test_adam():
-    mx.random.seed(0)
     opt1 = PyAdam
     opt2 = mx.optimizer.Adam
     shape = (3, 4, 5)
@@ -631,11 +634,16 @@ def test_adam():
                                 ('multi_precision' not in kwarg or
                                     not kwarg['multi_precision'])):
                             continue
-                        compare_optimizer(opt1(**kwarg), opt2(**kwarg), shape, dtype)
+                        # atol 2e-5 needed to pass with seed 1248389097
+                        compare_optimizer(opt1(**kwarg), opt2(**kwarg), shape, dtype,
+                                          rtol=1e-4, atol=2e-5)
+                        # atol 2e-5 needed to pass with seed 781809840
                         compare_optimizer(opt1(sparse_update=True, **kwarg), opt2(**kwarg), shape,
-                                          dtype, w_stype='row_sparse', g_stype='row_sparse')
+                                          dtype, w_stype='row_sparse', g_stype='row_sparse',
+                                          rtol=1e-4, atol=2e-5)
                         compare_optimizer(opt1(**kwarg), opt2(lazy_update=False, **kwarg), shape,
-                                          dtype, w_stype='row_sparse', g_stype='row_sparse')
+                                          dtype, w_stype='row_sparse', g_stype='row_sparse',
+                                          rtol=1e-4, atol=2e-5)
 
 # Signum
 class PySignum(mx.optimizer.Optimizer):
@@ -689,8 +697,8 @@ def update(self, index, weight, grad, state):
         else:
             weight[:] = (1 - lr*(wd+self.wd_lh))*weight - lr*mx.nd.sign(grad)
 
+@with_seed(0)
 def test_signum():
-    mx.random.seed(0)
     opt1 = PySignum
     opt2 = mx.optimizer.Signum
     shape = (3, 4, 5)
@@ -823,8 +831,8 @@ def update(self, index, weight, grad, state):
              mx.ndarray.clip(weight, -self.clip_weights, self.clip_weights, out=weight)
 
 @unittest.skip("Test fails intermittently. Temporarily disabled until fixed. Tracked at https://github.com/apache/incubator-mxnet/issues/8230")
+@with_seed(0)
 def test_rms():
-    mx.random.seed(0)
     opt1 = PyRMSProp
     opt2 = mx.optimizer.RMSProp
     shape = (3, 4, 5)
@@ -909,8 +917,8 @@ def update(self, index, weight, grad, state):
             weight[row] = (mx.nd.sign(dn[row]) * self.lamda1 - dn[row]) / \
                           ((self.beta + mx.nd.sqrt(n[row])) / lr + wd) * (mx.nd.abs(dn[row]) > self.lamda1)
 
+@with_seed()
 def test_ftrl():
-    mx.random.seed(0)
     opt1 = PyFtrl
     opt2 = mx.optimizer.Ftrl
     shape = (3, 4, 5)
@@ -928,6 +936,7 @@ def test_ftrl():
         compare_optimizer(opt1(sparse_update=True, **kwarg), opt2(**kwarg), shape,
                           np.float32, w_stype='row_sparse', g_stype='row_sparse')
 
+@with_seed(1234)
 def test_nadam():
 
     def get_net(num_hidden, flatten=True):
@@ -938,7 +947,7 @@ def get_net(num_hidden, flatten=True):
         act2 = mx.symbol.Activation(fc2, name='relu2', act_type="relu")
         fc3 = mx.symbol.FullyConnected(act2, name='fc3', num_hidden=num_hidden, flatten=flatten)
         return fc3
-    np.random.seed(1234)
+
     N = 20
     data = mx.random.uniform(-1, 1, shape=(N, 10))
     label = mx.random.uniform(-1, 1, shape=(N, 1))
diff --git a/tests/python/unittest/test_random.py b/tests/python/unittest/test_random.py
index d0c1798eb4..6b77fc13d4 100644
--- a/tests/python/unittest/test_random.py
+++ b/tests/python/unittest/test_random.py
@@ -19,6 +19,8 @@
 import mxnet as mx
 from mxnet.test_utils import verify_generator, gen_buckets_probs_with_ppf
 import numpy as np
+import random as rnd
+from common import setup_module, with_seed, random_seed
 import scipy.stats as ss
 
 def same(a, b):
@@ -191,6 +193,7 @@ def check_with_device(device, dtype):
                 for check_name, check_func, tol in symbdic['checks']:
                     assert np.abs(check_func(samples, params)) < tol, "symbolic test: %s check for `%s` did not pass" % (check_name, name)
 
+@with_seed()
 def test_random():
     check_with_device(mx.context.current_context(), 'float16')
     check_with_device(mx.context.current_context(), 'float32')
@@ -206,6 +209,7 @@ def set_seed_variously(init_seed, num_init_seeds, final_seed):
     return end_seed
 
 # Tests that seed setting of std (non-parallel) rng is synchronous w.r.t. rng use before and after.
+@with_seed()
 def test_random_seed_setting():
     ctx = mx.context.current_context()
     seed_to_test = 1234
@@ -227,6 +231,7 @@ def test_random_seed_setting():
 
 
 # Tests that seed setting of parallel rng is synchronous w.r.t. rng use before and after.
+@with_seed()
 def test_parallel_random_seed_setting():
     ctx = mx.context.current_context()
     seed_to_test = 1234
@@ -267,12 +272,15 @@ def test_parallel_random_seed_setting():
                 "symbolic seed-setting test: `uniform` should give the same result with the same seed"
 
 
+@with_seed()
 def test_sample_multinomial():
     x = mx.nd.array([[0,1,2,3,4],[4,3,2,1,0]])/10.0
     dx = mx.nd.ones_like(x)
     mx.contrib.autograd.mark_variables([x], [dx])
+    # Adding rtol and increasing samples needed to pass with seed 2951820647
+    samples = 5000
     with mx.autograd.record():
-        y, prob = mx.nd.random.multinomial(x, shape=1000, get_prob=True)
+        y, prob = mx.nd.random.multinomial(x, shape=samples, get_prob=True)
         r = prob * 5
         r.backward()
 
@@ -280,31 +288,43 @@ def test_sample_multinomial():
     x = x.asnumpy()
     for i in range(x.shape[0]):
 
-        freq = np.bincount(y[i], minlength=5)/1000.0*x[i].sum()
-        mx.test_utils.assert_almost_equal(freq, x[i], rtol=0.25)
+        freq = np.bincount(y[i], minlength=5)/np.float32(samples)*x[i].sum()
+        mx.test_utils.assert_almost_equal(freq, x[i], rtol=0.20)
         rprob = x[i][y[i]]/x[i].sum()
         mx.test_utils.assert_almost_equal(np.log(rprob), prob.asnumpy()[i])
 
         real_dx = np.zeros((5,))
-        for j in range(1000):
+        for j in range(samples):
             real_dx[y[i][j]] += 5.0 / rprob[j]
-        mx.test_utils.assert_almost_equal(real_dx, dx.asnumpy()[i])
+        mx.test_utils.assert_almost_equal(real_dx, dx.asnumpy()[i], rtol=1e-4)
 
 # Test the generators with the chi-square testing
+@with_seed()
 def test_normal_generator():
     ctx = mx.context.current_context()
+    samples = 1000000
+    # Default success rate is 0.25, so 2 successes of 8 trials will pass.
+    trials = 8
+    num_buckets = 5
     for dtype in ['float16', 'float32', 'float64']:
         for mu, sigma in [(0.0, 1.0), (1.0, 5.0)]:
             print("ctx=%s, dtype=%s, Mu=%g, Sigma=%g:" % (ctx, dtype, mu, sigma))
-            buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.norm.ppf(x, mu, sigma), 5)
+            buckets, probs = gen_buckets_probs_with_ppf(lambda x: ss.norm.ppf(x, mu, sigma), num_buckets)
+            # Quantize bucket boundaries to reflect the actual dtype and adjust probs accordingly
+            buckets = np.array(buckets, dtype=dtype).tolist()
+            probs = [(ss.norm.cdf(buckets[i][1], mu, sigma) -
+                      ss.norm.cdf(buckets[i][0], mu, sigma)) for i in range(num_buckets)]
             generator_mx = lambda x: mx.nd.random.normal(mu, sigma, shape=x, ctx=ctx, dtype=dtype).asnumpy()
-            verify_generator(generator=generator_mx, buckets=buckets, probs=probs)
+            verify_generator(generator=generator_mx, buckets=buckets, probs=probs,
+                             nsamples=samples, nrepeat=trials)
             generator_mx_same_seed =\
                 lambda x: np.concatenate(
                     [mx.nd.random.normal(mu, sigma, shape=x // 10, ctx=ctx, dtype=dtype).asnumpy()
                      for _ in range(10)])
-            verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
+            verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs,
+                             nsamples=samples, nrepeat=trials)
 
+@with_seed()
 def test_uniform_generator():
     ctx = mx.context.current_context()
     for dtype in ['float16', 'float32', 'float64']:
@@ -323,6 +343,7 @@ def test_uniform_generator():
                      for _ in range(10)])
             verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
 
+@with_seed()
 def test_gamma_generator():
     ctx = mx.context.current_context()
     for dtype in ['float16', 'float32', 'float64']:
@@ -337,6 +358,7 @@ def test_gamma_generator():
                      for _ in range(10)])
             verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
 
+@with_seed()
 def test_exponential_generator():
     ctx = mx.context.current_context()
     for dtype in ['float16', 'float32', 'float64']:
@@ -351,6 +373,7 @@ def test_exponential_generator():
                      for _ in range(10)])
             verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
 
+@with_seed()
 def test_poisson_generator():
     ctx = mx.context.current_context()
     for dtype in ['float16', 'float32', 'float64']:
@@ -366,6 +389,7 @@ def test_poisson_generator():
                      for _ in range(10)])
             verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
 
+@with_seed()
 def test_negative_binomial_generator():
     ctx = mx.context.current_context()
     for dtype in ['float16', 'float32', 'float64']:
@@ -396,21 +420,106 @@ def test_negative_binomial_generator():
                  for _ in range(10)])
         verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
 
+@with_seed()
 def test_multinomial_generator():
+    # This test fails with dtype float16 if the probabilities themselves cannot be
+    # well-represented in float16.  When the float16 random picks are assigned to buckets,
+    # only certain bucket-probabilities are possible.  Here we map the desired probabilites
+    # (e.g. 0.1) to nearby float16 probabilities (e.g. 0.10009766) that are achievable.
+    def quantize_probs(probs, dtype):
+        if dtype == 'float16':
+            # float16 has a 10-bit fraction plus an implicit leading 1, so all probabilities
+            # of the form N/2^11 (where N is an integer) are representable.
+            num_quanta = 2048.0
+            quantized_probs = np.rint(np.array(probs) * num_quanta) / num_quanta
+            # Ensure probabilities add to 1
+            quantized_probs[0] += 1.0 - quantized_probs.sum()
+        else:
+            # no need to quantize probs with this data precision
+            quantized_probs = np.array(probs)
+        return quantized_probs
+
     ctx = mx.context.current_context()
     probs = [0.1, 0.2, 0.3, 0.05, 0.15, 0.2]
+    samples = 1000000
+    trials = 5
     buckets = list(range(6))
     for dtype in ['float16', 'float32', 'float64']:
         print("ctx=%s, dtype=%s" %(ctx, dtype))
-        generator_mx = lambda x: mx.nd.random.multinomial(data=mx.nd.array(np.array(probs), ctx=ctx, dtype=dtype),
+        quantized_probs = quantize_probs(probs, dtype)
+        generator_mx = lambda x: mx.nd.random.multinomial(data=mx.nd.array(quantized_probs, ctx=ctx, dtype=dtype),
                                                           shape=x).asnumpy()
-        verify_generator(generator_mx, buckets, probs)
+        verify_generator(generator=generator_mx, buckets=buckets, probs=quantized_probs,
+                         nsamples=samples, nrepeat=trials)
         generator_mx_same_seed = \
             lambda x: np.concatenate(
-                [mx.nd.random.multinomial(data=mx.nd.array(np.array(probs), ctx=ctx, dtype=dtype),
+                [mx.nd.random.multinomial(data=mx.nd.array(quantized_probs, ctx=ctx, dtype=dtype),
                                                           shape=x // 10).asnumpy()
                  for _ in range(10)])
-        verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=probs)
+        verify_generator(generator=generator_mx_same_seed, buckets=buckets, probs=quantized_probs,
+                         nsamples=samples, nrepeat=trials)
+
+
+@with_seed()
+def test_with_random_seed():
+    ctx = mx.context.current_context()
+    size = 100
+    shape = (size,)
+
+    def check_same(x, y, name):
+        assert same(x, y), \
+            "%s rng should give the same result with the same seed" % name
+
+    def check_diff(x, y, name):
+        assert not same(x, y), \
+            "%s rng should give different results with different seeds" % name
+
+    # generate python, numpy and mxnet datasets with the given seed
+    def gen_data(seed=None):
+        with random_seed(seed):
+            python_data = [rnd.random() for _ in range(size)]
+            np_data = np.random.rand(size)
+            mx_data = mx.nd.random_uniform(shape=shape, ctx=ctx).asnumpy()
+        return (seed, python_data, np_data, mx_data)
+
+    # check data, expecting them to be the same or different based on the seeds
+    def check_data(a, b):
+        seed_a = a[0]
+        seed_b = b[0]
+        if seed_a == seed_b and seed_a is not None:
+            check_same(a[1], b[1], 'python')
+            check_same(a[2], b[2], 'numpy')
+            check_same(a[3], b[3], 'mxnet')
+        else:
+            check_diff(a[1], b[1], 'python')
+            check_diff(a[2], b[2], 'numpy')
+            check_diff(a[3], b[3], 'mxnet')
+
+    # 5 tests that include a duplicated seed 1 and randomizing seed None
+    seeds = [1, 2, 1, None, None]
+    data = [gen_data(seed) for seed in seeds]
+
+    # Add more complicated test case scenarios
+    with random_seed(1):
+        seeds.append(None)
+        data.append(gen_data(None))
+    with random_seed(2):
+        seeds.append(None)
+        data.append(gen_data(None))
+    with random_seed():
+        seeds.append(1)
+        data.append(gen_data(1))
+    with random_seed():
+        seeds.append(2)
+        data.append(gen_data(2))
+    with random_seed(1):
+        seeds.append(2)
+        data.append(gen_data(2))
+
+    num_seeds = len(seeds)
+    for i in range(0, num_seeds-1):
+        for j in range(i+1, num_seeds):
+            check_data(data[i],data[j])
 
 
 if __name__ == '__main__':
diff --git a/tests/python/unittest/test_recordio.py b/tests/python/unittest/test_recordio.py
index 7de582e236..51d80c3350 100644
--- a/tests/python/unittest/test_recordio.py
+++ b/tests/python/unittest/test_recordio.py
@@ -22,7 +22,9 @@
 import tempfile
 import random
 import string
+from common import setup_module, with_seed
 
+@with_seed()
 def test_recordio():
     frec = tempfile.mktemp()
     N = 255
@@ -43,6 +45,7 @@ def test_recordio():
         else:
             assert res == bytes(str(chr(i)), 'utf-8')
 
+@with_seed()
 def test_indexed_recordio():
     fidx = tempfile.mktemp()
     frec = tempfile.mktemp()
@@ -67,6 +70,7 @@ def test_indexed_recordio():
         else:
             assert res == bytes(str(chr(i)), 'utf-8')
 
+@with_seed()
 def test_recordio_pack_label():
     frec = tempfile.mktemp()
     N = 255
diff --git a/tests/python/unittest/test_sparse_ndarray.py b/tests/python/unittest/test_sparse_ndarray.py
index ab389b6d03..3d6f9d0711 100644
--- a/tests/python/unittest/test_sparse_ndarray.py
+++ b/tests/python/unittest/test_sparse_ndarray.py
@@ -19,6 +19,7 @@
 
 from mxnet.ndarray import NDArray
 from mxnet.test_utils import *
+from common import setup_module, with_seed, random_seed
 from mxnet.base import mx_real_t
 from numpy.testing import assert_allclose
 import numpy.random as rnd
@@ -30,6 +31,7 @@ def sparse_nd_ones(shape, stype):
     return mx.nd.ones(shape).tostype(stype)
 
 
+@with_seed()
 def test_sparse_nd_elemwise_add():
     def check_sparse_nd_elemwise_binary(shapes, stypes, f, g):
         # generate inputs
@@ -55,6 +57,7 @@ def check_sparse_nd_elemwise_binary(shapes, stypes, f, g):
         check_sparse_nd_elemwise_binary(shape, ['row_sparse', 'row_sparse'], op, g)
 
 
+@with_seed()
 def test_sparse_nd_copy():
     def check_sparse_nd_copy(from_stype, to_stype, shape):
         from_nd = rand_ndarray(shape, from_stype)
@@ -76,6 +79,7 @@ def check_sparse_nd_copy(from_stype, to_stype, shape):
     check_sparse_nd_copy('row_sparse', 'default', shape_3d)
     check_sparse_nd_copy('default', 'row_sparse', shape_3d)
 
+@with_seed()
 def test_sparse_nd_basic():
     def check_sparse_nd_basic_rsp():
         storage_type = 'row_sparse'
@@ -88,6 +92,7 @@ def check_sparse_nd_basic_rsp():
     check_sparse_nd_basic_rsp()
 
 
+@with_seed()
 def test_sparse_nd_setitem():
     def check_sparse_nd_setitem(stype, shape, dst):
         x = mx.nd.zeros(shape=shape, stype=stype)
@@ -105,8 +110,9 @@ def check_sparse_nd_setitem(stype, shape, dst):
     # scalar assigned to row_sparse NDArray
     check_sparse_nd_setitem('row_sparse', shape, 2)
 
+@with_seed()
 def test_sparse_nd_slice():
-    shape = (rnd.randint(2, 10), rnd.randint(2, 10))    
+    shape = (rnd.randint(2, 10), rnd.randint(2, 10))
     stype = 'csr'
     A, _ = rand_sparse_ndarray(shape, stype)
     A2 = A.asnumpy()
@@ -118,13 +124,13 @@ def test_sparse_nd_slice():
     assert same(A[:end].asnumpy(), A2[:end])
     ind = rnd.randint(-shape[0], shape[0] - 1)
     assert same(A[ind].asnumpy(), A2[ind][np.newaxis, :])
-        
+
     start_col = rnd.randint(0, shape[1] - 1)
     end_col = rnd.randint(start_col + 1, shape[1])
     result = mx.nd.slice(A, begin=(start, start_col), end=(end, end_col))
     result_dense = mx.nd.slice(mx.nd.array(A2), begin=(start, start_col), end=(end, end_col))
     assert same(result_dense.asnumpy(), result.asnumpy())
-    
+
     A = mx.nd.sparse.zeros('csr', shape)
     A2 = A.asnumpy()
     assert same(A[start:end].asnumpy(), A2[start:end])
@@ -148,6 +154,7 @@ def check_slice_nd_csr_fallback(shape):
     check_slice_nd_csr_fallback(shape)
 
 
+@with_seed()
 def test_sparse_nd_equal():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -159,6 +166,7 @@ def test_sparse_nd_equal():
         assert (z.asnumpy() == np.ones(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_not_equal():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -170,6 +178,7 @@ def test_sparse_nd_not_equal():
         assert (z.asnumpy() == np.zeros(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_greater():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -183,6 +192,7 @@ def test_sparse_nd_greater():
         assert (z.asnumpy() == np.zeros(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_greater_equal():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -198,6 +208,7 @@ def test_sparse_nd_greater_equal():
         assert (z.asnumpy() == np.ones(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_lesser():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -211,6 +222,7 @@ def test_sparse_nd_lesser():
         assert (z.asnumpy() == np.zeros(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_lesser_equal():
     for stype in ['row_sparse', 'csr']:
         shape = rand_shape_2d()
@@ -226,6 +238,7 @@ def test_sparse_nd_lesser_equal():
         assert (z.asnumpy() == np.ones(shape)).all()
 
 
+@with_seed()
 def test_sparse_nd_binary():
     N = 3
     def check_binary(fn, stype):
@@ -262,6 +275,7 @@ def check_binary(fn, stype):
         check_binary(lambda x, y: x == y, stype)
 
 
+@with_seed()
 def test_sparse_nd_binary_scalar_op():
     N = 3
     def check(fn, stype, out_stype=None):
@@ -291,6 +305,8 @@ def check(fn, stype, out_stype=None):
         check(lambda x: x + 0, stype, out_stype=stype)
         check(lambda x: x - 0, stype, out_stype=stype)
 
+
+@with_seed()
 def test_sparse_nd_binary_iop():
     N = 3
     def check_binary(fn, stype):
@@ -319,6 +335,8 @@ def inplace_mul(x, y):
         for fn in fns:
             check_binary(fn, stype)
 
+
+@with_seed()
 def test_sparse_nd_negate():
     def check_sparse_nd_negate(shape, stype):
         npy = np.random.uniform(-10, 10, rand_shape_2d())
@@ -336,6 +354,8 @@ def check_sparse_nd_negate(shape, stype):
     for stype in stypes:
         check_sparse_nd_negate(shape, stype)
 
+
+@with_seed()
 def test_sparse_nd_broadcast():
     sample_num = 1000
     # TODO(haibin) test with more than 2 dimensions
@@ -363,6 +383,7 @@ def test_broadcast_to(stype):
         test_broadcast_to(stype)
 
 
+@with_seed()
 def test_sparse_nd_transpose():
     npy = np.random.uniform(-10, 10, rand_shape_2d())
     stypes = ['csr', 'row_sparse']
@@ -370,6 +391,8 @@ def test_sparse_nd_transpose():
         nd = mx.nd.array(npy).tostype(stype)
         assert_almost_equal(npy.T, (nd.T).asnumpy())
 
+
+@with_seed()
 def test_sparse_nd_storage_fallback():
     def check_output_fallback(shape):
         ones = mx.nd.ones(shape)
@@ -392,6 +415,8 @@ def check_fallback_with_temp_resource(shape):
     check_input_fallback(shape)
     check_fallback_with_temp_resource(shape)
 
+
+@with_seed()
 def test_sparse_nd_random():
     """ test sparse random operator on cpu """
     # gpu random operator doesn't use fixed seed
@@ -402,15 +427,14 @@ def test_sparse_nd_random():
     for fn in fns:
         rsp_out = mx.nd.zeros(shape=shape, stype='row_sparse')
         dns_out = mx.nd.zeros(shape=shape, stype='default')
-        mx.random.seed(0)
-        np.random.seed(0)
-        fn(shape=shape, out=dns_out)
-        mx.random.seed(0)
-        np.random.seed(0)
-        fn(shape=shape, out=rsp_out)
+        with random_seed(0):
+            fn(shape=shape, out=dns_out)
+        with random_seed(0):
+            fn(shape=shape, out=rsp_out)
         assert_almost_equal(dns_out.asnumpy(), rsp_out.asnumpy())
 
 
+@with_seed()
 def test_sparse_nd_astype():
     stypes = ['row_sparse', 'csr']
     for stype in stypes:
@@ -419,8 +443,8 @@ def test_sparse_nd_astype():
         assert(y.dtype == np.int32), y.dtype
 
 
+@with_seed(0)
 def test_sparse_nd_pickle():
-    np.random.seed(0)
     repeat = 1
     dim0 = 40
     dim1 = 40
@@ -439,8 +463,8 @@ def test_sparse_nd_pickle():
                 assert same(a.asnumpy(), b.asnumpy())
 
 
+@with_seed(0)
 def test_sparse_nd_save_load():
-    np.random.seed(0)
     repeat = 1
     stypes = ['default', 'row_sparse', 'csr']
     stype_dict = {'default': NDArray, 'row_sparse': RowSparseNDArray, 'csr': CSRNDArray}
@@ -471,6 +495,8 @@ def test_sparse_nd_save_load():
             assert same(x.asnumpy(), y.asnumpy())
     os.remove(fname)
 
+
+@with_seed()
 def test_sparse_nd_unsupported():
     nd = mx.nd.zeros((2,2), stype='row_sparse')
     fn_slice = lambda x: x._slice(None, None)
@@ -484,6 +510,8 @@ def test_sparse_nd_unsupported():
         except:
             pass
 
+
+@with_seed()
 def test_create_csr():
     def check_create_csr_from_nd(shape, density, dtype):
         matrix = rand_ndarray(shape, 'csr', density)
@@ -560,6 +588,8 @@ def assert_csr_almost_equal(nd, sp):
         check_create_csr_from_scipy(shape, density, mx.nd.sparse.array)
         check_create_csr_from_scipy(shape, density, mx.nd.array)
 
+
+@with_seed()
 def test_create_row_sparse():
     dim0 = 50
     dim1 = 50
@@ -576,6 +606,8 @@ def test_create_row_sparse():
         rsp_copy = mx.nd.array(rsp_created)
         assert(same(rsp_copy.asnumpy(), rsp_created.asnumpy()))
 
+
+@with_seed()
 def test_create_sparse_nd_infer_shape():
     def check_create_csr_infer_shape(shape, density, dtype):
         try:
@@ -618,6 +650,8 @@ def check_create_rsp_infer_shape(shape, density, dtype):
         check_create_rsp_infer_shape(shape, density, dtype)
         check_create_rsp_infer_shape(shape_3d, density, dtype)
 
+
+@with_seed()
 def test_create_sparse_nd_from_dense():
     def check_create_from_dns(shape, f, dense_arr, dtype, default_dtype, ctx):
         arr = f(dense_arr, dtype=dtype, ctx=ctx)
@@ -640,6 +674,7 @@ def check_create_from_dns(shape, f, dense_arr, dtype, default_dtype, ctx):
                             else np.float32
             check_create_from_dns(shape, f, dense_arr, dtype, default_dtype, ctx)
 
+@with_seed()
 def test_create_sparse_nd_from_sparse():
     def check_create_from_sp(shape, f, sp_arr, dtype, src_dtype, ctx):
         arr = f(sp_arr, dtype=dtype, ctx=ctx)
@@ -671,6 +706,8 @@ def check_create_from_sp(shape, f, sp_arr, dtype, src_dtype, ctx):
     for sp_arr in rsp_arrs:
         check_create_from_sp(shape, f_rsp, sp_arr, dtype, src_dtype, ctx)
 
+
+@with_seed()
 def test_create_sparse_nd_empty():
     def check_empty(shape, stype):
         arr = mx.nd.empty(shape, stype=stype)
@@ -710,6 +747,8 @@ def check_rsp_empty(shape, dtype, ctx):
     check_rsp_empty(shape, dtype, ctx)
     check_rsp_empty(shape_3d, dtype, ctx)
 
+
+@with_seed()
 def test_synthetic_dataset_generator():
     def test_powerlaw_generator(csr_arr, final_row=1):
         """Test power law distribution
@@ -742,6 +781,8 @@ def test_powerlaw_generator(csr_arr, final_row=1):
     test_powerlaw_generator(csr_arr_big, final_row=4)
     test_powerlaw_generator(csr_arr_square, final_row=6)
 
+
+@with_seed()
 def test_sparse_nd_fluent():
     def check_fluent_regular(stype, func, kwargs, shape=(5, 17), equal_nan=False):
         with mx.name.NameManager():
@@ -774,6 +815,7 @@ def check_fluent_regular(stype, func, kwargs, shape=(5, 17), equal_nan=False):
         check_fluent_regular('csr', func, {'axis': 0})
 
 
+@with_seed()
 def test_sparse_nd_exception():
     """ test invalid sparse operator will throw a exception """
     a = mx.nd.ones((2,2))
@@ -783,6 +825,7 @@ def test_sparse_nd_exception():
     assertRaises(ValueError, mx.nd.sparse.row_sparse_array, (2,2), shape=(3,2))
     assertRaises(ValueError, mx.nd.sparse.zeros, "invalid_stype", (2,2))
 
+@with_seed()
 def test_sparse_nd_check_format():
     """ test check_format for sparse ndarray """
     shape = rand_shape_2d()
diff --git a/tests/python/unittest/test_sparse_operator.py b/tests/python/unittest/test_sparse_operator.py
index 84dfc5878c..54809d9419 100644
--- a/tests/python/unittest/test_sparse_operator.py
+++ b/tests/python/unittest/test_sparse_operator.py
@@ -16,6 +16,7 @@
 # under the License.
 
 from mxnet.test_utils import *
+from common import setup_module, with_seed
 import random
 import warnings
 
@@ -151,6 +152,7 @@ def gen_rsp_random_indices(shape, density=.5, force_indices=None):
 def all_zero(var):
     return 0
 
+@with_seed()
 def test_elemwise_binary_ops():
     def test_elemwise_binary_op(name, lhs_stype, rhs_stype, shape,
                                 forward_mxnet_call, forward_numpy_call, backward_numpy_call,
@@ -509,6 +511,8 @@ def check_elemwise_binary_ops(lhs_stype, rhs_stype, shape,
                                                   rhs_density=rhs_density,
                                                   ograd_density=ograd_density)
 
+
+@with_seed()
 def test_elemwise_csr_same_zeros():
     # Zeroes
     a = mx.nd.sparse.zeros('csr', (1,1))
@@ -516,6 +520,7 @@ def test_elemwise_csr_same_zeros():
     res = a.asnumpy() + a.asnumpy()
     assert_almost_equal(b.asnumpy(), res)
 
+
 def as_dense(arr):
     if arr.stype != 'default':
         return mx.nd.cast_storage(arr, stype='default')
@@ -684,6 +689,7 @@ def check_sparse_mathematical_core(name, stype,
         assert_almost_equal(arr_grad, input_grad, equal_nan=True)
 
 
+@with_seed()
 def test_sparse_mathematical_core():
     def util_sign(a):
         if np.isclose(a, -0, rtol=1.e-3, atol=1.e-3, equal_nan=True):
@@ -1119,6 +1125,7 @@ def check_mathematical_core(stype, output_grad_stype=None,
 
 
 
+@with_seed()
 def test_elemwise_add_ex():
     def check_elemwise_add_ex(lhs_stype, rhs_stype, shape, lhs_grad_stype=None, rhs_grad_stype=None):
         lhs = mx.symbol.Variable('lhs', stype=lhs_stype)
@@ -1148,6 +1155,7 @@ def check_elemwise_add_ex(lhs_stype, rhs_stype, shape, lhs_grad_stype=None, rhs_
                               lhs_grad_stype='row_sparse', rhs_grad_stype='row_sparse')
 
 
+@with_seed()
 def test_cast_storage_ex():
     def check_cast_storage(shape, density, from_stype, to_stype, check_numeric_grad=True):
         x = mx.symbol.Variable('x', stype=from_stype)
@@ -1196,6 +1204,7 @@ def check_cast_storage(shape, density, from_stype, to_stype, check_numeric_grad=
                                check_numeric_grad=False)
 
 
+@with_seed()
 def test_sparse_dot():
     def test_dot_csr(lhs_shape, rhs_shape, rhs_stype, trans_lhs, lhs_density, rhs_density):
         lhs_nd = rand_ndarray(lhs_shape, 'csr', density=lhs_density, shuffle_csr_indices=False)
@@ -1283,6 +1292,7 @@ def test_sparse_dot_zero_output(lhs_shape, trans_lhs, rhs_num_cols):
     test_sparse_dot_zero_output(rand_shape_2d(50, 200), True, 40)
 
 
+@with_seed()
 def test_sparse_slice():
     def check_csr_slice(shape, slice_input):
         storage_type = 'csr'
@@ -1298,6 +1308,7 @@ def check_csr_slice(shape, slice_input):
     check_csr_slice(shape, False)
 
 
+@with_seed()
 def test_sparse_retain():
     def check_sparse_retain(shape, density, index_type=np.int64):
         num_rows = shape[0]
@@ -1330,6 +1341,7 @@ def check_sparse_retain(shape, density, index_type=np.int64):
             check_sparse_retain(shape_3d, density, itype)
 
 
+@with_seed()
 def test_sparse_unary_with_numerics():
     def check_sparse_simple(name, stype, mxnet_func, forward_numpy_call,
                             backward_numpy_call, output_grad_stype=None,
@@ -1402,6 +1414,7 @@ def check_sparse_function(name, mxnet_func, forward_numpy_call, backward_numpy_c
                           backward_is_use_output=True)
 
 
+@with_seed()
 def test_sparse_nd_zeros():
     def check_sparse_nd_zeros(stype, shape):
         zero = mx.nd.zeros(shape)
@@ -1414,6 +1427,7 @@ def check_sparse_nd_zeros(stype, shape):
     check_sparse_nd_zeros('default', shape)
 
 
+@with_seed()
 def test_sparse_nd_zeros_like():
     def check_sparse_nd_zeros_like(stype, shape):
         zero = mx.nd.zeros(shape, stype=stype)
@@ -1425,6 +1439,7 @@ def check_sparse_nd_zeros_like(stype, shape):
     check_sparse_nd_zeros_like('csr', shape)
 
 
+@with_seed()
 def test_sparse_axis_operations():
     def test_variations(func_name):
         dim0 = 30
@@ -1455,6 +1470,7 @@ def test_fallback(func_name, axis=0, keepdims=True, exclude=True):
     test_fallback(mx.nd.mean, axis=0, keepdims=True, exclude=True)
 
 
+@with_seed()
 def test_sparse_square_sum():
     dim0 = 30
     dim1 = 30
@@ -1514,6 +1530,7 @@ def test_sparse_square_sum():
                                        atol=1e-2, rtol=0.1)
 
 
+@with_seed()
 def test_sparse_storage_fallback():
     """ test operators which don't implement FComputeEx or FStatefulComputeEx """
     def check_broadcast_add(shape, lhs_stype, rhs_stype):
@@ -1583,6 +1600,7 @@ def check_operator_with_temp_resource(shape, stype):
             check_softmax_with_shape(rhs, rhs, shape, preserve_shape=True)
 
 
+@with_seed()
 def test_sparse_elementwise_sum():
     def check_sparse_elementwise_sum_with_shape(stype, shape, n):
         # forward
@@ -1614,6 +1632,7 @@ def check_sparse_elementwise_sum_with_shape(stype, shape, n):
         check_sparse_elementwise_sum_with_shape('row_sparse', shape, np.random.randint(1, 9))
 
 
+@with_seed()
 def test_sparse_embedding():
     ''' test sparse embedding op on cpu '''
     def check_sparse_embedding(executor, weight_ref, data_onehot, grad, density):
@@ -1654,6 +1673,7 @@ def check_sparse_embedding(executor, weight_ref, data_onehot, grad, density):
         check_sparse_embedding(exe_test, weight, np_onehot, grad, density)
 
 
+@with_seed()
 def test_scatter_ops():
     def csr_get_seen_points(name, csr_array, verbose=False):
         """Get a unique list of points int he CSR array as well as a
@@ -1798,6 +1818,8 @@ def check_scatter_ops(name, shape, lhs_stype, rhs_stype, forward_mxnet_call, for
                           lambda l, r: l + r,
                           rhs_is_scalar=True, verbose=False, density=0.5)
 
+
+@with_seed()
 def test_sparse_nd_where():
     def get_forward_expected_output(condition, x, y):
         original_shape = x.shape


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services