| 28 | return J |
| 29 | |
| 30 | def numerical_jacobian(func, input, eps = 1e-3): |
| 31 | output = func(input) |
| 32 | |
| 33 | ji = input.numpy().reshape(-1).shape[-1] |
| 34 | jo = output.numpy().reshape(-1).shape[-1] |
| 35 | NJ = np.zeros((jo, ji), dtype=np.float32) |
| 36 | |
| 37 | for i in range(ji): |
| 38 | eps_perturb = mask_like(input, i, mask_value = eps) |
| 39 | |
| 40 | output_perturb_add = func(Tensor(input.numpy() + eps_perturb)).numpy().reshape(-1) |
| 41 | output_perturb_sub = func(Tensor(input.numpy() - eps_perturb)).numpy().reshape(-1) |
| 42 | |
| 43 | grad_approx = ((output_perturb_add) - (output_perturb_sub)) / (2*eps) |
| 44 | |
| 45 | NJ[:,i] = grad_approx |
| 46 | return NJ |
| 47 | |
| 48 | def gradcheck(func, input, eps = 1e-3, atol = 1e-3, rtol = 1e-3): |
| 49 | NJ = numerical_jacobian(func, input, eps) |