class_docstr: References:
  ===========
      - https://towardsdatascience.com/deep-reinforcement-learning-build-a-deep-q-network-dqn-to-play-cartpole-with-tensorflow-2-and-gym-8e105744b998
      - https://pytorch.org/tutorials/intermediate/reinforcement_q_learning.html#dqn-algorithm
      - https://arxiv.org/abs/1802.00308
code: def train(
      self,
      n_steps: int = 1000,
      n_episodes: int = 10,
      save_every: int = None,
      save_path: str = "agent/",
      callback: callable = None,
      **kwargs,
  ) -> float:
      batch_size: int = kwargs.get("batch_size", 256)
      memory_capacity: int = kwargs.get("memory_capacity", n_steps * 10)
      discount_factor: float = kwargs.get("discount_factor", 0.95)
      learning_rate: float = kwargs.get("learning_rate", 0.01)
      eps_start: float = kwargs.get("eps_start", 0.9)
      eps_end: float = kwargs.get("eps_end", 0.05)
      eps_decay_steps: int = kwargs.get("eps_decay_steps", n_steps)
      update_target_every: int = kwargs.get("update_target_every", 1000)
      render_interval: int = kwargs.get(
          "render_interval", n_steps // 10
      )  # in steps, None for episode end renderers only
  
      memory = ReplayMemory(
          memory_capacity, transition_type=DQNTransition
      )
      episode = 0
      total_steps_done = 0
      total_reward = 0
      stop_training = False
  
      if n_steps and not n_episodes:
          n_episodes = np.iinfo(np.int32).max
  
      print("====      AGENT ID: {}      ====".format(self.id))
  
      while episode < n_episodes and not stop_training:
          state = self.env.reset()
          done = False
          steps_done = 0
  
          while not done:
              threshold = eps_end + (eps_start - eps_end) * np.exp(
                  -total_steps_done / eps_decay_steps
              )
              action = self.get_action(state, threshold=threshold)
              next_state, reward, done, _ = self.env.step(action)
  
              memory.push(state, action, reward, next_state, done)
  
              state = next_state
              total_reward += reward
              steps_done += 1
              total_steps_done += 1
  
              if len(memory) < batch_size:
                  continue
  
              self._apply_gradient_descent(
                  memory, batch_size, learning_rate, discount_factor
              )
  
              if n_steps and steps_done >= n_steps:
                  done = True
  
              if (
                  render_interval is not None
                  and steps_done % render_interval == 0
              ):
                  self.env.render(
                      episode=episode,
                      max_episodes=n_episodes,
                      max_steps=n_steps,
                  )
  
              if steps_done % update_target_every == 0:
                  self.target_network = tf.keras.models.clone_model(
                      self.policy_network
                  )
                  self.target_network.trainable = False
  
          is_checkpoint = save_every and episode % save_every == 0
  
          if save_path and (is_checkpoint or episode == n_episodes - 1):
              self.save(save_path, episode=episode)
  
          if not render_interval or steps_done < n_steps:
              self.env.render(
                  episode=episode,
                  max_episodes=n_episodes,
                  max_steps=n_steps,
              )  # renderers final state at episode end if not rendered earlier
  
          self.env.save()
  
          episode += 1
  
      mean_reward = total_reward / steps_done
  
      return mean_reward
  
file_path: tensortrade/tensortrade/agents/dqn_agent.py
imports: from deprecated import deprecated
  import random
  import numpy
  import tensorflow
  from collections import namedtuple
  from tensortrade.agents import Agent, ReplayMemory
  from datetime import datetime
label_desc: Use image node_id 7 for calling the DQNAgent obj's underlying member method code with example usage: obj.train(n_steps, n_episodes, save_every, save_path, callback) and returns: mean_reward