def check_equivalent(A, B, rtol=RTOL, atol=ATOL): assert base_class(type(A)) is base_class(type(B)),\ "Types are: {0} and {1}".format(type(A), type(B)) if isinstance(A, (tuple, list)): for a, b in zip(A, B): check_equivalent(a, b) elif isinstance(A, dict): assert len(A) == len(B) for k in A: check_equivalent(A[k], B[k]) else: if isinstance(A, np.ndarray): assert A.shape == B.shape, "Shapes are analytic: {0} and numeric: {1}".format( A.shape, B.shape) assert A.dtype == B.dtype, "Types are analytic: {0} and numeric: {1}".format( A.dtype, B.dtype) assert np.allclose(A, B, rtol=rtol, atol=atol), \ "Diffs are:\n{0}.\nanalytic is:\n{A}.\nnumeric is:\n{B}.".format(A - B, A=A, B=B)
def quick_grad_check(fun, arg0, extra_args=(), kwargs={}, verbose=True, eps=EPS, rtol=RTOL, atol=ATOL, rs=None): """Checks the gradient of a function (w.r.t. to its first arg) in a random direction""" if verbose: print("Checking gradient of {0} at {1}".format(fun, arg0)) if rs is None: rs = np.random.RandomState() random_dir = rs.standard_normal(np.shape(arg0)) random_dir = random_dir / np.sqrt(np.sum(random_dir * random_dir)) unary_fun = lambda x : fun(arg0 + x * random_dir, *extra_args, **kwargs) numeric_grad = unary_nd(unary_fun, 0.0, eps=eps) analytic_grad = np.sum(grad(fun)(arg0, *extra_args, **kwargs) * random_dir) assert np.allclose(numeric_grad, analytic_grad, rtol=rtol, atol=atol), \ "Check failed! nd={0}, ad={1}".format(numeric_grad, analytic_grad) if verbose: print("Gradient projection OK (numeric grad: {0}, analytic grad: {1})".format( numeric_grad, analytic_grad))