DaSE-Computer-Vision-2021
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.9 KiB

  1. from __future__ import print_function
  2. from builtins import range
  3. from past.builtins import xrange
  4. import numpy as np
  5. from random import randrange
  6. def eval_numerical_gradient(f, x, verbose=True, h=0.00001):
  7. """
  8. a naive implementation of numerical gradient of f at x
  9. - f should be a function that takes a single argument
  10. - x is the point (numpy array) to evaluate the gradient at
  11. """
  12. fx = f(x) # evaluate function value at original point
  13. grad = np.zeros_like(x)
  14. # iterate over all indexes in x
  15. it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
  16. while not it.finished:
  17. # evaluate function at x+h
  18. ix = it.multi_index
  19. oldval = x[ix]
  20. x[ix] = oldval + h # increment by h
  21. fxph = f(x) # evalute f(x + h)
  22. x[ix] = oldval - h
  23. fxmh = f(x) # evaluate f(x - h)
  24. x[ix] = oldval # restore
  25. # compute the partial derivative with centered formula
  26. grad[ix] = (fxph - fxmh) / (2 * h) # the slope
  27. if verbose:
  28. print(ix, grad[ix])
  29. it.iternext() # step to next dimension
  30. return grad
  31. def eval_numerical_gradient_array(f, x, df, h=1e-5):
  32. """
  33. Evaluate a numeric gradient for a function that accepts a numpy
  34. array and returns a numpy array.
  35. """
  36. grad = np.zeros_like(x)
  37. it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
  38. while not it.finished:
  39. ix = it.multi_index
  40. oldval = x[ix]
  41. x[ix] = oldval + h
  42. pos = f(x).copy()
  43. x[ix] = oldval - h
  44. neg = f(x).copy()
  45. x[ix] = oldval
  46. grad[ix] = np.sum((pos - neg) * df) / (2 * h)
  47. it.iternext()
  48. return grad
  49. def eval_numerical_gradient_blobs(f, inputs, output, h=1e-5):
  50. """
  51. Compute numeric gradients for a function that operates on input
  52. and output blobs.
  53. We assume that f accepts several input blobs as arguments, followed by a
  54. blob where outputs will be written. For example, f might be called like:
  55. f(x, w, out)
  56. where x and w are input Blobs, and the result of f will be written to out.
  57. Inputs:
  58. - f: function
  59. - inputs: tuple of input blobs
  60. - output: output blob
  61. - h: step size
  62. """
  63. numeric_diffs = []
  64. for input_blob in inputs:
  65. diff = np.zeros_like(input_blob.diffs)
  66. it = np.nditer(input_blob.vals, flags=['multi_index'],
  67. op_flags=['readwrite'])
  68. while not it.finished:
  69. idx = it.multi_index
  70. orig = input_blob.vals[idx]
  71. input_blob.vals[idx] = orig + h
  72. f(*(inputs + (output,)))
  73. pos = np.copy(output.vals)
  74. input_blob.vals[idx] = orig - h
  75. f(*(inputs + (output,)))
  76. neg = np.copy(output.vals)
  77. input_blob.vals[idx] = orig
  78. diff[idx] = np.sum((pos - neg) * output.diffs) / (2.0 * h)
  79. it.iternext()
  80. numeric_diffs.append(diff)
  81. return numeric_diffs
  82. def eval_numerical_gradient_net(net, inputs, output, h=1e-5):
  83. return eval_numerical_gradient_blobs(lambda *args: net.forward(),
  84. inputs, output, h=h)
  85. def grad_check_sparse(f, x, analytic_grad, num_checks=10, h=1e-5):
  86. """
  87. sample a few random elements and only return numerical
  88. in this dimensions.
  89. """
  90. for i in range(num_checks):
  91. ix = tuple([randrange(m) for m in x.shape])
  92. oldval = x[ix]
  93. x[ix] = oldval + h # increment by h
  94. fxph = f(x) # evaluate f(x + h)
  95. x[ix] = oldval - h # increment by h
  96. fxmh = f(x) # evaluate f(x - h)
  97. x[ix] = oldval # reset
  98. grad_numerical = (fxph - fxmh) / (2 * h)
  99. grad_analytic = analytic_grad[ix]
  100. rel_error = (abs(grad_numerical - grad_analytic) /
  101. (abs(grad_numerical) + abs(grad_analytic)))
  102. print('numerical: %f analytic: %f, relative error: %e'
  103. %(grad_numerical, grad_analytic, rel_error))