code: def gradient_calc(
      seq_len,
      input_size,
      hidden_size,
      batch_size,
      epsilon=None,
      rand_scale=None,
      inp_bl=None,
  ):
      NervanaObject.be.bsz = NervanaObject.be.batch_size = batch_size
  
      input_shape = (input_size, seq_len * batch_size)
  
      # generate input if one is not given
      if inp_bl is None:
          inp_bl = np.random.randn(*input_shape)
  
      # neon rnn instance
      rnn = Recurrent(hidden_size, Gaussian(), activation=Tanh())
      inpa = rnn.be.array(np.copy(inp_bl))
  
      # run fprop on the baseline input
      rnn.configure((input_size, seq_len))
      rnn.prev_layer = True
      rnn.allocate()
  
      dtree = DeltasTree()
      rnn.allocate_deltas(dtree)
      dtree.allocate_buffers()
      rnn.set_deltas(dtree)
  
      out_bl = rnn.fprop(inpa).get()
  
      # random scaling/hash to generate fake loss
      if rand_scale is None:
          rand_scale = np.random.random(out_bl.shape) * 2.0 - 1.0
      # loss function would be:
      # loss_bl = np.sum(rand_scale * out_bl)
  
      # run back prop with rand_scale as the errors
      # use copy to avoid any interactions
      deltas_neon = rnn.bprop(rnn.be.array(np.copy(rand_scale))).get()
  
      # add a perturbation to each input element
      grads_est = np.zeros(inpa.shape)
      inp_pert = inp_bl.copy()
      for pert_ind in range(inpa.size):
          save_val = inp_pert.flat[pert_ind]
  
          inp_pert.flat[pert_ind] = save_val + epsilon
          reset_rnn(rnn)
          rnn.allocate()
          out_pos = rnn.fprop(rnn.be.array(inp_pert)).get()
  
          inp_pert.flat[pert_ind] = save_val - epsilon
          reset_rnn(rnn)
          rnn.allocate()
          out_neg = rnn.fprop(rnn.be.array(inp_pert)).get()
  
          # calculate the loss with perturbations
          loss_pos = np.sum(rand_scale * out_pos)
          loss_neg = np.sum(rand_scale * out_neg)
          # compute the gradient estimate
          grad = 0.5 * (loss_pos - loss_neg) / epsilon
  
          grads_est.flat[pert_ind] = grad
  
          # reset the perturbed input element
          inp_pert.flat[pert_ind] = save_val
  
      del rnn
      return (grads_est, deltas_neon)
  
file_path: neon/tests/test_recurrent.py
imports: import os
  import pytest
  import subprocess
  import itertools
  import numpy
  from neon import NervanaObject, logger
  from neon.initializers.initializer import Constant, Gaussian
  from neon.layers import Recurrent
  from neon.layers.container import DeltasTree
  from neon.transforms import Tanh
  from recurrent_ref import Recurrent
  from utils import allclose_with_out
label_desc: Use image node_id 8 for calling a global function with example usage: gradient_calc(seq_len, input_size, hidden_size, batch_size, epsilon, rand_scale, inp_bl) and returns: grads_est,  deltas_neon