class_docstr: **Base class for Variational Inference**
  
  Communicates Operator, Approximation and Test Function to build Objective Function
  
  Parameters
  ----------
  op : Operator class    #:class:`~pymc.variational.operators`
  approx : Approximation class or instance    #:class:`~pymc.variational.approximations`
  tf : TestFunction instance  #?
  model : Model
      PyMC Model
  kwargs : kwargs passed to :class:`Operator` #:class:`~pymc.variational.operators`, optional
docstr: Perform Operator Variational Inference
  
  Parameters
  ----------
  n : int
      number of iterations
  score : bool
      evaluate loss on each iteration or not
  callbacks : list[function: (Approximation, losses, i) -> None]
      calls provided functions after each iteration step
  progressbar : bool
      whether to show progressbar or not
  
  Other Parameters
  ----------------
  obj_n_mc: int
      Number of monte carlo samples used for approximation of objective gradients
  tf_n_mc: `int`
      Number of monte carlo samples used for approximation of test function gradients
  obj_optimizer: function (grads, params) -> updates
      Optimizer that is used for objective params
  test_optimizer: function (grads, params) -> updates
      Optimizer that is used for test function params
  more_obj_params: `list`
      Add custom params for objective optimizer
  more_tf_params: `list`
      Add custom params for test function optimizer
  more_updates: `dict`
      Add custom updates to resulting updates
  total_grad_norm_constraint: `float`
      Bounds gradient norm, prevents exploding gradient problem
  fn_kwargs: `dict`
      Add kwargs to pytensor.function (e.g. `{'profile': True}`)
  more_replacements: `dict`
      Apply custom replacements before calculating gradients
  
  Returns
  -------
  :class:`Approximation`
docstr_tok: ["Perform","Operator","Variational","Inference","Parameters","--","--","--","--","--","n",":","int","number","of","iterations","score",":","bool","evaluate","loss","on","each","iteration","or","not","callbacks",":","list","[","function",":","(","Approximation",",","losses",",","i",")","-",">","None","]","calls","provided","functions","after","each","iteration","step","progressbar",":","bool","whether","to","show","progressbar","or","not","Other","Parameters","--","--","--","--","--","--","--","--","obj_n_mc",":","int","Number","of","monte","carlo","samples","used","for","approximation","of","objective","gradients","tf_n_mc",":","`","int","`","Number","of","monte","carlo","samples","used","for","approximation","of","test","function","gradients","obj_optimizer",":","function","(","grads",",","params",")","-",">","updates","Optimizer","that","is","used","for","objective","params","test_optimizer",":","function","(","grads",",","params",")","-",">","updates","Optimizer","that","is","used","for","test","function","params","more_obj_params",":","`","list","`","Add","custom","params","for","objective","optimizer","more_tf_params",":","`","list","`","Add","custom","params","for","test","function","optimizer","more_updates",":","`","dict","`","Add","custom","updates","to","resulting","updates","total_grad_norm_constraint",":","`","float","`","Bounds","gradient","norm",",","prevents","exploding","gradient","problem","fn_kwargs",":","`","dict","`","Add","kwargs","to","pytensor.function","(","e.g",".","`","{","'profile","'",":","True","}","`",")","more_replacements",":","`","dict","`","Apply","custom","replacements","before","calculating","gradients","Returns","--","--","--","-",":","class",":","`","Approximation","`"]
code: def fit(
      self,
      n=10000,
      score=None,
      callbacks=None,
      progressbar=True,
      **kwargs,
  ):
      """Perform Operator Variational Inference
  
      Parameters
      ----------
      n : int
          number of iterations
      score : bool
          evaluate loss on each iteration or not
      callbacks : list[function: (Approximation, losses, i) -> None]
          calls provided functions after each iteration step
      progressbar : bool
          whether to show progressbar or not
  
      Other Parameters
      ----------------
      obj_n_mc: int
          Number of monte carlo samples used for approximation of objective gradients
      tf_n_mc: `int`
          Number of monte carlo samples used for approximation of test function gradients
      obj_optimizer: function (grads, params) -> updates
          Optimizer that is used for objective params
      test_optimizer: function (grads, params) -> updates
          Optimizer that is used for test function params
      more_obj_params: `list`
          Add custom params for objective optimizer
      more_tf_params: `list`
          Add custom params for test function optimizer
      more_updates: `dict`
          Add custom updates to resulting updates
      total_grad_norm_constraint: `float`
          Bounds gradient norm, prevents exploding gradient problem
      fn_kwargs: `dict`
          Add kwargs to pytensor.function (e.g. `{'profile': True}`)
      more_replacements: `dict`
          Apply custom replacements before calculating gradients
  
      Returns
      -------
      :class:`Approximation`
      """
      if callbacks is None:
          callbacks = []
      score = self._maybe_score(score)
      step_func = self.objective.step_function(score=score, **kwargs)
      if progressbar:
          progress = progress_bar(range(n), display=progressbar)
      else:
          progress = range(n)
      if score:
          state = self._iterate_with_loss(
              0, n, step_func, progress, callbacks
          )
      else:
          state = self._iterate_without_loss(
              0, n, step_func, progress, callbacks
          )
  
      # hack to allow pm.fit() access to loss hist
      self.approx.hist = self.hist
      self.state = state
  
      return self.approx
  
imports: import collections
  import logging
  import warnings
  import numpy
  from fastprogress.fastprogress import progress_bar
  import pymc
  from pymc.variational import test_functions
  from pymc.variational.approximations import Empirical, FullRank, MeanField
  from pymc.variational.operators import KL, KSD
label_desc: Use image node_id 4 for calling the Inference obj's underlying member method code with example usage: obj.fit(n, score, callbacks, progressbar) and returns: self