code: def learn_from_batch(self, batch):
      actor = self.networks["actor"]
      critic = self.networks["critic"]
  
      actor_keys = self.ap.network_wrappers[
          "actor"
      ].input_embedders_parameters.keys()
      critic_keys = self.ap.network_wrappers[
          "critic"
      ].input_embedders_parameters.keys()
  
      # TD error = r + discount*max(q_st_plus_1) - q_st
      next_actions, actions_mean = actor.parallel_prediction(
          [
              (actor.target_network, batch.next_states(actor_keys)),
              (actor.online_network, batch.states(actor_keys)),
          ]
      )
  
      critic_inputs = copy.copy(batch.next_states(critic_keys))
      critic_inputs["action"] = next_actions
      q_st_plus_1 = critic.target_network.predict(critic_inputs)[0]
  
      # calculate the bootstrapped TD targets while discounting terminal states according to
      # use_non_zero_discount_for_terminal_states
      if self.ap.algorithm.use_non_zero_discount_for_terminal_states:
          TD_targets = (
              batch.rewards(expand_dims=True)
              + self.ap.algorithm.discount * q_st_plus_1
          )
      else:
          TD_targets = (
              batch.rewards(expand_dims=True)
              + (1.0 - batch.game_overs(expand_dims=True))
              * self.ap.algorithm.discount
              * q_st_plus_1
          )
  
      # clip the TD targets to prevent overestimation errors
      if self.ap.algorithm.clip_critic_targets:
          TD_targets = np.clip(
              TD_targets, *self.ap.algorithm.clip_critic_targets
          )
  
      self.TD_targets_signal.add_sample(TD_targets)
  
      # get the gradients of the critic output with respect to the action
      critic_inputs = copy.copy(batch.states(critic_keys))
      critic_inputs["action"] = actions_mean
      action_gradients = critic.online_network.predict(
          critic_inputs,
          outputs=critic.online_network.gradients_wrt_inputs[1][
              "action"
          ],
      )
  
      # train the critic
      critic_inputs = copy.copy(batch.states(critic_keys))
      critic_inputs["action"] = batch.actions(
          len(batch.actions().shape) == 1
      )
  
      # also need the inputs for when applying gradients so batchnorm's update of running mean and stddev will work
      result = critic.train_and_sync_networks(
          critic_inputs, TD_targets, use_inputs_for_apply_gradients=True
      )
      total_loss, losses, unclipped_grads = result[:3]
  
      # apply the gradients from the critic to the actor
      initial_feed_dict = {
          actor.online_network.gradients_weights_ph[
              0
          ]: -action_gradients
      }
      gradients = actor.online_network.predict(
          batch.states(actor_keys),
          outputs=actor.online_network.weighted_gradients[0],
          initial_feed_dict=initial_feed_dict,
      )
  
      # also need the inputs for when applying gradients so batchnorm's update of running mean and stddev will work
      if actor.has_global:
          actor.apply_gradients_to_global_network(
              gradients,
              additional_inputs=copy.copy(batch.states(critic_keys)),
          )
          actor.update_online_network()
      else:
          actor.apply_gradients_to_online_network(
              gradients,
              additional_inputs=copy.copy(batch.states(critic_keys)),
          )
  
      return total_loss, losses, unclipped_grads
  
imports: import copy
  from typing import Union
  from collections import OrderedDict
  import numpy
  from rl_coach.agents.actor_critic_agent import ActorCriticAgent
  from rl_coach.agents.agent import Agent
  from rl_coach.architectures.embedder_parameters import InputEmbedderParameters
  from rl_coach.architectures.head_parameters import DDPGActorHeadParameters, DDPGVHeadParameters
  from rl_coach.architectures.middleware_parameters import FCMiddlewareParameters
  from rl_coach.base_parameters import NetworkParameters, AlgorithmParameters, AgentParameters, EmbedderScheme
  from rl_coach.core_types import ActionInfo, EnvironmentSteps
  from rl_coach.exploration_policies.ou_process import OUProcessParameters
  from rl_coach.memories.episodic.episodic_experience_replay import EpisodicExperienceReplayParameters
  from rl_coach.spaces import BoxActionSpace, GoalsSpace
label_desc: Use image node_id 3 for calling the DDPGAgent obj's underlying member method code with example usage: obj.learn_from_batch(batch) and returns: total_loss,  losses,  unclipped_grads