Assertion and Testing¶
Chainer provides some facilities to make debugging easy.
Type checking utilities¶
Function uses a systematic type checking of the chainer.utils.type_check module.
It enables users to easily find bugs of forward and backward implementations.
You can find examples of type checking in some function implementations.
-
class
chainer.utils.type_check.Expr(priority)[source]¶ Abstract syntax tree of an expression.
It represents an abstract syntax tree, and isn’t a value. You can get its actual value with
eval()function, and get syntax representation with the__str__()method. Each comparison operator (e.g.==) generates a newExprobject which represents the result of comparison between two expressions.Example
Let
xandybe instances ofExpr, then>>> x = Variable(1, 'x') >>> y = Variable(1, 'y') >>> c = (x == y)
is also an instance of
Expr. To evaluate and get its value, calleval()method:>>> c.eval() True
Call
strfunction to get a representation of the original equation:>>> str(c) 'x == y'
You can actually compare an expression with a value:
>>> (x == 1).eval() True
Note that you can’t use boolean operators such as
and, as they try to cast expressions to boolean values:>>> z = Variable(1, 'z') >>> x == y and y == z # raises an error Traceback (most recent call last): RuntimeError: Don't convert Expr to bool. Please call Expr.eval method to evaluate expression.
-
chainer.utils.type_check.expect(*bool_exprs)[source]¶ Evaluates and tests all given expressions.
This function evaluates given boolean expressions in order. When at least one expression is evaluated as
False, that means the given condition is not satisfied. You can check conditions with this function.Parameters: bool_exprs (tuple of Bool expressions) – Bool expressions you want to evaluate.
-
class
chainer.utils.type_check.TypeInfo(shape, dtype)[source]¶ Type information of an input/gradient array.
It contains type information of an array, such as the shape of array and the number of dimensions. This information is independent of CPU or GPU array.
Gradient checking utilities¶
Most function implementations are numerically tested by gradient checking.
This method computes numerical gradients of forward routines and compares their results with the corresponding backward routines.
It enables us to make the source of issues clear when we hit an error of gradient computations.
The chainer.gradient_check module makes it easy to implement the gradient checking.
-
chainer.gradient_check.check_backward(func, x_data, y_grad, params=(), eps=0.001, atol=1e-05, rtol=0.0001, no_grads=None, dtype=None)[source]¶ Test backward procedure of a given function.
This function automatically check backward-process of given function. For example, when you have a
FunctionclassMyFunc, that gets two arguments and returns one value, you can make its test like this:>> def test_my_func(self): >> func = MyFunc() >> x1_data = xp.array(...) >> x2_data = xp.array(...) >> gy_data = xp.array(...) >> check_backward(func, (x1_data, x2_data), gy_data)
This method creates
Variableobjects withx_dataand callsfuncwith theVariables to get its result asVariable. Then, it setsy_gradarray togradattribute of the result and callsbackwardmethod to get gradients of the inputs. To check correctness of the gradients, the function callsnumerical_grad()to calculate numerically the gradients and compares the types of gradients withchainer.testing.assert_allclose(). If input objects (x1_dataor/andx2_datain this example) represent integer variables, their gradients are ignored.You can simplify a test when
MyFuncgets only one argument:>> check_backward(func, x1_data, gy_data)
If
MyFuncis a loss function which returns a zero-dimensional array, passNonetogy_data. In this case, it sets1togradattribute of the result:>> check_backward(my_loss_func, (x1_data, x2_data), None)
If
MyFuncreturns multiple outputs, pass all gradients for outputs as a tuple:>> gy1_data = xp.array(...) >> gy2_data = xp.array(...) >> check_backward(func, x1_data, (gy1_data, gy2_data))
You can also test a
Link. To check gradients of parameters of the link, set a tuple of the parameters toparamsarguments:>> check_backward(my_link, (x1_data, x2_data), gy_data, >> (my_link.W, my_link.b))
Note that
paramsare notndarrays, butVariabless.Function objects are acceptable as
funcargument:>> check_backward(lambda x1, x2: f(x1, x2), >> (x1_data, x2_data), gy_data)
Note
funcis called many times to get numerical gradients for all inputs. This function doesn’t work correctly whenfuncbehaves randomly as it gets different gradients.Parameters: - func (callable) – A function which gets
Variables and returnsVariables.funcmust returns a tuple ofVariables or oneVariable. You can useFunctionobject,Linkobject or a function satisfying the condition. - x_data (ndarray or tuple of ndarrays) – A set of
ndarrays to be passed tofunc. Ifx_datais onendarrayobject, it is treated as(x_data,). - y_grad (ndarray or tuple of ndarrays or None) – A set of
ndarrays representing gradients of return-values offunc. Ify_gradis onendarrayobject, it is treated as(y_grad,). Iffuncis a loss-function,y_gradshould be set toNone. - params (Variable or tuple of ~chainder.Variable) – A set of
Variables whose gradients are checked. Whenfuncis aLinkobject, set its parameters asparams. Ifparamsis oneVariableobject, it is treated as(params,). - eps (float) – Epsilon value to be passed to
numerical_grad(). - atol (float) – Absolute tolerance to be passed to
chainer.testing.assert_allclose(). - rtol (float) – Relative tolerance to be passed to
chainer.testing.assert_allclose(). - no_grads (list of bool) – Flag to skip variable for gradient assertion.
It should be same length as
x_data. - dtype (dtype) –
x_dataandy_gradare casted to this dtype when calculating numerical gradients. Only float types andNoneare allowed.
- See:
numerical_grad()
- func (callable) – A function which gets
-
chainer.gradient_check.numerical_grad(f, inputs, grad_outputs, eps=0.001)[source]¶ Computes numerical gradient by finite differences.
This function is used to implement gradient check. For usage example, see unit tests of
chainer.functions.Parameters: - f (function) – Python function with no arguments that runs forward computation and returns the result.
- inputs (tuple of arrays) – Tuple of arrays that should be treated as inputs. Each element of them is slightly modified to realize numerical gradient by finite differences.
- grad_outputs (tuple of arrays) – Tuple of arrays that are treated as output gradients.
- eps (float) – Epsilon value of finite differences.
Returns: Numerical gradient arrays corresponding to
inputs.Return type:
Standard Assertions¶
The assertions have same names as NumPy’s ones.
The difference from NumPy is that they can accept both numpy.ndarray
and cupy.ndarray.
Function testing utilities¶
Chainer provides some utilities for testing its functions.
-
chainer.testing.unary_math_function_unittest(func, func_expected=None, label_expected=None, make_data=None)[source]¶ Decorator for testing unary mathematical Chainer functions.
This decorator makes test classes test unary mathematical Chainer functions. Tested are forward and backward computations on CPU and GPU across parameterized
shapeanddtype.Parameters: - func (Function) – Chainer function to be tested by the decorated test class.
- func_expected – Function used to provide expected values for
testing forward computation. If not given, a corresponsing numpy
function for
funcis implicitly picked up by its class name. - label_expected (string) – String used to test labels of Chainer
functions. If not given, the class name of
funclowered is implicitly used. - make_data – Function to customize input and gradient data used
in the tests. It takes
shapeanddtypeas its arguments, and returns a tuple of input and gradient data. By default, uniform destribution ranged[-1, 1]is used for both.
The decorated test class tests forward and backward computations on CPU and GPU across the following
parameterize()ed parameters:- shape: rank of zero, and rank of more than zero
- dtype:
numpy.float16,numpy.float32andnumpy.float64
Additionally, it tests the label of the Chainer function.
Chainer functions tested by the test class decorated with the decorator should have the following properties:
- Unary, taking one parameter and returning one value
dtypeof input and output are the same- Elementwise operation for the supplied ndarray
Example
The following code defines a test class that tests
sin()Chainer function, which takes a parameter withdtypeof float and returns a value with the samedtype.>>> import unittest >>> from chainer import testing >>> from chainer import functions as F >>> >>> @testing.unary_math_function_unittest(F.Sin()) ... class TestSin(unittest.TestCase): ... pass
Because the test methods are implicitly injected to
TestSinclass by the decorator, it is enough to placepassin the class definition.Now the test is run with
nosemodule.>>> import nose >>> nose.run( ... defaultTest=__name__, argv=['', '-a', '!gpu'], exit=False) True
To customize test data,
make_dataoptional parameter can be used. The following is an example of testingsqrtChainer function, which is tested in positive value domain here instead of the default input.>>> import numpy >>> >>> def make_data(shape, dtype): ... x = numpy.random.uniform(0.1, 1, shape).astype(dtype) ... gy = numpy.random.uniform(-1, 1, shape).astype(dtype) ... return x, gy ... >>> @testing.unary_math_function_unittest(F.Sqrt(), ... make_data=make_data) ... class TestSqrt(unittest.TestCase): ... pass ... >>> nose.run( ... defaultTest=__name__, argv=['', '-a', '!gpu'], exit=False) True
make_datafunction which returns input and gradient data generated in proper value domains with givenshapeanddtypeparameters is defined, then passed to the decorator’smake_dataparameter.