code: def rmsprop(
      loss_or_grads=None,
      params=None,
      learning_rate=1.0,
      rho=0.9,
      epsilon=1e-6,
  ):
      """RMSProp updates
  
      Scale learning rates by dividing with the moving average of the root mean
      squared (RMS) gradients. See [1]_ for further description.
  
      Parameters
      ----------
      loss_or_grads: symbolic expression or list of expressions
          A scalar loss expression, or a list of gradient expressions
      params: list of shared variables
          The variables to generate update expressions for
      learning_rate: float or symbolic scalar
          The learning rate controlling the size of update steps
      rho: float or symbolic scalar
          Gradient moving average decay factor
      epsilon: float or symbolic scalar
          Small value added for numerical stability
  
      Returns
      -------
      OrderedDict
          A dictionary mapping each parameter to its update expression
  
      Notes
      -----
      `rho` should be between 0 and 1. A value of `rho` close to 1 will decay the
      moving average slowly and a value close to 0 will decay the moving average
      fast.
  
      Using the step size :math:`\\eta` and a decay factor :math:`\\rho` the
      learning rate :math:`\\eta_t` is calculated as:
  
      .. math::
         r_t &= \\rho r_{t-1} + (1-\\rho)*g^2\\\\
         \\eta_t &= \\frac{\\eta}{\\sqrt{r_t + \\epsilon}}
  
  
      Optimizer can be called without both loss_or_grads and params
      in that case partial function is returned
  
      References
      ----------
      .. [1] Tieleman, at. and Hinton, G. (2012):
             Neural Networks for Machine Learning, Lecture 6.5 - rmsprop.
             Coursera. http://www.youtube.com/watch?v=O3sxAc4hxZU (formula @5:20)
  
      Examples
      --------
      >>> a = pytensor.shared(1.)
      >>> b = a*2
      >>> updates = rmsprop(b, [a], learning_rate=.01)
      >>> isinstance(updates, dict)
      True
      >>> optimizer = rmsprop(learning_rate=.01)
      >>> callable(optimizer)
      True
      >>> updates = optimizer(b, [a])
      >>> isinstance(updates, dict)
      True
      """
      if loss_or_grads is None and params is None:
          return partial(rmsprop, **_get_call_kwargs(locals()))
      elif loss_or_grads is None or params is None:
          raise ValueError(
              "Please provide both `loss_or_grads` and `params` to get updates"
          )
      grads = get_or_compute_grads(loss_or_grads, params)
      updates = OrderedDict()
  
      # Using pytensor constant to prevent upcasting of float32
      one = pt.constant(1)
  
      for param, grad in zip(params, grads):
          value = param.get_value(borrow=True)
          accu = pytensor.shared(
              np.zeros(value.shape, dtype=value.dtype),
              shape=param.type.shape,
          )
          accu_new = rho * accu + (one - rho) * grad**2
          updates[accu] = accu_new
          updates[param] = param - (
              learning_rate * grad / pt.sqrt(accu_new + epsilon)
          )
  
      return updates
  
imports: from collections import OrderedDict
  from functools import partial
  import numpy
  import pytensor
  import pytensor.tensor
  import pymc
label_desc: Use image node_id 10 for calling a global function with example usage: rmsprop(loss_or_grads, params, learning_rate, rho, epsilon) and returns: updates, partial