class_docstr: Write me
      
code: def backward(self, reward, terminal):
      metrics = [np.nan for _ in self.metrics_names]
      if not self.training:
          # We're done here. No need to update the experience memory since we only use the working
          # memory to obtain the state over the most recent observations.
          return metrics
  
      # Train the network on a single stochastic batch.
      if (
          self.step > self.nb_steps_warmup
          and self.step % self.train_interval == 0
      ):
          # Start by extracting the necessary parameters (we use a vectorized implementation).
          self.rewards.append(reward)
          if len(self.observations) < 2:
              return metrics  # not enough data yet
  
          state0_batch = [self.observations[0]]
          reward_batch = [self.rewards[0]]
          action_batch = [self.actions[0]]
          terminal1_batch = [0.0] if terminal else [1.0]
          state1_batch = [self.observations[1]]
          action1_batch = [self.actions[1]]
  
          # Prepare and validate parameters.
          state0_batch = self.process_state_batch(state0_batch)
          state1_batch = self.process_state_batch(state1_batch)
          terminal1_batch = np.array(terminal1_batch)
          reward_batch = np.array(reward_batch)
          assert reward_batch.shape == (1,)
          assert terminal1_batch.shape == reward_batch.shape
          assert len(action_batch) == len(reward_batch)
  
          batch = self.process_state_batch(state1_batch)
          q_values = self.compute_q_values(batch)
          q_values = q_values.reshape((1, self.nb_actions))
  
          q_batch = q_values[0, action1_batch]
  
          assert q_batch.shape == (1,)
          targets = np.zeros((1, self.nb_actions))
          dummy_targets = np.zeros((1,))
          masks = np.zeros((1, self.nb_actions))
  
          # Compute r_t + gamma * Q(s_t+1, a_t+1)
          discounted_reward_batch = self.gamma * q_batch
          # Set discounted reward to zero for all states that were terminal.
          discounted_reward_batch *= terminal1_batch
          assert discounted_reward_batch.shape == reward_batch.shape
          Rs = reward_batch + discounted_reward_batch
          for idx, (target, mask, R, action) in enumerate(
              zip(targets, masks, Rs, action_batch)
          ):
              target[
                  action
              ] = R  # update action with estimated accumulated reward
              dummy_targets[idx] = R
              mask[action] = 1.0  # enable loss for this specific action
          targets = np.array(targets).astype("float32")
          masks = np.array(masks).astype("float32")
  
          # Finally, perform a single update on the entire batch. We use a dummy target since
          # the actual loss is computed in a Lambda layer that needs more complex input. However,
          # it is still useful to know the actual target to compute metrics properly.
          state0_batch = state0_batch.reshape((1,) + state0_batch.shape)
          ins = (
              [state0_batch]
              if type(self.model.input) is not list
              else state0_batch
          )
          metrics = self.trainable_model.train_on_batch(
              ins + [targets, masks], [dummy_targets, targets]
          )
          metrics = [
              metric
              for idx, metric in enumerate(metrics)
              if idx not in (1, 2)
          ]  # throw away individual losses
          metrics += self.policy.metrics
          if self.processor is not None:
              metrics += self.processor.metrics
      return metrics
  
imports: import collections
  import numpy
  from keras.callbacks import History
  from keras.models import Model
  from keras.layers import Input, Lambda
  import keras.backend
  from rl.core import Agent
  from rl.agents.dqn import mean_q
  from rl.util import huber_loss
  from rl.policy import EpsGreedyQPolicy, GreedyQPolicy
  from rl.util import get_object_config
label_desc: Use image node_id 11 for calling the SARSAAgent obj's underlying member method code with example usage: obj.backward(reward, terminal) and returns: metrics, metrics, metrics