code: def __init__(
      self,
      name,
      game_inputs=None,
      callbacks=None,
      seed=420133769,
      input_shape=None,
      ppo_kwargs=None,
      logger=Loggers.NOOP,
      logger_kwargs=None,
  ):
      super().__init__(
          name,
          game_inputs=game_inputs,
          callbacks=callbacks,
          seed=seed,
          logger=logger,
          logger_kwargs=logger_kwargs,
      )
  
      if len(game_inputs) > 1:
          raise SerpentError(
              "PPOAgent only supports a single axis of game inputs."
          )
  
      if game_inputs[0]["control_type"] != InputControlTypes.DISCRETE:
          raise SerpentError(
              "PPOAgent only supports discrete input spaces"
          )
  
      if torch.cuda.is_available():
          self.device = torch.device("cuda")
  
          torch.set_default_tensor_type("torch.cuda.FloatTensor")
          torch.backends.cudnn.benchmark = True
  
          torch.cuda.manual_seed_all(seed)
      else:
          self.device = torch.device("cpu")
          torch.set_num_threads(1)
  
      torch.manual_seed(seed)
  
      agent_kwargs = dict(
          algorithm="PPO",
          is_recurrent=False,
          surrogate_objective_clip=0.2,
          epochs=4,
          batch_size=32,
          value_loss_coefficient=0.5,
          entropy_regularization_coefficient=0.01,
          learning_rate=0.0001,
          adam_epsilon=0.00001,
          max_grad_norm=0.3,
          memory_capacity=1024,
          discount=0.99,
          gae=False,
          gae_tau=0.95,
          save_steps=10000,
          model=f"datasets/ppo_{self.name}.pth",
          seed=seed,
      )
  
      if isinstance(ppo_kwargs, dict):
          for key, value in ppo_kwargs.items():
              if key in agent_kwargs:
                  agent_kwargs[key] = value
  
      self.discount = agent_kwargs["discount"]
  
      self.gae = agent_kwargs["gae"]
      self.gae_tau = agent_kwargs["gae_tau"]
  
      input_shape = (
          4,
          input_shape[0],
          input_shape[1],
      )  # 4x Grayscale OR Quantized
  
      self.actor_critic = Policy(
          input_shape,
          len(self.game_inputs[0]["inputs"]),
          agent_kwargs["is_recurrent"],
      )
  
      if torch.cuda.is_available():
          self.actor_critic.cuda(device=self.device)
  
      self.agent = PPO(
          self.actor_critic,
          agent_kwargs["surrogate_objective_clip"],
          agent_kwargs["epochs"],
          agent_kwargs["batch_size"],
          agent_kwargs["value_loss_coefficient"],
          agent_kwargs["entropy_regularization_coefficient"],
          lr=agent_kwargs["learning_rate"],
          eps=agent_kwargs["adam_epsilon"],
          max_grad_norm=agent_kwargs["max_grad_norm"],
      )
  
      self.storage = RolloutStorage(
          agent_kwargs["memory_capacity"],
          1,
          input_shape,
          len(self.game_inputs[0]["inputs"]),
          self.actor_critic.state_size,
      )
  
      if torch.cuda.is_available():
          self.storage.cuda(device=self.device)
  
      self.current_episode = 1
      self.current_step = 0
  
      self.mode = PPOAgentModes.TRAIN
  
      self.save_steps = agent_kwargs["save_steps"]
  
      self.model_path = agent_kwargs["model"]
  
      if os.path.isfile(self.model_path):
          self.restore_model()
  
      self.logger.log_hyperparams(agent_kwargs)
  
file_path: SerpentAI/serpent/machine_learning/reinforcement_learning/agents/ppo_agent.py
imports: from serpent.machine_learning.reinforcement_learning.agent import Agent
  from serpent.game_frame import GameFrame
  from serpent.game_frame_buffer import GameFrameBuffer
  from serpent.enums import InputControlTypes
  from serpent.logger import Loggers
  from serpent.utilities import SerpentError
  import os
  import enum
  import copy
  import json
  import numpy
label_desc: Use image node_id 1 to create a new PPOAgent object from inherited base classes: Agent with example: obj = PPOAgent(name, game_inputs, callbacks, seed, input_shape, ppo_kwargs, logger, logger_kwargs)